From 55c21e71038581f95df8a371e69f318b6c65a332 Mon Sep 17 00:00:00 2001 From: Jonathan Styles Date: Wed, 27 Aug 2025 08:51:31 -0400 Subject: [PATCH 1/2] Claude generated fix to mobile matrix bug Fixed problem where mobile address bar showing and hiding caused canvas to re-render --- app/components/ui/hacker-bg.tsx | 84 ++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 11 deletions(-) diff --git a/app/components/ui/hacker-bg.tsx b/app/components/ui/hacker-bg.tsx index 877bef1..b56d68a 100644 --- a/app/components/ui/hacker-bg.tsx +++ b/app/components/ui/hacker-bg.tsx @@ -22,13 +22,27 @@ const HackerBackground: React.FC = ({ const ctx = canvas.getContext("2d"); if (!ctx) return; + let resizeTimeout: NodeJS.Timeout; + let isResizing = false; + const resizeCanvas = () => { - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; + const newWidth = window.innerWidth; + const newHeight = window.innerHeight; + + // Only resize if dimensions actually changed to prevent unnecessary clearing + if (canvas.width !== newWidth || canvas.height !== newHeight) { + // Preserve canvas content during resize + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + + canvas.width = newWidth; + canvas.height = newHeight; + + // Restore the preserved content + ctx.putImageData(imageData, 0, 0); + } }; resizeCanvas(); - window.addEventListener("resize", resizeCanvas); let animationFrameId: number; @@ -67,18 +81,64 @@ const HackerBackground: React.FC = ({ animationFrameId = requestAnimationFrame(draw); - // Update columns and drops when the window is resized - const handleResize = () => { - resizeCanvas(); - columns = Math.floor(canvas.width / fontSize); - drops = new Array(columns).fill(1); + // Debounced resize handler to prevent frequent resets on mobile + const debouncedResize = () => { + console.log("Resize event triggered:", { + currentWidth: canvas.width, + currentHeight: canvas.height, + windowWidth: window.innerWidth, + windowHeight: window.innerHeight, + timestamp: new Date().toLocaleTimeString(), + }); + + clearTimeout(resizeTimeout); + isResizing = true; + + resizeTimeout = setTimeout(() => { + const oldWidth = canvas.width; + const oldHeight = canvas.height; + const oldColumns = columns; + const oldDrops = [...drops]; + + resizeCanvas(); + + // Only recalculate if canvas dimensions actually changed + if (canvas.width !== oldWidth || canvas.height !== oldHeight) { + console.log("Canvas dimensions actually changed:", { + oldWidth, + oldHeight, + newWidth: canvas.width, + newHeight: canvas.height, + }); + + columns = Math.floor(canvas.width / fontSize); + + // Preserve existing drop positions when possible + if (columns !== oldColumns) { + const newDrops = new Array(columns); + for (let i = 0; i < columns; i++) { + if (i < oldDrops.length) { + newDrops[i] = oldDrops[i]; + } else { + newDrops[i] = Math.random() * (canvas.height / fontSize); + } + } + drops = newDrops; + } + } else { + console.log("Resize event but no dimension change - ignoring"); + } + + isResizing = false; + }, 150); // 150ms debounce }; - window.addEventListener("resize", handleResize); + // Use passive listener for better scroll performance on mobile + window.addEventListener("resize", debouncedResize, { passive: true }); return () => { - window.removeEventListener("resize", resizeCanvas); - window.removeEventListener("resize", handleResize); + clearTimeout(resizeTimeout); + window.removeEventListener("resize", debouncedResize); cancelAnimationFrame(animationFrameId); }; }, [color, fontSize, speed]); @@ -99,6 +159,8 @@ const HackerBackground: React.FC = ({ left: 0, width: "100%", height: "100%", + willChange: "auto", + backfaceVisibility: "hidden", }} /> ); From 7b25599e7cc72818ec8c19f17a48b4be8dc1f645 Mon Sep 17 00:00:00 2001 From: Jonathan Styles Date: Wed, 27 Aug 2025 09:26:02 -0400 Subject: [PATCH 2/2] Attempt 2 --- app/components/ui/hacker-bg.tsx | 64 ++++++++++++--------------------- 1 file changed, 23 insertions(+), 41 deletions(-) diff --git a/app/components/ui/hacker-bg.tsx b/app/components/ui/hacker-bg.tsx index b56d68a..5b9ced9 100644 --- a/app/components/ui/hacker-bg.tsx +++ b/app/components/ui/hacker-bg.tsx @@ -27,18 +27,14 @@ const HackerBackground: React.FC = ({ const resizeCanvas = () => { const newWidth = window.innerWidth; - const newHeight = window.innerHeight; + // Add buffer on mobile to prevent address bar resize issues + const isMobile = window.innerWidth <= 768; + const newHeight = window.innerHeight + (isMobile ? 200 : 0); // Only resize if dimensions actually changed to prevent unnecessary clearing if (canvas.width !== newWidth || canvas.height !== newHeight) { - // Preserve canvas content during resize - const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); - canvas.width = newWidth; canvas.height = newHeight; - - // Restore the preserved content - ctx.putImageData(imageData, 0, 0); } }; @@ -81,52 +77,38 @@ const HackerBackground: React.FC = ({ animationFrameId = requestAnimationFrame(draw); - // Debounced resize handler to prevent frequent resets on mobile + // On mobile, only resize for width changes to avoid address bar issues const debouncedResize = () => { - console.log("Resize event triggered:", { - currentWidth: canvas.width, - currentHeight: canvas.height, - windowWidth: window.innerWidth, - windowHeight: window.innerHeight, - timestamp: new Date().toLocaleTimeString(), - }); + const isMobile = window.innerWidth <= 768; + const currentWidth = canvas.width; + const newWidth = window.innerWidth; + + // On mobile, only resize if width changes (ignore height changes from address bar) + if (isMobile && Math.abs(newWidth - currentWidth) < 10) { + return; // Ignore minor width changes and all height changes on mobile + } clearTimeout(resizeTimeout); isResizing = true; resizeTimeout = setTimeout(() => { - const oldWidth = canvas.width; - const oldHeight = canvas.height; const oldColumns = columns; const oldDrops = [...drops]; resizeCanvas(); - - // Only recalculate if canvas dimensions actually changed - if (canvas.width !== oldWidth || canvas.height !== oldHeight) { - console.log("Canvas dimensions actually changed:", { - oldWidth, - oldHeight, - newWidth: canvas.width, - newHeight: canvas.height, - }); - - columns = Math.floor(canvas.width / fontSize); - - // Preserve existing drop positions when possible - if (columns !== oldColumns) { - const newDrops = new Array(columns); - for (let i = 0; i < columns; i++) { - if (i < oldDrops.length) { - newDrops[i] = oldDrops[i]; - } else { - newDrops[i] = Math.random() * (canvas.height / fontSize); - } + columns = Math.floor(canvas.width / fontSize); + + // Preserve existing drop positions when possible + if (columns !== oldColumns) { + const newDrops = new Array(columns); + for (let i = 0; i < columns; i++) { + if (i < oldDrops.length) { + newDrops[i] = oldDrops[i]; + } else { + newDrops[i] = Math.random() * (canvas.height / fontSize); } - drops = newDrops; } - } else { - console.log("Resize event but no dimension change - ignoring"); + drops = newDrops; } isResizing = false;