Wassim SAMAD 6a4de8cff5 Drop wall + fence feature flags: register unconditionally; remove verification logs
Parity comparison against deployed prod is now cleaner than juggling
env-var flag toggles locally. Both kinds enter builtinPlugin.nodes
unconditionally; the Phase 0 dispatch shims (<LegacySystem kind="X">
wrappers + NodeRenderer's registry-first branch) handle the cutover.

Files deleted:
 - packages/nodes/src/wall/feature-flag.ts
 - packages/nodes/src/fence/feature-flag.ts

Files changed:
 - packages/nodes/src/index.ts: drops isWallRegistryEnabled /
   isFenceRegistryEnabled gates; wallDefinition + fenceDefinition
   land directly in builtinPlugin.nodes.
 - packages/nodes/src/{wall,fence}/index.ts: drop the flag re-export.
 - packages/nodes/src/{wall,fence}/renderer.tsx: drop the one-shot
   verification console.info. Same for the system.tsx wrappers.
 - packages/viewer/src/components/renderers/{wall,fence}/{wall,fence}-
   renderer.tsx: drop the paired [X:legacy] verification logs (no
   longer comparing flag-toggled paths).

Net DX: no env var to remember when starting `bun dev:community`. To
A/B test, compare against editor.pascal.app deployed prod.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 11:59:09 -04:00

85 lines
2.7 KiB
TypeScript

'use client'
import { useRegistry, useScene, type WallNode } from '@pascal-app/core'
import { getVisibleWallMaterials, NodeRenderer, useNodeEvents } from '@pascal-app/viewer'
import { useEffect, useLayoutEffect, useMemo, useRef } from 'react'
import { BufferGeometry, Float32BufferAttribute, type Mesh } from 'three'
/**
* Thin wall renderer.
*
* Mounts a placeholder mesh, registers it with `sceneRegistry`, marks the
* node dirty so `WallSystem` fills the geometry on the next frame, and
* recursively renders hosted children (doors / windows / wall-mounted
* items) inside the wall's local frame.
*
* Behaviorally identical to the legacy `WallRenderer` in
* `@pascal-app/viewer/components/renderers/wall/wall-renderer.tsx`.
* Phase 6 deletes the legacy file; until then both coexist and the Phase 0
* shims pick which one renders based on `nodeRegistry.has('wall')`.
*
* No `geometry` field on the wall definition yet — wall's geometry depends
* on level-batch miter data (see `WallSystem.calculateLevelMiters`), which
* doesn't fit the generic `(node, ctx) => Group` shape without `ctx.levelData`.
* That decision lands in a later milestone; for now the system retains
* ownership of the rebuild loop.
*/
function createEmptyWallGeometry(): BufferGeometry {
const geometry = new BufferGeometry()
geometry.setAttribute('position', new Float32BufferAttribute([], 3))
geometry.addGroup(0, 0, 0)
geometry.addGroup(0, 0, 1)
geometry.addGroup(0, 0, 2)
return geometry
}
const WallRenderer = ({ node }: { node: WallNode }) => {
const ref = useRef<Mesh>(null!)
const placeholderGeometry = useMemo(createEmptyWallGeometry, [])
const collisionPlaceholderGeometry = useMemo(() => {
const geometry = new BufferGeometry()
geometry.setAttribute('position', new Float32BufferAttribute([], 3))
return geometry
}, [])
useRegistry(node.id, 'wall', ref)
useLayoutEffect(() => {
useScene.getState().markDirty(node.id)
}, [node.id])
useEffect(() => {
return () => {
placeholderGeometry.dispose()
collisionPlaceholderGeometry.dispose()
}
}, [collisionPlaceholderGeometry, placeholderGeometry])
const handlers = useNodeEvents(node, 'wall')
const material = getVisibleWallMaterials(node)
return (
<mesh
castShadow
geometry={placeholderGeometry}
material={material}
receiveShadow
ref={ref}
visible={node.visible}
>
<mesh
geometry={collisionPlaceholderGeometry}
name="collision-mesh"
visible={false}
{...handlers}
/>
{node.children.map((childId) => (
<NodeRenderer key={`${node.id}:${childId}`} nodeId={childId} />
))}
</mesh>
)
}
export default WallRenderer