A single-page web app that loads a JSON recording produced by jsPsych.getSessionRecording() (record_session: true) and reconstructs a visual replay of the participant's session.
The replayer is purely observational — it applies recorded DOM mutations and visualizes recorded input events. It does not re-run plugin code.
Schema contract: recordings with schema_version: 1 are supported. Any other version is rejected.
- Load recordings via file picker or drag-and-drop
- Trial sidebar — list of all trials with plugin name; click to jump
- Trial data viewer — see the recorded
trial_dataJSON for the selected trial - DOM replay — reconstructs
initial_domat each trial'son_loadstate - Event playback — applies mutations, mouse/touch/keyboard input events in real time
- Player controls — play, pause, restart, prev/next trial
- Scrub bar — seek anywhere within a trial (applies events synchronously up to the target)
- Speed control — 0.25×, 0.5×, 1×, 2×, 4×
- Cursor overlay — tracks
mouse.move/touchpositions - Keystroke indicator — last 3 keys shown on-screen
- Focus/blur overlay — shows when the window was blurred during the session
- Viewport resizing — iframe resizes to match
viewport/viewport_changes
pnpm install
pnpm devOpen http://localhost:5173 and use Load Recording… (or drag-and-drop a .json file onto the page) to load a recording.
pnpm buildOutput is in dist/ — a static SPA that can be served from any web server or opened locally.
pnpm testUnit tests (vitest) cover:
validate()— schema version checking, field validation, JSON string inputinstantiateDom()— element/text/comment node creation, id map registration, security (noon*attrs), recursive childrenReplayEngine.applyEventsSync()—dom.text,dom.attr, security, empty events
src/
├── main.ts # bootstrap: file picker, wires sidebar + player
├── schema/
│ └── types.ts # schema types + validate()
├── replay/
│ ├── dom.ts # instantiateDom(), removeFromMap()
│ ├── engine.ts # ReplayEngine: scheduling + event dispatch
│ └── viewport.ts # ViewportManager: iframe sizing
└── ui/
├── player.ts # Player: play/pause/seek/speed/trial nav
├── sidebar.ts # Sidebar: trial list + trial_data viewer
└── overlay.ts # cursor dot + keystroke indicator + focus overlay
The replay stage is an <iframe sandbox="allow-same-origin"> so the recorded DOM cannot fire scripts.
- Add
record_session: trueto yourinitJsPsychcall. - On finish, run in the console:
copy(JSON.stringify(jsPsych.getSessionRecording())). - Save the output as a
.jsonfile and open it in this app.
This replayer only supports schema_version: 1. Recordings with any other version will display a validation error. See jspsych/jsPsych#3661 for the full schema specification.