cavijs 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/LICENSE +27 -0
  2. package/README.md +379 -2
  3. package/dist-lib/cavijs.js +4051 -0
  4. package/dist-lib/cavijs.js.map +1 -0
  5. package/dist-lib/core.js +21 -0
  6. package/dist-lib/core.js.map +1 -0
  7. package/dist-lib/shared-CVyJHksc.js +856 -0
  8. package/dist-lib/shared-CVyJHksc.js.map +1 -0
  9. package/dist-lib/types/component/cables.d.ts +55 -0
  10. package/dist-lib/types/component/history.d.ts +121 -0
  11. package/dist-lib/types/component/interactionwc.d.ts +47 -0
  12. package/dist-lib/types/component/jack.d.ts +368 -0
  13. package/dist-lib/types/component/plug.d.ts +209 -0
  14. package/dist-lib/types/component/wirewc.d.ts +127 -0
  15. package/dist-lib/types/component/worldwc.d.ts +91 -0
  16. package/dist-lib/types/core/cavi.d.ts +307 -0
  17. package/dist-lib/types/core/coords.d.ts +99 -0
  18. package/dist-lib/types/core/events.d.ts +76 -0
  19. package/dist-lib/types/core/frame.d.ts +31 -0
  20. package/dist-lib/types/core/index.d.ts +19 -0
  21. package/dist-lib/types/core/node.d.ts +45 -0
  22. package/dist-lib/types/core/render-data.d.ts +57 -0
  23. package/dist-lib/types/core/types.d.ts +84 -0
  24. package/dist-lib/types/core/wasm.d.ts +23 -0
  25. package/dist-lib/types/core/wire.d.ts +194 -0
  26. package/dist-lib/types/core/world.d.ts +253 -0
  27. package/dist-lib/types/debug/debugwc.d.ts +115 -0
  28. package/dist-lib/types/debug/format.d.ts +11 -0
  29. package/dist-lib/types/debug/stats.d.ts +74 -0
  30. package/dist-lib/types/index.d.ts +40 -0
  31. package/dist-lib/types/interaction/interaction.d.ts +88 -0
  32. package/dist-lib/types/interaction/keyboard.d.ts +66 -0
  33. package/dist-lib/types/renderer/pointer.d.ts +34 -0
  34. package/dist-lib/types/renderer/renderer-svg.d.ts +104 -0
  35. package/dist-lib/types/renderer/renderer.d.ts +132 -0
  36. package/dist-lib/types/renderer/resize.d.ts +36 -0
  37. package/package.json +76 -4
package/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Teo Basili
4
+
5
+ Permission is hereby granted, free of charge, to any
6
+ person obtaining a copy of this software and associated
7
+ documentation files (the "Software"), to deal in the
8
+ Software without restriction, including without
9
+ limitation the rights to use, copy, modify, merge,
10
+ publish, distribute, sublicense, and/or sell copies of
11
+ the Software, and to permit persons to whom the Software
12
+ is furnished to do so, subject to the following
13
+ conditions:
14
+
15
+ The above copyright notice and this permission notice
16
+ shall be included in all copies or substantial portions
17
+ of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
20
+ ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
21
+ TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
22
+ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
23
+ SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
26
+ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
+ DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,380 @@
1
- # Temporary Holding Version
1
+ # Cavijs
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ cavijs is a wrapper written in typescript that allow to use cavi inside browser without handle directly with cavi.
4
+
5
+ The main purpose of cavi is to handle cable and mouse interaction, generating as a result spline point to be passed in js, js receive the point and renders wires.
6
+
7
+ The purpose is to avoid to store render information in the wasm project and let js to handle renderer and keep information about that, this because in that manner is possible to easly extend rendere behavior.
8
+
9
+ The TS project contain following classes:
10
+
11
+ - **Cavi** - Main entry point and facade
12
+ - **World** - Simulation container
13
+ - **Wire** - Individual wire representation
14
+ - **Node** - Individual node/point in a wire
15
+ - **Renderer** - Canvas-based rendering implementation
16
+ - **SvgRenderer** - SVG-based rendering implementation, drop-in alternative to Renderer
17
+
18
+ And these custom elements:
19
+
20
+ - **`<cavi-world>`** - a world declared in HTML: creates the `Cavi`, its canvas and renderer
21
+ - **`<cavi-jack>`** / **`<cavi-plug>`** - fixed connection points, and the cable ends that plug into them
22
+ - **`<cavi-wire>`** - a cable declared in HTML, with its two plugs
23
+ - **`<cavi-interaction>`** - attaches the interaction controllers: `StandardInteractionController` (mouse, touch) and `KeyboardInteractionController` (Tab, Space/Enter, Escape)
24
+ - **`<cavi-debug>`** - debug panel: statistics, event log, overlays
25
+
26
+ ## Architecture
27
+
28
+ The architecture separates concerns:
29
+
30
+ - **Rust/WASM**: Physics simulation, collision detection, spline calculations
31
+ - **TypeScript**: Rendering, metadata, UI interaction, extensibility
32
+
33
+ ## Classes
34
+
35
+ ### Cavi
36
+
37
+ Main facade class that simplifies usage. Provides:
38
+
39
+ - WASM initialization
40
+ - Wire management through World wrapper
41
+ - Renderer integration
42
+ - Convenience methods for common operations
43
+
44
+ **Methods:**
45
+
46
+ ```typescript
47
+ static initWasm(): Promise<void>
48
+ init(): Promise<void>
49
+ getWorld(): World
50
+ setRenderer(renderer: IRenderer): void
51
+ getRenderer(): IRenderer | null
52
+ addWire(x1, y1, x2, y2, nodes, tension, radius, type): Wire
53
+ deleteWire(index: number): void
54
+ clearAllWires(): void
55
+ setAcceleration(x: number, y: number): void
56
+ getAcceleration(): { x: number, y: number }
57
+ getWireByIndex(index: number): Wire | null
58
+ getWires(): Wire[]
59
+ update(): void
60
+ setMouse(x: number, y: number): void
61
+ render(): void
62
+ ```
63
+
64
+ ### World
65
+
66
+ Main container for cavi simulation. Exposes all methods to interact with cables and global parameter configuration.
67
+
68
+ **Capabilities:**
69
+
70
+ - Add a new Wire
71
+ - Delete a Wire
72
+ - Set acceleration (gravity)
73
+ - Get acceleration
74
+ - Set renderer class
75
+ - Get wires by their index
76
+
77
+ **Methods:**
78
+
79
+ ```typescript
80
+ addWire(x1, y1, x2, y2, nodes, tension, radius, renderType): Wire
81
+ deleteWire(index: number): void
82
+ clearAllWires(): void
83
+ setAcceleration(x: number, y: number): void
84
+ getAcceleration(): { x: number, y: number }
85
+ setRenderer(renderer: IRenderer): void
86
+ getRenderer(): IRenderer | null
87
+ getWireByIndex(index: number): Wire | null
88
+ getWires(): Wire[]
89
+ getWireCount(): number
90
+ update(): void
91
+ setMouse(x: number, y: number): void
92
+ setMouseRadius(radius: number): void
93
+ setFriction(friction: number): void
94
+ ```
95
+
96
+ During render, the renderer class receives the wire instance with its context that allows rendering the wire with specific color passed in early initialization.
97
+
98
+ ### Wire
99
+
100
+ Wire is the TypeScript class corresponding to Wire in cavi.
101
+
102
+ Wire is logically connected to the WASM Wire but contains methods to change properties like radius and tension. It also contains a meta dictionary that allows the user to extend with information useful for rendering, for example adding the color.
103
+
104
+ **Minimal implementation methods:**
105
+
106
+ - Add a node
107
+ - Remove a node
108
+ - Change and set meta data (for example render color)
109
+ - Change radius
110
+
111
+ **Methods:**
112
+
113
+ ```typescript
114
+ addNode(x: number, y: number, fixed?: boolean): void
115
+ addNodeAt(index: number, x: number, y: number, fixed?: boolean): void
116
+ removeNode(index: number): void
117
+ getNodeCount(): number
118
+ setMetaData(key: string, value: any): void
119
+ getMetaData(key: string): any
120
+ getAllMetaData(): WireMeta
121
+ setColor(color: string): void
122
+ getColor(): string | undefined
123
+ setRadius(radius: number): void
124
+ getRadius(): number
125
+ getIndex(): number
126
+ ```
127
+
128
+ **Metadata Example:**
129
+
130
+ ```typescript
131
+ const wire = world.addWire(100, 100, 500, 100, 20, 10, 5, 1);
132
+ wire.setColor('#ff0000');
133
+ wire.setMetaData('thickness', 2);
134
+ wire.setMetaData('pattern', 'dashed');
135
+ ```
136
+
137
+ ### Node
138
+
139
+ Node is the corresponding TypeScript class of Node in cavi. Represents a single point in a wire with position, velocity, and fixed state.
140
+
141
+ **Properties:**
142
+
143
+ ```typescript
144
+ x: number (readonly, from WASM)
145
+ y: number (readonly, from WASM)
146
+ fixed: boolean (get/set)
147
+ ```
148
+
149
+ **Methods:**
150
+
151
+ ```typescript
152
+ setPosition(x: number, y: number): void
153
+ ```
154
+
155
+ ### Renderer
156
+
157
+ Renderer class is responsible to render wires inside a `<canvas>`. In each render cycle it uses the WASM buffer and wire metadata instances to determine rendering properties like color.
158
+
159
+ **Constructor:**
160
+
161
+ ```typescript
162
+ constructor(container: HTMLElement, world: World, options?: RendererOptions & { canvas?: HTMLCanvasElement })
163
+ ```
164
+
165
+ Uses `options.canvas` (any canvas, anywhere on the page — its placement is measured every frame), else an existing `#wireCanvas` inside the host (`options.surface`, else `container`), creating one if there is none. `<cavi-world>` (`src/component/worldwc.ts`) creates the canvas and keeps it sized through its `IResizeController`. `options.surface` enables the pan/zoom-friendly mode described in [Pan/zoom and multiple worlds](#panzoom-and-multiple-worlds).
166
+
167
+ **Features:**
168
+
169
+ - Direct WASM memory access for efficient rendering (zero-copy)
170
+ - HiDPI: the canvas backing store follows `devicePixelRatio`
171
+ - Uses wire metadata for rendering colors (with fallback to default colors)
172
+ - Supports both segment and Bezier curve rendering
173
+ - Built-in animation loop with FPS tracking
174
+ - Mouse interaction visualization (pointer and mouse radii)
175
+ - Automatic physics updates in render cycle
176
+
177
+ **Methods:**
178
+
179
+ ```typescript
180
+ render(): void // Starts the animation loop (idempotent, restartable after stop())
181
+ clear(): void // Clear the canvas
182
+ getFPS(): number // Get current frames per second
183
+ drawInteractionRadii(x: number, y: number): void // Draw mouse interaction zones
184
+ getSurface(): HTMLElement // options.surface, else the container
185
+ stop(): void // Cancel the loop, remove the pointer listener, clear the canvas
186
+ ```
187
+
188
+ The renderer reads wire colors from metadata and automatically handles the render loop, physics updates, and visualization.
189
+
190
+ ### SvgRenderer
191
+
192
+ `SvgRenderer` is a drop-in alternative to `Renderer`: it implements the same `IRenderer` interface and renders each wire as an SVG `<path>` (one pooled, updated-in-place element per wire) instead of stroking a `<canvas>`. Anywhere `Renderer` is used, `SvgRenderer` can be substituted without other code changes.
193
+
194
+ Unlike `Renderer`, it is **self-contained**: its constructor creates its own `<svg id="wireSvg">` inside the given container if one doesn't already exist, and manages its own sizing internally (an internal `ResizeObserver`, no `viewBox` — wire coordinates map 1:1 to SVG user-space pixels, just like the canvas backing store).
195
+
196
+ **Constructor:**
197
+
198
+ ```typescript
199
+ constructor(container: HTMLElement, world: World, options?: RendererOptions)
200
+ ```
201
+
202
+ `container` can be any plain `HTMLElement` (it does not need a pre-created `#wireSvg`, nor does it need to come from `<cavi-world>`).
203
+
204
+ **Features:**
205
+
206
+ - Same zero-copy WASM buffer reading and wire-color-fallback logic as `Renderer`
207
+ - Per-wire `<path>` pooling: DOM nodes are created/removed only when the wire count changes, never recreated every frame
208
+ - Segment and Bezier curve rendering via `M`/`L`/`C` path commands
209
+ - Debug overlay (physics nodes, mouse/pointer interaction radii) as SVG `<circle>`/`<text>` elements, toggled the same way as `Renderer`
210
+ - Dispatches a `cavi-resize` CustomEvent on `container` on every resize — same contract as `StandardResizeController` (`src/renderer/resize.ts`), so code that listens for `cavi-resize` (e.g. to reposition jacks, see `examples/patchbay-shared.ts`) works unchanged regardless of which renderer is active
211
+
212
+ **Methods:**
213
+
214
+ ```typescript
215
+ render(): void // Main render method (includes animation loop)
216
+ getFPS(): number // Get current frames per second
217
+ setDebugDrawNodes(enabled: boolean): void
218
+ getDebugDrawNodes(): boolean
219
+ getContainer(): HTMLElement
220
+ stop(): void // Cancel the animation loop and disconnect the internal ResizeObserver
221
+ ```
222
+
223
+ **Usage** (swap-in replacement for `Renderer`):
224
+
225
+ ```typescript
226
+ import { Cavi, SvgRenderer } from 'cavijs';
227
+
228
+ await Cavi.initWasm();
229
+ const cavi = new Cavi();
230
+
231
+ const container = document.getElementById('wireArea') as HTMLElement;
232
+ const renderer = new SvgRenderer(container, cavi.getWorld());
233
+ cavi.setRenderer(renderer);
234
+
235
+ renderer.render();
236
+ ```
237
+
238
+ ## Usage Example
239
+
240
+ ```typescript
241
+ import { Cavi, Renderer } from 'cavijs';
242
+
243
+ // Initialize WASM
244
+ await Cavi.initWasm();
245
+
246
+ // Create instance
247
+ const cavi = new Cavi();
248
+
249
+ // Setup renderer (pass the container holding a #wireCanvas element, and world)
250
+ const container = document.getElementById('container') as HTMLElement;
251
+ const renderer = new Renderer(container, cavi.getWorld());
252
+ cavi.setRenderer(renderer);
253
+
254
+ // Add wires with metadata for custom colors
255
+ const wire1 = cavi.addWire(100, 100, 500, 100, 20, 10, 5, 1);
256
+ wire1.setColor('#ff0000');
257
+ wire1.setMetaData('label', 'Cable A');
258
+
259
+ const wire2 = cavi.addWire(100, 200, 500, 200, 25, 15, 8, 1);
260
+ wire2.setColor('#00ff00');
261
+
262
+ // Configure physics
263
+ cavi.setAcceleration(0, 9.8);
264
+
265
+ // Start rendering (renderer handles animation loop internally)
266
+ renderer.render();
267
+ ```
268
+
269
+ ## Pan/zoom and multiple worlds
270
+
271
+ cavijs does not implement pan/zoom: the page transforms a wrapper around `<cavi-world>` (e.g. with d3-zoom) and registers the current transform with `setCoordinateTransform(() => ({ scale, translateX, translateY }))`, calling `notifyCoordinateTransformChanged()` after each step.
272
+
273
+ To keep cables visible and sharp at any zoom, give the world a **surface**, an untransformed element such as the frame the zoom listens on: `<cavi-world surface="#zoomFrame">`, or `new Renderer(container, world, { surface })` / `new SvgRenderer(container, world, { surface })`. The canvas/svg is then placed in and sized to that element, and the renderer applies the zoom itself, so cables are no longer clipped to the container's box when zooming out.
274
+
275
+ To draw into a canvas of your own — e.g. stacked above jacks and plugs — use `<cavi-world canvas="#myCanvas">` (or the `.canvas` property; `{ canvas }` / `{ svg }` for a hand-made renderer). It can sit anywhere on the page: its on-screen position is measured every frame.
276
+
277
+ Several `<cavi-world>`s can coexist on one page, also inside shadow roots: every element resolves its own world with `Cavi.for(element)`, `<cavi-plug jack="id">` looks the id up among its own world's jacks (so worlds can reuse ids), and each world has a single interaction controller with its own pointer and drag state — see `examples/demo-two-worlds.html`. `Cavi.shared` remains as a fallback for single-world setups.
278
+
279
+ Details: [doc/en/06-zoom-multiworld.md](doc/en/06-zoom-multiworld.md).
280
+
281
+ ## Saving and restoring cables
282
+
283
+ `captureCables(cavi)` reads a world's cables as plain JSON-safe data — for each cable its `id`, the ids of the jacks its two ends are plugged into, and its attributes — and `applyCables(cavi, snapshot)` puts them back, touching only the cables that differ. Jacks are not saved: the page restores them first, with the same ids. `Plug.connect(jack)`/`disconnect()` plug and unplug from code, and `CaviWireElement.delete()` deletes a cable freeing its jacks right away.
284
+
285
+ `CaviHistory` builds undo/redo on top: a step at the end of every gesture on the cables (the `cavi-change` event) and whenever the page commits a change of its own, with the page's own state (jacks, modules) put back before the cables. `examples/demo-d3-interaction.html` has Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z and Save/Load.
286
+
287
+ Details: [doc/en/03-api.md](doc/en/03-api.md#saving-and-restoring-cables), [undo and redo](doc/en/03-api.md#undo-and-redo-cavihistory).
288
+
289
+ ## `cavijs/core`: the simulation alone
290
+
291
+ `import { World, initWasm, forEachWireRender, svgPathData } from 'cavijs/core'` gets the engine without the page: no custom element registered, no DOM touched. `initWasm(source?)` loads the WASM once (from a URL of your choice if needed), a `World` runs from your own frame loop, `forEachWireRender`/`svgPathData` turn its cables into SVG path data, and `Wire.growTo`/`shrinkTo` with `nodeCountForDistance` keep a cable's length in step with its ends — the pieces to draw cavijs cables as another library's edges.
292
+
293
+ Details: [doc/en/03-api.md](doc/en/03-api.md#cavijscore-srccoreindexts).
294
+
295
+ ## Debug overlay and events
296
+
297
+ Drop `<cavi-debug>` next to (or inside) a world for live stats — FPS, wires, nodes, jacks/plugs, physics and view parameters, a per-wire table — and a log of the events the world emits (`cavi-wire-add`, `cavi-plug-attach`, `cavi-cable-end`, …). `mode="floating"` is a draggable window, `mode="panel"` a panel docked to the right edge; `Alt+Shift+D` toggles it.
298
+
299
+ ```html
300
+ <cavi-debug for="panel" open></cavi-debug>
301
+ ```
302
+
303
+ Details: [doc/en/07-debug.md](doc/en/07-debug.md).
304
+
305
+ ## Building
306
+
307
+ ```bash
308
+ pnpm build # type-check + demo site (dist/, deployed to GitHub Pages)
309
+ pnpm build:lib # library: dist-lib/cavijs.js, dist-lib/core.js (cavijs/core) + dist-lib/types/*.d.ts
310
+ pnpm test # vitest (jsdom + the real cavi WASM module)
311
+ pnpm test:e2e # Playwright: the demos in Chrome, driven with a real mouse
312
+ ```
313
+
314
+ The end-to-end tests (`e2e/`) start their own Vite server and use the locally installed Google Chrome, so no browser download is needed. They cover every demo loading and drawing, cable creation/relocation/drop with both interaction controllers, fixed-rate physics on emulated 120 Hz and 30 Hz displays, the held cable, the release throw, sleeping, a world removed and inserted back, and two worlds (one in a shadow root) with the same jack ids.
315
+
316
+ The WASM engine comes from the `cavi` package; after modifying its Rust code, rebuild it there with `wasm-pack build --target web`.
317
+
318
+ ## Control panels
319
+
320
+ `<cavi-debug>` is the library's debug panel for any world on the page: live statistics, the event log, and toggles for the debug overlays (see `doc/en/07-debug.md`).
321
+
322
+ `demo-basic.html` and `demo-svg.html` have their own panel, `<cavi-controls>` (`examples/controls.ts`), with sliders for the physics and buttons to add or clear wires. It is example code: it drives the `Cavi` those demos build by hand, not any world.
323
+
324
+ ## Development
325
+
326
+ The TypeScript wrapper is designed to be extended. Custom renderers can be created by implementing the `IRenderer` interface:
327
+
328
+ ```typescript
329
+ interface IRenderer {
330
+ render(): void;
331
+ stop(): void;
332
+ setDebugDrawNodes(enabled: boolean): void;
333
+ getDebugDrawNodes(): boolean;
334
+ getContainer(): HTMLElement;
335
+ getSurface?(): HTMLElement; // optional, defaults to getContainer()
336
+ }
337
+ ```
338
+
339
+ The default `Renderer` (canvas) and `SvgRenderer` (SVG) classes both provide complete implementations with:
340
+
341
+ - Efficient zero-copy WASM memory access
342
+ - Wire metadata support (colors and custom properties)
343
+ - Built-in animation loop and physics updates
344
+ - Mouse interaction visualization
345
+ - FPS tracking accessible via `getFPS()`
346
+
347
+ `SvgRenderer` (see above) is a working example of an alternative `IRenderer` implementation — a reasonable reference for anyone writing a third one (e.g. WebGL).
348
+
349
+ Wire metadata allows attaching arbitrary rendering information without modifying core WASM code. Colors and other properties set via wire metadata are automatically used during rendering.
350
+
351
+ ## Project Layout
352
+
353
+ - `src/` — the library itself, nothing else. Organized by concern:
354
+ - `src/core/` — `Cavi`, `World`, `Wire`, `Node`, the WASM loader (`wasm.ts`), the render buffer reader (`render-data.ts`), and the shared `types.ts` (`IRenderer`, `IInteractionController`, `WireMeta`, ...); `index.ts` is the `cavijs/core` entry point
355
+ - `src/renderer/` — `Renderer` (canvas), `SvgRenderer` (SVG), `StandardResizeController`
356
+ - `src/interaction/` — `StandardInteractionController` (pointer), `KeyboardInteractionController` (keyboard)
357
+ - `src/component/` — the custom elements: `<cavi-jack>`, `<cavi-plug>`, `<cavi-wire>`, `<cavi-world>`, `<cavi-interaction>`
358
+ - `src/debug/` — `<cavi-debug>`, statistics and event formatting
359
+ - `src/index.ts` — the public entry point, re-exporting the above
360
+ - `src/tests/` — all `*.test.ts` files
361
+ - `examples/` — every demo page and its driving script, kept out of `src/` since none of it is library code. Vite's `root` points here (see `vite.config.ts`), so `npm run dev` serves `examples/index.html` at `/`.
362
+
363
+ ## Demos
364
+
365
+ The `examples/demo-*.html` pages (built via `vite.config.ts`'s `build.rollupOptions.input`) show the library in different setups:
366
+
367
+ | Demo | Script | Renderer | Description |
368
+ | -------------------------------------- | ------------------------------------ | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
369
+ | `examples/demo-basic.html` | `examples/main.ts` | `Renderer` (canvas) | Minimal setup, a few static wires, with the demos' own control panel (`examples/controls.ts`) |
370
+ | `examples/demo-svg.html` | `examples/main-svg.ts` | `SvgRenderer` | Same minimal setup, using the SVG renderer |
371
+ | `examples/demo-jack-plug.html` | `examples/example2.ts` | `Renderer` (canvas, via `<cavi-world>`) | Hand-authored `<cavi-jack>`/`<cavi-wire>` markup |
372
+ | `examples/demo-noop-interaction.html` | `examples/exampleNoopInteraction.ts` | `Renderer` (canvas, via `<cavi-world>`) | Custom no-op `IInteractionController` example |
373
+ | `examples/demo-patchbay.html` | `examples/example3.ts` | `Renderer` (canvas, via `<cavi-world>`) | Full modular-synth patchbay: many jacks materialized from CSS layout, pre-patched cables, interactive drag-to-connect |
374
+ | `examples/demo-patchbay-svg.html` | `examples/example3-svg.ts` | `SvgRenderer` | Same patchbay, wired manually to `SvgRenderer` (shares its logic via `examples/patchbay-shared.ts`) |
375
+ | `examples/demo-patchbay-zoom.html` | `examples/demo-patchbay-zoom.ts` | `Renderer` (canvas, via `<cavi-world>`) | Full-screen d3-zoom pan/zoom with CSS-positioned jacks and a draggable module, using `surface` |
376
+ | `examples/demo-patchbay-zoom-svg.html` | `examples/demo-patchbay-zoom-svg.ts` | `SvgRenderer` | Same full-screen zoom demo on the SVG renderer |
377
+ | `examples/demo-d3-interaction.html` | `examples/demo-d3-interaction.ts` | `Renderer` (canvas, via `<cavi-world>`) | Custom `IInteractionController` built on d3-drag, several draggable modules under d3-zoom |
378
+ | `examples/demo-two-worlds.html` | `examples/demo-two-worlds.ts` | `Renderer` (canvas, via `<cavi-world>`) | Two worlds on one page, one inside a shadow root, with the same jack ids |
379
+
380
+ `examples/index.html` links every demo. Run `npm run dev` and open any of these pages to try them.