Adds the floor-plan side of the three-checkbox composition model documented in wiki/architecture/node-definitions.md. Mirrors the 3D side (def.geometry → <GeometrySystem> → <ParametricNodeRenderer>) but emits SVG primitives instead of three.js Object3Ds, and runs inside the floor-plan panel. Type-side (packages/core/src/registry/types.ts): - New FloorplanGeometry tagged union covering path / polygon / polyline / rect / circle / line / group. FloorplanStyle props map straight to SVG attributes. Coordinates are level-local meters; rotations are radians (three.js convention). - New `def.floorplan?: (node, ctx) => FloorplanGeometry | null` field on NodeDefinition, independent of `geometry` and `renderer`. Re- exported via packages/core/src/registry/index.ts. Runtime (packages/editor): - <FloorplanGeometryRenderer> walks the FloorplanGeometry tree and emits the matching React-SVG elements. Pure data → DOM; no per-kind logic. - <FloorplanRegistryLayer> reads the active levelId, walks the level subtree, looks up each node's def.floorplan, builds a GeometryContext, calls the builder, and renders the output via FloorplanGeometryRenderer. - Mounted in floorplan-panel.tsx just before <FloorplanMarqueeLayer> so registry-driven kinds layer above legacy inline content. Shelf migration (proof port): - New nodes/src/shelf/floorplan.ts — buildShelfFloorplan(node) emits a group with the rotation/translation transform and a width × depth rectangle in the shelf's color. Brackets omitted (hidden under top board from above). - Wired to shelfDefinition.floorplan. Shelf now appears in the floor plan view for the first time (was missing from the legacy panel's inline switch). Pattern proven; every future kind migrating in Phase 5 follows the same shape: a pure (node, ctx) => FloorplanGeometry function. As kinds register their floor-plan builders, the corresponding inline branches in floorplan-panel.tsx become dead code and can be deleted in the same PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
44 lines
1.4 KiB
TypeScript
44 lines
1.4 KiB
TypeScript
import type { FloorplanGeometry } from '@pascal-app/core'
|
||
import type { ShelfNode } from './schema'
|
||
|
||
/**
|
||
* 2D floor-plan representation of a shelf. The top board (the largest
|
||
* visible surface from above) projects to a rectangle of `width × depth`
|
||
* centered on `(position.x, position.z)`, rotated by the shelf's Y angle.
|
||
*
|
||
* Brackets are intentionally omitted — they're hidden under the top
|
||
* board from a top-down view, and adding them as separate rects clutters
|
||
* the plan without conveying useful information at typical zoom levels.
|
||
*
|
||
* Coordinates are level-local meters; the floor-plan panel applies the
|
||
* world→SVG transform via its viewBox. Rotation is radians (three.js
|
||
* convention); the renderer converts to SVG degrees.
|
||
*
|
||
* Pairs with `buildShelfGeometry(node)` — the 3D builder. Same shape,
|
||
* different output projection.
|
||
*/
|
||
export function buildShelfFloorplan(node: ShelfNode): FloorplanGeometry {
|
||
const [px, , pz] = node.position
|
||
const ry = node.rotation[1] ?? 0
|
||
const halfW = node.width / 2
|
||
const halfD = node.depth / 2
|
||
|
||
return {
|
||
kind: 'group',
|
||
transform: { translate: [px, pz], rotate: ry },
|
||
children: [
|
||
{
|
||
kind: 'rect',
|
||
x: -halfW,
|
||
y: -halfD,
|
||
width: node.width,
|
||
height: node.depth,
|
||
fill: node.color,
|
||
stroke: '#1f2937',
|
||
strokeWidth: 0.015,
|
||
opacity: 0.9,
|
||
},
|
||
],
|
||
}
|
||
}
|