Session replay
Replay re-drives a captured session in your own scene: camera pose is applied directly, and pointer / mesh / custom / input events are surfaced to callbacks so you can draw a cursor, highlight a mesh, or annotate a timeline.
Option A — npm
Section titled “Option A — npm”npm install @uptimizr/replayimport { fetchSessionEvents, ReplayPlayer } from "@uptimizr/replay";import { createBabylonReplayDriver } from "@uptimizr/replay/babylon";
const events = await fetchSessionEvents({ endpoint, apiKey, sessionId });const driver = createBabylonReplayDriver({ scene, onPointer: (screen, hitPoint, hitMesh, type) => { /* draw cursor / flash */ }, onMeshInteraction: (mesh, kind) => { /* highlight */ }, onCustom: (name, props) => { /* timeline marker */ }, onInputAction: (input, ts) => { /* input.action / input.source / input.code / input.button */ }, onLifecycle: (event, ts) => { /* viewport_resize / focus_change / context_lost / … */ }, onError: (error, ts) => { /* mark a runtime_error (only if captureErrors was on) */ },});
const player = new ReplayPlayer(events, driver, { speed: 1 });player.play();// player.pause(); player.seek(ms); player.stop();import { fetchSessionEvents, ReplayPlayer } from "@uptimizr/replay";import { createThreeReplayDriver } from "@uptimizr/replay/three";
const events = await fetchSessionEvents({ endpoint, apiKey, sessionId });// three has no scene.activeCamera, so `camera` is required.const driver = createThreeReplayDriver({ scene, camera, // required onPointer: (screen, hitPoint, hitMesh, type) => { /* draw cursor / flash */ },});
const player = new ReplayPlayer(events, driver, { speed: 1 });player.play();ReplayPlayer is deterministic — seeking backward resets the driver and replays from the start.
player.durationMs gives the total length.
Replaying scene actors
Section titled “Replaying scene actors”To replay scene actors
(node_transform), pass a nodes map from each recorded nodeId to the engine node to
drive, and/or an onNodeTransform callback to observe every sample:
const driver = createBabylonReplayDriver({ scene, nodes: { "npc-guard": () => scene.getMeshByName("Guard_root"), // resolver, name, or ref }, onNodeTransform: (sample, ts) => { /* sample.nodeId / sample.boneId? / sample.position / sample.rotation / sample.scale? */ },});The Babylon, three, and PlayCanvas drivers re-apply Tier-1 root transforms and Tier-2 skeleton bones
(matching each bone by name on the node’s skeleton). The babylon-lite driver drives the Tier-1 root
and forwards bone samples to the callback only. Unknown nodeId / boneId are skipped without error
(forward/back-compatible).
Option B — <script> tag
Section titled “Option B — <script> tag”The global build exposes window.UptimizrReplay, with a one-call replayInScene convenience that
fetches and plays a session:
const r = document.createElement("script");r.src = "https://cdn.jsdelivr.net/npm/@uptimizr/replay/dist/uptimizr-replay.global.js";r.onload = () => { UptimizrReplay.replayInScene({ scene, endpoint: "https://collect.example.com", apiKey: "your-project-api-key", sessionId: "<copy from the dashboard Sessions table>", debug: true, // log fetch/play progress to the console });};document.head.appendChild(r);replayInScene starts playback immediately — it does not wait for the scene to be “ready”, so call it
once scene exists and has an activeCamera. It always logs a concise summary and warns about the
common “nothing happens” causes: an empty session, a session with no camera_sample events (camera
won’t move), or a scene with no active camera. (pnpm playground prints this snippet pre-filled and
serves the bundle at /uptimizr-replay.global.js.)
Troubleshooting
Section titled “Troubleshooting”403from the events endpoint — raw-session retention is off (ENABLE_RAW_SESSION_RETENTION).200with 0 events — usually an API-key / project mismatch: reads are scoped to the key’s project, so a valid session id looked up with another project’s key returns nothing. Copy the session id and the API key from the same dashboard project.- Camera doesn’t move — the session has no
camera_sampleevents.
In the dashboard: replay + live follow
Section titled “In the dashboard: replay + live follow”The dashboard’s Session replay birdview is the same engine, no code required. Open a session from the Sessions table to scrub its camera path, interaction rays, and moving scene actors, with a colour-coded event timeline you can click to seek. Each tracked actor is drawn as one labelled marker per root — a subtree actor (an articulated character) shows a single dot for “where it is” rather than a marker per joint; its full per-joint motion still reconstructs when you replay it in your own scene.
When the session is live right now (it has produced an event within the active-now window), the same window switches to live follow: new camera moves and interactions stream in and the timeline grows in real time. A ● LIVE control pins the playhead to the live edge; scrub back (or press Play) to review what already happened, then press ● LIVE to jump back to the edge. Live follow uses the same raw-retention gate as replay — with retention off, the window shows nothing to follow.