Wassim SAMAD 6a1d853dd8 IconRef: add url kind, point registered kinds at palette assets
User pointed at the palette's PNG icons in the bottom toolbar — they
expected the inspector title to use the same artwork, not the iconify
lucide glyphs. Different visual style.

- IconRef gains `{ kind: 'url'; src: string }`. Plain `<img>` render
  in ParametricInspector (no next/image — the inspector is
  `'use client'`).
- All currently-registered kinds switched to URL refs matching their
  palette `iconSrc`:
    fence    → /icons/fence.png
    slab     → /icons/floor.png
    ceiling  → /icons/ceiling.png
    wall     → /icons/wall.png
    spawn    → /icons/site.png
    shelf    → /icons/column.png (placeholder, same as palette)
- Kind-owned panels (slab/ceiling) already pass URL strings to their
  own PanelWrapper; unchanged.

Door/window/item will get URL refs when they register at Stage A.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 10:41:45 -04:00

98 lines
2.8 KiB
TypeScript

import type { NodeDefinition } from '@pascal-app/core'
import { buildCeilingFloorplan } from './floorplan'
import { ceilingParametrics } from './parametrics'
import { CeilingNode } from './schema'
/**
* Ceiling — Phase 5 batch kind, polygon-based. Structurally similar to
* slab but with React-rendered hosted children + TSL shader materials +
* named meshes that other systems poke (`getObjectByName('ceiling-grid')`).
*
* **Stage B intentionally skipped**: pure `def.geometry` extraction
* would lose the React children rendering (hosted items) and the
* named-mesh structure. Ceiling keeps `def.renderer` as the custom
* escape hatch (per plans/editor-node-registry.md "custom-behavior
* escape hatch"). Renderer wraps the legacy CeilingRenderer; system
* wraps the legacy CeilingSystem.
*
* **Stage C completed**: `def.floorplan` builder draws the ceiling
* polygon as a dashed outline in floor plan; legacy `ceilingPolygons`
* short-circuits to [] when ceiling is registered.
*/
export const ceilingDefinition: NodeDefinition<typeof CeilingNode> = {
kind: 'ceiling',
schemaVersion: 1,
schema: CeilingNode,
category: 'structure',
defaults: () => ({
object: 'node',
parentId: null,
visible: true,
metadata: {},
children: [],
polygon: [],
holes: [],
holeMetadata: [],
height: 2.5,
autoFromWalls: false,
}),
capabilities: {
selectable: { hitVolume: 'bbox' },
surfaces: {
top: { height: (n) => (n as CeilingNode).height },
},
duplicable: true,
deletable: true,
},
relations: {
hosts: ['item'],
cascadeDelete: 'descendants',
},
parametrics: ceilingParametrics,
// Stage D: kind-owned placement tool. Multi-click polygon drawing
// with a vertical TSL-gradient connector + ground-shadow lines.
tool: () => import('./tool'),
// Stage D — all four ceiling drag-affordances live in this folder.
// 1:1 port of the legacy tools (scene.update per tick + history
// dance + preview fill/outline overlay on move).
affordanceTools: {
'boundary-edit': () => import('./boundary-editor'),
'hole-edit': () => import('./hole-editor'),
move: () => import('./move-tool'),
},
renderer: {
kind: 'parametric',
module: () => import('./renderer'),
},
system: {
module: () => import('./system'),
priority: 4,
},
floorplan: buildCeilingFloorplan,
toolHints: [
{ key: 'Left click', label: 'Trace ceiling outline' },
{ key: 'Enter', label: 'Finish ceiling' },
{ key: 'Esc', label: 'Cancel' },
],
presentation: {
label: 'Ceiling',
description: 'A polygon-bounded ceiling surface that hosts ceiling-mounted items.',
icon: { kind: 'url', src: '/icons/ceiling.png' },
paletteSection: 'structure',
paletteOrder: 40,
},
mcp: {
description: 'A polygon-bounded ceiling with optional cutout holes.',
},
}