node-graph
Reusable node-graph editor shell. Schema-agnostic — consumed bypanels/modular/ (Songbird Modular DSP graph), and designed for a
future video-compositing editor to mount as well. See the modular
plan §4.1 in handoffs/future/2026-05-12-songbird-modular.md.
What it owns
NodeGraphCanvas.tsx— the layout + viewport-state owner + pointer state machine. Hosts the world-space transformed layer and routes pointer events to pan / drag / cable-drag.NodeBlock.tsx— one block: header, port columns, param widgets. Param widgets pick fromKnob(linear/log) orStyledSelect(stepped) based onParamMeta.taper.Cables.tsx— SVG cubic-Bezier cables between port world positions plus the dashed ghost cable while dragging.AddNodeMenu.tsx— searchable, category-grouped popover for the ”+ Add node” button.portLayout.ts— pure math for port world positions and cable paths. Splits flat port lists into directional columns.types.ts— the contract:NodeMeta,PortMeta,ParamMeta,ConnectionPlacement,NodePlacement,NodeGraphHandlers,Viewport.createGraphStore— Zustand factory for viewport, selection, and drag-in-flight state. Each panel gets its own store instance.
What it doesn’t own
- Sync engine integration — the consumer wires
NodeGraphHandlersto its sync commands. - Per-node custom UIs and visualisers — passed in via
nodeUiRegistry/visualiserRegistryprops. - Side drawers (template browsers, inspectors) — passed in via the
drawerSlotprop.
Status
Phase 2c (this commit): pan/zoom/drag, cable drag-and-drop with SVG ghost preview, real param widgets (Knob / StyledSelect), and a searchable add-node popover. All DOM — no GL layer yet. Phase 2d (next): TSL cables in a single global R3F Canvas behind the DOM blocks; per-node TSL visualisers via drei<View>
mounted by template-id world rects.
Tests
cargo test doesn’t cover React — use ./utils/validate vitest for
unit tests next to components, and ./utils/validate ts for type
checks.