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>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
3f3818f3b0
commit
ac36297e7e
@@ -22,6 +22,9 @@ export type {
|
||||
CuttableConfig,
|
||||
DragAction,
|
||||
EditorCtx,
|
||||
FloorplanGeometry,
|
||||
FloorplanPoint,
|
||||
FloorplanStyle,
|
||||
GeometryContext,
|
||||
HostableConfig,
|
||||
IconRef,
|
||||
|
||||
@@ -26,6 +26,58 @@ export type GeometryContext = {
|
||||
parent: AnyNode | null
|
||||
}
|
||||
|
||||
// ─── FloorplanGeometry ───────────────────────────────────────────────
|
||||
//
|
||||
// Output shape for `def.floorplan(node, ctx)`. The floor-plan panel
|
||||
// converts these primitives to React-SVG elements via a generic renderer
|
||||
// — kinds never touch SVG nodes directly. Coordinates are level-local
|
||||
// meters; the panel handles world→SVG transform via its viewBox.
|
||||
//
|
||||
// Visual styling lives in the geometry so an AI-authored kind can pick
|
||||
// its own colors without needing to know about CSS / theme tokens. The
|
||||
// renderer maps these directly to SVG attributes.
|
||||
|
||||
export type FloorplanPoint = readonly [x: number, y: number]
|
||||
|
||||
export type FloorplanStyle = {
|
||||
stroke?: string
|
||||
fill?: string
|
||||
strokeWidth?: number
|
||||
strokeDasharray?: string
|
||||
opacity?: number
|
||||
}
|
||||
|
||||
export type FloorplanGeometry =
|
||||
| ({ kind: 'path'; d: string } & FloorplanStyle)
|
||||
| ({ kind: 'polygon'; points: readonly FloorplanPoint[] } & FloorplanStyle)
|
||||
| ({
|
||||
kind: 'polyline'
|
||||
points: readonly FloorplanPoint[]
|
||||
} & FloorplanStyle)
|
||||
| ({
|
||||
kind: 'rect'
|
||||
x: number
|
||||
y: number
|
||||
width: number
|
||||
height: number
|
||||
rx?: number
|
||||
ry?: number
|
||||
} & FloorplanStyle)
|
||||
| ({ kind: 'circle'; cx: number; cy: number; r: number } & FloorplanStyle)
|
||||
| ({
|
||||
kind: 'line'
|
||||
x1: number
|
||||
y1: number
|
||||
x2: number
|
||||
y2: number
|
||||
} & FloorplanStyle)
|
||||
| {
|
||||
kind: 'group'
|
||||
children: FloorplanGeometry[]
|
||||
/** Optional transform applied to all children. Rotation in radians. */
|
||||
transform?: { translate?: FloorplanPoint; rotate?: number }
|
||||
}
|
||||
|
||||
// ─── Plugin manifest ─────────────────────────────────────────────────
|
||||
|
||||
export type Plugin = {
|
||||
@@ -76,6 +128,21 @@ export type NodeDefinition<S extends ZodObject<any>> = {
|
||||
* work (animations, named-mesh material poking).
|
||||
*/
|
||||
geometry?: (node: z.infer<S>, ctx: GeometryContext) => Object3D
|
||||
/**
|
||||
* Pure 2D builder for floor-plan rendering. Mirrors `geometry` but emits
|
||||
* plain `FloorplanGeometry` data (SVG-renderable) rather than three.js
|
||||
* Object3D. Coordinates are level-local meters — the floor-plan panel
|
||||
* applies the world→SVG transform.
|
||||
*
|
||||
* Returns `null` when the kind shouldn't appear in floor plan (e.g. an
|
||||
* invisible utility node, or a kind that's 3D-only). Kinds that need
|
||||
* floor-plan rendering but no 3D mesh set `floorplan` without `geometry`.
|
||||
*
|
||||
* See `wiki/architecture/node-definitions.md` ("floor-plan rendering"
|
||||
* section) and Phase 5 of the registry plan for the migration plan off
|
||||
* the legacy `floorplan-panel.tsx` monolith.
|
||||
*/
|
||||
floorplan?: (node: z.infer<S>, ctx: GeometryContext) => FloorplanGeometry | null
|
||||
system?: SystemContribution
|
||||
tool?: LazyComponent
|
||||
affordances?: Affordance<z.infer<S>>[]
|
||||
|
||||
Reference in New Issue
Block a user