asciinema-player
Embed a lightweight, timing-accurate terminal-session player in any web page, no video files required.
Repository Health
Technical Analysis
asciinema-player is a web player for terminal session recordings. Unlike a typical video player that streams heavyweight .mp4/.mov files, it replays lightweight, text-based asciicast recordings (and ttyrec/typescript captures) frame by frame, so terminal output stays copy-pasteable, crisp at any zoom level, and tiny to download. It ships as an npm package or a standalone IIFE bundle and drops into any HTML page with a single line of JavaScript.
Under the hood the player pairs a Solid.js UI with a Rust-compiled-to-WASM terminal emulator (vt-js, built on the avt crate) for accurate VT100/xterm rendering, and supports multiple input drivers beyond static files, including WebSocket and Server-Sent Events for live terminal streaming, plus idle-time compression, markers, themes, keystroke overlays, and a JS API for programmatic playback control.
What You Get
- A single
AsciinemaPlayer.create(src, element, opts)call that mounts a full player UI (terminal, control bar, overlays) into any DOM element - A Rust/WASM terminal emulator (vt-js, built on the
avtcrate) for accurate VT100/xterm-style rendering instead of naive text replay - Built-in drivers for static recordings, live WebSocket/EventSource streams, benchmarking, and a synthetic clock/random source for demos
- A programmatic control API (
play,pause,seek,getCurrentTime,getDuration,addEventListener) for building custom playback UIs - Configurable color themes, adjustable playback speed, idle-time compression, markers with auto-pause, keystroke overlays, and a full-screen mode
Common Use Cases
- Embedding a CLI tool demo or terminal walkthrough directly in project documentation or a README-rendered site
- Showing a live, streaming terminal session on a status page or conference-talk slide via the WebSocket/EventSource drivers
- Replacing screen-recording video files in blog posts and tutorials with a lightweight, text-based, copy-pasteable recording
- Building a custom playback UI on top of the player’s JS API (custom scrubber, playlist, or synced captions)
Under The Hood
Architecture
A Core class (src/core.js) owns the recording/playback state machine: it resolves a src value into one of six pluggable drivers (recording, websocket, eventsource, benchmark, random, clock) and, for file-based recordings, one of three parsers (asciicast, ttyrec, typescript), then serializes every play/pause/seek/step call through an internal command queue so operations always run after driver initialization and in the order they were issued. Rendering is fully decoupled: view.js mounts a Solid.js component tree (Player.js composing Terminal, ControlBar, and overlay components) that talks to Core only through its public methods and an event-handler map, so the state machine has no knowledge of the DOM. The terminal emulation itself is pushed further down into a Rust/WASM module (src/vt), keeping VT100 parsing off the reactive UI layer entirely.
Tech Stack
The JS side is plain ES modules built with Rollup (rollup.config.mjs) and Babel’s Solid preset, targeting “defaults and supports wasm” browsers with no transpilation of newer syntax. The UI layer uses Solid.js 1.x for fine-grained reactivity without a virtual DOM. The terminal engine is a separate Rust crate (vt-js, Rust 2024 edition) built on the avt VT100 emulator crate and wasm-bindgen/serde-wasm-bindgen, compiled via @wasm-tool/rollup-plugin-rust and optimized for small code size (opt-level = "z", stripped). Styling is authored in Less and compiled separately. The build produces both a monolithic ESM/IIFE bundle and a split UI/worker bundle pair for offloading emulation to a Web Worker on high-frame-rate streams.
Code Quality
Testing is comprehensive and layered: Playwright drives full browser end-to-end specs (tests/player.spec.js and friends) against real .cast fixture files covering initialization, option handling, and error paths, while dedicated unit specs cover parsers (asciicast, ttyrec, typescript), drivers (recording, buffer, segmented/full playback), and utilities (colors, keystrokes, theme, option parsing) in isolation. ESLint 9’s flat config with the Solid plugin and a strict no-unused-vars rule, plus Prettier formatting and a GitHub Actions build workflow, keep style consistent. The public JS API has no TypeScript source but ships a hand-maintained index.d.ts covering options, events, and the returned player object, so type safety is enforced only at the API boundary rather than throughout the implementation.
API Design
A single create() entry point returns a small, focused player object (play, pause, seek, getCurrentTime, getDuration, dispose, addEventListener) rather than exposing internal state, and option parsing (opts.js) tolerates both camelCase and legacy-cased keys plus JSON-null values from non-JS embedders. The driver/parser registry pattern makes adding a new recording source or format additive rather than invasive, and the index.d.ts typings give consumers autocomplete and event-payload shapes even though the implementation itself is untyped JS.
Used by 2 apps in this directory
Gitea
Devops · Developer Tools · Project Management
Self-hosted DevOps in a single Go binary — Git hosting, GitHub Actions-compatible CI/CD, and 30+ package registries without any SaaS dependency.
hoop
Security · Monitoring
A wire-protocol gateway that enforces data masking, command blocking, approval workflows, and full session recording for engineers and AI agents accessing production infrastructure.