diff --git a/apps/editor/public/material/concrete/concrete_plate/concrete_plate_ao_512.ktx2 b/apps/editor/public/material/concrete/concrete_plate/concrete_plate_ao_512.ktx2 new file mode 100644 index 00000000..35e24b31 Binary files /dev/null and b/apps/editor/public/material/concrete/concrete_plate/concrete_plate_ao_512.ktx2 differ diff --git a/apps/editor/public/material/concrete/concrete_plate/concrete_plate_basecolor_512.ktx2 b/apps/editor/public/material/concrete/concrete_plate/concrete_plate_basecolor_512.ktx2 new file mode 100644 index 00000000..7d82bd56 Binary files /dev/null and b/apps/editor/public/material/concrete/concrete_plate/concrete_plate_basecolor_512.ktx2 differ diff --git a/apps/editor/public/material/concrete/concrete_plate/concrete_plate_normal_512.ktx2 b/apps/editor/public/material/concrete/concrete_plate/concrete_plate_normal_512.ktx2 new file mode 100644 index 00000000..4da4bb11 Binary files /dev/null and b/apps/editor/public/material/concrete/concrete_plate/concrete_plate_normal_512.ktx2 differ diff --git a/apps/editor/public/material/concrete/concrete_plate/concrete_plate_roughness_512.ktx2 b/apps/editor/public/material/concrete/concrete_plate/concrete_plate_roughness_512.ktx2 new file mode 100644 index 00000000..8a5044f2 Binary files /dev/null and b/apps/editor/public/material/concrete/concrete_plate/concrete_plate_roughness_512.ktx2 differ diff --git a/apps/editor/public/material/concrete/concrete_plate/concrete_plate_thumb.webp b/apps/editor/public/material/concrete/concrete_plate/concrete_plate_thumb.webp new file mode 100644 index 00000000..495ef6ca Binary files /dev/null and b/apps/editor/public/material/concrete/concrete_plate/concrete_plate_thumb.webp differ diff --git a/packages/core/src/material-library.ts b/packages/core/src/material-library.ts index d743d03c..88b7068b 100644 --- a/packages/core/src/material-library.ts +++ b/packages/core/src/material-library.ts @@ -3860,6 +3860,44 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ }, }, }, + { + id: 'concrete-plate', + label: 'Concrete Plate', + category: 'concrete', + surfaces: ['wall', 'floor'], + description: 'Smooth cast concrete plate', + previewThumbnailUrl: '/material/concrete/concrete_plate/concrete_plate_thumb.webp', + preset: { + maps: { + albedoMap: '/material/concrete/concrete_plate/concrete_plate_basecolor_512.ktx2', + normalMap: '/material/concrete/concrete_plate/concrete_plate_normal_512.ktx2', + roughnessMap: '/material/concrete/concrete_plate/concrete_plate_roughness_512.ktx2', + aoMap: '/material/concrete/concrete_plate/concrete_plate_ao_512.ktx2', + }, + mapProperties: { + color: '#ffffff', + roughness: 0.8, + metalness: 0, + repeatX: 0.5, + repeatY: 0.5, + rotation: 0, + wrapS: 'Repeat', + wrapT: 'Repeat', + normalScaleX: 1, + normalScaleY: 1, + emissiveIntensity: 1, + displacementScale: 0, + transparent: false, + flipY: false, + bumpScale: 1, + emissiveColor: '#000000', + aoMapIntensity: 1, + side: 0, + opacity: 1, + lightMapIntensity: 1, + }, + }, + }, { id: 'concrete-stucco', label: 'White Stucco', diff --git a/packages/core/src/schema/nodes/wall.ts b/packages/core/src/schema/nodes/wall.ts index c356ae60..c1d65e4b 100644 --- a/packages/core/src/schema/nodes/wall.ts +++ b/packages/core/src/schema/nodes/wall.ts @@ -52,8 +52,8 @@ export type WallSurfaceSide = 'interior' | 'exterior' // May be a `#rrggbb` colour or a `library:` ref. Textures-off still // collapses to the themed wall role (the escape hatch). export const WALL_SLOT_DEFAULT: Record = { - interior: '#ffffff', - exterior: '#ffffff', + interior: 'library:concrete-plate', + exterior: 'library:concrete-plate', } export type WallSurfaceMaterialSpec = { diff --git a/packages/nodes/src/ceiling/slots.ts b/packages/nodes/src/ceiling/slots.ts index 7ca5e286..7b7c48a9 100644 --- a/packages/nodes/src/ceiling/slots.ts +++ b/packages/nodes/src/ceiling/slots.ts @@ -2,8 +2,9 @@ import type { SlotDeclaration } from '@pascal-app/core' export type CeilingSlotId = 'surface' -// Visual parity with the retired DEFAULT_CEILING_MATERIAL (warm beige). -export const CEILING_SLOT_DEFAULT_COLOR = '#f5f5dc' +// Soft white — the default underside colour for an unpainted ceiling. (A +// ceiling renders flat-tinted, so this is a colour, not a `library:` finish.) +export const CEILING_SLOT_DEFAULT_COLOR = '#f2eee6' /** A ceiling exposes a single paintable underside surface. */ export function ceilingSlots(): SlotDeclaration[] { diff --git a/packages/nodes/src/slab/geometry.ts b/packages/nodes/src/slab/geometry.ts index b15c1726..851660ec 100644 --- a/packages/nodes/src/slab/geometry.ts +++ b/packages/nodes/src/slab/geometry.ts @@ -8,9 +8,10 @@ import { generateSlabGeometry, type RenderShading, resolveMaterialRef, + resolveSlotDefaultMaterial, } from '@pascal-app/viewer' import { FrontSide, Group, type Material, Mesh, type Texture } from 'three' -import { SLAB_SLOT_DEFAULT_COLOR } from './slots' +import { SLAB_SLOT_DEFAULT } from './slots' /** * Stage B builder for slab. Reuses `generateSlabGeometry` (pure @@ -62,8 +63,8 @@ function getSlabMaterial( return getLegacySlabMaterial(node, shading) } - // Declared slot default (visual parity with the retired DEFAULT_SLAB_MATERIAL). - return createDefaultMaterial(SLAB_SLOT_DEFAULT_COLOR, 0.8, shading) + // Declared slot default — a catalog `library:` finish or a flat colour. + return resolveSlotDefaultMaterial(SLAB_SLOT_DEFAULT, shading, 0.8) } function getLegacySlabMaterial(node: SlabNode, shading: RenderShading): Material { @@ -83,7 +84,7 @@ function getLegacySlabMaterial(node: SlabNode, shading: RenderShading): Material ? createDefaultMaterial('#ffffff', 0.5, shading) : node.material ? createMaterial(node.material, shading).clone() - : createDefaultMaterial(SLAB_SLOT_DEFAULT_COLOR, 0.8, shading) + : createDefaultMaterial('#e5e5e5', 0.8, shading) if (preset) { applyMaterialPresetToMaterials(material, preset) diff --git a/packages/nodes/src/slab/slots.ts b/packages/nodes/src/slab/slots.ts index febe029b..094bdb0c 100644 --- a/packages/nodes/src/slab/slots.ts +++ b/packages/nodes/src/slab/slots.ts @@ -2,10 +2,12 @@ import type { SlotDeclaration } from '@pascal-app/core' export type SlabSlotId = 'surface' -// Visual parity with the retired DEFAULT_SLAB_MATERIAL (light grey). -export const SLAB_SLOT_DEFAULT_COLOR = '#e5e5e5' +// Declared default appearance for an unpainted slab surface in colored mode — +// a catalog `library:` finish or a `#rrggbb` colour. Textures-off collapses +// to the themed floor role (the escape hatch). +export const SLAB_SLOT_DEFAULT = 'library:wood-woodplank48' /** A slab exposes a single paintable floor surface. */ export function slabSlots(): SlotDeclaration[] { - return [{ slotId: 'surface', label: 'Surface', default: SLAB_SLOT_DEFAULT_COLOR }] + return [{ slotId: 'surface', label: 'Surface', default: SLAB_SLOT_DEFAULT }] } diff --git a/packages/viewer/src/index.ts b/packages/viewer/src/index.ts index f8e55fa3..7d2c9469 100644 --- a/packages/viewer/src/index.ts +++ b/packages/viewer/src/index.ts @@ -69,6 +69,7 @@ export { PRESET_PALETTES, type RenderShading, resolveMaterialRef, + resolveSlotDefaultMaterial, resolveSurfaceColor, WHITE_PALETTE, } from './lib/materials' diff --git a/packages/viewer/src/lib/materials.ts b/packages/viewer/src/lib/materials.ts index fbfdc1ac..677b1d13 100644 --- a/packages/viewer/src/lib/materials.ts +++ b/packages/viewer/src/lib/materials.ts @@ -516,6 +516,26 @@ export function resolveMaterialRef( return createMaterial(sceneMaterial.material, shading) } +/** + * Resolve a node kind's declared slot default — either a catalog `library:` + * finish or a flat `#rrggbb` colour — to a renderable material. Shared by the + * procedural kinds whose colored-mode unpainted appearance comes from a + * declarative default (slab, wall). + */ +export function resolveSlotDefaultMaterial( + slotDefault: string, + shading: RenderShading = 'rendered', + roughness = 0.9, +): THREE.Material { + if (parseMaterialRef(slotDefault)?.kind === 'library') { + return ( + createMaterialFromPresetRef(slotDefault, shading) ?? + createDefaultMaterial('#ffffff', roughness, shading) + ) + } + return createDefaultMaterial(slotDefault, roughness, shading) +} + export function createDefaultMaterial( color = '#ffffff', roughness = 0.9,