Column exposes shaft / base / capital / frame slots on node.slots (base when baseStyle!=none, capital when capitalStyle!=none, frame only for non-vertical support styles). The single material context is widened to a per-slot map plus a ColumnSlotContext; each part subtree is wrapped in <ColumnSlot> so every mesh primitive resolves its material AND stamps userData.slotId from the same context. Decorative shaft parts inherit shaft, base/capital carvings inherit their parent slot. Resolution: textures-off wall role -> node.slots ref -> legacy material/preset -> declared default (shaft/base/capital concrete-plaster, frame metal-steel). Monochrome unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
30 lines
996 B
TypeScript
30 lines
996 B
TypeScript
import type { SlotDeclaration } from '@pascal-app/core'
|
|
import type { ColumnNode } from './schema'
|
|
|
|
export type ColumnSlotId = 'shaft' | 'base' | 'capital' | 'frame'
|
|
|
|
export const COLUMN_SHAFT_DEFAULT = 'library:concrete-plaster'
|
|
export const COLUMN_BASE_DEFAULT = 'library:concrete-plaster'
|
|
export const COLUMN_CAPITAL_DEFAULT = 'library:concrete-plaster'
|
|
export const COLUMN_FRAME_DEFAULT = 'library:metal-steel'
|
|
|
|
export function columnSlots(node: ColumnNode): SlotDeclaration[] {
|
|
const slots: SlotDeclaration[] = [
|
|
{ slotId: 'shaft', label: 'Shaft', default: COLUMN_SHAFT_DEFAULT },
|
|
]
|
|
|
|
if (node.baseStyle !== 'none') {
|
|
slots.push({ slotId: 'base', label: 'Base', default: COLUMN_BASE_DEFAULT })
|
|
}
|
|
|
|
if (node.capitalStyle !== 'none') {
|
|
slots.push({ slotId: 'capital', label: 'Capital', default: COLUMN_CAPITAL_DEFAULT })
|
|
}
|
|
|
|
if (node.supportStyle !== 'vertical') {
|
|
slots.push({ slotId: 'frame', label: 'Frame', default: COLUMN_FRAME_DEFAULT })
|
|
}
|
|
|
|
return slots
|
|
}
|