Devtools
Ripl ships browser developer tools for inspecting and editing live scenes. They come in two parts: the @ripl/devtools package (a small runtime bridge you opt into in your app) and the Ripl Devtools Chrome extension that adds a Ripl panel to the browser devtools, much like the built-in Elements panel.
Once bound, the panel shows the full element tree of every Ripl context on the page, lets you edit element properties live, toggles renderer debug overlays, and records every event the scene fires onto a timeline.
NOTE
For the full API, see the Devtools API Reference.
Demo
The scene below is bound to the devtools. In fact, every demo on this site is devtools-bound: install the extension, open your browser devtools, and select the Ripl panel to inspect any of them live.
Installation
npm install @ripl/devtoolsSetup
Call createDevtools once per context, passing the context and, optionally, its scene and renderer. Binding the scene enables the element tree; binding the renderer enables the debug overlay switches.
import {
createContext,
createRenderer,
createScene,
} from '@ripl/web';
import {
createDevtools,
} from '@ripl/devtools';
const context = createContext('.container');
const scene = createScene(context);
const renderer = createRenderer(scene);
if (import.meta.env.DEV) {
const devtools = createDevtools(context, scene, renderer);
// Later, when tearing the scene down:
// devtools.dispose();
}A few things to know:
sceneandrendererare optional. With just a context you still get context detection and metadata; add the scene for the element tree and the renderer for debug overlays.- One binding per context. Calling
createDevtoolsagain for the same context returns the existing binding. - Idle by default. Until you open the Ripl panel, a binding only announces its presence. No scene serialization or event listening happens, so it is effectively zero-cost. This is why the example gates on
import.meta.env.DEV: it is safe to ship, but there is rarely a reason to bind in production. - Self-cleaning. A binding disposes automatically when its context, scene, or renderer is destroyed. Call
dispose()yourself if you need to unbind sooner.
TIP
Bindings are cheap, but you can leave them enabled in production too if you want your live app to be inspectable. The bridge stays idle until someone opens the panel.
Options
createDevtools accepts an optional options object as its final argument.
| Option | Type | Description |
|---|---|---|
label | string | Human-readable label shown for this binding in the devtools UI. Defaults to the context's type. |
createDevtools(context, scene, renderer, {
label: 'Sales chart',
});Browser extension
The companion Chrome extension adds a Ripl panel to your browser devtools, split into two tabs.
Elements shows:
- an element tree of every context on the page, rendered as pseudo-XML with each element's set properties as attributes, scrollable sideways to read long attribute lists, and expandable or collapsible in one click;
- a search and type filter that narrows the tree to matching elements, keeping the groups that contain them so a match still reads in place;
- an editable properties panel to change numbers, strings, colors and more, with edits that round-trip to the live element, badging Ripl's own elements as built-in and linking to their documentation;
- renderer debug switches for an FPS counter, element count, and bounding boxes;
- an events list showing which events the selected element emits and whether any listeners are attached.
Events records what the scene actually did:
- a timeline — itself drawn with Ripl — with a lane per event source and a scrub window you drag to select a slice of the recording;
- a list of the events inside that window, with each one's name, time and originating element, narrowable by the same search and type filter;
- a details panel showing the full payload of the selected event, and a jump back to its element in the Elements tab.
The timeline always shows the whole recording; the window selects what the list shows, so scrubbing narrows the list rather than rescaling the timeline. Searching and filtering narrow the view only — they never change what is captured.
Recording uses the '*' wildcard subscription, so it observes the scene without changing how it behaves — an observed element is still not a hit-test target.
updated, render and tick are excluded by default because they fire every frame or every state write; switch any of them back on from the toolbar. That filter is applied in the page, so events you have excluded are never sent.
Pointer events that the context re-emits from the DOM are not recorded. The elements those events reach record them as they bubble, so capturing both would only duplicate the stream.
Every context also reports the version of Ripl the page is running, shown beside it in the toolbar popup and in the Context section of the properties panel.
A toolbar icon lights up when Ripl is detected on the page; clicking it lists the contexts it found.
NOTE
Event recording needs a page-side bridge that supports it. A page running an older @ripl/devtools still works for everything else; the Events tab tells you to upgrade rather than showing an empty timeline.
TIP
Install Ripl Devtools from the Chrome Web Store.
Prefer to run it from source? Build the apps/devtools-extension workspace and load its dist/ folder via Load unpacked at chrome://extensions (with Developer mode enabled). See the extension's README.md for the full steps.