diff --git a/src/components/effects/GradientBlinds.tsx b/src/components/effects/GradientBlinds.tsx index f53da04..9f3b787 100644 --- a/src/components/effects/GradientBlinds.tsx +++ b/src/components/effects/GradientBlinds.tsx @@ -66,6 +66,7 @@ const GradientBlinds: React.FC = ({ const mouseTargetRef = useRef<[number, number]>([0, 0]); // Optimization: store raw pointer position (viewport coords) to decouple event handling from calculation const pointerPosRef = useRef<{ x: number; y: number } | null>(null); + const isMobileRef = useRef(false); const lastTimeRef = useRef(0); const firstResizeRef = useRef(true); const rectRef = useRef(null); @@ -283,6 +284,7 @@ void main() { const rect = container.getBoundingClientRect(); rectRef.current = rect; if (typeof window !== 'undefined') { + isMobileRef.current = window.innerWidth <= 768; scrollPosRef.current = { x: window.scrollX, y: window.scrollY }; } renderer.setSize(rect.width, rect.height); @@ -311,7 +313,30 @@ void main() { ro.observe(container); const onPointerMove = (e: PointerEvent) => { - pointerPosRef.current = { x: e.clientX, y: e.clientY }; + if (isMobileRef.current) { + // On mobile, calculate relative position immediately and store in target. + // This prevents the "ghost drift" effect when scrolling with inertia after lifting finger, + // because we won't be updating the target based on scroll position in the loop. + const scale = (renderer as unknown as { dpr?: number }).dpr || 1; + let x, y; + + if (rectRef.current) { + const dx = window.scrollX - scrollPosRef.current.x; + const dy = window.scrollY - scrollPosRef.current.y; + const rectLeft = rectRef.current.left - dx; + const rectTop = rectRef.current.top - dy; + x = (e.clientX - rectLeft) * scale; + y = (rectRef.current.height - (e.clientY - rectTop)) * scale; + } else { + const rect = canvas.getBoundingClientRect(); + x = (e.clientX - rect.left) * scale; + y = (rect.height - (e.clientY - rect.top)) * scale; + } + mouseTargetRef.current = [x, y]; + pointerPosRef.current = null; // Ensure loop doesn't override + } else { + pointerPosRef.current = { x: e.clientX, y: e.clientY }; + } }; const loop = (t: number) => { @@ -351,7 +376,7 @@ void main() { cur[0] += (target[0] - cur[0]) * factor; cur[1] += (target[1] - cur[1]) * factor; } else { - if (pointerPosRef.current) { + if (pointerPosRef.current || isMobileRef.current) { uniforms.iMouse.value = mouseTargetRef.current; } lastTimeRef.current = t;