Element Lifecycle
StageRoutine manages element lifecycles to keep presentations responsive and preserve laptop battery during talks.
Lifecycle Events
Every element, decorator, and background follows four lifecycle events:
onMount: Runs once when the element is added to the stage.onActivate: Runs when the element enters the current scene. Use this to start or resume active media.onDeactivate: Runs when the element leaves the scene and is no longer visible. Use this to pause active media and timers.onUnmount: Runs when the presentation closes or the stage is destroyed. Clean up global event listeners here.
Resource Efficiency at Rest
Presentations spend most of their time at rest between steps while the speaker talks. StageRoutine helps preserve system resources automatically:
Automatic Animation Pausing
Explicitly requested backgrounds, repeating pulses, typewriter effects, and camera motion continue between steps while visible. They stop on scene exit or disposal. Completing a step transition does not stop them. You do not need to write cleanup code for CSS animations.
Managing Timers and Streams
Video playback and webcam streams follow visibility. Bind custom ambient timers to onActivate and onDeactivate. Dispose listeners and resources on unmount. For work that should run only during step transitions, use evt:stage:activityChanged instead.
Prefer onUpdate for small effects such as grain. It runs during stage updates and needs no interval. For a raw DOM target, grain()(node) returns a handle with dispose().
This counter opts into running only during step transitions:
/** @jsxImportSource stageroutine */
import { Element, type DOMElement, type ElementOptions, type Stage } from "stageroutine";
export function SecondsCounter(stage: Stage, options: ElementOptions = {}): DOMElement {
const label = <span>0s</span>;
const counter = Element(label, options);
let seconds = 0;
let timerId: number | undefined;
const stop = () => {
if (timerId !== undefined) window.clearInterval(timerId);
timerId = undefined;
};
const detach = stage.on("evt:stage:activityChanged", ({ active }) => {
stop();
if (active && counter.isActive) {
timerId = window.setInterval(() => {
label.textContent = String(++seconds) + "s";
}, 1000);
}
});
counter.onDeactivate(stop);
counter.onUnmount(() => { stop(); detach(); });
return counter;
}
Use the component in your presentation:
const counter = SecondsCounter(stage, { position: [80, 36], origin: "top" });
stage.scene("Live Demo").with(counter);
The RAF metric includes procedural background and overlay loops. Browser animations and typewriter timers have separate metrics. A presentation with visible ambient effects is still doing animation work between steps.