castwrightv0.6.0

CLI

castwright build, validate and dev.

Errors go to stderr, results to stdout, so the commands compose. A missing or unwritable file is reported in one line (castwright: cannot read demo.terminal.yaml: no such file or directory) and exits 1.

castwright --version prints the installed version, and castwright <command> --help prints that command’s usage.

build

castwright build <file> [-o|--out <dir>] [--format cast|svg|gif|mp4] [--no-chrome] [--loop-delay <ms>] [--start final|beginning] [--allow-exec [--record]] [--allow-show-outside-root]

Compiles a *.terminal.yaml — or a VHS .tape — to <dir>/<name>.<format> and prints the path. -o (long form --out) defaults to dist, --format to cast.

$ castwright build demo.terminal.yaml
dist/demo.cast

The output is asciicast v2 — newline-delimited JSON — and it is deterministic: the same input compiles to the same bytes on every machine.

Formats

Format Output Needs
cast asciicast v2, for the player and the asciinema tools —
svg One self-contained animated SVG: real text, no script, loops —
gif Animated GIF, rendered by agg agg on PATH
mp4 h264 video, agg’s GIF re-encoded by ffmpeg agg and ffmpeg on PATH

svg is the one for a README or a page that should not load a player. The animation is pure CSS with no script and no external references, so it plays inside a plain <img> — which is how GitHub embeds images in a README. The theme, bold, italic, dim and underline come across; the column grid is pinned with textLength, so a different monospace font on the viewer’s machine changes glyph shapes but never alignment. prefers-reduced-motion shows the finished screen.

The SVG opens on the finished screen: the loop’s first pass starts in the final hold, so a visitor sees the end result first, and after --loop-delay the demo plays from the beginning. Every pass after that is the same replay. A screen that is blank only between two others — after a clear:, until the next prompt — is left out; the previous screen stays up until the next one has content.

![castwright demo](docs/demo.svg)

Three options apply to svg only:

Option Effect
--no-chrome Drops the window title bar with the traffic lights.
--loop-delay <ms> How long the finished screen holds before the loop restarts, on top of a closing wait:. Default 2000.
--start final|beginning Where the first pass starts. final (default) opens on the finished screen; beginning opens on the empty terminal.

Size grows with the length of the demo, at roughly 2 KB per second of typing and output before compression — about 50 KB for 20 seconds, 120 KB for a minute. Each line of the terminal is animated on its own, so a keystroke or a scroll adds a few bytes rather than a copy of the screen. For a README, keep demos short; the GIF of the same demo is usually larger.

gif and mp4 are for places that take nothing else — social posts, slides. castwright does not rasterise anything itself; agg does, using the theme in the cast header, and a missing tool is reported with an install hint and a non-zero exit.

exec: steps

exec is not supported on Windows: the build stops with an error there.

Option Effect
--allow-exec Lets exec steps run their commands. Without it, a file containing one fails to build.
--record Runs them once and rewrites the file with what they printed, as run + output. For a .tape, writes a new .terminal.yaml next to it instead. Needs --allow-exec.
castwright build demo.terminal.yaml --allow-exec --record   # once
castwright build demo.terminal.yaml                         # every build after

show: steps

A show: file must live inside the working directory; a path that resolves outside it (../, an absolute path, a symlink out) fails the build. --allow-show-outside-root lifts that. See show.

validate

castwright validate <file>... [--allow-show-outside-root]

Checks every file given, not just up to the first failure, and exits non-zero if any has an error. Silent when everything is fine, which makes it usable as a pre-commit hook.

$ castwright validate demos/*.terminal.yaml
demos/broken.terminal.yaml:4:5: step 'clear' must be `true` (or omitted entirely)

    - clear: false
      ^

show: steps are checked too: the file must exist inside the working directory, a lines: range must fit, and the language must be known (the last needs Shiki installed; nothing is highlighted). Warnings are printed but do not fail the command.

Glob patterns are not expanded by the command itself: a pre-commit hook passes an explicit file list, and a shell has already expanded *.terminal.yaml before the process starts.

dev

castwright dev <file> [-p|--port <n>] [--allow-exec] [--allow-show-outside-root]

Serves one demo and reloads it on save (-p is the short form of --port). Edit the YAML, watch the terminal in the browser change.

dev needs Vite and @casoon/castwright-player: it serves a real page with a real player on it. Both are optional dependencies — a project that only runs castwright build in CI should not have to install either — so if one is missing, the command says so and names the fix.

pnpm add -D vite @casoon/castwright-player

asciicast interop

The output is a standard asciicast, so the rest of that ecosystem works on it:

castwright build demo.terminal.yaml
asciinema play dist/demo.cast

The header carries the spec’s own field names — fg, bg and a colon-joined palette of 8 or 16 colours — so any v2 reader understands it. asciicast v2 has no field for the cursor colour, so a theme’s cursor tint is not written to the file; a player falls back to the foreground colour, which is the terminal default anyway.

It works the other way too: <castwright-demo src="recording.cast"> plays a real asciinema rec recording, with no castwright involved in making it. Resize (r) events are applied as they happen and input (i) events are skipped, since keystrokes are not screen output.

Edit this page on GitHub · Docs for v0.6.0