castwrightv0.3.0

Recipes

The demos people actually need — a landing-page snippet, a README SVG, an error message, real commands, an existing VHS tape.

Each recipe is a job someone has, the smallest file that does it, and the result playing. Every player on this page was compiled from the file under its “Source”.

An install snippet for a landing page

A hero wants the terminal and nothing else: no title bar, no control bar in the way. The controls stay reachable — hover the demo or tab to it — because a loop that never stops needs a way to stop it.

<TerminalDemo demo={install} autoplay loop chrome="none" controls="hover" />

chrome none, controls on hover

Source: site/src/demos/hero.terminal.yaml
version: 1
terminal:
  title: castwright
  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{/}
  - wait: 1500
$ pnpm add -D @casoon/castwright
✓ added 3 packages
$ castwright build demo.terminal.yaml
dist/demo.cast

Keep it short: two or three commands, a result that reads as success, and a wait at the end so the final frame holds before the loop starts over.

An animated demo in a README

GitHub runs no script in a README, and a GIF of a terminal is large and blurry. An SVG is neither: text stays text, and the animation is CSS.

castwright build demo.terminal.yaml --format svg -o .github/readme
<img src=".github/readme/demo.svg" alt="What the demo shows, in one sentence." width="720">

The SVG honours reduced motion — a visitor who has it switched on sees the finished screen, standing still. --no-chrome drops the title bar; --loop-delay <ms> sets how long the last frame holds. For places that take no SVG (chat, social cards), --format gif renders the same cast through agg.

An error message, and what fixes it

Documentation of a CLI is mostly documentation of what goes wrong. Show the real message rather than a paraphrase of it: run the failing command once with exec: and record it.

A typo, reported and fixed

Source: site/src/demos/error-fix.terminal.yaml
# Scenario: an error, and its fix. Recorded like first-demo: real commands,
# run once with `castwright build --allow-exec --record`.
version: 1
terminal:
  title: ~/my-site
  cols: 116
  rows: 20
  theme: catppuccin-mocha
steps:
  - run: castwright validate demos/deploy.terminal.yaml
  - output:
      raw: |
        demos/deploy.terminal.yaml:5:5: unknown key 'sped' in step 'run' — known keys: run, speed, jitter, pause, prompt

              sped: 30
              ^
    delay: 16
  - wait: 2500
  - run: perl -pi -e 's/sped:/speed:/' demos/deploy.terminal.yaml
  - wait: 400
  - run: castwright validate demos/deploy.terminal.yaml && echo "✓ valid"
  - output:
      raw: |
        ✓ valid
  - wait: 800
  - run: castwright build demos/deploy.terminal.yaml --format svg
  - output:
      raw: |
        dist/deploy.svg
  - wait: 2500
$ castwright validate demos/deploy.terminal.yaml
demos/deploy.terminal.yaml:5:5: unknown key 'sped' in step 'run' — known keys: run, speed, jitter, pause, prompt

      sped: 30
      ^
$ perl -pi -e 's/sped:/speed:/' demos/deploy.terminal.yaml
$ castwright validate demos/deploy.terminal.yaml && echo "✓ valid"
✓ valid
$ castwright build demos/deploy.terminal.yaml --format svg
dist/deploy.svg

Real command output, without running it on every build

Writing out a long, coloured output by hand is error-prone. exec: runs the command in a pseudo-terminal and records what it printed, with its timing:

steps:
  - exec: castwright validate broken.terminal.yaml
castwright build demo.terminal.yaml --allow-exec --record   # once
castwright build demo.terminal.yaml                         # every build after

--record rewrites the file: the exec: step becomes the command and exactly what it printed. From then on nothing runs, and every build produces the same bytes. Commands never run without --allow-exec, and the build warns when the output contains something that looks like a token or your home directory.

An exec: step, after --record

Source: examples/recorded.terminal.yaml
version: 1

terminal:
  title: castwright validate
  cols: 110
  rows: 9
  theme: catppuccin-mocha

steps:
  # Recorded, not written: this was an exec: step, and
  # `castwright build --allow-exec --record` ran it once and replaced it
  # with the command and exactly what it printed.
  - run: castwright validate broken.terminal.yaml
  - output:
      raw: |
        broken.terminal.yaml:5:5: unknown key 'sped' in step 'run' — known keys: run, speed, jitter, pause, prompt

              sped: 30
              ^
    delay: 50
  - wait: 1500
$ castwright validate broken.terminal.yaml
broken.terminal.yaml:5:5: unknown key 'sped' in step 'run' — known keys: run, speed, jitter, pause, prompt

      sped: 30
      ^

A config file, shown in the terminal

show: puts a file on screen, highlighted with Shiki at build time — the output of a cat without copying the file into the demo. Edit the file and the demo follows.

steps:
  - run: cat astro.config.ts
  - show: snippets/astro.config.ts

show: with Shiki

Source: examples/show.terminal.yaml
version: 1

terminal:
  title: show
  cols: 64
  rows: 12
  theme: catppuccin-mocha

steps:
  - run: cat astro.config.ts
  - show: snippets/astro.config.ts
  - wait: 1500
$ cat astro.config.ts
import castwright from '@casoon/astro-castwright';
import { defineConfig } from 'astro/config';

// Compiles every *.terminal.yaml at build time.
export default defineConfig({
  integrations: [castwright()],
});

An existing VHS tape

If you already have VHS tapes, build them as they are. With --allow-exec their commands run and their output is recorded, as VHS would do it — without a headless browser.

castwright build demo.tape --format svg --allow-exec

examples/vhs.tape, as is

The commands in this tape ran during this site's build; the hidden cd included.

Source: examples/vhs.tape
# A VHS tape, built by castwright as is:
#   castwright build examples/vhs.tape --format svg --allow-exec
Set FontSize 20
Set Width 900
Set Height 360
Set Theme "Catppuccin Mocha"
Set TypingSpeed 40ms

Hide
Type "cd snippets && clear" Enter
Show

Type "ls" Sleep 300ms Enter
Sleep 1s
Type "head -3 astro.config.ts" Sleep 300ms Enter
Sleep 2s
> ls
astro.config.ts  broken.terminal.yaml
> head -3 astro.config.ts
import castwright from '@casoon/astro-castwright';
import { defineConfig } from 'astro/config';

> 

VHS tapes lists what is translated and what is not.

The same demo in another theme

A cast stores colours as palette indices and carries its palette in the header, so a theme is one line — terminal.theme — and a light-mode page gets a light terminal.

theme: github-light

$ pnpm add -D @casoon/castwright
✓ added 3 packages
$ castwright build demo.terminal.yaml
dist/demo.cast

The seven bundled themes are listed in Theming.

Edit this page on GitHub · Docs for v0.3.0