- Add 'concrete-drywall' (Prepared Drywall) catalog finish + 512 KTX2/webp runtime assets; default walls (WALL_SLOT_DEFAULT interior+exterior) and the roof wall/trim band to it so roofs read continuous with walls. - fence: replace the 2-slot panel/rail split with 4 slots that match the panel's build options — posts / infill (showInfill) / base (grounded only) / rail — each its own mesh with userData.slotId; conditional slots track the build state. Defaults: posts/infill/base charcoal, rail wood-finewood27. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
22 lines
841 B
TypeScript
22 lines
841 B
TypeScript
import type { AnyNode, FenceNode, PaintResolveArgs } from '@pascal-app/core'
|
|
import { createSlotPaintCapability, previewGeometrySlot } from '../shared/slot-paint'
|
|
|
|
const FENCE_SLOT_IDS = new Set<string>(['posts', 'infill', 'base', 'rail'])
|
|
|
|
function resolveFenceRole(args: PaintResolveArgs): string | null {
|
|
const slotId = (args.hitObject?.userData as { slotId?: unknown } | undefined)?.slotId
|
|
return typeof slotId === 'string' && FENCE_SLOT_IDS.has(slotId) ? slotId : null
|
|
}
|
|
|
|
export const fencePaint = createSlotPaintCapability({
|
|
resolveRole: resolveFenceRole,
|
|
applyPreview: previewGeometrySlot,
|
|
legacyEffective: (node: AnyNode) => {
|
|
const fence = node as FenceNode
|
|
if (fence.materialPreset || fence.material) {
|
|
return { material: fence.material, materialPreset: fence.materialPreset }
|
|
}
|
|
return null
|
|
},
|
|
})
|