- 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>
Wire KTX2 into the catalog finish path and add 15 textured finishes across four
new families, all as GPU-compressed KTX2 (512px) + a webp picker thumbnail.
- Shared `ktx2-loader.ts`: one KTX2Loader (Basis transcoder) used by both the
GLB loader and catalog textures; `ensureKtx2Support(renderer)` runs once at
viewer init (GPUDeviceWatcher) so `.ktx2` finishes load even with no GLB in
the scene. `use-gltf-ktx2` now reuses the shared instance.
- `materials.ts`: texture loaders pick the KTX2 loader for `.ktx2` urls, the
image loader otherwise (all three load paths).
- `material-library.ts`: 15 entries (fabric ×6, leather ×2, concrete ×4,
metal ×3). Neutral albedo for tinting, `flipY: false` (compressed textures
can't flip), `repeat` per real-world tile size, metals `metalness: 1`.
Normals encoded UASTC, data maps ETC1S/linear.
Assets generated from raw sources via the new community
`scripts/build-material-textures.ts`. 1024/256 tiers + raws kept out of git.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>