
Vhs
- 40 installs
- 15 repo stars
- Updated August 1, 2026
- connorads/dotfiles
Provides VHS best practices (47 rules) for writing .tape files that produce professional, optimized terminal GIFs and videos for CLI documentation.
About
Provides Charmbracelet VHS best practices for writing and reviewing .tape files that produce professional terminal GIFs and videos. A developer uses it when creating terminal demos, CLI documentation, or automating GIF generation in CI.
- 47 prioritized rules across 8 categories for writing .tape files
- Covers config structure, dependency management, timing, and output optimization
Vhs by the numbers
- 40 all-time installs (skills.sh)
- Ranked #333 of 550 CLI & Terminal skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/connorads/dotfiles --skill vhsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 40 |
|---|---|
| repo stars | ★ 15 |
| Last updated | August 1, 2026 |
| Repository | connorads/dotfiles ↗ |
What it does
Provides VHS best practices (47 rules) for writing .tape files that produce professional, optimized terminal GIFs and videos for CLI documentation.
Files
Charmbracelet VHS Best Practices
Comprehensive best practices guide for VHS terminal recordings, maintained by Charmbracelet. Contains 47 rules across 8 categories, prioritized by impact to guide creation of professional, portable, and optimized terminal demos.
When to Apply
Reference these guidelines when:
- Writing new VHS tape files
- Creating terminal demos for documentation
- Setting up CI/CD for automated GIF generation
- Optimizing recording file size and quality
- Troubleshooting tape file issues
- Reviewing tape files for best practices
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Configuration Structure | CRITICAL | config- |
| 2 | Dependency Management | CRITICAL | deps- |
| 3 | Command Syntax | HIGH | cmd- |
| 4 | Timing & Synchronization | HIGH | timing- |
| 5 | Output Optimization | MEDIUM-HIGH | output- |
| 6 | Visual Quality | MEDIUM | visual- |
| 7 | CI/Automation | MEDIUM | ci- |
| 8 | Advanced Patterns | LOW | advanced- |
Quick Reference
1. Configuration Structure (CRITICAL)
- `config-settings-order` - Place all settings before commands
- `config-output-first` - Declare output at file start
- `config-shell-explicit` - Explicitly set shell type
- `config-typing-speed-global` - Set global TypingSpeed early
- `config-dimensions-explicit` - Set explicit terminal dimensions
- `config-comments-document` - Use comments to document tape structure
2. Dependency Management (CRITICAL)
- `deps-require-early` - Use Require for dependency validation
- `deps-require-order` - Place Require before settings
- `deps-require-all` - Require all external commands
- `deps-system-requirements` - Verify system dependencies
3. Command Syntax (HIGH)
- `cmd-type-syntax` - Use correct Type command syntax
- `cmd-enter-explicit` - Always follow Type with Enter
- `cmd-key-repeat` - Use key repeat counts
- `cmd-ctrl-combinations` - Use Ctrl combinations for terminal control
- `cmd-hide-show` - Use Hide/Show for sensitive operations
- `cmd-env-variables` - Use Env for environment variables
- `cmd-screenshot` - Use Screenshot for static captures
- `cmd-multiline-type` - Handle multiline commands properly
4. Timing & Synchronization (HIGH)
- `timing-sleep-after-enter` - Add Sleep after commands for output
- `timing-wait-pattern` - Use Wait for dynamic command completion
- `timing-type-speed-override` - Override TypingSpeed for emphasis
- `timing-sleep-units` - Use explicit time units
- `timing-final-sleep` - End recordings with final Sleep
- `timing-natural-pauses` - Add natural pauses between actions
- `timing-wait-timeout` - Set appropriate Wait timeouts
- `timing-playback-speed` - Use PlaybackSpeed for final adjustments
5. Output Optimization (MEDIUM-HIGH)
- `output-format-selection` - Choose output format based on use case
- `output-framerate` - Optimize framerate for file size
- `output-dimensions-optimize` - Right-size terminal dimensions
- `output-loop-offset` - Use LoopOffset for seamless loops
- `output-multiple-formats` - Generate multiple output formats
- `output-relative-paths` - Use relative paths for portability
6. Visual Quality (MEDIUM)
- `visual-font-readable` - Choose readable font settings
- `visual-theme-selection` - Select appropriate theme
- `visual-window-decoration` - Add window decorations for polish
- `visual-spacing` - Adjust letter and line spacing
- `visual-padding-margin` - Use padding and margins effectively
- `visual-cursor-visibility` - Ensure cursor visibility
7. CI/Automation (MEDIUM)
- `ci-github-action` - Use official VHS GitHub Action
- `ci-auto-commit` - Auto-commit generated assets
- `ci-golden-files` - Use golden files for integration testing
- `ci-matrix-builds` - Generate platform-specific demos
- `ci-caching` - Cache VHS dependencies in CI
8. Advanced Patterns (LOW)
- `advanced-source-include` - Use Source for reusable tape components
- `advanced-clipboard` - Use Copy and Paste for complex input
- `advanced-recording-live` - Record live sessions then edit
- `advanced-server-mode` - Use server mode for remote access
How to Use
Read individual reference files for detailed explanations and code examples:
- Section definitions - Category structure and impact levels
- Rule template - Template for adding new rules
Reference Files
| File | Description |
|---|---|
| AGENTS.md | Complete compiled guide with all rules |
| references/_sections.md | Category definitions and ordering |
| assets/templates/_template.md | Template for new rules |
| metadata.json | Version and reference information |
VHS
Version 0.1.0 Charmbracelet January 2026
Note:
This document is mainly for agents and LLMs to follow when maintaining,
generating, or refactoring codebases. Humans may also find it useful,
but guidance here is optimized for automation and consistency by AI-assisted workflows.
---
Abstract
Comprehensive best practices guide for VHS terminal recordings, designed for AI agents and LLMs. Contains 47 rules across 8 categories, prioritized by impact from critical (configuration structure, dependency management) to incremental (advanced patterns). Each rule includes detailed explanations, real-world examples comparing incorrect vs. correct implementations, and specific guidance to create professional, portable, and optimized terminal GIFs and videos.
---
Table of Contents
1. Configuration Structure — CRITICAL
- 1.1 Declare Output at File Start — CRITICAL (prevents missing output files)
- 1.2 Explicitly Set Shell Type — CRITICAL (ensures consistent cross-platform behavior)
- 1.3 Place All Settings Before Commands — CRITICAL (prevents silent setting failures)
- 1.4 Set Explicit Terminal Dimensions — HIGH (prevents content clipping and inconsistent layouts)
- 1.5 Set Global TypingSpeed Early — HIGH (establishes consistent pacing throughout recording)
- 1.6 Use Comments to Document Tape Structure — MEDIUM (improves maintainability and team collaboration)
2. Dependency Management — CRITICAL
- 2.1 Place Require Before Settings — CRITICAL (ensures early failure before any processing)
- 2.2 Require All External Commands — HIGH (documents and validates all dependencies)
- 2.3 Use Require for Dependency Validation — CRITICAL (prevents silent failures from missing programs)
- 2.4 Verify System Dependencies — HIGH (prevents cryptic ffmpeg and ttyd errors)
3. Command Syntax — HIGH
- 3.1 Always Follow Type with Enter — HIGH (ensures commands actually execute)
- 3.2 Handle Multiline Commands Properly — MEDIUM (prevents broken command entry in recordings)
- 3.3 Use Correct Type Command Syntax — HIGH (prevents command parsing failures)
- 3.4 Use Ctrl Combinations for Terminal Control — HIGH (enables proper terminal interaction patterns)
- 3.5 Use Env for Environment Variables — MEDIUM (cleaner than export commands, persists throughout recording)
- 3.6 Use Hide/Show for Sensitive Operations — HIGH (prevents exposing secrets or boring setup in demos)
- 3.7 Use Key Repeat Counts — HIGH (reduces tape file verbosity by 5-10×)
- 3.8 Use Screenshot for Static Captures — MEDIUM (creates PNG snapshots for documentation)
4. Timing & Synchronization — HIGH
- 4.1 Add Natural Pauses Between Actions — MEDIUM (creates human-like interaction flow)
- 4.2 Add Sleep After Commands for Output — HIGH (ensures command output is captured before next action)
- 4.3 End Recordings with Final Sleep — MEDIUM (prevents abrupt GIF endings)
- 4.4 Override TypingSpeed for Emphasis — HIGH (draws attention to important commands)
- 4.5 Set Appropriate Wait Timeouts — MEDIUM (prevents infinite hangs and CI failures)
- 4.6 Use Explicit Time Units — MEDIUM (prevents confusion between seconds and milliseconds)
- 4.7 Use PlaybackSpeed for Final Adjustments — MEDIUM (adjusts recording duration without re-recording)
- 4.8 Use Wait for Dynamic Command Completion — HIGH (eliminates guesswork for variable-duration commands)
5. Output Optimization — MEDIUM-HIGH
- 5.1 Choose Output Format Based on Use Case — MEDIUM-HIGH (10-50× file size difference between formats)
- 5.2 Generate Multiple Output Formats — MEDIUM (single render produces all needed formats)
- 5.3 Optimize Framerate for File Size — MEDIUM-HIGH (2-3× file size reduction with lower framerate)
- 5.4 Right-Size Terminal Dimensions — MEDIUM-HIGH (2-4× file size impact from oversized dimensions)
- 5.5 Use LoopOffset for Seamless Loops — MEDIUM (creates professional-looking continuous playback)
- 5.6 Use Relative Paths for Portability — MEDIUM (ensures tape files work across machines and CI)
6. Visual Quality — MEDIUM
- 6.1 Add Window Decorations for Polish — MEDIUM (creates professional-looking terminal appearance)
- 6.2 Adjust Letter and Line Spacing — LOW-MEDIUM (fine-tunes readability for specific fonts)
- 6.3 Choose Readable Font Settings — MEDIUM (improves accessibility and viewer comprehension)
- 6.4 Ensure Cursor Visibility — LOW-MEDIUM (helps viewers track typing position)
- 6.5 Select Appropriate Theme — MEDIUM (affects brand consistency and readability)
- 6.6 Use Padding and Margins Effectively — LOW-MEDIUM (prevents content from touching edges)
7. CI/Automation — MEDIUM
- 7.1 Auto-Commit Generated Assets — MEDIUM (keeps documentation synchronized automatically)
- 7.2 Cache VHS Dependencies in CI — LOW-MEDIUM (reduces CI run time by 30-60 seconds)
- 7.3 Generate Platform-Specific Demos — LOW-MEDIUM (ensures demos work across different shells)
- 7.4 Use Golden Files for Integration Testing — MEDIUM (detects unintended output changes)
- 7.5 Use Official VHS GitHub Action — MEDIUM (simplifies CI setup and ensures compatibility)
8. Advanced Patterns — LOW
- 8.1 Record Live Sessions Then Edit — LOW (2-5× faster tape creation for complex workflows)
- 8.2 Use Copy and Paste for Complex Input — LOW (simplifies long or complex text entry)
- 8.3 Use Server Mode for Remote Access — LOW (eliminates per-machine VHS installation)
- 8.4 Use Source for Reusable Tape Components — LOW (enables DRY patterns across multiple tapes)
---
References
1. https://github.com/charmbracelet/vhs 2. https://github.com/charmbracelet/vhs/blob/main/README.md 3. https://github.com/charmbracelet/vhs-action 4. https://github.com/charmbracelet/vhs/tree/main/examples
---
Source Files
This document was compiled from individual reference files. For detailed editing or extension:
| File | Description |
|---|---|
| references/_sections.md | Category definitions and impact ordering |
| assets/templates/_template.md | Template for creating new rules |
| SKILL.md | Quick reference entry point |
| metadata.json | Version and reference URLs |
Rule Title Here
{1-3 sentences explaining WHY this matters. Focus on performance or correctness implications.}
Incorrect ({what's wrong}):
{Bad code example - production-realistic, not strawman}
{# Comments explaining the cost}Correct ({what's right}):
{Good code example - minimal diff from incorrect}
{# Comments explaining the benefit}{Optional sections as needed:}
Alternative ({context}):
{Alternative approach when applicable}When NOT to use this pattern:
- {Exception 1}
- {Exception 2}
Benefits:
- {Benefit 1}
- {Benefit 2}
Reference: [{Reference Title}]({Reference URL})
VHS Best Practices Skill
A comprehensive best practices guide for creating terminal recordings with VHS by Charmbracelet.
Overview
VHS is a CLI tool for recording terminal sessions as GIFs, MP4s, or WebM videos using declarative tape files. This skill provides 47 rules across 8 categories to help you create polished, optimized, and portable terminal demos.
Getting Started
# Install VHS (macOS)
brew install vhs
# Install VHS (Go)
go install github.com/charmbracelet/vhs@latest
# Validate skill structure
pnpm install
pnpm build
pnpm validateCategories
| Priority | Category | Rules | Focus |
|---|---|---|---|
| 1 | Configuration | 6 | Settings order, shell, dimensions |
| 2 | Dependencies | 4 | Require validation, system deps |
| 3 | Commands | 8 | Type syntax, keys, Hide/Show |
| 4 | Timing | 8 | Sleep, Wait, pacing |
| 5 | Output | 6 | Format, framerate, optimization |
| 6 | Visual | 6 | Fonts, themes, decorations |
| 7 | CI | 5 | GitHub Actions, automation |
| 8 | Advanced | 4 | Source, clipboard, server |
Creating a New Rule
1. Choose the appropriate category based on the rule's focus 2. Create a new file in references/ with the category prefix 3. Follow the template in assets/templates/_template.md 4. Run validation to check formatting
Rule File Structure
Each rule file follows this structure:
---
title: Rule Title
impact: CRITICAL|HIGH|MEDIUM-HIGH|MEDIUM|LOW-MEDIUM|LOW
impactDescription: quantified impact
tags: category-prefix, related-tags
---
## Rule Title
Explanation of why this matters.
**Incorrect (what's wrong):**
\`\`\`tape
bad example
\`\`\`
**Correct (what's right):**
\`\`\`tape
good example
\`\`\`File Naming Convention
Rule files follow the pattern: {category-prefix}-{descriptive-slug}.md
Examples:
config-settings-order.mdtiming-sleep-after-enter.mdoutput-format-selection.md
Impact Levels
| Level | Description |
|---|---|
| CRITICAL | Causes failures or silent bugs if ignored |
| HIGH | Significant quality or reliability impact |
| MEDIUM-HIGH | Notable improvement in output quality |
| MEDIUM | Recommended for polish and maintainability |
| LOW-MEDIUM | Minor improvements, nice to have |
| LOW | Advanced patterns for specific use cases |
Scripts
# Build AGENTS.md from references
node scripts/build-agents-md.js .
# Validate skill structure and rules
node scripts/validate-skill.js .Contributing
1. Read existing rules to understand the style 2. Create a new rule following the template 3. Run validation before submitting 4. Ensure examples are realistic and minimal
References
Version
- Skill Version: 0.1.0
- Last Updated: January 2026
Sections
This file defines all sections, their ordering, impact levels, and descriptions. The section ID (in parentheses) is the filename prefix used to group rules.
---
1. Configuration Structure (config)
Impact: CRITICAL Description: Settings order and structure fundamentally determine tape behavior; misplaced settings are silently ignored, causing recordings to fail without warning.
2. Dependency Management (deps)
Impact: CRITICAL Description: Missing dependencies cause silent failures or incorrect output that wastes entire recording cycles; early validation prevents costly reruns.
3. Command Syntax (cmd)
Impact: HIGH Description: Correct command usage prevents recording failures and produces intended terminal interactions; syntax errors halt execution entirely.
4. Timing & Synchronization (timing)
Impact: HIGH Description: Proper timing prevents race conditions, ensures readable output, and creates professional-looking recordings that viewers can follow.
5. Output Optimization (output)
Impact: MEDIUM-HIGH Description: File size, format selection, and quality settings directly impact deliverable usability; wrong choices result in bloated or unusable files.
6. Visual Quality (visual)
Impact: MEDIUM Description: Font, theme, and dimension settings affect readability and professional appearance; poor choices reduce demo effectiveness.
7. CI/Automation (ci)
Impact: MEDIUM Description: Proper CI setup enables automated testing and keeps demos synchronized with code; manual updates become unsustainable at scale.
8. Advanced Patterns (advanced)
Impact: LOW Description: Source inclusion, clipboard operations, and server mode enable complex workflows for power users with specific requirements.
Use Copy and Paste for Complex Input
Use Copy and Paste commands to handle long URLs, complex commands, or text that would be tedious to type character by character.
Incorrect (typing long URLs):
Type "git clone https://github.com/charmbracelet/very-long-repository-name.git"
Enter
# Slow typing for a URL viewers don't need to read character-by-characterCorrect (copy/paste for long text):
Copy "https://github.com/charmbracelet/very-long-repository-name.git"
Type "git clone "
Paste
EnterDemonstrating clipboard workflows:
# Show copying from command output
Type "mycli generate-token"
Enter
Sleep 1s
# Simulating copy from output
Copy "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Type "curl -H 'Authorization: Bearer "
Paste
Type "' https://api.example.com"
EnterWhen to use:
- Long URLs (> 50 characters)
- API keys or tokens
- Complex JSON or configuration strings
- Demonstrating paste workflows
Reference: VHS README - Clipboard
Record Live Sessions Then Edit
Use vhs record to capture a live terminal session, then edit the generated tape file to perfect timing and remove mistakes. This is faster than writing tape files from scratch for complex workflows.
Incorrect (writing from scratch):
# Manually writing every command and timing
Output demo.gif
Set Shell "bash"
Type "cd myproject"
Enter
Sleep 500ms
Type "ls -la"
Enter
Sleep 1s
# Tedious for complex multi-step workflows
# Hard to get natural timing rightCorrect (record then polish):
# Step 1: Record live session
vhs record > draft.tape
# Step 2: Edit the generated tape
vim draft.tape# draft.tape after editing
Output demo.gif
Set Shell "bash"
Set FontSize 32
Type "cd myproject"
Enter
Sleep 500ms
Type "ls -la"
Enter
Sleep 1s
Type "npm start"
Enter
Sleep 3sBenefits:
- Natural command flow from real interaction
- Captures realistic timing baseline
- Edit out mistakes and dead time
- Add proper settings and output declarations
Reference: VHS README - Recording
Use Server Mode for Remote Access
VHS has a built-in SSH server that allows remote tape execution. This is useful for teams where not everyone has VHS installed locally, or for running VHS on a dedicated build server.
Incorrect (local installation required):
# Every team member must install VHS
brew install vhs
brew install ffmpeg ttyd
# Each machine may have different versions
vhs --version # v0.7.0 on one machine
vhs --version # v0.6.0 on another
# Inconsistent output between machines
vhs demo.tapeCorrect (centralized server):
# Server setup (once)
vhs serve
# Any team member can generate demos
ssh -p 1976 vhs.internal.example.com < demo.tape
# Consistent environment and versions
# No local installation neededServer configuration:
# Environment variables
VHS_PORT=1976 # SSH port (default: 1976)
VHS_HOST=0.0.0.0 # Bind address
VHS_KEY_PATH=~/.ssh/key # Host key path
VHS_AUTHORIZED_KEYS_PATH=~/.ssh/authorized_keysWhen to use server mode:
- Centralized demo generation for teams
- Team members without VHS installed
- Consistent rendering environment
- Dedicated build servers with dependencies
Reference: VHS README - SSH Server
Use Source for Reusable Tape Components
Use the Source command to include commands from another tape file. This enables reusable setup sequences, consistent styling, and modular tape organization.
Incorrect (duplicating setup across tapes):
# demo1.tape
Output demo1.gif
Set Shell "bash"
Set FontSize 32
Set Width 1200
Set Height 600
Set Theme "Catppuccin Mocha"
Require mycli
Type "mycli feature1"
Enter# demo2.tape (duplicated settings)
Output demo2.gif
Set Shell "bash"
Set FontSize 32
Set Width 1200
Set Height 600
Set Theme "Catppuccin Mocha"
Require mycli
Type "mycli feature2"
EnterCorrect (shared configuration):
# _common.tape (shared settings, no Output)
Set Shell "bash"
Set FontSize 32
Set Width 1200
Set Height 600
Set Theme "Catppuccin Mocha"
Set TypingSpeed 50ms
Require mycli# demo1.tape
Output demo1.gif
Source _common.tape
Type "mycli feature1"
Enter
Sleep 3s# demo2.tape
Output demo2.gif
Source _common.tape
Type "mycli feature2"
Enter
Sleep 3sUse cases:
- Shared visual styling across all project demos
- Common setup sequences (cd, source .env, etc.)
- Reusable demonstration patterns
Reference: VHS README - Source
Auto-Commit Generated Assets
Configure your workflow to automatically commit generated GIFs back to the repository. This keeps demos synchronized with code changes without manual intervention.
Incorrect (manual GIF updates):
# Generate but don't commit—requires manual download and commit
- uses: charmbracelet/vhs-action@v2
with:
path: demo.tapeCorrect (auto-commit generated files):
name: Generate Demo GIF
on:
push:
paths:
- 'src/**'
- 'demo.tape'
jobs:
demo:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: charmbracelet/vhs-action@v2
with:
path: demo.tape
- name: Commit generated GIF
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "chore: update demo GIF"
file_pattern: "*.gif *.mp4 *.webm"Trigger on relevant changes only:
on:
push:
paths:
- 'src/**' # Source code changes
- 'demo.tape' # Tape file changes
- '.github/workflows/demo.yml'Reference: VHS GitHub Action
Cache VHS Dependencies in CI
When not using the official action, cache VHS and its dependencies to speed up CI runs. The official action handles this automatically.
Incorrect (downloading every run):
steps:
- name: Install VHS
run: |
go install github.com/charmbracelet/vhs@latest
# Downloads Go and VHS every runCorrect (with caching):
steps:
- uses: actions/setup-go@v5
with:
go-version: '1.21'
cache: true
- name: Cache VHS binary
uses: actions/cache@v4
with:
path: ~/go/bin/vhs
key: vhs-${{ runner.os }}-${{ hashFiles('.vhs-version') }}
- name: Install VHS
run: |
if [ ! -f ~/go/bin/vhs ]; then
go install github.com/charmbracelet/vhs@latest
fiBetter approach—use official action:
# The official action handles caching automatically
- uses: charmbracelet/vhs-action@v2
with:
path: demo.tapeReference: VHS GitHub Action
Use Official VHS GitHub Action
Use the official charmbracelet/vhs-action for GitHub Actions instead of manually installing VHS. The action handles dependencies, caching, and updates automatically.
Incorrect (manual installation):
# .github/workflows/demo.yml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y ffmpeg
go install github.com/charmbracelet/vhs@latest
- name: Generate demo
run: vhs demo.tape
# Complex, error-prone, slowCorrect (using official action):
# .github/workflows/demo.yml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: charmbracelet/vhs-action@v2
with:
path: demo.tapeWith additional options:
- uses: charmbracelet/vhs-action@v2
with:
path: demo.tape
version: latest
install-fonts: true # Adds extra font supportReference: VHS GitHub Action
Use Golden Files for Integration Testing
Use VHS's .txt or .ascii output format to generate golden files for integration testing. Store these in version control to detect unintended changes in CLI output.
Incorrect (only generating GIFs):
Output demo.gif
# No way to detect if output content changedCorrect (golden file for testing):
Output demo.gif
Output demo.txt # Text output for comparison
Type "mycli --version"
Enter
Sleep 1s
Type "mycli help"
Enter
Sleep 2sCI workflow with golden file comparison:
name: Test CLI Output
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: charmbracelet/vhs-action@v2
with:
path: test.tape
- name: Compare golden file
run: |
diff -u expected/demo.txt demo.txt
# Fails if output differs from expectedUpdate golden files intentionally:
# After intentional changes, update golden files
vhs test.tape
cp demo.txt expected/demo.txt
git add expected/demo.txt
git commit -m "update: golden file for new output format"Reference: VHS README
Generate Platform-Specific Demos
Use CI matrix builds to generate demos for different shells or platforms when your CLI behaves differently across environments.
Incorrect (single shell assumption):
- uses: charmbracelet/vhs-action@v2
with:
path: demo.tape
# Only generates for default shellCorrect (matrix for multiple shells):
name: Generate Shell-Specific Demos
jobs:
demo:
runs-on: ubuntu-latest
strategy:
matrix:
shell: [bash, zsh, fish]
steps:
- uses: actions/checkout@v4
- name: Install shell
run: sudo apt-get install -y ${{ matrix.shell }}
- name: Create shell-specific tape
run: |
sed "s/Set Shell.*/Set Shell \"${{ matrix.shell }}\"/" \
demo.tape > demo-${{ matrix.shell }}.tape
- uses: charmbracelet/vhs-action@v2
with:
path: demo-${{ matrix.shell }}.tape
- name: Rename output
run: mv demo.gif demo-${{ matrix.shell }}.gifWhen to use platform-specific demos:
- Shell-specific syntax highlighting
- Different command availability
- Platform-specific paths or behaviors
Reference: VHS GitHub Action
Use Ctrl Combinations for Terminal Control
VHS supports Ctrl+<key> combinations for terminal control sequences. Use these for interrupting processes, clearing screens, and navigating within terminal applications.
Incorrect (trying to type control characters):
Type "^C" # Types literal ^C, doesn't send interrupt
Type "^L" # Types literal ^L, doesn't clear screenCorrect (using Ctrl combinations):
# Start a long-running process
Type "sleep 100"
Enter
Sleep 1s
# Interrupt it
Ctrl+C
# Clear the screen
Ctrl+L
# Common Ctrl combinations
Ctrl+A # Move to beginning of line
Ctrl+E # Move to end of line
Ctrl+K # Kill to end of line
Ctrl+U # Kill to beginning of line
Ctrl+W # Delete word backward
Ctrl+R # Reverse search history
Ctrl+D # EOF/Exit
Ctrl+Z # Suspend processWith modifiers:
Ctrl+Alt+Delete # Multiple modifiers
Ctrl+Shift+T # Common terminal shortcutsReference: VHS README - Keys
Always Follow Type with Enter
After typing a command, you must explicitly use Enter to execute it. Type only simulates keystrokes—it does not press Enter automatically. Forgetting Enter leaves commands sitting at the prompt without execution.
Incorrect (missing Enter):
Type "echo hello"
Sleep 2s
Type "echo world"
Sleep 2s
# Neither command executes—both just sit at the promptCorrect (explicit Enter after each command):
Type "echo hello"
Enter
Sleep 1s
Type "echo world"
Enter
Sleep 1sWhen typing partial content (no Enter needed):
# Interactive typing demonstration
Type "git com"
Sleep 500ms
Tab # Autocomplete
Type "it -m "
Sleep 500ms
Type "'Initial commit'"
EnterReference: VHS README - Type
Use Env for Environment Variables
Use the Env command to set environment variables instead of typing export commands. Env sets variables before the shell starts, making them available immediately and keeping your tape cleaner.
Incorrect (typing export commands):
Type "export NODE_ENV=production"
Enter
Type "export DEBUG=true"
Enter
Type "npm start"
Enter
# Clutters recording with setup commandsCorrect (using Env command):
Env NODE_ENV production
Env DEBUG true
Type "npm start"
Enter
# Variables are set, recording focuses on the demoComplex values with spaces:
Env GREETING "Hello World"
Env PATH "/custom/bin:$PATH"
Type "echo $GREETING"
EnterWhen NOT to use this pattern:
- When demonstrating how to set environment variables
- When the export itself is part of the tutorial
Reference: VHS README - Env
Use Hide/Show for Sensitive Operations
Use Hide to stop capturing frames and Show to resume. This is essential for hiding sensitive information like passwords, API keys, or lengthy setup commands that would bore viewers.
Incorrect (sensitive data in recording):
Output demo.gif
Type "export API_KEY=sk-1234567890abcdef"
Enter
Type "mycli auth"
Enter
# API key is now visible in your GIF!Correct (hide sensitive operations):
Output demo.gif
Hide
Type "export API_KEY=$REAL_API_KEY"
Enter
Show
Type "mycli auth"
Enter
Sleep 2s
# Key is set but not visible in recordingHide boring setup:
Output demo.gif
Hide
# Setup that viewers don't need to see
Type "cd ~/projects/demo"
Enter
Type "source .env"
Enter
Type "clear"
Enter
Show
# Now show the interesting part
Type "mycli demo"
EnterReference: VHS README - Display
Use Key Repeat Counts
Navigation and editing keys accept an optional repeat count. Use this instead of repeating the same key command multiple times, which bloats tape files and increases maintenance burden.
Incorrect (repeated key commands):
Type "some long command here"
Enter
# Go back to edit
Up
Left
Left
Left
Left
Left
Backspace
Backspace
Backspace
Type "new"
EnterCorrect (using repeat counts):
Type "some long command here"
Enter
# Go back to edit
Up
Left 5
Backspace 3
Type "new"
EnterKeys supporting repeat counts:
- Arrow keys:
Left 10,Right 5,Up 3,Down 2 - Editing:
Backspace 5,Delete 3 - Navigation:
Tab 2,Space 4 - Special:
Enter 2,Escape 2
Reference: VHS README - Keys
Handle Multiline Commands Properly
For multiline commands, use the shell's line continuation character (\) followed by Enter, then continue typing. Don't try to include newlines directly in the Type string.
Incorrect (newline in Type string):
Type "docker run -d \
-p 8080:80 \
nginx"
Enter
# Parsing error or unexpected behaviorCorrect (explicit line continuation):
Type "docker run -d \"
Enter
Type " -p 8080:80 \"
Enter
Type " -v ./html:/usr/share/nginx/html \"
Enter
Type " nginx:latest"
EnterAlternative (single long line):
Type "docker run -d -p 8080:80 -v ./html:/usr/share/nginx/html nginx:latest"
Enter
# Works but may be hard to read if terminal is narrowFor heredocs:
Type "cat << 'EOF'"
Enter
Type "line 1"
Enter
Type "line 2"
Enter
Type "EOF"
EnterReference: VHS README - Type
Use Screenshot for Static Captures
Use Screenshot to capture the current terminal state as a PNG image. This is useful for documentation, README files, or when a static image is more appropriate than an animated GIF.
Incorrect (using GIF for static content):
Output static-example.gif
Type "mycli --help"
Enter
Sleep 5s
# Creates a 5-second GIF of static contentCorrect (screenshot for static content):
Output demo.gif
Type "mycli --help"
Enter
Sleep 1s
Screenshot help-output.png
Type "mycli version"
Enter
Sleep 1s
Screenshot version-output.pngScreenshot for key moments:
Output tutorial.gif
Type "npm run build"
Enter
Sleep 5s
Screenshot build-success.png # Capture successful build
Type "npm test"
Enter
Sleep 3s
Screenshot test-results.png # Capture test outputReference: VHS README - Screenshot
Use Correct Type Command Syntax
The Type command requires the text to be enclosed in double quotes. Missing or mismatched quotes cause parsing errors that halt tape execution entirely.
Incorrect (missing quotes):
Type echo hello
# Error: parsing tape file
Type 'echo hello'
# Error: single quotes not supportedCorrect (double quotes):
Type "echo hello"
Enter
Type "echo 'single quotes inside are fine'"
Enter
Type "echo \"escaped double quotes\""
EnterFor special characters:
# Backticks
Type "echo \`date\`"
Enter
# Dollar signs (literal)
Type "echo \$HOME"
Enter
# Dollar signs (expanded in shell)
Type "echo $HOME"
EnterReference: VHS README - Type
Use Comments to Document Tape Structure
Add comments using # to document the purpose of tape sections, explain timing choices, and note any non-obvious behavior. Comments are stripped from output and help future maintainers understand your intent.
Incorrect (no documentation):
Output demo.gif
Set Shell "bash"
Set FontSize 32
Set Width 1200
Set Height 600
Type "npm install"
Enter
Sleep 5s
Type "npm run build"
Enter
Sleep 10sCorrect (documented structure):
# Demo: npm project build workflow
# Author: Team Name
# Last updated: 2026-01
Output demo.gif
# Terminal configuration
Set Shell "bash"
Set FontSize 32
Set Width 1200
Set Height 600
# Install dependencies (wait for completion)
Type "npm install"
Enter
Sleep 5s # npm install typically takes 3-5s on this project
# Run build process
Type "npm run build"
Enter
Sleep 10s # Build takes ~8s, adding buffer for CI varianceReference: VHS README
Set Explicit Terminal Dimensions
Always specify Width and Height to ensure your content fits properly and renders consistently. Default dimensions may clip long commands or output, and vary across VHS versions.
Incorrect (relying on defaults):
Output demo.gif
Type "ls -la /usr/local/bin | head -20"
Enter
# Content may be clipped if default width is too narrowCorrect (explicit dimensions for content):
Output demo.gif
Set Width 1200
Set Height 600
Type "ls -la /usr/local/bin | head -20"
EnterRecommended dimensions:
- Documentation/README: 1200×600 (wide, compact height)
- Full terminal demos: 1200×800 (standard aspect ratio)
- Social media: 800×600 (square-ish for previews)
- Minimal examples: 800×400 (compact)
Reference: VHS README - Settings
Declare Output at File Start
Declare Output commands at the top of your tape file to clearly indicate what files will be generated. While VHS defaults to out.gif, explicit output declarations prevent confusion and ensure outputs are written to expected locations.
Incorrect (relying on defaults):
Set FontSize 32
Type "echo hello"
Enter
Sleep 2s
# Where does the output go? Defaults to out.gif in current directoryCorrect (explicit output declaration):
Output demo.gif
Output demo.mp4
Set FontSize 32
Type "echo hello"
Enter
Sleep 2sWhen NOT to use this pattern:
- Quick local testing where default
out.gifis acceptable
Reference: VHS README - Output
Place All Settings Before Commands
VHS requires all Set commands (except TypingSpeed) to appear before any non-setting or non-output commands. Settings placed after commands are silently ignored, causing recordings to use default values without warning.
Incorrect (settings after commands are ignored):
Output demo.gif
Type "echo hello"
Enter
Set FontSize 32
Set Theme "Catppuccin Mocha"
# These settings are silently ignored!Correct (all settings before commands):
Output demo.gif
Set FontSize 32
Set Theme "Catppuccin Mocha"
Set Width 1200
Set Height 600
Type "echo hello"
EnterReference: VHS README - Settings
Explicitly Set Shell Type
Always specify the shell explicitly with Set Shell to ensure consistent behavior across different machines and CI environments. Without this, VHS uses the system default shell, which varies between macOS (zsh), Linux (bash), and user configurations.
Incorrect (relies on system default):
Output demo.gif
Set FontSize 32
Type "echo $SHELL"
Enter
# Output varies: /bin/zsh, /bin/bash, /usr/bin/fish...Correct (explicit shell declaration):
Output demo.gif
Set Shell "bash"
Set FontSize 32
Type "echo $SHELL"
Enter
# Always outputs /bin/bashBenefits:
- Reproducible recordings across team members
- Consistent CI/CD behavior
- Predictable prompt and syntax highlighting
Reference: VHS README - Settings
Set Global TypingSpeed Early
Set a global TypingSpeed near the top of your tape file to establish consistent pacing. Unlike other settings, TypingSpeed can be changed mid-file, but setting a sensible default prevents inconsistent typing speeds throughout your demo.
Incorrect (no global default, inconsistent pacing):
Output demo.gif
Type "echo 'fast'"
Enter
Type "echo 'also fast at default 50ms'"
EnterCorrect (global default with intentional overrides):
Output demo.gif
Set TypingSpeed 75ms
Type "echo 'normal speed'"
Enter
Type@200ms "echo 'deliberately slow for emphasis'"
Enter
Type "echo 'back to normal'"
EnterRecommended speeds:
- 25-50ms: Fast, for experienced users or long commands
- 50-100ms: Normal, readable for most viewers
- 100-200ms: Slow, for emphasis or tutorials
Reference: VHS README - Typing Speed
Require All External Commands
Add a Require statement for every external command used in your tape file, not just the primary tool being demonstrated. This serves as documentation and ensures portability across different systems.
Incorrect (only requiring main tool):
Require mycli
Output demo.gif
Set Shell "bash"
Type "mycli init"
Enter
Sleep 2s
Type "jq '.name' package.json"
Enter
Sleep 1s
Type "bat config.yaml"
Enter
# jq and bat might not be installed!Correct (requiring all external commands):
Require mycli
Require jq
Require bat
Output demo.gif
Set Shell "bash"
Type "mycli init"
Enter
Sleep 2s
Type "jq '.name' package.json"
Enter
Sleep 1s
Type "bat config.yaml"
EnterWhen NOT to use this pattern:
- Standard shell built-ins (echo, cd, pwd, export)
- Commands guaranteed by the specified shell
Reference: VHS README - Require
Use Require for Dependency Validation
Use Require commands to validate that all necessary programs are available before execution. Without Require, missing programs cause "command not found" errors to appear in your recording, wasting the entire render cycle.
Incorrect (no dependency validation):
Output demo.gif
Set Shell "bash"
Type "glow README.md"
Enter
Sleep 2s
# If glow isn't installed: "bash: glow: command not found" in your GIFCorrect (fail-fast with Require):
Output demo.gif
Require glow
Set Shell "bash"
Type "glow README.md"
Enter
Sleep 2s
# VHS fails immediately if glow is missing, before renderingBenefits:
- Fails immediately with clear error message
- Saves render time on missing dependencies
- Documents tape file requirements explicitly
Reference: VHS README - Require
Place Require Before Settings
Place all Require commands at the very top of your tape file, before settings and output declarations. This ensures VHS fails as early as possible if dependencies are missing, before spending time on configuration.
Incorrect (Require after settings):
Output demo.gif
Set Shell "bash"
Set FontSize 32
Set Width 1200
Set Height 600
Set Theme "Catppuccin Mocha"
Require glow
Require bat
# VHS already processed settings before failingCorrect (Require first):
# Dependencies
Require glow
Require bat
# Output
Output demo.gif
# Settings
Set Shell "bash"
Set FontSize 32
Set Width 1200
Set Height 600
Set Theme "Catppuccin Mocha"Reference: VHS README - Require
Verify System Dependencies
VHS requires ttyd and ffmpeg to be installed and available on $PATH. Missing these causes cryptic errors during rendering. Document these requirements and verify them before running tape files.
Incorrect (assuming dependencies exist):
Output demo.gif
Set Shell "bash"
Type "echo hello"
Enter
# Error: ttyd not found in PATH
# Error: ffmpeg: command not foundCorrect (verify before running):
# Check system dependencies before running VHS
which ttyd ffmpeg
# Install if missing (macOS)
brew install ttyd ffmpeg
# Install if missing (Ubuntu/Debian)
sudo apt install ttyd ffmpeg
# Then run your tape
vhs demo.tapeCI/CD verification:
# GitHub Actions example
- name: Install VHS dependencies
run: |
sudo apt-get update
sudo apt-get install -y ffmpeg
# ttyd is installed by vhs-action
- uses: charmbracelet/vhs-action@v2
with:
path: demo.tapeReference: VHS README - Installation
Right-Size Terminal Dimensions
Set terminal dimensions appropriate for your content. Oversized terminals waste pixels on empty space, dramatically increasing file size. Undersized terminals clip content.
Incorrect (oversized for content):
Output demo.gif
Set Width 1920
Set Height 1080
Type "echo hello"
Enter
Sleep 2s
# Massive GIF with 90% empty spaceCorrect (sized to content):
Output demo.gif
Set Width 800
Set Height 400
Type "echo hello"
Enter
Sleep 2s
# Compact GIF, fast to loadDimension guidelines by content:
| Content Type | Width | Height |
|---|---|---|
| Simple command | 600-800 | 300-400 |
| README demo | 1000-1200 | 500-600 |
| Full terminal | 1200-1400 | 700-800 |
| Wide output (logs) | 1400-1600 | 600-700 |
Test your dimensions:
Output test.gif
Set Width 1000
Set Height 500
# Run your longest command
Type "your-command --with --many --flags"
Enter
# Verify nothing is clippedReference: VHS README - Settings
Choose Output Format Based on Use Case
Select the appropriate output format based on where your recording will be used. GIF is universally compatible but large; MP4/WebM offer better compression but limited platform support.
Incorrect (always using GIF):
Output documentation-demo.gif # 15MB GIF for a 30-second demoCorrect (format matched to platform):
# For GitHub README (GIF required, auto-plays)
Output demo.gif
# For documentation sites (modern formats supported)
Output demo.webm
Output demo.mp4
# For generating multiple formats simultaneously
Output demo.gif
Output demo.mp4
Output demo.webmFormat comparison:
| Format | Size | Compatibility | Best For |
|---|---|---|---|
| GIF | Large (10-50MB) | Universal | README, GitHub |
| MP4 | Small (1-5MB) | Most browsers | Documentation |
| WebM | Smallest (0.5-3MB) | Modern browsers | Web apps |
| PNG frames | Variable | Processing | Post-processing |
Generate multiple formats:
Output demo.gif # For GitHub
Output demo.mp4 # For docs
Output demo.webm # For web
Output frames/ # For custom processingReference: VHS README - Output
Optimize Framerate for File Size
Reduce framerate to significantly decrease file size without noticeably affecting quality for terminal recordings. Terminal content changes slowly compared to video, so high framerates are unnecessary.
Incorrect (default high framerate):
Output demo.gif
# Default framerate creates unnecessarily large filesCorrect (optimized framerate):
Output demo.gif
Set Framerate 15 # Half the frames, significantly smaller file
Type "npm install"
Enter
Sleep 5sFramerate guidelines:
- 30 fps: High quality, large files (rarely needed)
- 20 fps: Good quality, moderate files
- 15 fps: Recommended for most demos
- 10 fps: Small files, slight choppiness on fast typing
When to use higher framerates:
- Animations or spinners that update rapidly
- Smooth cursor movement demos
- High-polish marketing materials
Reference: VHS README - Settings
Use LoopOffset for Seamless Loops
Set LoopOffset to start the GIF loop from a point other than the beginning. This creates smoother loops by starting from a stable state rather than an empty terminal.
Incorrect (jarring loop restart):
Output demo.gif
Type "mycli demo"
Enter
Sleep 5s
# Loop restarts from empty prompt—jarring transitionCorrect (smooth loop with offset):
Output demo.gif
Set LoopOffset 75% # Loop starts at 75% through
Type "mycli demo"
Enter
Sleep 5s
# Loop starts from near the end, showing output briefly before restartLoopOffset strategies:
0%: Start from beginning (default)50%: Start from middle (good for short demos)75-90%: Start near end (shows result, then loops)100%: Effectively shows last frame only
For continuous-looking demos:
Set LoopOffset 80%
Type "watch -n1 date"
Enter
Sleep 10s
Ctrl+C
# Loops smoothly, always shows date updatingReference: VHS README - Settings
Generate Multiple Output Formats
Specify multiple Output commands to generate several formats in a single render pass. This is more efficient than running VHS multiple times and ensures all outputs are identical.
Incorrect (separate renders for each format):
# Running VHS multiple times
vhs demo-gif.tape # Contains: Output demo.gif
vhs demo-mp4.tape # Contains: Output demo.mp4
vhs demo-webm.tape # Contains: Output demo.webm
# Inefficient, may produce inconsistent resultsCorrect (single tape, multiple outputs):
# Generate all formats in one pass
Output demo.gif
Output demo.mp4
Output demo.webm
Output frames/ # PNG sequence for custom processing
Set Shell "bash"
Set FontSize 32
Set Width 1200
Set Height 600
Type "mycli demo"
Enter
Sleep 5sOrganize outputs by directory:
Output assets/gifs/demo.gif
Output assets/videos/demo.mp4
Output assets/videos/demo.webmReference: VHS README - Output
Use Relative Paths for Portability
Use relative paths in Output commands to ensure tape files work on any machine. Output paths are relative to the current working directory when VHS runs, not the tape file location.
Incorrect (absolute paths):
Output /Users/developer/projects/myapp/docs/demo.gif
# Fails on other machines or CIIncorrect (assuming tape file directory):
# In ./docs/demo.tape
Output demo.gif
# Outputs to CWD, not ./docs/Correct (relative paths from CWD):
Output docs/demo.gif
Output assets/demo.mp4Run from project root:
# From project root
vhs docs/demo.tape
# Output: ./docs/demo.gif (relative to CWD)For CI consistency:
# GitHub Actions
- name: Generate demo
working-directory: ${{ github.workspace }}
run: vhs docs/demo.tape
# Outputs relative to workspace rootReference: VHS Issues - Output Paths
End Recordings with Final Sleep
Always end your tape file with a Sleep command to give viewers time to see the final output before the GIF loops. Recordings that end immediately after the last command feel abrupt and unprofessional.
Incorrect (abrupt ending):
Type "mycli demo"
Enter
# GIF ends immediately, loops back before viewer processes outputCorrect (pause before loop):
Type "mycli demo"
Enter
Sleep 3s # Give viewers time to read output
# Or use LoopOffset for seamless loopingWith LoopOffset for seamless loops:
Set LoopOffset 80% # Start loop at 80% through
Type "mycli demo"
Enter
Sleep 5s # Final output visible, then loops smoothlyRecommended final sleep durations:
- Simple output: 2-3s
- Complex output: 4-5s
- Output viewers need to read: 5-10s
Reference: VHS README - Settings
Add Natural Pauses Between Actions
Add short pauses between actions to simulate natural human interaction. Without pauses, recordings feel robotic and are harder for viewers to follow.
Incorrect (machine-gun pacing):
Type "ls"
Enter
Type "cd src"
Enter
Type "cat main.js"
Enter
# Feels robotic, hard to followCorrect (natural pauses):
Type "ls"
Enter
Sleep 1s # Let viewer see listing
Type "cd src"
Enter
Sleep 500ms # Brief pause, directory change is quick
Type "cat main.js"
Enter
Sleep 3s # Let viewer read file contentsPause guidelines by action type:
- After directory listing: 1-2s
- After cd/navigation: 300-500ms
- After typing, before Enter: 200-300ms (thinking pause)
- After command output: 1-5s based on content length
- Between unrelated commands: 500ms-1s
Reference: VHS README
Use PlaybackSpeed for Final Adjustments
Use Set PlaybackSpeed to adjust the final recording speed without changing timing in your tape file. This is useful for making long demos shorter or slowing down fast sections.
Incorrect (adjusting all Sleep values manually):
# Original: too slow at 30 seconds total
Sleep 5s
Type "command"
Sleep 5s
# Manually halving all sleeps: error-prone
Sleep 2.5s
Type "command"
Sleep 2.5sCorrect (using PlaybackSpeed):
Set PlaybackSpeed 2.0 # 2× faster playback
Sleep 5s
Type "command"
Sleep 5s
# Renders in 15 seconds instead of 30PlaybackSpeed values:
0.5: 2× slower (30s recording → 60s playback)1.0: Normal speed (default)1.5: 1.5× faster2.0: 2× faster (30s recording → 15s playback)
When to use each:
0.5: Complex demos viewers need time to understand1.0: Standard tutorials1.5-2.0: README GIFs that should be brief
Reference: VHS README - Settings
Add Sleep After Commands for Output
Always add a Sleep command after Enter to give the command time to execute and display output. Without this, VHS may proceed to the next command before output is visible, creating confusing recordings.
Incorrect (no wait for output):
Type "npm install"
Enter
Type "npm run build"
Enter
# Install output never visible, immediately types next commandCorrect (sleep for output visibility):
Type "npm install"
Enter
Sleep 3s # Wait for install to show progress
Type "npm run build"
Enter
Sleep 5s # Wait for build outputAdjust sleep duration based on command:
- Simple echo/print: 500ms-1s
- File operations: 1-2s
- Network operations: 2-5s
- Build/compile: 5-30s
Reference: VHS README - Sleep
Use Explicit Time Units
Always specify time units (s for seconds, ms for milliseconds) in Sleep commands. While VHS accepts bare numbers as seconds, explicit units prevent confusion and make tape files more readable.
Incorrect (ambiguous units):
Sleep 2 # Is this 2 seconds or 2 milliseconds?
Sleep 500 # 500 seconds?! No, VHS treats this as 500ms
Sleep .5 # Half a second? Works but unclearCorrect (explicit units):
Sleep 2s # Clearly 2 seconds
Sleep 500ms # Clearly 500 milliseconds
Sleep 0.5s # Clearly half a second
Sleep 1500ms # Clearly 1.5 secondsUnit reference:
ms: milliseconds (1000ms = 1s)s: seconds- Bare numbers: interpreted as seconds (avoid)
Reference: VHS README - Sleep
Override TypingSpeed for Emphasis
Use the @<time> suffix on Type to override typing speed for specific commands. Slow down for important commands viewers should notice, speed up for boilerplate they can skim.
Incorrect (uniform speed throughout):
Set TypingSpeed 50ms
Type "cd my-project"
Enter
Type "npm install"
Enter
Type "npm run dangerous-command --force" # Same speed, easy to miss
EnterCorrect (varied speed for emphasis):
Set TypingSpeed 50ms
Type "cd my-project"
Enter
Sleep 500ms
Type@25ms "npm install" # Fast, routine command
Enter
Sleep 3s
Type@150ms "npm run dangerous-command --force" # Slow, draws attention
Enter
Sleep 2sSpeed guidelines:
@25ms: Very fast, for familiar boilerplate@50ms: Normal reading speed@100ms: Slightly slow, noticeable@150-200ms: Deliberate, for important content@500ms: Very slow, dramatic effect
Reference: VHS README - Type
Use Wait for Dynamic Command Completion
Use Wait with a regex pattern to wait for specific output instead of guessing sleep durations. This creates reliable recordings regardless of system speed or network latency.
Incorrect (guessing sleep duration):
Type "npm install"
Enter
Sleep 30s # Might be too long or too short
Type "npm run build"
Enter
Sleep 60s # Build time varies wildlyCorrect (wait for completion patterns):
Type "npm install"
Enter
Wait /added .* packages/ # Wait for npm completion message
Type "npm run build"
Enter
Wait /Build complete/ # Wait for build success messageWait scopes:
# Wait for pattern anywhere on screen
Wait+Screen /ready/
# Wait for pattern on current line only (default)
Wait+Line /\$/ # Wait for prompt
# Wait with timeout
Wait+Screen@30s /Server started/Common patterns:
- Shell prompt:
/\$\s*$/or/>\s*$/ - npm completion:
/added .* packages/ - Build success:
/Build complete|Successfully compiled/ - Error detection:
/error:|Error:/
Reference: VHS README - Wait
Set Appropriate Wait Timeouts
Always set explicit timeouts on Wait commands to prevent infinite hangs when expected output never appears. The default 15-second timeout may be too short for slow operations or too long for quick checks.
Incorrect (default timeout may fail):
Type "npm run build"
Enter
Wait /Build complete/ # Default 15s timeout—build takes 30s
# VHS times out and failsCorrect (appropriate timeouts):
Type "npm run build"
Enter
Wait@60s /Build complete/ # 60-second timeout for slow builds
Type "echo test"
Enter
Wait@2s /test/ # 2-second timeout for instant commandsTimeout guidelines:
- Instant commands (echo, pwd): 2-5s
- File operations: 5-10s
- Network operations: 10-30s
- Build/compile: 30-120s
- CI operations: 60-300s
In CI environments:
# CI is often slower, use generous timeouts
Wait@120s /Build succeeded/
Wait@60s /Tests passed/Reference: VHS README - Wait
Ensure Cursor Visibility
Ensure your theme provides good cursor visibility. A clearly visible cursor helps viewers track where typing is happening, especially in longer recordings.
Incorrect (cursor blends with background):
Output demo.gif
Set Theme {
"background": "#ffffff",
"cursor": "#f0f0f0"
}
# Cursor nearly invisible on white backgroundCorrect (high-contrast cursor):
Output demo.gif
Set Theme {
"name": "Custom",
"background": "#1e1e2e",
"foreground": "#cdd6f4",
"cursor": "#f5e0dc",
"cursorAccent": "#1e1e2e"
}Using built-in themes with good cursors:
Set Theme "Catppuccin Mocha" # Pink cursor, high visibility
Set Theme "Dracula" # Green cursor
Set Theme "One Dark" # Blue cursorTest cursor visibility:
Type "Look at the cursor position"
Sleep 1s
Left 10
Sleep 1s
# Cursor should be clearly visible at new positionReference: VHS README - Theme
Choose Readable Font Settings
Set appropriate font size and family for readability. Default sizes may be too small for GitHub README previews or too large for documentation embeds. Monospace fonts with clear character distinction work best.
Incorrect (default or tiny font):
Output demo.gif
# Default font size may be hard to read in GitHub preview
Set FontSize 14 # Too small for most use casesCorrect (optimized for viewing context):
Output demo.gif
Set FontFamily "JetBrains Mono"
Set FontSize 28 # Readable in README previews
Type "echo 'Clear and readable'"
EnterFont size guidelines by context:
| Context | Font Size |
|---|---|
| GitHub README | 24-32 |
| Documentation embed | 18-24 |
| Presentation slides | 32-48 |
| Social media | 28-36 |
Recommended font families:
- JetBrains Mono (default, excellent)
- Fira Code (ligatures)
- Source Code Pro (clean)
- Hack (highly readable)
Reference: VHS README - Settings
Use Padding and Margins Effectively
Use Padding for space inside the terminal window and Margin with MarginFill for space outside. This prevents content from touching edges and creates a cleaner appearance.
Incorrect (content touching edges):
Output demo.gif
Set Padding 0
Type "mycli demo --output"
Enter
# Text touches window edges, looks crampedCorrect (comfortable spacing):
Output demo.gif
Set Padding 20
Set Margin 30
Set MarginFill "#282a36"
Type "mycli demo --output"
EnterSpacing strategies:
# Minimal padding (compact)
Set Padding 10
# Standard padding (balanced)
Set Padding 20
# Generous padding (presentations)
Set Padding 40
# With decorative margin
Set Margin 40
Set MarginFill "#6B50FF" # Brand color backgroundMargin vs Padding:
- Padding: Space inside the terminal, same color as background
- Margin: Space outside the terminal, can be different color/image
Reference: VHS README - Settings
Adjust Letter and Line Spacing
Use LetterSpacing and LineHeight to fine-tune text appearance when default spacing doesn't work well with your chosen font or content density.
Incorrect (cramped or sparse text):
Output demo.gif
Set FontFamily "Fira Code"
# Default spacing may be too tight for this font
Type "function hello() { console.log('world'); }"
EnterCorrect (adjusted for readability):
Output demo.gif
Set FontFamily "Fira Code"
Set LetterSpacing 1
Set LineHeight 1.4
Type "function hello() { console.log('world'); }"
EnterSpacing guidelines:
| Setting | Default | Compact | Spacious |
|---|---|---|---|
| LetterSpacing | 0 | -1 | 1-2 |
| LineHeight | 1.0 | 0.9 | 1.2-1.5 |
When to adjust:
- Dense code blocks: Increase LineHeight to 1.3-1.5
- Wide terminals: Slight LetterSpacing increase improves readability
- Narrow fonts: May need LetterSpacing increase
Reference: VHS README - Settings
Select Appropriate Theme
Choose a theme that matches your project's branding and provides good contrast. Dark themes work well for most terminal demos; light themes may be needed for specific documentation contexts.
Incorrect (default theme may clash):
Output demo.gif
# Default theme may not match your project's styleCorrect (themed for context):
Output demo.gif
Set Theme "Catppuccin Mocha" # Popular dark theme
Type "mycli demo"
EnterList available themes:
vhs themes # Shows all built-in themesPopular theme choices:
- Catppuccin Mocha/Frappe: Modern, soft colors
- Dracula: Popular dark theme
- One Dark: Atom-style theme
- Tokyo Night: Calm, easy on eyes
- Nord: Minimal, arctic palette
Custom theme:
Set Theme {
"name": "Custom",
"background": "#1e1e2e",
"foreground": "#cdd6f4",
"cursor": "#f5e0dc"
}Reference: VHS README - Theme
Add Window Decorations for Polish
Use WindowBar and related settings to add macOS-style window decorations, giving your recordings a polished, professional look.
Incorrect (no window decoration):
Output demo.gif
Type "mycli demo"
Enter
# Plain terminal, no visual contextCorrect (with window decorations):
Output demo.gif
Set WindowBar Colorful
Set WindowBarSize 40
Set BorderRadius 10
Type "mycli demo"
EnterWindowBar options:
Rings: macOS-style colored dots on leftRingsRight: Colored dots on rightColorful: Vibrant colored dots on leftColorfulRight: Vibrant dots on right
Combined with margins:
Set WindowBar Colorful
Set WindowBarSize 40
Set BorderRadius 12
Set Margin 20
Set MarginFill "#1e1e2e" # Match theme background
Set Padding 10
# Creates a nicely framed terminal windowReference: VHS README - Settings