@vectorvesper/motionCore Engine · Frame Governor

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

Headroom Drops First Frame Time Overruns Quality Tier Sheds
Demo loads on scroll

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).

TierVerdictTrigger ThresholdRecommended Shed Action
0highUnder 10% of recent frames running longRun full visual treatment: bloom, particle lattice, glass blurs.
1medium>30% of last 90 frames exceed 1.11× budgetShed heavy compositing: backdrop-filter, multi-pass bloom.
2lowTier 1 persisting >1.5s or >15% frames exceeding 2.04× budgetSurvival 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.fieldTypeDefaultDescription
getAnimationBudget()AnimationBudgetSingletonReturns the shared global instance. Safe to call in SSR environments.
budget.subscribe(fn)(fn: (state: BudgetState) => void) => () => voidSubscriptionSubscribes to quality tier transitions and low-frequency telemetry heartbeats. Returns cleanup function.
useAnimationBudget()() => BudgetStateReact HookReact hook that subscribes to the budget and returns the current BudgetState snapshot.

Return Value

BudgetState

Snapshot containing tier, label, avgFrameMs, slowRatio, headroom, workMs, and frameBudgetMs.

Properties & State

Properties.fieldTypeDescription
budget.stateBudgetStateThe live snapshot containing current quality verdict and frame interval metrics.

BudgetState

BudgetState.fieldTypeDescription
tier0 | 1 | 2The quality verdict: 0 = high, 1 = medium, 2 = low.
label"high" | "medium" | "low"The tier verdict as a readable string.
avgFrameMsnumberRolling average frame presentation interval in milliseconds.
slowRationumberShare of recent frames below degradation threshold (0.0 to 1.0).
headroomnumberEstimated milliseconds remaining in the current frame budget. Positive = headroom available; <= 0 = overrun.
workMsnumberMilliseconds the motion runtime spent executing subscribers on the last frame.
frameBudgetMsnumberOne 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.

1. Vanilla JS UsageManual Subscribe / Unsubscribe
2. React Hook UsageAutomatic Cleanup

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.

HIGH (0)4/4 FX
full treatment active
MEDIUM (1)2/4 FX
shed: multi-layer bloom, ambient shadow map
LOW (2)0/4 FX
shed: multi-layer bloom, ambient shadow map, particle lattice field, backdrop blur HUD

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

Making immediate quality decisions before the first frame renders.
→ instead The budget requires ~40 frame samples to establish baseline. Use AdaptiveQuality, which fuses instant hardware signals with live frame telemetry.
Gating a heavy component's initial mount.
→ instead Use useSafeToMount: it inspects headroom before paying initial mount cost.
Tracking per-frame values in React state.
→ instead Subscribe to the conductor and mutate DOM styles directly. Storing state at 60fps causes continuous layout thrashing.
Honouring prefers-reduced-motion user preferences.
→ instead Read prefers-reduced-motion directly via AdaptiveQuality: user accessibility preference is distinct from hardware frame rate.

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