Renderer
A Renderer provides an automatic render loop for a Scene, powered by requestAnimationFrame. It continuously re-renders the scene each frame, enabling smooth animations and interactive effects. The renderer also provides a transition() method for animating element properties.
The Renderer is what brings your scene to life. Without it, you'd need to manually call scene.render() every time something changes. With a Renderer, you describe what should change (via transitions) and the renderer handles when and how — including easing, chaining, staggering, and automatic start/stop to conserve resources when idle.
Demo
Click "Animate" to run a transition. Click "Stagger" to see per-element staggered animation.
Creating a Renderer
import {
createRenderer,
createScene,
} from '@ripl/web';
const scene = createScene('.my-container', {
children: [circle, rect],
});
const renderer = createRenderer(scene);Options
The renderer accepts autoStart (default true) and autoStop (default true). With autoStop, the renderer pauses when idle and restarts when needed:
const renderer = createRenderer(scene, {
autoStart: false,
autoStop: false,
});Debug Mode
The renderer includes built-in debug overlays to help you inspect and profile your scene. Pass the debug option to createRenderer to enable them.
Setting debug: true enables all overlays at once:
const renderer = createRenderer(scene, {
debug: true,
});For granular control, pass an object with the specific overlays you want:
const renderer = createRenderer(scene, {
debug: {
fps: true, // frames-per-second counter
elementCount: true, // number of elements in the scene buffer
boundingBoxes: true, // red outline around every element's bounding box
},
});| Option | Description |
|---|---|
fps | Displays a smoothed frames-per-second counter in an overlay badge |
elementCount | Shows the total number of elements rendered each frame |
boundingBoxes | Draws a red stroke rectangle around every element's bounding box |
When fps or elementCount is enabled, a semi-transparent overlay badge appears in the top-left corner of the scene. boundingBoxes renders directly onto the canvas after each element, making it easy to verify hit areas and layout.
Demo
Toggle the debug overlays below to see them in action.
Render Loop
When running, the renderer executes a tick on every animation frame:
- Clears the context
- Advances all active transitions
- Renders every element in the scene buffer
- Requests the next frame
With autoStop enabled (default), the renderer automatically stops when there are no active transitions and the mouse leaves the scene. It restarts when the mouse re-enters or a new transition is created.
Transitions
The transition() method smoothly animates element properties from their current values to new target values. It returns a Promise-like Transition that resolves when the animation completes.
Basic Transition
await renderer.transition(circle, {
duration: 1000,
state: {
radius: 100,
fill: '#ff006e',
},
});Easing Functions
Ripl provides a full set of easing functions:
import {
easeInCubic,
easeInOutCubic, easeInOutQuad, easeInOutQuart,
easeInOutQuint, easeInQuad, easeInQuart,
easeInQuint, easeLinear, easeOutCubic,
easeOutQuad, easeOutQuart, easeOutQuint,
} from '@ripl/web';
await renderer.transition(circle, {
duration: 800,
ease: easeOutCubic,
state: { radius: 100 },
});Chaining Transitions
Because transition() returns a promise, you can chain animations sequentially:
await renderer.transition(circle, {
duration: 500,
ease: easeOutCubic,
state: { radius: 100 },
});
await renderer.transition(circle, {
duration: 500,
ease: easeOutCubic,
state: { radius: 50 },
});Animating Multiple Elements
Pass an array of elements or a group to animate them all with the same options:
await renderer.transition([circle, rect], {
duration: 800,
ease: easeOutCubic,
state: { fill: '#ff006e' },
});Per-Element Options
Pass a function instead of an options object to customize the transition per element. This is useful for staggered animations:
await renderer.transition(group, (element, index, total) => ({
duration: 500,
delay: index * 100, // stagger by 100ms
ease: easeOutCubic,
state: { fill: '#ff006e' },
}));Manual Control
start()
Manually start the render loop:
renderer.start();stop()
Manually stop the render loop. Clears all active transitions:
renderer.stop();Events
The renderer emits start and stop events to track the render loop lifecycle:
renderer.on('start', (event) => {
console.log('Renderer started at', event.data.startTime);
});Cleanup
The renderer automatically destroys itself when the scene is destroyed. You can also destroy it manually:
renderer.destroy(); // stops the loop and cleans upNOTE
For the full list of Renderer properties, methods, and events, see the Renderer API Reference.