Builds on the explicit per-mesh slot tagging (currentDoorSlot/currentWindowSlot): - Per-part painting: door = panel/frame/glass/hardware, window = frame/glass, each independently paintable. The recessed door/window body sits behind the wall, so the proud invisible cutout wins the scene raycast over the wall and the shared resolveSlotByReRaycast() re-raycasts the kind's own subtree to pick the exact part under the cursor (panel↔frame↔glass↔hardware). Hover tracks the cursor via a re-eval (idempotent, no flicker). - Door frame is its own slot (separate frameMaterial); hardware = new flat 'metal-chrome'. - Library defaults (generic): panel/frame -> library:preset-softwhite, glass -> library:preset-glass (flipped preset-glass to FrontSide — DoubleSide poisons the WebGPU MRT pass; it's the only glass we use). - Catalog: add flat (non-PBR) 'metal-chrome' + 'metal-brass'; drop metal metalness 1 -> 0.6 so metals are lit by existing lights (no env needed). - World-scale UVs (1 unit = 1m) on door/window box meshes via shared box-uv.ts, so finishes tile at real-world scale instead of stretching. - PaintResolveArgs gains an optional for subtree re-raycasting. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
26 lines
1.0 KiB
TypeScript
26 lines
1.0 KiB
TypeScript
import type { SlotDeclaration } from '@pascal-app/core'
|
|
|
|
export type DoorSlotId = 'panel' | 'frame' | 'glass' | 'hardware'
|
|
|
|
// Picker swatches. Rendering falls back to the live body/glass/hardware defaults
|
|
// (which already track shading + theme), so these are just the indicator colours.
|
|
const PANEL_DEFAULT = 'library:preset-softwhite'
|
|
const FRAME_DEFAULT = 'library:preset-softwhite'
|
|
const GLASS_DEFAULT = 'library:preset-glass'
|
|
// Chrome — a flat (non-PBR) catalog metal finish.
|
|
const HARDWARE_DEFAULT = 'library:metal-chrome'
|
|
|
|
/**
|
|
* A door exposes four paintable slots: `panel` (leaf faces), `frame`, `glass`,
|
|
* and `hardware` (handle / hinges / closer / panic bar). The opening reveal
|
|
* keeps its own material.
|
|
*/
|
|
export function doorSlots(): SlotDeclaration[] {
|
|
return [
|
|
{ slotId: 'panel', label: 'Panel', default: PANEL_DEFAULT },
|
|
{ slotId: 'frame', label: 'Frame', default: FRAME_DEFAULT },
|
|
{ slotId: 'glass', label: 'Glass', default: GLASS_DEFAULT },
|
|
{ slotId: 'hardware', label: 'Hardware', default: HARDWARE_DEFAULT },
|
|
]
|
|
}
|