Walkr
Create polished web product demos, programmatically.
Walkr lets you script interactive walkthroughs of any website — animated cursor movements, clicks, typing, highlights — and export them as videos or embeddable players. Think screen recording, but deterministic, editable, and pixel-perfect every time.
Write a short TypeScript script, point it at your app, and get a production-ready product demo you can embed in your landing page, docs, or sales deck.

Documentation
Install
Walkr ships as a single CLI package that includes everything you need:
npm install -g @walkrstudio/cli
Or use it without installing:
npx @walkrstudio/cli dev demo.ts
Prerequisites
- Node.js >= 18
- Chromium — the recorder needs a local Chromium-based browser. Install one if you don't already have it:
- Arch Linux:
sudo pacman -S chromium
- Ubuntu/Debian:
sudo apt install chromium-browser
- macOS:
brew install --cask chromium
- Or set
CHROMIUM_PATH to point at any Chrome/Brave/Edge binary
- ffmpeg — required for video export (
mp4, webm, gif)
Quick start
Create a file called demo.ts:
import { walkr, moveTo, click, type, highlight, hover, wait, drag } from "@walkrstudio/core";
export default walkr({
url: "https://your-app.com",
title: "Signup walkthrough",
steps: [
moveTo("#email-input", { name: "Focus email field", duration: 600 }),
click("#email-input", { name: "Click email input" }),
type("[email protected]", { name: "Enter email", selector: "#email-input", delay: 35 }),
wait(300, { name: "Pause before highlight" }),
highlight(".submit-btn", { name: "Spotlight submit", spotlight: true, color: "#22d3ee", duration: 1200 }),
moveTo(".submit-btn", { name: "Move to submit", duration: 400 }),
click(".submit-btn", { name: "Submit form" }),
],
});
Preview with live reload:
walkr dev demo.ts
Export to video:
walkr export demo.ts --format mp4 --output demo.mp4
CLI reference
walkr dev <script> Start Walkr Studio with live script reload
walkr export <script> [options] Export walkthrough as video or embed
Export options
| Flag | Description | Default |
|---|
--format | mp4, gif, webm, or embed | mp4 |
--output | Output file path | output.<ext> |
--width | Video width in px | 1920 |
--height | Video height in px | 1080 |
--realtime | Use real-time screencast instead of virtual time | off |
Export formats
- mp4 — H.264 video, good default for most uses
- webm — VP9 video, works natively in browsers
- gif — animated GIF at 15 fps, scaled to 1280px wide
- embed — self-contained HTML file with a built-in frame player (all frames inlined as base64)
Capture modes
Virtual time (default) uses Chrome's virtual time API to step through the walkthrough frame-by-frame. Every frame is a full captureScreenshot, so the output is fully deterministic — identical input always produces identical output. Frames stream directly to ffmpeg with no temp files.
Real-time (--realtime) plays the walkthrough at 1x speed using Chrome's Page.startScreencast for push-based frame delivery. Wall-clock time roughly equals walkthrough duration. Useful when your app has animations or transitions that depend on real browser timing.
# Deterministic capture (default)
walkr export demo.ts --format mp4
# Real-time capture
walkr export demo.ts --format mp4 --realtime
Step functions
All step functions are imported from @walkrstudio/core.
Step names
Every step accepts an optional name in its options. Names appear in the Studio timeline, engine lifecycle events (step_start, step_end, step_error), and error messages — making walkthroughs easier to read and debug.
moveTo('#settings', { name: 'Open settings menu' })
click('#save-btn', { name: 'Save changes' })
wait(1000, { name: 'Wait for animation' })
When a step has no name, the Studio timeline falls back to showing the step type (e.g. CLICK).
walkr(options)
Define a walkthrough. Returns a Walkthrough object.
walkr({
url: "https://your-app.com", // target URL to load in the iframe
title: "My Demo", // optional title (shown in embed player)
description: "A product demo.", // optional description
viewport: { width: 1920, height: 1080 },
cursor: { shape: "arrow", color: "#10b981", size: 24, shadow: true },
steps: [ /* ... */ ],
})
moveTo(selector, options?)
Animate the cursor to the center of a DOM element.
moveTo("#signup-btn", { duration: 600, easing: "ease-in-out" })