Wall Phase 3 milestone B: runtime port behind feature flag

Brings the wall kind onto the registry path when
NEXT_PUBLIC_USE_REGISTRY_FOR_WALL=true; default-off keeps wall on its
legacy path unchanged.

Files added:

- nodes/src/wall/renderer.tsx — thin placeholder-mesh mount point.
  Identical pattern to the legacy WallRenderer: registers ref via
  useRegistry, marks dirty on mount, renders hosted children
  recursively via NodeRenderer. The legacy WallSystem fills geometry
  on the next frame regardless of which mount path is active.

- nodes/src/wall/system.tsx — a bundle component that renders
  <WallSystem /> + <WallCutout /> (both re-exported from viewer).
  Registered via def.system with priority 4 to mirror the legacy
  WallSystem's useFrame priority. Zero logic duplication — the
  ~970 lines of CSG/mitering/cutaway code stays in viewer.

Files changed:

- packages/viewer/src/index.ts — new exports for WallSystem, WallCutout,
  and NodeRenderer. The first two so the registry-driven system bundle
  can compose them; NodeRenderer so any parent kind (wall, slab,
  ceiling, building) can recursively render hosted children without
  reaching into viewer internals.

- nodes/src/wall/definition.ts — adds renderer + system fields. Tool
  field stays absent (wall placement / endpoint drag remain bespoke
  for now; the affordance port is a later milestone).

- nodes/src/index.ts — conditionally appends wallDefinition to
  builtinPlugin.nodes based on isWallRegistryEnabled(). With the flag
  off, the array is identical to before this commit; with it on,
  Phase 0 dispatch shims switch wall to the registry path:
    * <LegacySystem kind="wall"> around WallSystem returns null
    * <LegacySystem kind="wall"> around WallCutout returns null
    * <NodeRenderer> takes the registry-first branch and mounts the
      new renderer instead of the legacy switch case for 'wall'
    * RegisteredSystems mounts the new system bundle, which re-mounts
      the same WallSystem + WallCutout components from viewer

No behavior change with the flag off. With the flag on, behavior should
be byte-identical (same components, same priority, same geometry path).
Manual verification next: place walls, t-junctions, walls-with-doors
with the flag toggled both ways; confirm visual + interactive parity.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Wassim SAMAD
2026-05-15 09:00:15 -04:00
co-authored by Claude Opus 4.7
parent 0a723fa1f2
commit 02aeca8439
5 changed files with 172 additions and 3 deletions
+11
View File
@@ -1,3 +1,8 @@
// `NodeRenderer` is the recursive dispatch component used by parent
// renderers (wall renders doors/windows, slab renders hosted items).
// Public so registry-driven kinds can compose children without reaching
// into viewer's internal paths.
export { NodeRenderer } from './components/renderers/node-renderer'
export { default as Viewer } from './components/viewer'
export type { HoverStyle, HoverStyles } from './components/viewer/post-processing'
export {
@@ -29,4 +34,10 @@ export { InteractiveSystem } from './systems/interactive/interactive-system'
export { snapLevelsToTruePositions } from './systems/level/level-utils'
export { getRoofMaterialArray } from './systems/roof/roof-materials'
export { getStairBodyMaterials, getStairRailingMaterial } from './systems/stair/stair-materials'
export { WallCutout } from './systems/wall/wall-cutout'
export { getVisibleWallMaterials } from './systems/wall/wall-materials'
// Wall internals re-exported so `@pascal-app/nodes`' registry-driven wall
// definition can compose them into `def.system` without duplicating the
// 800+ lines of CSG / mitering logic during Phase 3. These exports are
// removed in Phase 6 when the legacy mount points are deleted.
export { WallSystem } from './systems/wall/wall-system'