AnimationBudget
Unmonitored animations run at full fidelity regardless of whether the device is lagging or dropping frames. AnimationBudget continuously samples presented frame intervals on the shared conductor, detects refresh-rate-relative frame drops, and outputs a coarse quality tier (high, medium, low) with asymmetric hysteresis to prevent flapping.
The AnimationBudget is accessed via the getAnimationBudget() singleton or the useAnimationBudget() React hook. Use the reported quality tier to toggle optional visual layers: particle lattice fields, heavy backdrop filters, screen-space reflections, and post-processing passes.
The governor continuously measures the interval between presented frames on the shared conductor and maps performance to three distinct tiers: 0: high (frames are healthy), 1: medium (sustained drops below 90% display refresh rate), and 2: low (survival mode under heavy main-thread pressure).
The state machine employs asymmetric hysteresis by design: degrading happens quickly (~1.5s of frame drops) so users do not endure sustained jank, while upgrading is slow and cautious (requiring 8s of stable frames) to guarantee quality never flickers back and forth.
◆Live Quality Tier Governor
Quick start
In React components, useAnimationBudget() returns the current tier and rolling slow ratio. Toggle decorative layers based on the tier.
The hook triggers re-renders exclusively on quality tier transitions and low-frequency ~2Hz telemetry heartbeats.
Quality Tier Thresholds & Degradation Metrics
The budget scores frames against multiples of the measured frame budget (16.7ms at 60Hz, 8.3ms at 120Hz).
| Tier | Verdict | Trigger Threshold | Recommended Shed Action |
|---|---|---|---|
| 0 | high | Under 10% of recent frames running long | Run full visual treatment: bloom, particle lattice, glass blurs. |
| 1 | medium | >30% of last 90 frames exceed 1.11× budget | Shed heavy compositing: backdrop-filter, multi-pass bloom. |
| 2 | low | Tier 1 persisting >1.5s or >15% frames exceeding 2.04× budget | Survival mode: flat vector rendering; core interaction preserved. |
API Reference
Syntax
The AnimationBudget API exposes real-time frame telemetry, headroom estimates, and coarse quality tiers.
Parameters
| Parameters.field | Type | Default | Description |
|---|---|---|---|
| getAnimationBudget() | AnimationBudget | Singleton | Returns the shared global instance. Safe to call in SSR environments. |
| budget.subscribe(fn) | (fn: (state: BudgetState) => void) => () => void | Subscription | Subscribes to quality tier transitions and low-frequency telemetry heartbeats. Returns cleanup function. |
| useAnimationBudget() | () => BudgetState | React Hook | React hook that subscribes to the budget and returns the current BudgetState snapshot. |
Return Value
Snapshot containing tier, label, avgFrameMs, slowRatio, headroom, workMs, and frameBudgetMs.
Properties & State
| Properties.field | Type | Description |
|---|---|---|
| budget.state | BudgetState | The live snapshot containing current quality verdict and frame interval metrics. |
BudgetState
| BudgetState.field | Type | Description |
|---|---|---|
| tier | 0 | 1 | 2 | The quality verdict: 0 = high, 1 = medium, 2 = low. |
| label | "high" | "medium" | "low" | The tier verdict as a readable string. |
| avgFrameMs | number | Rolling average frame presentation interval in milliseconds. |
| slowRatio | number | Share of recent frames below degradation threshold (0.0 to 1.0). |
| headroom | number | Estimated milliseconds remaining in the current frame budget. Positive = headroom available; <= 0 = overrun. |
| workMs | number | Milliseconds the motion runtime spent executing subscribers on the last frame. |
| frameBudgetMs | number | One presented frame at detected display refresh rate (16.7ms at 60Hz, 8.3ms at 120Hz). |
Subscription Cleanup
Subscriptions to AnimationBudget should be cleaned up on unmount to release listener callbacks.
Lifecycle & Invariant Guarantees
- →Asymmetric hysteresis: Degradation executes in ~1.5s of missed frames to stop jank, while upgrades require 8 full seconds of clean frames to eliminate flickering.
- →Refresh-rate awareness: Thresholds scale dynamically with display refresh rates (60Hz, 120Hz, 144Hz, 240Hz) rather than hardcoded 60fps constants.
- →Honest headroom calculation: While frames land on time, headroom measures budget minus actual work; when frames miss, wall-clock overrun is subtracted.
- →Zero re-renders in frame loops: useAnimationBudget re-renders only on tier transitions and ~2Hz heartbeats, keeping your component tree calm.
The Three Quality Tiers
The same 3D kinetic object, rendered across all three quality tiers. The core mesh and rotation mechanics are identical in all three; the governor selectively sheds heavy post-processing passes.
◆Production Examples
Battle-tested production patterns ready to copy directly into your codebase.
Shed optional visual layers in cost order while preserving all product copy and buy buttons.
When NOT to use this
Rules & Gotchas
- →Shed the highest-cost optional work first: Backdrop filters and multi-pass bloom cost significantly more than 2D transforms. Profile and shed in cost order.
- →Never re-key WebGL canvases on tier change: Mutate live scenes or disable passes: context re-initialization adds severe multi-frame lag.
- →Core content is non-sheddable: Images, copy, prices, and CTA buttons must survive all tiers without layout shift.
- →Pre-check mounting work with headroom: Headroom dips before the quality tier verdict changes: use headroom as your leading indicator.
Related Motion Components
See it live in the lab: /lab/shedding