- 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
Root cause: 225 individually animated DOM elements forced Chrome's
compositor to create separate paint regions per element. Any hover
state change on page content triggered re-compositing of all 225
regions, causing visible flickering on all pages.
Canvas fix: single <canvas> element renders the entire grid effect
via requestAnimationFrame. Canvas content is pixel-based and cannot
be affected by DOM hover state changes on other elements.
Additional fixes:
- Fix z-index collision: portal z-index -1 → -2 (was same as body::before noise)
- Replace all transition-all with specific properties on .btn, .btn-icon,
.input, .nav-item, .bottom-nav-item, checkbox
- Remove backdrop-blur-sm from desktop .bento-card and .card
(forced Chrome to re-sample animated background pixels on every hover)
The boxes background was creating 225 motion.div elements, each running
independent opacity animations via framer-motion JS on the main thread.
This blocked hover transitions on cards, causing visible flickering.
CSS @keyframes run on the compositor thread and have zero main-thread
cost, eliminating the interference with user interactions.
- Use 300% oversized CSS grid container instead of fixed-size flex cells
- Grid with 1fr units auto-fills the container, skew+scale covers viewport
- Simplified to flat cell array, removed SVG crosses for cleaner look
- Use original Aceternity positioning: translate(-40%,-60%) with
-top-1/4 left-1/4 to cover viewport after skew transform
- Switch from CSS grid to flex layout matching original structure
- Add cross (+) SVG markers at grid intersections
- Use pastel color palette from original, animate opacity per cell
- Increase default rows to 20 for better coverage