Why it matters
A perpetual rAF loop (canvas, WebGL, JS-driven marquee) burns CPU and battery on every frame even when nothing is visible, and competes with scrolling.
How to fix it
Pause loops when the element is off-screen (IntersectionObserver) or the tab is hidden, and render on demand instead of every frame.
Example
new IntersectionObserver(([e]) => e.isIntersecting ? start() : stop()).observe(canvas);More smoothness rules
void smooth reports 13 rules in this category. How the page feels after it loads: dropped frames during a scripted scroll, long animation frames, INP of real clicks, shifts after input, animated layout properties, idle rAF loops and reduced-motion handling.
layout-shift-after-inputLayout shifts long after an interactionlayout-shift-on-scrollLayout shifts while scrollinganimate-layout-propertyAnimation of a layout-triggering propertytransition-alltransition: allwill-change-overusewill-change is applied too broadlyreduced-motion-ignoredAnimations keep running with prefers-reduced-motionscroll-timeline-no-fallbackContent is invisible without scroll-driven-animation supportmultiple-webgl-contextsMultiple WebGL contexts