Recording Demos [[release_demos: NarrativeDoc]]NarrativeDoc
How the terminal demos shown across these docs (e.g. the Quickstart on the home page)
are produced: a small, repeatable pipeline that turns a content script into a .cast, then
a .gif and a high-quality .mp4. Built on asciinema + agg +
ffmpeg.
Pipeline [[demos_pipeline: text]]text
One engine script drives every demo:
docs/.assets/<name>.demo.sh ──record──▶ <name>.cast ──render──▶ <name>.gif + <name>.mp4
All artifacts share a stem and live next to each other in docs/.assets/. Recording (build
the .cast) is separate from rendering (produce .gif / .mp4), so you can iterate on the
script and on the output formats independently.
scripts/demos/demo.sh record [name] # run <name>.demo.sh under asciinema → .cast
scripts/demos/demo.sh gif [name] # .cast → .gif
scripts/demos/demo.sh mp4 [name] # .cast → .mp4 (H.264, high quality)
scripts/demos/demo.sh render [name] # gif + mp4
scripts/demos/demo.sh all [name] # record + render (default; name defaults to quickstart)
Install the tools once: brew install asciinema agg ffmpeg (and jq for MCP demos).
Add a New Demo [[demos_add: text]]text
Drop a single content script docs/.assets/<name>.demo.sh — no boilerplate. The runner
sources scripts/demos/demo.sh into it first, so the helpers below are already available.
Then run scripts/demos/demo.sh all <name>.
A minimal example:
cd "$(mktemp -d)" # work in a throwaway dir
echo '# Demo [[demo: __Workspace]]' > readme.qmd.md
note "A heading is an object, list items are fields:"
run_live "cat readme.qmd.md"
note "Query it like a database:"
run_live 'qmdc query . "SELECT __id, __kind FROM objects"'
Helpers [[demos_helpers: text]]text
Provided by scripts/demos/demo.sh when sourced:
note "text"— a cyan narration line (the "why" before a command).run_live "cmd"— type the command, run it live, print output, then pause.run_shown "cmd" "$OUTPUT"— type the command but print pre-captured output instantly (used for MCP, whose stdio server needs stdin held open briefly to flush — a piping quirk, not real latency).qmdc …— the repo CLI, so typed commands read as plainqmdc.mcp_request <tool> <args-json> <file>/mcp_capture <file> <jq-filter>— build and run a one-shot MCP Server JSON-RPCtools/calland extract the payload withjq.
Tunables (env): TYPE_SPEED, NOTE_PAUSE, and the auto-pause PAUSE_BASE_CS /
PAUSE_PER_LINE_CS / PAUSE_MAX_CS (centiseconds). The reading pause after each command
scales with how many lines it printed, so dense output gets more time on screen.
Embedding on the Site [[demos_embed: text]]text
Reference the rendered gif from any page with plain Markdown — no attributes:

The SSG (build) copies every referenced image into the built site and rewrites
the link (so a source in the hidden .assets/ dir still ships), and the glightbox plugin
makes it click-to-zoom. Keep the .demo.sh / .cast / .mp4 in .assets/ too; they are
never published (the dir is hidden, and only referenced media is copied). For an in-editor
equivalent, see the extension's preview command Open Preview.
Tips [[demos_tips: text]]text
- Keep output on screen — pipe long output through
headso the command and a sample of its result both stay visible; the demo's auto-pause already scales with line count. - Instant feel — every
qmdccall is ~10–50ms; pre-capture MCP output withmcp_captureso the recording shows the true speed instead of the stdio keep-alive. - Re-render only — after tweaking themes or sizes, run
demo.sh render <name>without re-recording; the.castis the stable intermediate.