|
| 1 | +--- |
| 2 | +name: vhs |
| 3 | +description: Techniques for creating deterministic terminal demo screencasts with VHS |
| 4 | +--- |
| 5 | + |
| 6 | +# VHS Demo Recording |
| 7 | + |
| 8 | +[VHS](https://github.com/charmbracelet/vhs) records terminal sessions by scripting keystrokes in `.tape` files and rendering them as GIFs. Use `Wait+Screen /regex/` to synchronize with interactive TUI elements instead of fragile fixed `Sleep` durations. VHS can only detect text *appearing* on screen, not disappearing — keep this constraint in mind when designing wait conditions. |
| 9 | + |
| 10 | +## Non-Deterministic TUI Responses |
| 11 | + |
| 12 | +When recording an LLM-powered TUI, detecting when a response is **complete** requires special care. Naive approaches all fail: |
| 13 | + |
| 14 | +| Approach | Why it fails | |
| 15 | +|---|---| |
| 16 | +| Fixed `Sleep` | Not deterministic | |
| 17 | +| Unique marker in prompt (`XYZENDXYZ`) | Appears in the typed prompt on screen — `Wait+Screen` matches immediately | |
| 18 | +| Math formula (`347+829` → wait for `1176`) | LLM computes the answer in its visible *thinking trace* before the response finishes | |
| 19 | +| `Wait+Line /^MARKER$/` | TUI padding/borders prevent exact line matching | |
| 20 | +| `Hide` + type marker | `Hide` only hides VHS command log, not terminal content | |
| 21 | + |
| 22 | +### The concatenation trick |
| 23 | + |
| 24 | +Ask the LLM to **concatenate two words** and print the result. The prompt contains both words *separately* but never the combined string: |
| 25 | + |
| 26 | +```tape |
| 27 | +Type "briefly explain this repo. Then print ALFA concatenated with BRAVO." |
| 28 | +Enter |
| 29 | +Wait+Screen /ALFABRAVO/ |
| 30 | +``` |
| 31 | + |
| 32 | +**Why it works:** |
| 33 | +1. **Typed prompt** shows `...ALFA concatenated with BRAVO` — no `ALFABRAVO` |
| 34 | +2. **Thinking trace** says "I need to concatenate ALFA and BRAVO" — no `ALFABRAVO` |
| 35 | +3. **Response** outputs `ALFABRAVO` — the only match |
| 36 | + |
| 37 | +Use uncommon words (ALFA, BRAVO, ZULU) so the combined form can't appear accidentally. |
| 38 | + |
| 39 | +## Tips |
| 40 | + |
| 41 | +- **Run VHS from the correct CWD** — it inherits the working directory. If the prompt references "this repo", the CWD must be the repo root, not a subdirectory. |
| 42 | +- **Inspect GIF frames** when debugging timing issues: |
| 43 | + ```bash |
| 44 | + ffmpeg -i demo.gif -vf "select='eq(n\,100)'" -vsync vfr /tmp/frame.png |
| 45 | + ``` |
| 46 | + |
| 47 | +## Nix Integration |
| 48 | + |
| 49 | +- If the project uses Nix, create a dedicated `flake.nix` for the demo (e.g., `doc/demo/flake.nix`) so anyone can reproduce the recording with `nix run`. |
| 50 | +- **Reference tape by Nix store path** in flake apps (`vhs "${./.}/demo.tape"`) — don't `cd` into the store, as it may contain a `flake.nix` that confuses `nix run` inside the recording. |
0 commit comments