diff --git a/components/canvas/world3d/World3DViewer.tsx b/components/canvas/world3d/World3DViewer.tsx index 3950b253c..dedb0e450 100644 --- a/components/canvas/world3d/World3DViewer.tsx +++ b/components/canvas/world3d/World3DViewer.tsx @@ -1106,6 +1106,7 @@ function WorldSplatScene({ const camera = useThree((state) => state.camera); const renderer = useThree((state) => state.gl); const orbitControlsRef = useRef(null); + const hotspotPointerDownRef = useRef<{ x: number; y: number } | null>(null); const hasAppliedInitialViewRef = useRef(false); const lastCameraPoseRef = useRef(null); const lastResetViewTokenRef = useRef(resetViewToken); @@ -1365,8 +1366,32 @@ function WorldSplatScene({ sparkRenderer.dirty = true; }); - const handlePointerDown = (event: ThreeEvent) => { + useEffect(() => { + hotspotPointerDownRef.current = null; + }, [interactionMode, splatUrl]); + + const handleHotspotPointerDown = (event: ThreeEvent) => { if (interactionMode !== "hotspot") return; + hotspotPointerDownRef.current = { + x: event.nativeEvent.clientX, + y: event.nativeEvent.clientY, + }; + }; + + const handleHotspotPointerMove = (event: ThreeEvent) => { + if (interactionMode !== "hotspot" || !hotspotPointerDownRef.current) return; + const deltaX = event.nativeEvent.clientX - hotspotPointerDownRef.current.x; + const deltaY = event.nativeEvent.clientY - hotspotPointerDownRef.current.y; + if (Math.hypot(deltaX, deltaY) > 6) { + hotspotPointerDownRef.current = null; + } + }; + + const handleHotspotClick = (event: ThreeEvent) => { + if (interactionMode !== "hotspot") return; + const pointerDown = hotspotPointerDownRef.current; + hotspotPointerDownRef.current = null; + if (!pointerDown) return; event.stopPropagation(); onPick?.({ point: [event.point.x, event.point.y, event.point.z], @@ -1387,7 +1412,12 @@ function WorldSplatScene({ ) : null} - + {particleCloudData ? : null}