From c3bd065f2f98ee7b365b8cb77b5249336b81697e Mon Sep 17 00:00:00 2001 From: Wassim SAMAD Date: Wed, 17 Jun 2026 09:42:48 -0400 Subject: [PATCH] fix(paint-slots): disable the CSG cutout's raycast so window/door paint hits the slots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The real interceptor was the 'cutout' mesh, not the hitbox: it's a 1m-deep CSG helper whose front face sits 0.5m proud of the glass, and current three.js raycasts invisible meshes — so every paint/hover ray resolved to 'cutout' (no slotId → role null). Disable its raycast; combined with the hitbox noop, paint/hover rays now land on the tagged frame/glass (panel/glass) children. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/viewer/src/systems/door/door-system.tsx | 4 ++++ packages/viewer/src/systems/window/window-system.tsx | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/viewer/src/systems/door/door-system.tsx b/packages/viewer/src/systems/door/door-system.tsx index d261cb80..257798e3 100644 --- a/packages/viewer/src/systems/door/door-system.tsx +++ b/packages/viewer/src/systems/door/door-system.tsx @@ -2412,6 +2412,10 @@ function syncDoorCutout(node: DoorNode, mesh: THREE.Mesh) { if (!cutout) { cutout = new THREE.Mesh() cutout.name = 'cutout' + // The cutout is a 1m-deep CSG helper for the wall hole — never interactive. + // three.js raycasts invisible meshes, so without this its front face (0.5m + // proud of the door) intercepts every paint/hover ray. + cutout.raycast = noopHitboxRaycast mesh.add(cutout) } cutout.geometry.dispose() diff --git a/packages/viewer/src/systems/window/window-system.tsx b/packages/viewer/src/systems/window/window-system.tsx index feed9e73..a45f4f12 100644 --- a/packages/viewer/src/systems/window/window-system.tsx +++ b/packages/viewer/src/systems/window/window-system.tsx @@ -3500,6 +3500,10 @@ function syncWindowCutout(node: WindowNode, mesh: THREE.Mesh) { if (!cutout) { cutout = new THREE.Mesh() cutout.name = 'cutout' + // The cutout is a 1m-deep CSG helper for the wall hole — never interactive. + // three.js raycasts invisible meshes, so without this its front face (0.5m + // proud of the glass) intercepts every paint/hover ray. + cutout.raycast = noopHitboxRaycast mesh.add(cutout) } cutout.geometry.dispose()