Skip to content

Tape Reference

This is the canonical reference for Betamax tape files. Use it with Tape Files, Outputs, and Examples when authoring tapes.

Betamax parses a tape before it starts a shell. Syntax errors, unknown commands, invalid regexes, unknown settings, type mismatches, unsupported output extensions, and startup-command ordering errors fail before the PTY is spawned.

  • A tape is line oriented.
  • Blank lines are ignored.
  • Lines whose trimmed form starts with # are comments.
  • Tokens are parsed with shell-like quoting and escaping through shell_words.
  • One physical line may contain more than one command, such as Type "echo hi" Enter.
  • Startup commands must appear before runtime commands.

Startup commands are Output, Require, Set, and Env. Runtime commands include typing, keys, waits, sleeps, captions, screenshots, state checkpoints, Hide, Show, Copy, and Paste.

CommandBehaviorNotes
Output <path>.gifWrite an animated GIFEncoded in process
Output <path>.pngWrite a final-frame PNGEncoded in process
Output <path>.jsonWrite final terminal stateSee State JSON
Output <path>.mp4Write MP4 videoRequires ffmpeg on PATH
Output <path>.webmWrite WebM videoRequires ffmpeg on PATH
Output <dir>Write numbered PNG frames into a directoryExtensionless path only
Screenshot <path>.pngWrite a checkpoint screenshot at this commandOnly .png is supported
State <path>.jsonWrite checkpoint terminal stateOnly .json is supported

Primary Output paths are grouped by output kind when written, not returned in source order. Checkpoint Screenshot and State commands are side effects at their position in the tape.

Settings use Set <name> <value>. Values are parsed before the setting name is interpreted: percentages become numbers in 0.0..=1.0, then numbers, booleans, durations, and finally strings are attempted in that order. Known settings reject the wrong value kind, so Set Width "wide" is an error rather than a quiet fallback.

SettingValue kindDefaultBehavior
Shellstring$SHELL or shShell command and optional arguments; split with shell-like rules
ThemestringAardvark BlueTheme name loaded from user Ghostty themes or bundled themes
FontFamilystringJetBrains MonoPreferred font family passed to the renderer
FontSizenumber22Font size in pixels
LetterSpacingnumber1Extra pixels between terminal cells
LineHeightnumber1Multiplier applied to the font size
Widthnumber1200Final output width in pixels
Heightnumber600Final output height in pixels
Paddingnumber60Inner padding between the terminal cells and terminal canvas edge
Frameratenumber50Capture cadence in frames per second
TypingSpeedduration50msDelay between characters typed by Type
PlaybackSpeednumber1.0Output playback multiplier; does not speed up command execution
LoopOffsetnumber or percentage0.0Rotates animated output frames to move the loop boundary
CursorBlinkbooltrueSimulates cursor blink in captured frames
KeyboardOverlayenumOffShows recent input chips in media
KeyboardOverlayLocationenumCaptionRowPlaces keyboard overlay chips
WaitTimeoutduration or number15sDefault timeout for wait commands; bare numbers are seconds
WaitPatternregex string>$Regex used by bare Wait
Marginnumber0Outer decoration margin in pixels
MarginFill#rrggbb stringtheme backgroundFill color for the outer margin; invalid colors fall back to theme bg
WindowBarstringempty / disabledNon-empty values draw a synthetic window bar
WindowBarSizenumber30Window bar height in pixels
BorderRadiusnumber0Rounded-corner mask radius in pixels

The terminal grid is derived after all settings are applied. Margin, window-bar decoration, and any presentation row needed for captions or KeyboardOverlayLocation CaptionRow are subtracted from width and height first, then padding, font size, letter spacing, and line height determine the PTY columns and rows. Extremely small dimensions are clamped to at least one row and one column.

Treat larger FontSize, larger Margin, and decorative frame settings as presentation zoom. When the tape is proving modal placement, centered content, wrapping, or split-pane layout, prefer the default FontSize, default Margin, and a wider Width or Height so the proof matches the application layout rather than the demo framing.

Set KeyboardOverlay Input draws compact time-aware input chips on generated PNG, GIF, video, screenshot, and frame-sequence media. Labels appear when input is queued and linger briefly after the input is typed, so review GIFs show the action near the terminal change it caused. The overlay is presentation-only: it does not change PTY input bytes, waits, state JSON, or final output dimensions. KeyboardOverlayLocation CaptionRow reserves a bottom presentation row before deriving the terminal grid so chips do not cover terminal content. Corner locations such as BottomRight draw chips inside the terminal canvas with a small inset from the terminal edge. Presentation overlays use a small optical inset based on half of BorderRadius near rounded terminal corners, so caption and chip edges feel aligned with the rounded frame.

Keyboard overlay modes are:

  • Off: no overlay.
  • Keys: explicit key commands only, such as Ctrl+P, Down, Enter, and Escape.
  • Input: key commands plus short typed input that reads like user intent.
  • All: every visible input event, including long Type commands summarized by character count.

Adds a primary output. Supported extensions are .gif, .png, .json, .mp4, and .webm. An extensionless output path is treated as a directory for numbered PNG frames. Unsupported extensions fail before shell startup.

Fails early if a program is not present on PATH. This is useful for tapes that call optional tools such as git, rg, cargo, or ffmpeg. The check runs before output files are written.

Applies one setting from the table above. Set commands must appear before runtime commands because they affect shell startup, PTY size, capture timing, rendering, or output decoration.

Adds or overrides an environment variable for the spawned shell. Betamax applies its terminal defaults first, then tape Env values, so a tape can intentionally override variables such as TERM, COLORTERM, NO_COLOR, or application-specific flags.

Types text into the PTY one Unicode scalar at a time. Type@25ms "hello" overrides the default typing speed for that command. Use Type for printable text and key commands for terminal control keys such as arrows, tab, delete, and interrupt.

Key commands send terminal key sequences to the PTY. They accept an optional @duration suffix and an optional repeat count:

Enter
Enter@250ms
Down 3
Shift+Tab
Ctrl+C
Alt+F
Ctrl+Alt+Shift+X
F5

Supported named keys are Escape, Backspace, Delete, Insert, Down, Enter, Space, Tab, Left, Right, Up, PageUp, PageDown, Home, End, and F1 through F25. Single-character key tokens are accepted for modified combinations such as Ctrl+C.

Pauses tape execution while continuing to drain PTY output and capture frames. Durations accept compact forms such as 500ms, 1s, and 2m, split forms such as 500 ms, and bare numbers as seconds.

In validation tapes, use sleeps as a last resort for behavior that cannot be matched with a prompt, status line, or visible screen text. In example and review-media tapes, sleeps are presentation pacing after a semantic wait has already proved the screen state.

Waits for terminal text while continuing to drain output and capture frames. A bare Wait checks the current cursor line with WaitPattern, which defaults to the VHS-style prompt regex >$. Wait@5s overrides the timeout for that command.

Waits are assertions and synchronization points. Put Wait, Wait+Line, or Wait+Screen before any sleep that only exists to make a GIF, video, or review artifact readable.

Use /.../ for regex patterns and plain text for substring patterns.

Waits against the current cursor line. This is equivalent to bare Wait with an explicit target, and it is useful when the tape should make the target obvious.

Waits against all visible viewport text. Use this for command output, full-screen TUIs, status lines, or any situation where cursor position should not matter.

Stops appending frames to animated outputs. The PTY still runs, terminal state still updates, waits still work, and checkpoint outputs still see the current terminal. Use this for compilation, setup, or teardown that should not appear in the final GIF/video.

Resumes frame capture and immediately captures the current terminal. This reveals the prepared state without showing the hidden commands that produced it.

Sets a caption rendered onto later visual media frames. The text is one token, so quote captions that contain spaces. Use Caption "" to clear the active caption.

Captions are presentation metadata only. They do not write to the PTY, alter terminal state, affect wait matching, or change final output dimensions. Active captions appear on GIF, PNG, MP4, WebM, frame directory, and Screenshot outputs. State JSON does not include captions. When a tape contains a caption, Betamax reserves a bottom presentation row before deriving the terminal grid so captions do not cover terminal content.

Caption does not capture a frame or add time to animated output by itself. The new caption appears on the next visual frame Betamax renders, such as a frame captured during a later Sleep, Wait, typing, key press, Show, final-frame output, or Screenshot. Add Sleep after a caption-only change when an animation should dwell on the new caption without changing terminal content.

Betamax renders captions below the terminal canvas, left-aligned with the terminal frame edge. Captions are single-line presentation text: if a caption does not fit beside right-aligned keyboard chips, Betamax truncates it with ... instead of wrapping. Caption glyphs are clipped to their reserved width as a final guard for font fallback and unusually wide characters. If the caption or keyboard overlay needs more room, increase the tape height or reduce presentation chrome such as margin and window bar size. Keyboard chips reserve caption space using their visible width, and caption and chip edges are optically inset by half of the rounded-corner radius.

Writes an immediate PNG screenshot using the same theme and frame decoration as primary outputs. Only .png checkpoint screenshots are supported.

Writes an immediate terminal-state snapshot. The state includes viewport text, scrollback text, cursor metadata, a default style, compact style deltas, and styled text spans. See State JSON for the schema and snapshot-testing tradeoffs.

Copy stores text in Betamax’s tape-local clipboard. Paste writes that clipboard into the PTY. This does not touch the host operating system clipboard, which keeps tapes deterministic and safe for CI.

Source is parsed for VHS-language compatibility, but execution is intentionally not implemented. A tape containing Source returns a targeted error instead of silently skipping the include.

Betamax currently exposes these CLI commands:

CommandBehavior
betamax new <path>Write a starter tape with an inline command summary
betamax run <path>Parse, execute, render, and write requested outputs
betamax run -Read a tape from standard input
betamax run -o out.gif demo.tapeAppend one CLI-provided output to the tape
betamax validate <path-or-glob>Parse tapes without starting shells or writing outputs
betamax themesList theme names available to Set Theme
betamax themes --jsonPrint theme names as JSON
betamax themes --markdownPrint theme names as Markdown bullets

publish, record, and serve remain explicit not-implemented commands so users migrating from VHS get a clear error message.