Skip to content

Outputs

A single tape can write several artifacts from the same captured terminal session. This is useful when one run should produce a README GIF, a final-frame PNG for quick inspection, and state JSON for snapshot tests.

See the Tape reference for extension validation and the exact command syntax.

See Generated media storage for guidance on keeping rendered media out of source control and publishing stable documentation assets.

Output Command example Written when Encoder
WebP animation Output demo.webp After the tape finishes In process
WebP screenshot Screenshot checkpoint.webp At that command In process
GIF Output demo.gif After the tape finishes In process
PNG final frame Output demo.png After the tape finishes In process
State JSON Output demo.json After the tape finishes In process
MP4 Output demo.mp4 After the tape finishes ffmpeg
WebM Output demo.webm After the tape finishes ffmpeg
Frame directory Output target/frames After the tape finishes In process PNGs
Screenshot Screenshot checkpoint.png At that command In process
Checkpoint state State checkpoint.json At that command In process

Use GIF for documentation and release notes. Use PNG screenshots when a human needs to review a single stable state. Use state JSON when a test should compare text, scrollback, cursor metadata, and styles without doing pixel comparisons.

Use Presentation overlays when generated visual media should explain a workflow step or review checkpoint without changing terminal behavior. Captions render on visual outputs only; they do not appear in state JSON. Captions share a bottom presentation row with keyboard overlay chips when both are active.

Frame directories are useful when debugging capture timing or feeding rendered frames to custom tooling. The path must not have an extension; Output target/frames writes numbered PNG files under that directory.

Use State checkpoints or final state JSON for automated assertions. Add screenshots to help debug failures.

For review, pair a GIF or video with a screenshot so readers can inspect a frame without pausing the animation. Name the screenshot after the state it shows and capture it after a wait:

Wait+Screen "Profile saved"
State target/snapshots/profile-saved.json
Screenshot target/review/profile-saved.png
Sleep 2s

To give viewers time to read, try 300-700 ms after simple transitions and 1.5-2.5 seconds for a screen of short output. Reserve 4-5 second pauses for the final screen. Allow more time for dense output.

Use Output demo.webp for an infinitely looping lossless animation. Use Screenshot ready.webp for a static image, including at the end of the tape for a final screenshot. CLI betamax run demo.tape --output demo.webp adds an animated output.

WebP uses the original RGBA frames, preserving colors and transparency without GIF palette quantization. It runs entirely in Rust on the supported macOS and Linux platforms; no ffmpeg, cwebp, or system WebP library is needed. The encoder favors straightforward full-frame lossless output over smaller files: it does not use libwebp’s frame-difference optimization or lossy modes.

Captured holds, including the final frame, are stored with millisecond precision. Cumulative boundaries round to the nearest millisecond, with a minimum of 1 ms per frame. Viewers may lengthen very short delays (especially 10 ms or less), so use normal presentation pacing for browser demos. A single-frame animation retains its hold. Dimensions must be 1–16384 pixels on each axis, each frame hold must fit in 16,777,215 ms (about 4.66 hours), and the file must be smaller than 4 GiB.

See examples/webp.tape for animated and static output from the same capture.

Betamax encodes MP4 and WebM with ffmpeg. Terminal execution, terminal parsing, rendering, GIF/WebP encoding, PNG encoding, and state JSON writing are in process. Betamax only requires ffmpeg when the tape requests .mp4 or .webm.

Video uses the original raster frames and their captured hold times, including the final frame. Framerate selects the constant output cadence: transitions and total duration are rounded to the nearest frame interval, with at least one output frame. States shorter than one interval may be omitted. Rates below 1 FPS are clamped to 1 FPS; video rates use three decimal places. GIF uses hundredths of a second for each delay, so its duration can differ slightly from video.

Install it with:

Terminal window
# macOS
brew install ffmpeg
# Debian/Ubuntu
sudo apt-get update
sudo apt-get install ffmpeg

Use Require ffmpeg if the tape should fail before doing any other work:

Output examples/output/demo.mp4
Require ffmpeg

Checkpoint outputs happen in the middle of a run. They are the right tool for tests and for documenting multi-step workflows.

Type "my-app --demo"
Enter
Wait+Screen "Ready"
Screenshot target/snapshots/ready.png
State target/snapshots/ready.json

The Screenshot preserves the decorated visual frame. The State JSON preserves terminal text and styles in a compact comparison format.

Captions annotate rendered media without changing the terminal session. They are useful when a GIF or screenshot needs to explain hidden setup, a review checkpoint, or a step in a TUI flow. See Presentation overlays for keyboard chips and placement tradeoffs. Use waits and state outputs for assertions. Captions only label the recording.

When a tape uses captions, Betamax reserves a bottom presentation row before deriving the terminal grid. Captions render below the terminal canvas instead of covering terminal rows. They are left-aligned with the terminal frame edge and remain single-line; if a caption needs to share space with right-aligned keyboard overlay 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.

Caption "Step 1: prepare the review frame"
Hide
Type "my-app --demo"
Enter
Wait+Screen "Ready"
Show
Sleep 700ms
Caption "Step 2: capture the ready state"
Screenshot target/snapshots/ready.png
State target/snapshots/ready.json
Caption ""
Sleep 300ms

The caption remains active until the next Caption command. Use Caption "" before later frames that should not have an overlay. Quote caption text that contains spaces.

Caption has no duration and does not capture a frame by itself. It changes the caption used by the next rendered visual frame: animation frames captured during later Sleep, Wait, typing, keys, Show, or final-frame output, and checkpoint screenshots captured by Screenshot. If the terminal is already stable and only the caption changed, add Sleep after Caption so GIF and video outputs hold that caption for a visible amount of time.

Captions render on visual outputs: GIF, WebP, PNG, MP4, WebM, frame directories, and screenshots. They do not appear in state JSON or change final output dimensions.