Stair exposes three paintable slots — treads / body / railing (railing only when railingMode != none) — on node.slots. The 2-material-index body mesh maps materialIndex 0->treads, 1->body via userData.slotIds; railing meshes tag userData.slotId='railing'. Per-slot resolution layers over the viewer's base body/railing materials only in textures-on mode: node.slots ref -> legacy per-part field (preserved) -> declared default (treads wood-woodplank48, body wood-woodfine2, railing metal-steel). A custom preview swaps the targeted body material-array index and whole-mesh railing materials. Monochrome unchanged. Stops using DEFAULT_STAIR_MATERIAL. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
21 lines
753 B
TypeScript
21 lines
753 B
TypeScript
import type { SlotDeclaration, StairNode } from '@pascal-app/core'
|
|
|
|
export type StairSlotId = 'treads' | 'body' | 'railing'
|
|
|
|
export const STAIR_TREADS_SLOT_DEFAULT = 'library:wood-woodplank48'
|
|
export const STAIR_BODY_SLOT_DEFAULT = 'library:wood-woodfine2'
|
|
export const STAIR_RAILING_SLOT_DEFAULT = 'library:metal-steel'
|
|
|
|
export function stairSlots(node: StairNode): SlotDeclaration[] {
|
|
const slots: SlotDeclaration[] = [
|
|
{ slotId: 'treads', label: 'Treads', default: STAIR_TREADS_SLOT_DEFAULT },
|
|
{ slotId: 'body', label: 'Body', default: STAIR_BODY_SLOT_DEFAULT },
|
|
]
|
|
|
|
if (node.railingMode && node.railingMode !== 'none') {
|
|
slots.push({ slotId: 'railing', label: 'Railing', default: STAIR_RAILING_SLOT_DEFAULT })
|
|
}
|
|
|
|
return slots
|
|
}
|