Files
editor/packages/nodes/src/shelf/definition.ts
T
Wassim SAMADandClaude Opus 4.7 ac36297e7e Phase 4 follow-on: registry-driven floor-plan rendering + shelf port
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>
2026-05-15 10:34:42 -04:00

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.',
},
}