CASOON Open Source
Terminal demos you write, not record.
castwright compiles a small YAML file to asciicast v2 and plays it as a real terminal — real ANSI, real cursor movement, selectable text — with no headless browser anywhere in your build.
pnpm add -D @casoon/castwrightnpm i -D @casoon/castwrightyarn add -D @casoon/castwright$ npx casoon create my-app ✓ Creating project ✓ Installing dependencies ✓ Project ready $ cd my-app && npm run dev ready in 412ms ➜ Local: http://localhost:4321/
- unit tests
- 381
- browser tests, desktop and mobile
- 22
- axe violations at WCAG 2.2 AA
- 0
- parser or compiler shipped to the browser
- 0 kB
What it does
Authored, not performed
No recording session to get right on the seventh take. Edit a line, rebuild, and the demo changes — the same way the rest of your documentation does.
A real terminal, not a lookalike
xterm.js interprets the bytes, so cursor movement, line rewrites and carriage returns behave as they would in a shell. Coloured spans in a <pre> cannot do that.
Deterministic output
The same input compiles to the same bytes on every machine. A generated .cast is a text file you commit and read in a diff, and typing jitter is seeded so it stays that way.
One file, every output
The same .cast plays in the page, exports to an animated SVG for a README — real text, no JavaScript — and to GIF or MP4 for everywhere else.
Real files and real commands
show: puts a file on screen, syntax-highlighted at build time. exec: runs a command for real, and --record writes its output back into the file so every later build replays the same bytes.
Accessible by construction
The element’s children are the terminal’s final text, generated at build time — real content before the script loads and if it never does. Reduced motion is honoured and there is always a pause control.
Generated at build time
All examples →version: 1
terminal:
cols: 72
rows: 12
theme: catppuccin-mocha
steps:
- run: pnpm add -D @casoon/castwright
- output: |
{green}✓{/} added 3 packages
- wait: 500
- run: castwright build demo.terminal.yaml
- output: |
{dim}dist/demo.cast{/}This is the file that produced the terminal at the top of the page, compiled during this build. No screenshots, nothing kept in step by hand.
examples/basic.terminal.yamlQuickstart
Three steps from install to a demo on the page. The walkthrough, the DSL reference and the integration guides are in the documentation.
- Register the Vite plugin, or the Astro integration that wraps it.
- Write a
*.terminal.yamlfile describing the session. - Import it and hand it to
<TerminalDemo>, or to the<castwright-demo>element directly.
---
import TerminalDemo from '@casoon/astro-castwright/TerminalDemo.astro';
import demo from '../demos/install.terminal.yaml';
---
<TerminalDemo demo={demo} autoplay loop />