Wholesale move of every remaining kind into its own subdirectory under
`packages/nodes/src/`, finishing the registry-driven migration. Each
kind now ships its definition, schema (re-exported from core), and any
of `geometry` / `renderer` / `system` / `floorplan` / `tool` /
`move-tool` / `panel` / `floorplan-move` / `floorplan-affordances` /
`parametrics` / `preview` it needs — no per-kind code remains under
`packages/editor/src/components/tools/` or
`packages/viewer/src/components/renderers/`.
Deleted (replaced by registry-driven equivalents):
- `tools/{ceiling,column,door,fence,item,slab,spawn,wall,window}/...`
(boundary editors, hole editors, placement tools, move tools,
endpoint movers, curve tools, helpers, math libs)
- `ui/helpers/{ceiling,slab,wall}-helper.tsx`
- `ui/panels/{column,door,elevator,item,roof,roof-segment,spawn,
stair,stair-segment,wall,window}-panel.tsx`
- `viewer/src/components/renderers/{building,ceiling,column,door,
elevator,fence,guide,item,level,roof,roof-segment,scan,site,slab,
spawn,stair,stair-segment,wall,window,zone}-renderer.tsx`
- `viewer/src/components/viewer/legacy-system.tsx`
Added under `packages/nodes/src/`:
- `building/`, `column/`, `elevator/`, `guide/`, `level/`, `roof/`,
`roof-segment/`, `scan/`, `shared/`, `site/`, `stair/`,
`stair-segment/` packages with definition + schema + renderer / system
/ floorplan / panel as appropriate.
- New `floorplan-move.ts` for every kind that supports 2D moves
(ceiling, door, item, shelf, slab, window) — single registry-driven
dispatch path via `def.floorplanMoveTarget`.
- New `floorplan-affordances.ts` for kinds with polygon / endpoint
drags (ceiling, fence, slab, wall) — using the shared
`polygon-vertex-affordance` factories.
- New per-kind `panel.tsx` for kinds with custom inspector content
(door, item, shelf, spawn, wall, window).
- New per-kind `tool.tsx` for placement (door, item, shelf, window).
- New per-kind `move-tool.tsx` for kinds with custom 3D move flows
(door, item, slab, window).
Coordinator + manager updates in `packages/editor/`:
- `tool-manager.tsx` resolves tools from the registry only — no
hardcoded type→component map.
- `panel-manager.tsx` resolves inspector panels the same way.
- `placement-{coordinator,strategies,types}.ts` extended with
shelf-surface placement.
- `selection-manager.tsx` adds the registry-selectable fallback.
- `floorplan-panel.tsx`, `floorplan-background-placement.ts`,
`floorplan-render-context.tsx` updated for the registry layer's new
contract (props, affordance dispatch, render context).
Viewer updates:
- `viewer/index.tsx` drops legacy renderer mounts.
- `node-renderer.tsx` resolves by registry only.
- `scene-bvh.tsx`, `use-node-events.ts`, `level-system.tsx`,
`wall-cutout.tsx`, `zone-system.tsx`, `materials.ts` adjusted for
the registry-only world.
Sidebar tree nodes for ceiling / fence / slab / shelf / tree-node
updated to read from the registered nodes instead of the deleted
legacy renderer trees.
Wiki: new `plugin-authoring.md` page, README index updated.
Tests in `packages/nodes/src/index.test.ts` validate every registered
kind has the required shape.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures the gotchas surfaced while building the shelf so the next
contributor adding a registry-driven kind doesn't rediscover them.
`node-definitions.md` — new Pitfalls section + a rule that builders
must emit local-space children. Covers:
- `<GeometrySystem>` must NOT mutate `group.position` / `group.rotation`
after rebuild (the renderer binds them via JSX prop).
- Tag geometry-built children with `userData.__fromGeometry` so
rebuilds don't dispose React-mounted hosted children (the
item-disappears-on-shelf bug).
- Previews must clone materials before mutating them when the kind's
builder caches at module scope.
- Host kinds need a `children: z.array(...).default([])` field on their
schema (and a migration patch for older scenes).
`tools.md` — three new move/placement pitfalls:
- Disable raycast on the moved mesh during drag, otherwise it captures
the ray and starves `grid:move` → commits land at the stale start.
- Commit handlers listen to `grid:click` AND every `${kind}:click` to
catch clicks that land on neighbouring 3D geometry first.
- Move tools must preserve the node's actual `rotation[1]` in
`useLiveTransforms` — hardcoding 0 makes the node un-rotate mid-drag.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two regressions in the Stage D port surfaced the same gap: the wiki
already said "the mesh offset must mirror the useLiveTransforms entry"
but didn't spell out that for polygon-based kinds (slab / fence /
ceiling / wall), the value to mirror is the DELTA (the group's local
position) — not the world location of the polygon's center.
Expanded the live-drag rule with a position-based vs polygon-based
split and an explicit note that ParametricNodeRenderer reconciles the
group's position via React on every Zustand notification, so the two
writes must agree to the exact value or they fight every frame.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New page covering the geometry/renderer/system trio that registry-driven
kinds opt into. Documents:
- The three optional fields on NodeDefinition and when each applies
- Generic <GeometrySystem> + <ParametricNodeRenderer> runtime
- GeometryContext shape (resolve / children / siblings / parent)
- Combination matrix for shelf / spawn / zone / door / window / GLB items
- Migration recipe from custom renderer+system files to def.geometry
- Rules around purity, dispose-on-rebuild, register-once
renderers.md and systems.md gain "prefer registry-driven" banners and
link out to the new page. Architecture README adds the page to the
index so review-architecture skill picks it up.
The pattern was validated by the shelf spike: inline-JSX geometry was
visibly laggy on parametric edits; moving to a per-kind system reading
dirtyNodes (mirroring door/wall/item) restored smoothness. The three-
checkbox model generalises that win so most future kinds need only a
pure geometry function.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace per-tool rule trees (.cursor/rules, .claude/rules, .codex/rules)
with a single wiki/architecture/ source — 11 pages + README — readable
as plain markdown by any agent. Canonical skills live in .agents/skills/;
.claude/skills, .cursor/skills, .codex/skills are directory symlinks.
AGENTS.md is the entrypoint (rewritten as a lean overview, no per-tool
path lists). CLAUDE.md, GEMINI.md, and .github/copilot-instructions.md
all point to it.
Add open-pr skill (uses .github/pull_request_template.md as the source
of truth for the PR body) and remove the dangling .claude/CLAUDE.md
relative symlink.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>