Skip to main content

Keys File Format

Keys files are declarative scripts that define terminal interactions for Betamax. Each file is self-describing and contains all the information needed to reproduce a terminal session.

Betamax keys file workflow

Overview

A keys file consists of:

  • Comments - Lines starting with #
  • Settings directives - Configure terminal dimensions, delays, and dependencies
  • Actions - Control timing, waiting, capturing, and recording
  • Keys - Individual keystrokes to send to the terminal

Each line contains exactly one directive, action, or key. Blank lines are ignored.

Comments and Blank Lines

Comments start with # and continue to the end of the line. Use them to document your keys files:

# This is a comment explaining the next action
@sleep:500

# Navigate through the menu
j
j
Enter

Blank lines are ignored and can be used to organize your file into logical sections.

Settings Directives

Settings at the top of a keys file make it self-describing and reproducible. CLI flags override these values when specified.

DirectiveDescriptionCLI Override
@set:cols:NTerminal width in columns--cols
@set:rows:NTerminal height in rows--rows
@set:delay:MSDefault delay between keys in milliseconds-d, --delay
@set:output:DIROutput directory for captures-o, --output-dir
@set:timeout:SECTimeout for wait operations in seconds-t, --timeout
@set:shell:PATHShell to use for consistent environment--shell
@set:gif_delay:MSFrame duration in GIF playback (default: 200ms)-
@set:speed:NGIF playback speed multiplier, 0.25-4.0 (default: 1.0)-
@set:loop_offset:MSDuplicate first MS of frames at end for seamless looping-
@set:theme:NAMEApply a color theme for decorations (see Theme System)-
@set:window_bar:STYLEAdd macOS-style window bar: colorful, colorful_right, rings, none-
@set:bar_color:RRGGBBWindow bar background color (6 hex digits, no # prefix)-
@set:bar_height:NWindow bar height in pixels (default: 30)-
@set:border_radius:NRounded corner radius in pixels-
@set:margin:NOuter margin in pixels-
@set:margin_color:RRGGBBMargin background color (6 hex digits, no # prefix)-
@set:padding:NInner padding in pixels-
@set:padding_color:RRGGBBPadding background color (6 hex digits, no # prefix)-
@set:shadow:BOOLEnable drop shadow (true or false)-
@set:shadow_blur:NShadow blur radius in pixels (0-100, default: 15)-
@set:shadow_offset_x:NHorizontal shadow offset (-200 to 200, default: 0)-
@set:shadow_offset_y:NVertical shadow offset (-200 to 200, default: 8)-
@set:shadow_opacity:NShadow opacity 0.0-1.0 (default: 0.4)-
@set:shadow_color:RRGGBBShadow color (6 hex digits, default: 000000)-

Note: Color values use 6 hex digits without the # prefix because # starts comments in keys files.

Example Settings Block

@set:cols:120
@set:rows:40
@set:delay:100
@set:output:./screenshots
@set:shell:/bin/bash
@set:gif_delay:150
@set:speed:1.5

# Decoration settings for polished GIFs
@set:window_bar:colorful
@set:bar_color:282a36
@set:border_radius:8
@set:margin:20
@set:margin_color:1a1a2e

# Drop shadow for floating window effect
@set:shadow:true
@set:shadow_blur:20
@set:shadow_offset_y:10
@set:shadow_opacity:0.5

Theme System

Betamax includes 30+ built-in themes for styling GIF decorations. Themes set colors for the window bar, padding, and margin to match popular terminal color schemes.

Using Themes

Apply a theme with @set:theme:NAME:

@set:theme:dracula
@set:window_bar:colorful
@set:padding:10
@set:margin:20
@record:start
# ... recording ...
@record:stop:demo.gif

Available Themes

Dark themes:

  • dracula - Dracula color scheme
  • catppuccin-mocha, catppuccin-macchiato, catppuccin-frappe - Catppuccin variants
  • gruvbox-dark - Gruvbox dark
  • nord - Nord theme
  • tokyo-night, tokyo-night-storm - Tokyo Night variants
  • one-dark - Atom One Dark
  • monokai - Monokai
  • solarized-dark - Solarized Dark
  • github-dark, github-dark-dimmed - GitHub Dark variants
  • ayu-dark, ayu-mirage - Ayu variants
  • rose-pine, rose-pine-moon - Rose Pine variants
  • everforest-dark - Everforest Dark
  • kanagawa - Kanagawa
  • material, material-darker - Material variants
  • night-owl - Night Owl
  • palenight - Material Palenight
  • synthwave-84 - Synthwave '84
  • cyberpunk - Cyberpunk theme

Light themes:

  • catppuccin-latte - Catppuccin Latte
  • gruvbox-light - Gruvbox Light
  • solarized-light - Solarized Light
  • github-light - GitHub Light
  • rose-pine-dawn - Rose Pine Dawn
  • everforest-light - Everforest Light

Theme Precedence

Themes provide default colors that can be overridden:

@set:theme:dracula        # Base colors from Dracula
@set:bar_color:ff0000 # Override just the bar color

Explicit color settings take precedence over theme values.

Note on Terminal Colors

Themes style the decorations (window bar, padding, margin) around your terminal content. The terminal content itself uses colors from termshot's built-in ANSI palette. For the most visually consistent results, use a terminal theme that complements your decoration theme.

Dependency Checking with @require

The @require:CMD directive checks that a command exists in PATH before running the keys file. This allows fast failure with clear error messages.

@require:termshot    # Required for PNG output
@require:aha # Required for HTML output
@require:ffmpeg # Required for GIF recording

If the required command is not found, Betamax exits immediately with an error.

Modular Keys Files with @source

The @source:PATH directive imports keys from another file, enabling reusable setup sequences and modular organization.

# main.keys
@source:common/setup.keys # Import shared setup
@source:themes/dracula.keys # Import decoration settings

@record:start
# ... your recording ...
@record:stop:demo.gif

Path Resolution

Paths are resolved relative to the current file's directory:

project/
├── demos/
│ └── main.keys # @source:../common/setup.keys
├── common/
│ └── setup.keys # Resolves correctly

Features

  • Relative paths: Resolve from the sourcing file's directory
  • Nested imports: Sourced files can themselves use @source
  • Circular detection: Betamax detects and reports circular imports with the full import chain
  • Depth limit: Maximum 10 levels of nesting to prevent runaway imports
  • Settings preservation: @set directives from sourced files are applied

Example: Shared Setup

# common/terminal-setup.keys
@set:cols:80
@set:rows:24
@set:delay:80
@require:termshot
@require:ffmpeg
# demos/vim-demo.keys
@source:../common/terminal-setup.keys
@set:gif_delay:150

@sleep:400
@record:start
i
@frame
# ... rest of recording

Error Handling

Betamax provides clear error messages for common issues:

  • File not found: Shows the full path that couldn't be found
  • Circular import: Shows the complete import chain (A → B → C → A)
  • Typo detection: Suggests @source if you use @import, @include, etc.

Actions

Actions control the flow of execution, timing, and output capture.

ActionDescription
@sleep:MSWait MS milliseconds before continuing
@sleep:MS:captureWait MS milliseconds, capture frames before and after (opt-in for GIF recording)
@wait:PATTERNWait for text pattern to appear in terminal
@wait:/REGEX/Wait for regex pattern to match in terminal
@captureCapture terminal state to stdout
@capture:NAME.pngSave screenshot as PNG (requires termshot)
@capture:NAME.htmlSave as HTML with colors (requires aha)
@capture:NAME.txtSave as plain text with ANSI codes
@capture:NAMESave in all available formats
@record:startStart GIF recording session
@record:pausePause frame capture (session continues), auto-captures on resume
@record:resumeResume frame capture, capturing current state
@hideHide recording - keys execute but frames not captured
@showShow recording - resume capturing frames (no auto-capture)
@frameCapture current state as a GIF frame (during recording)
@record:stop:NAME.gifStop recording and save animated GIF
@repeat:NBegin a loop that repeats N times
@endEnd the current @repeat loop
@pauseWait for Enter key (interactive debugging)

Wait Patterns

Wait for specific text or patterns before continuing:

@wait:Ready           # Wait for literal text "Ready"
@wait:/Loading\.+/ # Wait for regex pattern

Capture Examples

@capture:screenshot.png    # Save PNG only
@capture:output.html # Save HTML only
@capture:terminal.txt # Save text with ANSI codes
@capture:demo # Save demo.png, demo.html, and demo.txt

Loop with @repeat

Use @repeat:N and @end to repeat a sequence of keys and actions:

@repeat:5
j
@frame
@end

This sends j five times, capturing a frame after each press.

Key Syntax

Keys use tmux send-keys format. Most printable characters are sent literally.

Literal Keys

Single characters are sent directly:

a
b
1
2

Special Keys

KeySyntax
EnterEnter
EscapeEscape
TabTab
Shift+TabBTab
SpaceSpace
BackspaceBSpace
DeleteDC
Arrow keysUp, Down, Left, Right
Home / EndHome, End
Page Up / DownPPage, NPage
Function keysF1, F2, ... F12
Ctrl+keyC-c, C-v, C-x
Alt+keyM-x, M-a

Examples

Escape          # Press Escape
C-c # Ctrl+C
M-x # Alt+X
F1 # Function key F1

Per-Key Timing

Override the default delay for individual keys using the @MS suffix:

key@MS

The number after @ specifies milliseconds to wait after sending that key.

Examples

j@50           # Press j, wait 50ms (fast navigation)
j@50
j@50
Enter@1000 # Press Enter, wait 1 second

This is useful for:

  • Rapid navigation - Use short delays like @50 for repeated keys
  • Waiting for responses - Use longer delays like @1000 after actions that take time

Complete Example

Here is a complete keys file demonstrating all features:

# demo-capture.keys
# Captures a screenshot of a TUI application

# Settings - make this file self-describing
@set:cols:120
@set:rows:40
@set:delay:100
@set:output:./screenshots
@set:shell:/bin/bash

# Dependencies - fail fast if missing
@require:termshot

# Wait for application to start
@sleep:500

# Wait for ready indicator
@wait:Ready

# Navigate the menu quickly
j@50
j@50
j@50

# Select item and wait for it to load
Enter@500

# Capture the screenshot
@capture:demo.png

# Exit the application
q
y

GIF Recording Example

# record-typing.keys
# Records an animated GIF of typing in vim

@set:cols:80
@set:rows:24
@set:delay:80
@set:gif_delay:150

@require:termshot
@require:ffmpeg

# Wait for vim to load
@sleep:400

# Start recording
@record:start

# Type "Hello" with frame after each character
i
@frame
H
@frame
e
@frame
l
@frame
l
@frame
o
@frame

# Exit insert mode
Escape
@sleep:300
@frame

# Quit vim
:q!
Enter

# Save the recording
@record:stop:typing-demo.gif

Loop Example

# scroll-demo.keys
# Demonstrates scrolling with @repeat

@set:cols:80
@set:rows:24
@set:delay:100

@sleep:500
@record:start

# Scroll down 10 times
@repeat:10
j
@frame
@end

# Scroll back up 10 times
@repeat:10
k
@frame
@end

@record:stop:scroll-demo.gif

Shadow Example

# shadow-demo.keys
# Creates a polished screenshot with drop shadow

@set:cols:80
@set:rows:20
@set:theme:dracula
@set:window_bar:colorful
@set:border_radius:10
@set:padding:8

# Enable drop shadow
@set:shadow:true
@set:shadow_blur:20
@set:shadow_offset_y:10
@set:shadow_opacity:0.5

@require:termshot

@sleep:300
echo "Hello from betamax!"
@sleep:200
@capture:shadow-demo.png

Shadow works with both PNG screenshots (@capture:NAME.png) and animated GIFs (@record:stop:NAME.gif). The shadow is rendered with full RGBA transparency.