diff --git a/packages/viewer/src/systems/slab/slab-system.tsx b/packages/viewer/src/systems/slab/slab-system.tsx index 5732a671..78addcf3 100644 --- a/packages/viewer/src/systems/slab/slab-system.tsx +++ b/packages/viewer/src/systems/slab/slab-system.tsx @@ -254,23 +254,12 @@ function generatePoolGeometry(slabNode: SlabNode): THREE.BufferGeometry { const positions: number[] = [] const uvs: number[] = [] const indices: number[] = [] - const bounds = new THREE.Box2() - - for (const [x, z] of polygon) { - bounds.expandByPoint(new THREE.Vector2(x, z)) - } - for (const hole of holePolygons) { - for (const [x, z] of hole) { - bounds.expandByPoint(new THREE.Vector2(x, z)) - } - } - - const floorWidth = Math.max(bounds.max.x - bounds.min.x, 0.001) - const floorHeight = Math.max(bounds.max.y - bounds.min.y, 0.001) const pushFloorVertex = (x: number, y: number, z: number) => { positions.push(x, y, z) - uvs.push((x - bounds.min.x) / floorWidth, (z - bounds.min.y) / floorHeight) + // Floor UVs in metres (shape-space x, -z), matching generatePositiveSlabGeometry's + // cap mapping so a finish tiles at the same world scale on every surface. + uvs.push(x, -z) } const pushWallVertex = (x: number, y: number, z: number, u: number, v: number) => { diff --git a/wiki/architecture/materials-and-themes.md b/wiki/architecture/materials-and-themes.md index c96c418a..47de0ccd 100644 --- a/wiki/architecture/materials-and-themes.md +++ b/wiki/architecture/materials-and-themes.md @@ -80,3 +80,17 @@ The editor UI chrome is always dark (a fixed `document.body.classList.add('dark' ## Adding a theme Append a `SceneTheme` to `SCENE_THEMES` with all required fields. `clayTints` is a `Partial` — any role you omit falls back to the active `colorPreset`. The theme pickers (toolbar + community overlay) render a 2×2 swatch from `clayTints` over `background`, so populate at least `wall`/`roof`/`floor`/`glazing` for a good swatch. + +## Texture world scale (UVs in metres) + +Every procedural surface generates UVs in metres: 1 UV unit = 1 m. + +This contract is shared by wall `systems/wall/wall-system.tsx` (`ExtrudeGeometry`), slab `systems/slab/slab-system.tsx` (`generatePositiveSlabGeometry`, and `generatePoolGeometry`), ceiling `systems/ceiling/ceiling-system.tsx`, roof `systems/roof/roof-system.tsx`, and chimney/dormer `nodes/src/chimney/geometry.ts`. + +GLB item slots follow the same ~1 UV unit/m authoring convention, enforced by the slot validator's UV-presence check and the phase-6 Blender recipe. This is an authoring requirement, not a render-time correction. + +A catalog material's `repeat` (`mapProperties.repeatX/repeatY` in `packages/core/src/material-library.ts`) is therefore a per-material world-scale setting: tiles per metre. + +`repeat: 1` means 1 tile/m, `0.4` means one tile every 2.5 m, and `1.5` means 1.5 tiles/m. + +Repeat is a property of the material, identical for every surface that uses it, never per-item or per-surface. Custom repeat values are intentional material scale, not per-surface hacks.