diff --git a/src/components/three/ModelViewer.tsx b/src/components/three/ModelViewer.tsx index 1262bf2..178f115 100644 --- a/src/components/three/ModelViewer.tsx +++ b/src/components/three/ModelViewer.tsx @@ -753,11 +753,30 @@ function SelectionHandler() { useModelStore.getState().toggleElementSelection(key); }; + const onR3FMiss = (event: Event) => { + const detail = (event as CustomEvent).detail; + if (!detail || detail.button !== 0) return; + const rect = canvas.getBoundingClientRect(); + mouse.x = ((detail.clientX - rect.left) / rect.width) * 2 - 1; + mouse.y = -((detail.clientY - rect.top) / rect.height) * 2 + 1; + raycaster.setFromCamera(mouse, camera); + const intersects = raycaster.intersectObjects(scene.children, true); + const hit = intersects.find((i) => isPickableModelMesh(i.object)); + if (!hit) return; + + const element = findElementRoot(hit.object); + const modelId = useModelStore.getState().activeModelId; + if (!modelId || !element) return; + useModelStore.getState().toggleElementSelection(elementKey(modelId, element)); + }; + canvas.addEventListener('pointerdown', onDown); canvas.addEventListener('pointerup', onUp); + canvas.addEventListener('tsxr-selection-miss', onR3FMiss); return () => { canvas.removeEventListener('pointerdown', onDown); canvas.removeEventListener('pointerup', onUp); + canvas.removeEventListener('tsxr-selection-miss', onR3FMiss); gl.domElement.style.cursor = prevCursor; }; }, [selectionMode, camera, scene, gl, raycaster, mouse]);