registry: generic FloorElevationSystem driven by a floorPlaced capability

Symptom: a shelf placed on a level with a raised slab underneath
visually clipped through it — `ItemSystem` lifted items onto slabs,
but shelves (and other floor-placed registry kinds) had no equivalent
path.

Fix: lift the slab-elevation logic out of `ItemSystem` into a generic
`<FloorElevationSystem>` keyed off a new `capabilities.floorPlaced`
config. Any kind that opts in declares a `footprint(node)` (dimensions
+ rotation used to query overlapping slabs) and an optional `applies`
predicate (skips items whose `asset.attachTo` is wall / ceiling).

The new system runs at frame priority 1 so its `mesh.position.y`
override lands before `ItemSystem` / `GeometrySystem` (priority 2)
clear the dirty mark. The spatial-grid sync's `markNodesOverlappingSlab`
also dropped its hardcoded `item` branch in favour of an iteration over
every registered kind that declares `floorPlaced` — so any new
floor-placed kind picks up slab-driven re-elevation automatically.

Tagged kinds:
 - `item`  — `footprint = getScaledDimensions`, `applies = !asset.attachTo`
 - `shelf` — `footprint = (w, h, d)`
 - `column` — `footprint = (w, h, d)`
 - `spawn` — `footprint = (0.6, 1.8, 0.6)` (marker)

`ItemSystem` retains only the wall-side z-offset block (`mesh.position.z =
wallThickness / 2`). The elevation block + its `getScaledDimensions` /
`resolveLevelId` / `spatialGridManager` imports moved to the generic
system.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Wassim SAMAD
2026-05-19 19:44:21 -04:00
co-authored by Claude Opus 4.7
parent 78e3ed13d8
commit 9a481f2511
10 changed files with 170 additions and 43 deletions
+11
View File
@@ -59,6 +59,17 @@ export const shelfDefinition: NodeDefinition<typeof ShelfNode> = {
selectable: { hitVolume: 'bbox' },
duplicable: true,
deletable: true,
// Slab elevation lift via the generic `<FloorElevationSystem>` — a
// shelf sitting over a raised slab visually rests on top of it.
floorPlaced: {
footprint: (node) => {
const shelf = node as ShelfNode
return {
dimensions: [shelf.width, shelf.height, shelf.depth] as [number, number, number],
rotation: shelf.rotation,
}
},
},
},
// Items host on shelves the same way they host on slabs / other items —