- fence: split into two paint slots — panel (posts/base/infill, default charcoal) and rail (cap, default wood-finewood27) — as separate meshes with userData.slotId. Fix applyFenceUVs to continuous world-space 1 UV unit = 1 m (drop the per-part min origin that broke tiling across parts). New generateFenceSlotGeometries. - roof: real catalog defaults for the segment surfaces via getRoofMaterialArray (the actual default path): wall/trim concrete-plate (matches walls), deck + soffit soft-white, shingle terracotta; textures-off role escape hatch kept. Align nodes getRoofMaterials no-parent fallback to match. - stair: body slot default -> preset-lightgrey. - (biome formatting normalization of the round-1 merged renderer files rides along.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
20 lines
747 B
TypeScript
20 lines
747 B
TypeScript
import type { AnyNode, FenceNode, PaintResolveArgs } from '@pascal-app/core'
|
|
import { createSlotPaintCapability, previewGeometrySlot } from '../shared/slot-paint'
|
|
|
|
function resolveFenceRole(args: PaintResolveArgs): string | null {
|
|
const slotId = (args.hitObject?.userData as { slotId?: unknown } | undefined)?.slotId
|
|
return slotId === 'panel' || slotId === 'rail' ? 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
|
|
},
|
|
})
|