From d885ea4e6b38fbd08ca534d0cdf3f51f53a06ee6 Mon Sep 17 00:00:00 2001 From: Timothy Pidashev Date: Tue, 22 Apr 2025 09:07:47 -0700 Subject: [PATCH] Fix requestAnimationFrame blurring background after switching views --- src/src/components/background/index.tsx | 26 ++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/src/components/background/index.tsx b/src/src/components/background/index.tsx index eee275f..8eeda9a 100644 --- a/src/src/components/background/index.tsx +++ b/src/src/components/background/index.tsx @@ -529,6 +529,24 @@ const Background: React.FC = ({ canvas.addEventListener('mouseup', handleMouseUp, { signal }); canvas.addEventListener('mouseleave', handleMouseLeave, { signal }); + const handleVisibilityChange = () => { + if (document.hidden) { + // Tab is hidden + if (animationFrameRef.current) { + cancelAnimationFrame(animationFrameRef.current); + animationFrameRef.current = undefined; + } + } else { + // Tab is visible again + if (!animationFrameRef.current) { + // Reset timing references to prevent catching up + lastUpdateTimeRef.current = performance.now(); + lastCycleTimeRef.current = performance.now(); + animationFrameRef.current = requestAnimationFrame(animate); + } + } + }; + const animate = (currentTime: number) => { if (signal.aborted) return; @@ -540,6 +558,10 @@ const Background: React.FC = ({ // Calculate time since last frame const deltaTime = currentTime - lastUpdateTimeRef.current; + + // Limit delta time to prevent large jumps when tab becomes active again + const clampedDeltaTime = Math.min(deltaTime, 100); + lastUpdateTimeRef.current = currentTime; // Calculate time since last cycle update @@ -552,7 +574,7 @@ const Background: React.FC = ({ lastCycleTimeRef.current = currentTime; } - updateCellAnimations(gridRef.current, deltaTime); + updateCellAnimations(gridRef.current, clampedDeltaTime); } // Draw frame @@ -641,11 +663,13 @@ const Background: React.FC = ({ animationFrameRef.current = requestAnimationFrame(animate); }; + document.addEventListener('visibilitychange', handleVisibilityChange, { signal }); window.addEventListener('resize', handleResize, { signal }); animate(performance.now()); return () => { controller.abort(); + document.removeEventListener('visibilitychange', handleVisibilityChange); window.removeEventListener('resize', handleResize); if (animationFrameRef.current) { cancelAnimationFrame(animationFrameRef.current);