useFramePressure
Knowing that a frame missed its 16.7ms deadline does not reveal the root cause. FramePressure decomposes the frame into motion runtime work, competing main-thread scripts, and off-thread rendering, classifying bottlenecks with confidence ratings so systems only downgrade visual fidelity when the GPU is genuinely saturated.
The useFramePressure hook diagnoses what is currently consuming frame budget. It breaks down each presented frame into three distinct components:
Using a low-overhead MessageChannel task probe sampled at ~10Hz, it measures uncoordinated main-thread work executing outside the FrameConductor.
When a frame exceeds 125% of budget (> 20.8ms at 60Hz), the classifier attributes the primary bottleneck with a calculated confidence rating. For automated scene degradation, use useSceneGate, which consumes this verdict through AdaptiveQuality with hysteresis and confidence floors.
◆Live Subsystem Bottleneck Sandbox
Quick start
Read frame pressure state to diagnose performance issues or implement custom telemetry reporting.
Frame pressure emits at a low-frequency ~2Hz cadence, making it safe to bind directly into React component state.
Subsystem Attribution Matrix & Honest Limits
How each verdict is categorized, and why off-thread time is treated as a remainder rather than direct GPU profiling.
| Verdict | Underlying Cause | Recommended Engineering Action |
|---|---|---|
| "none" | Frames are healthy or within 125% of budget. | No action needed. Minor frame drops are handled by AnimationBudget. |
| "runtime" | Conductor subscribers represent the largest cost. | Conductor priority lanes automatically shed decorative work. |
| "main-thread" | Uncoordinated third-party scripts or layout thrashing. | Profile and optimize blocking scripts. Lowering 3D scene quality will not unblock the main thread. |
| "render" | Main thread is free, but compositor or GPU is saturated. | Reduce resolution, simplify shaders, or lower 3D geometry detail. |
| "unknown" | Insufficient probe samples to establish winner. | Hold current quality settings until confidence stabilizes. |
Standard Web APIs do not expose hardware GPU timing queries. unattributedMs calculates the remaining duration after subtracting measured conductor time and sampled main-thread work. A high unattributed value indicates render bottlenecks with strong statistical likelihood.
API Reference
Syntax
React hook that returns smoothed frame pressure telemetry and diagnostic classifications at 2Hz.
Return Value
Object containing the classified pressure source, confidence, and millisecond breakdown.
Properties & State
| Properties.field | Type | Description |
|---|---|---|
| source | PressureSource ("none" | "runtime" | "main-thread" | "render" | "unknown") | The primary subsystem bottleneck identified for over-budget frames. |
| confidence | number | 0.0 to 1.0 score indicating statistical margin over competing subsystems. |
| frameMs | number | Smoothed wall-clock duration between consecutive presented animation frames. |
| budgetMs | number | Target frame budget based on detected display refresh rate (e.g. 16.7ms for 60Hz, 8.3ms for 120Hz). |
| runtimeMs | number | Smoothed execution time spent inside motion runtime subscribers. |
| mainOtherMs | number | null | Sampled duration of external main-thread work. Null until probe has collected sufficient samples. |
| unattributedMs | number | Remainder duration attributed to GPU rendering, compositing, and rasterization. |
| longTasks | number | Number of long task blocks (> 50ms) observed in the current sampling window. |
Core Singleton Methods
| Core Singleton Methods.field | Method | Returns | Description |
|---|---|---|---|
| getFramePressure() | FramePressure | Returns the shared singleton instance, safe for use outside React or during SSR. | |
| getFramePressure().state | PressureState | Synchronously reads the current verdict. Safe to read directly inside frame callbacks. | |
| getFramePressure().subscribe(fn) | () => void | Calls fn with each new verdict at ~2Hz cadence. Returns an unbind function. |
Probe Lifecycle & Subscriber Teardown
The background MessageChannel probe activates lazily upon the first subscriber and cleans up when all listeners unmount.
Lifecycle & Invariant Guarantees
- →Negligible probe overhead: Runs a MessageChannel sample at 10Hz rather than per-frame, consuming less than 0.05ms of CPU time.
- →Confidence margin verification: Emits high confidence only when the winning subsystem clearly exceeds competing costs.
- →Low-frequency React re-renders: Updates React state at a conservative 2Hz cadence, avoiding UI thread contention.
- →SSR and Server Component safety: Returns static initial state on the server without throwing window or MessageChannel errors.
◆Production Examples
Battle-tested production patterns ready to copy directly into your codebase.
Lower WebGL resolution only when render pressure is confirmed with high confidence.
When NOT to use this
Rules & Gotchas
- →Enforce a confidence floor before triggering degradation: Real-world heavy scenes frequently report confidence near 0.5. Require a confidence floor (e.g. >= 0.4) to prevent UI quality flickering.
- →Treat unattributedMs as a statistical remainder: Do not assume unattributedMs equals raw GPU compute time; it represents remaining unmeasured frame duration.
- →Do not degrade visual quality on main-thread pressure: If a third-party script blocks the main thread, lowering 3D resolution will not fix frame rates and makes the page worse.
- →Read state synchronously inside frame callbacks: When reading pressure inside FrameConductor loops, access getFramePressure().state to avoid React state hooks.