perf: optimize animated backgrounds for mobile — reduce GPU load and memory pressure

- Add useAnimationLoop hook with FPS throttling (30fps mobile/60fps desktop),
  Page Visibility API pause, and Telegram WebApp activated/deactivated events
- Add useAnimationPause hook for CSS/Framer Motion components
- Validate animation config with type allowlist, numeric clamping, JSON size guard
- Move ctx.setTransform from per-frame to init/resize across all canvas backgrounds
- Move ctx.lineCap to init/resize in vortex, replace Float32Array.set with direct writes
- Pre-compute shooting star delay instead of per-frame Math.random
- Cap DPR to 1.5 on mobile, reduce particle counts, cap blur to 4px
- Disable aurora CSS animation on mobile, remove blur on mobile spotlight
- Remove mix-blend-hard-light on mobile gradient-animation
- Add NaN/Infinity guard to clampNumber, remove dead CSS variables
- Add conditional unmount for Framer Motion backgrounds when paused
- Add animationPlayState pause for CSS-animated backgrounds
This commit is contained in:
Fringg
2026-03-01 22:36:57 +03:00
parent 430b703bbe
commit a933f661e4
18 changed files with 926 additions and 450 deletions

View File

@@ -1,24 +1,31 @@
import { cn } from '@/lib/utils';
import { safeBoolean } from './types';
import { useAnimationPause } from '@/hooks/useAnimationLoop';
interface Props {
settings: Record<string, unknown>;
}
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768;
export default function AuroraBackground({ settings }: Props) {
const showRadialGradient = (settings.showRadialGradient as boolean) ?? true;
const showRadialGradient = safeBoolean(settings.showRadialGradient, true);
const paused = useAnimationPause();
return (
<div className="absolute inset-0 overflow-hidden">
<div
className={cn(
'pointer-events-none absolute -inset-[10px] animate-aurora opacity-50 blur-[10px] will-change-transform',
'pointer-events-none absolute -inset-[10px] opacity-50',
!isMobile && 'animate-aurora',
showRadialGradient &&
'[mask-image:radial-gradient(ellipse_at_100%_0%,black_10%,transparent_70%)]',
)}
style={{
backgroundImage:
'repeating-linear-gradient(100deg, #000 0%, #000 7%, transparent 10%, transparent 12%, #000 16%), repeating-linear-gradient(100deg, #3b82f6 10%, #a5b4fc 15%, #93c5fd 20%, #ddd6fe 25%, #60a5fa 30%)',
backgroundSize: '300%, 200%',
backgroundSize: isMobile ? '100%, 100%' : '300%, 200%',
animationPlayState: paused ? 'paused' : 'running',
}}
/>
</div>