Playgrounds: Wiremarks - #27
Merged
Merged
Conversation
Refactors the app to support multiple playgrounds via a typed registry and sidebar selection, replacing the single hardcoded Playground scene with dynamic components. Adds a new Wiremarks playground (DSL editor, pan/zoom/drag canvas interactions, SVG export) and moves the existing primitives grid into a dedicated Components Showcase playground. Also fixes DOM prop application in Provider by setting the `class` attribute directly for `className`.
Replace the imperative Two.js wiremark/entity/connection classes with a declarative React scene. This adds typed graph parsing, a `useWiremarksGraph` hook for parsed data and drag state, and new entity/connection components for rendering nodes, labels, and animated dashed edges while keeping pan/zoom behavior in `WiremarkCanvas`.
Add ignoreDeprecations flag to tsconfig.app.json to suppress TypeScript 6.0 deprecation warnings.
Switch the Wiremarks playground from SVG to the canvas renderer to match the intended rendering path.
Comment out the Wiremarks playground canvas `className` and `style` props, removing the grab cursor and `userSelect: 'none'` behavior from the interactive graph canvas.
Removes the ZUI dependency and all zoom/pan interaction (mousewheel, pinch, touch gestures). Replaces ZUI-aware coordinate transforms with simple DOM rect-based hit testing. Only node dragging is retained.
Replaced canvas-level mouse hit testing and global drag state in `WiremarkCanvas` with pointer-driven drag callbacks wired through `WiremarksScene` into `WiremarkEntity`. Each entity now starts/stops dragging on pointer events, reports movement deltas, and updates node positions from captured start coordinates. This also adds hover/drag visual feedback by adjusting entity stroke color and line width.
Refactors event lifecycle handling across shape components so event shapes are only unregistered on unmount, while handlers are re-registered on updates. Hit testing was expanded to support custom contains(), bounding-rect checks with Two.js viewport offsets, and recursive group child checks; Provider now passes the Two instance state into point queries. This also exports event types from lib/main, switches playground imports to type-only TwoEvent usage, and moves wiremark pointer handlers to the Group container for more reliable hover/drag behavior.
Adds a new test file for the event system (hitTest utility, Group event handling, hover state stability). Updates vitest config to include tests from all directories. Enhances test-setup.ts with a global canvas context mock for JSDOM.
Add Vitest coverage for the playground registry and Wiremarks DSL parser, including ID fallback behavior, labeled edges, comments, and invalid input handling. Update the Vitest config with path aliases so the new tests resolve app and library imports consistently.
Add sortFrontToBack() to order hit shapes by draw order (frontmost first), using parent.children index when shapes share a parent group, or registration order otherwise. Pointer move and enter/leave events now target only the topmost shape and its parent hierarchy, matching expected browser-like behavior. Includes tests for sorting logic and overlapping shape interaction.
Introduce `useZUI` and `useZUIState` to add Two.js zoom/pan controls to `Group` refs, with typed ZUI wrappers and reusable gesture math helpers. The event/context layer now exposes `hitTestPoint` so background panning is blocked when pointer input lands on interactive shapes, avoiding conflicts with node dragging. Documentation, tests, and the wiremarks playground were updated to cover and demonstrate the new zoom/pan behavior.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR expands the repo’s demo surface into a multi-playground architecture and adds a new “Wiremarks” graph playground built with declarative react-two.js components. It also introduces useZUI / useZUIState hooks for zoom/pan interactions and upgrades the event system (hit testing + front-to-back ordering), alongside a new Vitest test suite to validate the new behaviors.
Changes:
- Add multi-playground registry and new Wiremarks playground (DSL parser + interactive scene + zoom/pan UI).
- Introduce
useZUI/useZUIStatehooks and supporting math/types, plus tests for ZUI and event system behavior. - Update event hit testing + hover ordering, and adjust config/build/test wiring (Vitest aliases, Rollup externals, TS ignoreDeprecations).
Reviewed changes
Copilot reviewed 50 out of 51 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| vitest.config.ts | Adds aliases and expands test include globs to cover tests/ + lib/. |
| vite.config.lib.ts | Adjusts Rollup externals patterns for React and Two.js. |
| tsconfig.app.json | Adds ignoreDeprecations. |
| tests/zuiMath.test.ts | Unit tests for pure ZUI gesture math helpers. |
| tests/zui.test.tsx | Integration tests for useZUI behavior (zoom/pan/bounds/coordinate transforms). |
| tests/wiremarks.test.ts | Tests for Wiremarks DSL parsing. |
| tests/registry.test.ts | Tests for playground registry behavior and wiremarks presence. |
| tests/events.test.tsx | Tests for updated event hit testing and front-to-back sorting. |
| src/test-setup.ts | Adds jsdom canvas + PointerEvent polyfills for tests. |
| src/playgrounds/wiremarks/WiremarksPlayground.tsx | Wiremarks UI: editor overlay, SVG export, zoom UI chrome. |
| src/playgrounds/wiremarks/WiremarkCanvas.tsx | Wiremarks scene wiring, node dragging logic, ZUI integration. |
| src/playgrounds/wiremarks/utils/color.ts | Color utilities for node/edge styling. |
| src/playgrounds/wiremarks/types.ts | Wiremarks graph/types definitions. |
| src/playgrounds/wiremarks/parser.ts | Wiremarks DSL parser producing nodes/edges. |
| src/playgrounds/wiremarks/hooks/useWiremarksGraph.ts | Hook for combining parsed graph data with drag position overrides. |
| src/playgrounds/wiremarks/constants.ts | Wiremarks rendering constants (unit, dashes, text styles). |
| src/playgrounds/wiremarks/components/WiremarksScene.tsx | Renders graph entities + connections; computes connection offsets. |
| src/playgrounds/wiremarks/components/WiremarkEntity.tsx | Renders draggable entity node with pointer handlers. |
| src/playgrounds/wiremarks/components/WiremarkConnection.tsx | Renders curved connections and labels between nodes. |
| src/playgrounds/types.ts | Adds shared playground typing. |
| src/playgrounds/registry.ts | Registers available playgrounds and lookup helper. |
| src/playgrounds/components-showcase/ComponentsShowcasePlayground.tsx | Moves the prior single playground into a dedicated “components showcase” playground. |
| src/Playground.tsx | Switches to rendering the active playground from the registry. |
| src/App.tsx | Adds a sidebar playground picker and wires active playground state. |
| README.md | Documents useZUI and useZUIState. |
| package.json | Updates dev dependency @types/node. |
| package-lock.json | Updates lockfile versions and dependency resolution. |
| lib/zuiTypes.ts | Adds local structural typings for Two.js ZUI extra. |
| lib/zuiMath.ts | Adds pure gesture math helpers for ZUI interactions. |
| lib/ZUI.ts | Implements useZUI and useZUIState. |
| lib/main.ts | Exports new ZUI hooks/types and Events types. |
| lib/Context.ts | Extends context with hitTestPoint. |
| lib/Events.ts | Adds bounds-based hit testing, world-point helpers, and front-to-back sorting. |
| lib/Provider.tsx | Adds hitTestPoint and updates hover/out logic and dev child validation. |
| lib/Circle.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/Group.tsx | Adjusts event shape registration/unregistration strategy and passes hitTestPoint. |
| lib/ArcSegment.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/Ellipse.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/Image.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/ImageSequence.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/Line.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/Path.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/Points.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/Polygon.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/Rectangle.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/RoundedRectangle.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/Sprite.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/Star.tsx | Adjusts event shape registration/unregistration strategy. |
| lib/SVG.tsx | Adjusts event shape registration/unregistration strategy and passes hitTestPoint. |
| lib/Text.tsx | Adjusts event shape registration/unregistration strategy. |
| CLAUDE.md | Documents useZUI / useZUIState usage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…label - Provider gated validateChildren() on NODE_ENV === 'production' while validateChildren() itself returns early in production, making the dev warning dead in every environment. The function self-guards, so the call site guard is removed. - hitTest() referenced Node/Element prototypes unguarded, which throws outside a DOM runtime. - Sidebar label 'Github' -> 'GitHub'. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Shapes stayed registered after their handler props were cleared, keeping
stale handlers alive and — now that hitTestPoint gates useZUI panning —
silently blocking background pan over non-interactive shapes.
- Each primitive now unregisters when its handler set becomes empty.
- Handler extraction ignores explicitly undefined values, so the common
onPointerDown={cond ? fn : undefined} idiom no longer registers a shape.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ignoreDeprecations: '6.0' is not valid for TypeScript 5.6, so tsc -p tsconfig.app.json failed before checking anything. Removing it surfaced a real typing error in the jsdom getContext stub, which is now asserted against the overloaded signature. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Editing the DSL mid-drag re-parses the graph and unmounts the entity before pointerup arrives, leaking window listeners and leaving the parent's draggingNodeId stale. The drag teardown is now held in a ref so an unmount effect can run it, and it notifies onDragEnd on every path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tate dashOffset was React state updated inside useFrame, re-rendering the whole graph 60 times a second and re-running every shape component's prop-application effect. Each WiremarkConnection now mutates its own Two.js path offset in useFrame, so the animation costs no renders. Removes the dashOffset prop threading through WiremarksScene, and adds setLineDash/getLineDash to the jsdom canvas stub so dashed paths render under test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR introduces a multi-playground architecture featuring a Wiremarks graph demo built with declarative
react-two.jscomponents. It upgrades the event system with bounds-based hit testing, front-to-back Z-order sorting, topmost hover/out event ordering, and stable event unregistration across all 16 primitive components, backed by a 14-test Vitest suite.Added
useZUIanduseZUIStatehooks toreact-two.jsfor rAF-coalesced zoom and pan interactions on<Group>components, gated on context shape hit-testing (hitTestPoint) so node drags and canvas panning never conflict. Integrated ZUI into the Wiremarks playground with pixel-accurate surface-space coordinate mapping (clientToSurface), floating zoom UI controls, and externalized ZUI build bundling.