High‑frequency interaction & manipulation layer for the RenderX Canvas. Whereas `@renderx-plugins/canvas` owns the visual shell, this plugin implements (or will house) the performance‑sensitive handlers and symphonies that mutate component state, coordina
@renderx-plugins/canvas owns the visual shell, this plugin implements (or will house) the performance‑sensitive handlers and symphonies that mutate component state, coordinate selection, and broker export / import lifecycles.
canvas.component.selection.changed; idempotent register to avoid duplicate listeners |
canvas.component.export*) with element existence validation |
.ui (or future format) ingestion | Topic canvas.component.import.requested enabling pluggable parsers |
perf.cp.*) | Feature flag gating; deferred Control Panel rerender scheduling |
EventRouter; fallback to direct resolveInteraction() ensuring resilience if routing plugin order changes.
register(conductor) sets a private sentinel; safe for multiple calls by host bootstraps or hot reload.
NODE_ENV=test coalescing shortcuts are disabled for predictable unit specs.
ts
import { register } from '@renderx-plugins/canvas-component';
// After migration:
import { handlers as dragHandlers } from '@renderx-plugins/canvas-component/symphonies/drag';
`
Local (staging) name: @renderx-plugins/canvas-component-local.
$3
Sets _canvasComponentRegistered on the conductor to avoid duplicate subscription / mounting logic. Currently defers sequence mounting to JSON catalogs (keeping boot cost low).
Drag Interaction Deep Dive (Example)
The drag symphony:
- Publishes lightweight topics for start / move / end (canvas.component.drag.*).
- Falls back to direct interaction play if the router is unavailable.
- Caches resolved interaction routes to avoid repeating expensive resolution during high‑frequency movement.
- Applies microtask‑first flush for the first update, then rAF scheduling to balance latency vs. paint timing.
- Channels Control Panel update requests through a single coalesced dispatch per frame.
Extending With a New Symphony
1. Create src/symphonies/.
2. Export a stable handlers object (pure functions where possible).
3. Add any sequence definitions to JSON catalogs (if runtime mounted) or route keys consumed by other plugins.
4. Expose via subpath export (./symphonies/*).
5. Add focused tests (happy path + high‑frequency stress scenario).
Event & Interaction Keys (Representative)
| Purpose | Topic / Interaction Key |
| ------- | ----------------------- |
| Drag start notification | canvas.component.drag.start |
| Drag move stream | canvas.component.drag.move |
| Drag end notification | canvas.component.drag.end |
| Selection changed | canvas.component.selection.changed |
| Component drop request | library.component.drop.requested |
| Container drop request | library.container.drop.requested |
| Export (generic) | canvas.component.export (resolved) |
| Export GIF | canvas.component.export.gif |
| Export MP4 | canvas.component.export.mp4 |
| Import request | canvas.component.import.requested |
Performance Flags (Illustrative)
| Flag | Effect |
| ---- | ------ |
| perf.cp.debug | Enables verbose console diagnostics for drag lifecycle. |
| perf.cp.render.dedupe | Allows deferred Control Panel rerender after drag end. |
| perf.microtaskFirstUpdate (planned) | Toggle microtask-first coalescing strategy. |
Source Layout (During Extraction)
src/symphonies/ currently re-exports legacy implementations from plugins/canvas-component/. Each will be inlined here so the package becomes self-contained.
Roadmap
- Inline all legacy handler code (remove deep relative exports).
- Add resize + rotate symphonies.
- Introduce snapping grid & alignment guides (consumer opt-in events).
- Structured telemetry hooks (duration, frame skip counts, coalescing stats).
- Tree-shakable feature flags via build-time conditionals.
Contributing (Local)
1. Implement or adjust a handler in the src/symphonies directory or other relevant source files.
2. Run npm run build to build the package.
3. Execute tests: npm test.
4. Run lint checks: npm run lint.
5. For development, use: npm run dev.
6. Measure latency (add temporary perf logs if needed under perf.cp.debug).
Testing Strategy
Write unit tests that assert:
- Correct topic publication order & payload shape.
- Coalescing (only one CP update per frame) when simulating multiple rapid move calls.
- Fallback path to direct interaction play when EventRouter.publish` throws.