# Animation frame budget of 16ms maintained

- **Pattern:** `ab-002048` (`performance-deep-dive.regression-prevention.animation-frame-budget`)
- **Severity:** info
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002048
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002048)

## Why it matters

At 60fps, each animation frame has a 16ms budget. Any JavaScript that runs synchronously inside a frame — including a `setInterval` callback or a DOM layout read followed by a write — can consume that budget entirely, causing the browser to skip the frame and produce visible stutter. ISO 25010:2011 time-behaviour captures the responsiveness requirement; the user-visible failure is an animation that stutters at irregular intervals, particularly during scroll or on lower-powered devices.

## Severity rationale

Info because frame-budget violations produce cosmetic jank rather than functional failures — they are worth fixing for polish and accessibility but do not prevent users from completing tasks.

## Remediation

Replace `setInterval`-driven animations with CSS transitions or `requestAnimationFrame`. For values that animate over time, CSS `transform` and `opacity` are GPU-composited and do not trigger layout.

```css
/* components/animated-card.module.css — GPU-composited animation */
.card {
  transition: transform 0.25s ease, opacity 0.25s ease;
  will-change: transform;  /* hint GPU layer promotion */
}

.card:hover {
  transform: translateY(-4px);
}
```

For JS-driven values, schedule work with `requestAnimationFrame` rather than `setInterval` to stay synchronized with the browser's paint cycle.

## Detection

- **ID:** `animation-frame-budget`
- **Severity:** `info`
- **What to look for:** Count all animation implementations. Enumerate which use `requestAnimationFrame` or CSS transforms vs. `setInterval` or property-based animations. Examine animation and scroll handling code. Check for use of `requestAnimationFrame`. Look for CSS transforms and transitions vs. property-based animations (JS-driven).
- **Pass criteria:** Animations use `requestAnimationFrame` or CSS transforms (GPU-accelerated). Frame rate stays at 60fps (16ms per frame). No jank during scrolling or animations. At least 90% of animations should use GPU-accelerated techniques (CSS transforms or requestAnimationFrame).
- **Fail criteria:** Animations use setInterval or property-based JS animations that block main thread. Frame rate drops below 60fps.
- **Skip (N/A) when:** The application has no animations or scroll interactions.

- **Cross-reference:** For paint profiling of animations, see `paint-profiling-clean`.
- **Detail on fail:** `"Scroll listeners change layout properties per frame — main thread blocked, frame rate drops to 30fps"` or `"Animations use setInterval instead of requestAnimationFrame"`
- **Remediation:** Use hardware-accelerated animations with CSS transforms or requestAnimationFrame.

  ```css
  /* components/animated-card.module.css — GPU-accelerated */
  .card { transition: transform 0.3s ease; }
  .card:hover { transform: translateY(-4px); }
  ```

## External references

- iso-25010 time-behaviour

Taxons: performance

HTML version: https://auditbuffet.com/patterns/ab-002048
