Skip to main content

Search rules

Search all UI Guides rules by name, category, or source

performance@Ibelick

Every rAF Loop Needs a Stop Condition

NEVER

NEVER: Ship a `requestAnimationFrame` loop with no terminal condition. `const tick = () => { draw(); requestAnimationFrame(tick); }` never ends: once the value has converged and the user has moved on, it still wakes 60x/sec to compute a delta of zero, burning a core and measurable battery even while the element is visible and idle — the usual cause of an idle tab at 10-15% CPU. Give every loop two exits: stop re-scheduling on convergence (or gesture end / `AbortSignal`), and call `cancelAnimationFrame` on teardown so an unmount cannot orphan the loop. (Distinct from `animations-ibelick-pause-offscreen`, which stops work the user cannot see.)

A requestAnimationFrame loop that re-schedules itself unconditionally never ends, and burns a core for as long as the tab lives

const tick = () => {
  if (settled()) return;               // terminal condition
  id = requestAnimationFrame(tick);
};
return () => cancelAnimationFrame(id); // teardown

Bad

Good

Why it matters

The shape is always the same: `const tick = () => { draw(); requestAnimationFrame(tick); }`. It is correct while the animation is running and wrong for every second after — the value has converged, the spring has settled, the user has moved on, and the loop is still waking up sixty times a second to compute a delta of zero. That is the usual explanation for an idle tab sitting at 10-15% CPU, and on a laptop it is measurable battery drain for no pixels.

Every loop needs two exits: a terminal condition (the value converged, the gesture ended, an AbortSignal fired) that stops re-scheduling, and a `cancelAnimationFrame` in the teardown so a component that unmounts mid-animation does not leave an orphan loop holding a reference to a dead tree. This is a different failure from animations-ibelick-pause-offscreen: that rule stops work the user cannot see, this one stops work nobody needs even when the element is in full view.

Built by Gleb Stroganov, design engineer at Evil Martians.

The rules come from other people's skills and guidelines — Vercel, Rauno Freiberg, @Ibelick, impeccable, Emil Kowalski, Tailwind, RAMS — each one credited on the Sources page. The work here is extraction and wiring: every rule is pulled into one corpus, given a good and a bad example you can operate, a MUST/SHOULD/NEVER rule an agent can paste, and a link back to where it came from.