@gdsf/editor (livedough)
VSCode extension providing an interactive 2D photonic layout editor with live constraint optimization.
Running
- Open the repo root in VSCode
- Press F5 to launch the Extension Development Host
- Cmd+Shift+P -> "Livedough: Open Routing Editor"
Controls
| Key / Action |
Effect |
| V |
Select tool — click to select, drag vertices or instances |
| I |
Add Instance — click to place a new component |
| R |
Add Route — click a source port, then a target port |
| Right-click route |
Edit bend parameters (width, radius, euler P, bend type, manhattan toggle, vertex count) |
| Scroll |
Zoom |
| Middle-click drag |
Pan |
| Delete / Backspace |
Remove selected instance or route |
| Escape |
Cancel current tool |
Architecture
src/
extension/
extension.ts VSCode extension host (webview panel lifecycle)
webview/
main.ts Frame loop: input -> optimizer -> render
types.ts Webview-specific types
scene/
scene.ts Demo scene creation + state management
hit-test.ts Spatial picking for selection
input/
input-state.ts Mouse/keyboard state tracking
tools.ts Tool mode handlers (select, add-instance, add-route)
ui/
context-menu.ts Right-click menus for instances and route bends
Frame loop (dirty-flag guarded)
requestAnimationFrame:
if scene.dirty:
1. enforceRouteConstraints(scene) TS: only dirty routes (manhattan H/V, terminal clamping)
2. snapToGrid(scene) TS: only dirty vertices + their instances
3. checkSpacingIncremental(dirtySegments) TS: rebuild hash, narrow-phase only dirty neighborhoods
4. expandBendIndicators(...) TS: full re-expand (cheap linear scan)
5. clear dirty flags
always:
6. 6 instanced draw calls WebGL2: grid, routes+bends, textures, SDF, labels, port triangles, vertex handles
All expensive per-frame work (constraint enforcement, grid snap, DRC spacing, bend indicators) is skipped when nothing changed. Mutations record which specific segments are dirty for incremental recomputation.
Routing
- Manhattan mode: toggled per-route via context menu. All segments follow strict H/V/H/V alternation. Segments are dragged as fragments (both endpoints move on the constrained axis). Terminal segment drag also moves the attached instance.
- Free mode: only terminal segments are locked to port orientation; interior vertices move freely.
- Terminal clamping: vertex 1 (and vertex 2) cannot cross behind the port plane, preventing segment inversion.
- Default vertex count: derived from port orientations — opposite ports → 2 (S-bend), orthogonal → 1 (L-bend), same direction → 4 (U-turn).
- PDK grid snap: configurable grid pitch (default 0.005 µm / 5 nm). Only dirty vertices and their instances are snapped.
Bend indicators
- Arc overlays shown only during route selection or instance/segment dragging (reduces clutter for bundles).
- Euler bends use a precomputed Reff/Rmin lookup table with bilinear interpolation for accurate effective radius.
- Segment violation thresholds: terminal segments at 1× effective radius, intermediate segments at 2×.
- Euler P parameter hidden in context menu when circular bend type is selected.
Live DRC spacing
- Inter-route spacing violations via spatial hash broad phase + general segment-to-segment narrow phase.
- Incremental: only dirty segments and their previous violation partners are rechecked. Hash is rebuilt cheaply (O(S), pre-allocated buffers); narrow phase runs only on dirty neighborhoods.
- Violating segments colored bright red; double-headed red arrows drawn between waveguide surfaces (not centerlines) showing the gap.
- Configurable
minGap (default 1 µm). Violation threshold: halfWidth_i + halfWidth_j + minGap.
- Scales to thousands of segments via 4096-bucket spatial hash with linked-list chaining.
Both WASM modules (playdough-wasm for optimization, sax-wasm for circuit simulation) are inlined as data URLs in the bundle via esbuild's .wasm dataurl loader, avoiding path resolution issues in the VSCode webview sandbox.