DevTools
A page runs at 22fps and the profiler shows a wall of scripting with no attribution. You cannot tell whether the cost is your effects, React, style, paint, or the GPU, so you tune the wrong thing. DevTools mounts a Shadow DOM overlay that splits each frame into per-subscriber execution time, lane, and remaining budget, reporting what the runtime cost separately from what everything else did.
The mountDevtools function attaches a real-time diagnostics overlay to the DOM. It displays every active FrameConductor subscriber, its assigned scheduler lane, its priority level, and its exact frame execution cost in milliseconds.
The overlay reads telemetry directly from getConductor().state and AnimationBudget. It operates inside an isolated Shadow DOM container with all: initial, preventing style leakage in either direction.
Repaints are throttled to 5Hz and write directly to DOM text nodes. By packaging as an independent entry point (@vectorvesper/motion/devtools), it adds zero bytes to production bundles when tree-shaken behind development environment flags.
◆Live Shadow DOM Inspector Toggle
Quick start
Mount the overlay conditionally in development environments. The returned function cleans up all DOM nodes and subscriptions on unmount.
Guarding behind NODE_ENV allows tree-shaking compilers to remove the entire devtools package from production output.
Inspector Telemetry Metrics & Isolation Guarantees
Understanding the six diagnostic metrics displayed in the HUD grid and subscriber priority rows.
| Metric Tile | Telemetry Source & Explanation |
|---|---|
| fps | Smoothed frames per second, measured from the rAF interval. |
| frame | Smoothed rAF-to-rAF interval in ms: the wall clock between presented frames. |
| runtime work | How much of that frame the motion runtime spent running subscribers. |
| headroom | Frame budget remaining. Turns red when negative. |
| tier | Current quality tier and its label (e.g. 0 high). |
| shed / frame | Subscribers skipped on the most recent frame. |
Uses an open shadow root with all: initial to guarantee complete styling encapsulation.
Repaints at 5Hz using direct textContent mutations to ensure the profiler does not perturb measured frame rates.
Registered as an essential subscriber so the inspector is never shed when inspecting heavy degradation events.
API Reference
Syntax
Mounts the diagnostic overlay into the specified DOM host and connects to runtime frame telemetry.
Parameters
| Parameters.field | Type | Default | Description |
|---|---|---|---|
| options.position | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "bottom-right" | Fixed viewport corner where the inspector docks. |
| options.expanded | boolean | true | Whether the subscriber table starts open. When collapsed, only the header FPS meter is painted. |
| options.hz | number | 5 | Refresh cadence per second for UI updates. |
| options.container | HTMLElement | document.body | Target DOM element where the Shadow DOM host is attached. |
Return Value
Cleanup function that unbinds conductor telemetry and removes the shadow host element.
Clean Teardown & SSR Safety
The inspector handles environment verification and lifecycle cleanup safely.
Lifecycle & Invariant Guarantees
- →Complete CSS encapsulation: Encapsulates all markup within an isolated Shadow DOM root with all: initial, preventing style collisions.
- →Zero framework dependencies: Constructed with pure TypeScript DOM APIs; operates seamlessly in React, Vue, Svelte, or vanilla JS.
- →Self-reporting measurement: Lists its own execution time directly in the subscriber table for complete transparency.
- →Tree-shakeable bundle: Isolated in a separate package subpath (@vectorvesper/motion/devtools) with zero impact on production bundles.
◆Production Examples
Battle-tested production patterns ready to copy directly into your codebase.
Mount the overlay conditionally in Next.js applications during local development.
When NOT to use this
Rules & Gotchas
- →Label all conductor subscribers: Unlabelled subscribers appear as 'anonymous' in the inspector table. Always provide options.label when calling subscribe().
- →Compare frame duration against runtime work: If the frame interval is 32ms while runtime work is 2ms, uncoordinated external scripts or GPU shader bottlenecks are responsible.
- →Watch shed count before headroom: Headroom going negative is an early indicator; actual subscriber shedding indicates noticeable UI degradation under load.
- →Tree-shake devtools imports in production: Import from @vectorvesper/motion/devtools only within development guards to exclude the inspector from production bundles.