From 7e89ccea5c8fceaedee2a550d1ba01d9074ac1b2 Mon Sep 17 00:00:00 2001 From: Fringg Date: Wed, 25 Feb 2026 13:27:14 +0300 Subject: [PATCH] fix: stop beams background from causing UI flickering in browser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove opacity from beamDash keyframes — opacity on SVG paths triggers full-page repaints. Animate only stroke-dashoffset (compositor-friendly). Reduce animated paths from 50 to 17 (every 3rd). Isolate container with contain:strict + will-change:transform for own compositor layer. --- .../ui/backgrounds/background-beams.tsx | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/components/ui/backgrounds/background-beams.tsx b/src/components/ui/backgrounds/background-beams.tsx index 26a6577..9763131 100644 --- a/src/components/ui/backgrounds/background-beams.tsx +++ b/src/components/ui/backgrounds/background-beams.tsx @@ -67,6 +67,11 @@ function seededRandom(seed: number) { return x - Math.floor(x); } +// Animate only every 3rd path (17 beams) — enough visual density, 3x fewer repaints +const animatedPaths = paths + .map((path, i) => ({ path, paramIndex: i })) + .filter((_, i) => i % 3 === 0); + // Pre-compute beam animation params at module level (stable across renders) const beamParams = paths.map((_, i) => ({ duration: 10 + seededRandom(i) * 10, // 10-20s @@ -81,12 +86,13 @@ function ensureStyles() { const style = document.createElement('style'); style.id = STYLE_ID; + // Only animate stroke-dashoffset — no opacity changes = no repaints + // The beam appears when dashoffset brings the segment into view + // and disappears when it exits — pure compositor work style.textContent = ` @keyframes beamDash { - 0% { stroke-dashoffset: 1; opacity: 0; } - 2% { opacity: 1; } - 80% { opacity: 1; } - 100% { stroke-dashoffset: -1; opacity: 0; } + 0% { stroke-dashoffset: 1; } + 100% { stroke-dashoffset: -1; } } `; document.head.appendChild(style); @@ -99,7 +105,10 @@ export default React.memo(function BackgroundBeams({ settings: _settings }: Prop }, []); return ( -
+
- {/* Animated beams — CSS stroke-dashoffset animation, GPU composited */} - {paths.map((path, i) => ( + {/* Animated beams — only every 3rd path (17 beams), pure stroke-dashoffset */} + {animatedPaths.map(({ path, paramIndex }) => ( ))}