diff --git a/src/components/effects/GradientBlinds.tsx b/src/components/effects/GradientBlinds.tsx index f53da04..e01a6bd 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) => {