Interaction
The Interaction capability answers how user input becomes semantic canvas behavior. It sits above the Renderer Runtime and consumes backend-neutral Input and Hit Results. Stable Document changes still go through Command/Kernel, while stable Selection and Viewport changes still go through Session.
Current delivery
| Layer | Package | Responsibility |
|---|---|---|
| Value contract | @nodebraid/interaction-api | Immutable Node Drag, Viewport Pan, Box Selection, and Connection Preview Projections |
| Port capability | @nodebraid/plugin-port | Node/domain Contributions resolved into revision-bound Port Snapshots |
| Runtime behavior | @nodebraid/plugin-interaction | Selection, Box Selection, Delete Selection, Drag, Pan, Zoom, and Port-aware/node-level Connection |
| Duplicate behavior | @nodebraid/plugin-duplicate-selection | Independent Duplicate Command, ID materialization, subgraph copy, and Ctrl/Cmd+D Binding |
| Clipboard behavior | @nodebraid/plugin-clipboard | Copy/Paste Commands with application-owned codec/transport and Ctrl/Cmd+C / Ctrl/Cmd+V Bindings |
| Projection adapter | @nodebraid/plugin-renderer | Exclusive Interaction Projection Binding and Renderer synchronization |
| Reference backend | @nodebraid/renderer-svg | Preview on real SVG geometry with aligned Hit/Input coordinates |
Renderer Input + Hit Result
│
▼
Interaction Runtime
├── Preview ─────────▶ Interaction Projection Binding
├── Selection/Viewport ▶ Session Service
└── final Node moves ─▶ Move Nodes Command ─▶ KernelBehavioral boundaries
- Pointer move updates only the Projection; it does not continuously write Kernel or Session.
- A primary-pointer drag from empty Canvas space creates a World Rect Box Selection. Pointerup evaluates current Node geometry and updates Session without a Transaction or History entry.
- Node Drag executes
interaction.nodes.moveonce on pointerup. One Transaction naturally creates at most one History Entry. - Mouse Connection uses Renderer-owned Node-level Anchors, an application Edge materializer, and one
interaction.edge.createTransaction. - When the Renderer owns Focus and no Active Gesture exists, Delete executes
interaction.selection.delete: explicit and incident Edges are removed before selected Nodes, naturally forming one undoable and redoable History Entry. - The independent Duplicate Selection Plugin executes
selection.duplicateover the selected-Node induced subgraph. The application provides only a complete ID mapping, while Ctrl/Cmd+D reaches the same Command through an Interaction Shortcut Binding. - The Clipboard Plugin reuses the same subgraph semantics through
@nodebraid/canvas-fragment. Copy captures one committed Fragment; Paste materializes it in one Transaction and then updates Selection. The application explicitly owns the text codec,navigator.clipboardAdapter, and opaque data rules. - Middle button or Space+primary can establish Pan. Wheel Zoom is anchored to a Screen Point and bounded by explicit configuration.
- One Activation owns one Gesture Pointer. Additional Pointers, Wheel during a Gesture, pointer cancellation, lost capture, and stale evidence all have explicit semantics and diagnostics.
- Dependency loss or Plugin unload stops input, clears Preview, releases Capture, clears local state, and unregisters the Command. Recovery creates a fresh idle Activation.
Non-goals
The first Clipboard version excludes Serialized Document, Persistence, cross-version text promises, HTML/image formats, rich text, and a generic JSON codec. Existing Connection, Box Selection, and Delete Selection non-goals remain unchanged. Pinch/touch tools, HTML overlays, text editing, collaboration presence, product UI, and a generic Tool Registry also remain out of scope.
Verification
The successful path composes the real Plugin Host, Kernel, Command, Session, Renderer, History, and SVG Provider in Chromium. Structural, recovery, and cleanup faults are injected only through public seams; a fake Renderer does not certify successful Selection, Drag, Pan, Zoom, or Capture behavior.