AdaptiveQuality
Static device heuristics guess instantly but never learn, while frame budgets measure reality only after frames accumulate. AdaptiveQuality fuses hardware capability detection (GPU unmasked renderer, WebGL2, CPU cores, memory) as an unbreakable floor with live conductor frame telemetry and attribution pressure, preventing the oscillation loop on underpowered hardware.
The AdaptiveQuality governor determines how much visual detail your application should render at any given moment. It combines static hardware detection (GPU tier, WebGL2 availability, memory, CPU concurrency) with live AnimationBudget frame telemetry, attribution pressure diagnostics, and accessibility preferences.
The device tier acts as an unbreakable floor. Live frame telemetry can reduce quality under heavy load, but never lifts it above what the hardware can sustain. Without that floor, low-end devices enter an endless oscillation cycle: quality degrades, frames recover because quality dropped, quality upgrades, severe jank resumes, and quality degrades again.
Every state reading carries a machine-readable cause string (such as "device", "render", "held", or "reduced-motion"). Branch on cause when you need to distinguish between an underpowered GPU and transient main-thread pressure.
◆Hardware Floor & Main-Thread Load Fusion
Quick start
Map the effective tier to a quality settings dictionary once, then pass it to your renderer.
Tier changes are rare: governed by the static hardware floor plus asymmetric hysteresis. It is designed for conditional rendering, not per-frame mutations.
Quality Cause Taxonomy & Attribution Matrix
Every reading returns a machine-readable cause explaining why the tier is in its current state.
| Cause | Meaning | Architectural Action |
|---|---|---|
| "ok" | Hardware capable and frames landing smoothly on time. | Run complete intended high-fidelity visual experience. |
| "device" | Hardware floor actively capping fidelity (e.g. mobile GPU or low RAM). | Quality stays at device floor even if current frames are idle. |
| "frame-rate" | Capable device suffering frame drops without attributed cause. | Trusts the AnimationBudget and steps down one quality tier. |
| "render" | Attribution engine proves rendering/GPU is the true bottleneck. | Reducing scene complexity will directly restore frame rate. |
| "held" | Frame drops caused by third-party main-thread blocking. | Quality is held steady; shedding graphics would not speed up third-party scripts. |
| "reduced-motion" | User prefers-reduced-motion media query is active. | Tier is forced to 2; render static accessible fallback. |
API Reference
Syntax
AdaptiveQuality exposes the fused quality tier, hardware diagnostics, and decision cause.
Parameters
| Parameters.field | Type | Default | Description |
|---|---|---|---|
| getAdaptiveQuality() | AdaptiveQuality | Singleton | Returns the global shared instance. Safe to call during server-side rendering. |
| quality.subscribe(fn) | (fn: (state: AdaptiveState) => void) => () => void | Subscription | Subscribes to fused tier changes. Fires immediately with current state. Returns cleanup function. |
| useAdaptiveQuality() | () => AdaptiveState | React Hook | React hook that subscribes to quality changes and returns the current AdaptiveState snapshot. |
Return Value
State snapshot containing effective tier, deviceTier, budgetTier, cause, reasons, and reducedMotion.
Properties & State
| Properties.field | Type | Description |
|---|---|---|
| quality.state | AdaptiveState | The live snapshot containing the effective tier and hardware diagnostic metadata. |
AdaptiveState
| AdaptiveState.field | Type | Description |
|---|---|---|
| tier | 0 | 1 | 2 | The effective quality tier to consume in UI and renderers (0 = high, 1 = medium, 2 = low). |
| label | "high" | "medium" | "low" | The effective tier verdict as a string. |
| deviceTier | 0 | 1 | 2 | Static hardware floor from initial probe. Never lifts at runtime. |
| budgetTier | 0 | 1 | 2 | Live tier from AnimationBudget based on presented frame intervals. |
| cause | "ok" | "device" | "reduced-motion" | "render" | "frame-rate" | "held" | Machine-readable reason for the effective tier verdict. |
| reasons | string[] | Human-readable explanation array from device probe (e.g. ["mobile-class GPU", "constrained memory/cores"]). |
| reducedMotion | boolean | Whether prefers-reduced-motion media query was matched during probe. |
Subscription Cleanup
Subscriptions to AdaptiveQuality should be cleaned up on component unmount.
Lifecycle & Invariant Guarantees
- →Immovable hardware floor: A low-end mobile phone or software renderer will never be promoted to tier 0, eliminating quality oscillation.
- →Zero external dependencies: Hardware heuristics use zero external GPU databases or remote network lookups, executing synchronously and locally in <1ms.
- →Attribution-aware shedding: When third-party ad scripts block the main thread, the governor flags the cause as 'held' rather than unnecessarily punishing visual quality.
- →Safe SSR defaults: During server-side rendering, probes safely default to tier 0 to ensure server output and first client hydration match without layout shift.
Hardware Inspection Telemetry
Real-time hardware capability probe executed on client initialization. Heuristics classify the device into an immovable baseline floor.
◆Production Examples
Battle-tested production patterns ready to copy directly into your codebase.
Map the tier to a settings object once, then feed it to the canvas backing store and particle pool.
When NOT to use this
Rules & Gotchas
- →Always consume the effective tier: deviceTier and budgetTier explain the verdict in telemetry; tier is the single fused value you render from.
- →The hardware floor never lifts: Clean frames do not promote a software-renderer or mobile envelope device to tier 0. The floor remains stable.
- →Map tier to a centralized settings object: Scattering raw tier === 0 checks across render passes makes testing difficult. Use a single dictionary map.
- →Never remount canvases on tier transitions: Mutate the live renderer in place. Re-keying a canvas re-allocates WebGL contexts and introduces severe startup stutter.