fix(selection): selected objects keep their texture (light glow, no wash)

Selecting a textured wall/slab/item replaced its surface with a flat
purple wash. Root cause: the selection highlight clones the material and
tints it, but `NodeMaterial.clone()` on the WebGPU backend drops the
texture-map node assignments, so the clone rendered flat — and a strong
albedo blend + emissive washed whatever was left.

Fix: re-attach the maps from the source material after cloning (shared by
reference) and drop the albedo tint, keeping only a gentle indigo emissive
so the real material/texture stays readable with a soft "selected" glow.
Applied to both highlight paths:
- generic editor highlight (slabs/items) in selection-manager
- wall path (walls are excluded from the generic one), built lazily +
  cached/self-healing so it survives the wall finish's async texture load

Removes the now-dead eager wall `highlightedVisible`/`selection` profile.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Wassim SAMAD
2026-06-19 17:17:41 -04:00
co-authored by Claude Opus 4.8
parent f2352616d9
commit 8633886eef
3 changed files with 95 additions and 31 deletions
@@ -568,10 +568,12 @@ const HIGHLIGHT_PROFILES = {
emissiveIntensity: 0.46,
},
selection: {
// Keep the real material/texture readable: no albedo tint, just a gentle
// indigo emissive glow so it reads as selected.
color: new Color('#818cf8'),
blend: 0.32,
emissiveBlend: 0.7,
emissiveIntensity: 0.42,
blend: 0,
emissiveBlend: 0.4,
emissiveIntensity: 0.12,
},
} as const
@@ -596,8 +598,30 @@ function isHighlightableMesh(object: Object3D): object is Mesh {
)
}
const TEXTURE_MAP_KEYS = [
'map',
'normalMap',
'roughnessMap',
'metalnessMap',
'aoMap',
'emissiveMap',
'bumpMap',
'displacementMap',
'alphaMap',
'lightMap',
] as const
function createHighlightedMaterial(material: Material, kind: HighlightKind): Material {
const highlightedMaterial = material.clone() as HighlightableMaterial
// `NodeMaterial.clone()` on the WebGPU backend drops the texture-map node
// assignments, so the clone renders flat. Re-attach the maps from the source
// material (they're shared by reference — same texture object) so the
// selected object keeps its texture under the highlight.
const src = material as unknown as Record<string, unknown>
const dst = highlightedMaterial as unknown as Record<string, unknown>
for (const key of TEXTURE_MAP_KEYS) {
if (src[key]) dst[key] = src[key]
}
const profile = HIGHLIGHT_PROFILES[kind]
if (highlightedMaterial.color instanceof Color) {