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>
73 lines
2.2 KiB
TypeScript
73 lines
2.2 KiB
TypeScript
import type { NodeDefinition } from '@pascal-app/core'
|
|
import { buildShelfFloorplan } from './floorplan'
|
|
import { buildShelfGeometry } from './geometry'
|
|
import { shelfParametrics } from './parametrics'
|
|
import { ShelfNode } from './schema'
|
|
|
|
export const shelfDefinition: NodeDefinition<typeof ShelfNode> = {
|
|
kind: 'shelf',
|
|
schemaVersion: 1,
|
|
schema: ShelfNode,
|
|
category: 'furnish',
|
|
|
|
defaults: () => ({
|
|
object: 'node',
|
|
parentId: null,
|
|
visible: true,
|
|
metadata: {},
|
|
position: [0, 0, 0],
|
|
rotation: [0, 0, 0],
|
|
width: 1.2,
|
|
depth: 0.3,
|
|
thickness: 0.04,
|
|
height: 0.9,
|
|
bracketStyle: 'minimal',
|
|
color: '#a07050',
|
|
}),
|
|
|
|
capabilities: {
|
|
movable: { axes: ['x', 'z'], gridSnap: true },
|
|
rotatable: {
|
|
axes: ['y'],
|
|
snapAngles: [0, Math.PI / 4, Math.PI / 2, (3 * Math.PI) / 4, Math.PI],
|
|
},
|
|
// The whole point of shelf: things can stack on it. Surface height
|
|
// resolves from the node so multiple shelves at different heights stack
|
|
// correctly (vs a fixed-height table).
|
|
surfaces: {
|
|
top: { height: (n) => (n as ShelfNode).height + (n as ShelfNode).thickness },
|
|
},
|
|
selectable: { hitVolume: 'bbox' },
|
|
duplicable: true,
|
|
deletable: true,
|
|
},
|
|
|
|
parametrics: shelfParametrics,
|
|
|
|
// Three-checkbox composition: shelf needs only pure builder functions.
|
|
// The framework's <ParametricNodeRenderer> + <GeometrySystem> handle 3D
|
|
// mount and rebuild on dirty; the <FloorplanRegistryLayer> calls
|
|
// buildShelfFloorplan for the 2D top-down view. No renderer.tsx, no
|
|
// system.tsx, no inline floor-plan SVG — see
|
|
// `wiki/architecture/node-definitions.md`. Shelf is the reference port
|
|
// proving Phase 4's boilerplate collapse for both 3D and 2D.
|
|
geometry: buildShelfGeometry,
|
|
floorplan: buildShelfFloorplan,
|
|
|
|
preview: () => import('./preview'),
|
|
tool: () => import('./tool'),
|
|
|
|
presentation: {
|
|
label: 'Shelf',
|
|
description: 'A horizontal surface for stacking other items.',
|
|
icon: { kind: 'iconify', name: 'lucide:layers' },
|
|
paletteSection: 'structure',
|
|
paletteOrder: 50,
|
|
},
|
|
|
|
mcp: {
|
|
description:
|
|
'A parametric shelf with adjustable dimensions and bracket style. Stackable on its top surface.',
|
|
},
|
|
}
|