cli-demo-generator — Claude Code skill: animated CLI GIFs
Records terminal commands through VHS and hands back an animated GIF. Useful for README demos and CLI documentation.
npx skills add daymade/claude-code-skills --skill cli-demo-generator -a claude-codeWhat cli-demo-generator does
The skill drives VHS, a tool that plays a tape file and captures the terminal as a GIF. You supply the commands, it writes the file. Four routes in: automated generation with auto_generate_demo.py, batch builds from a YAML config, interactive recording of a live session, and a hand-written tape when you want frame-level control.
Inside are Python scripts and tape templates. Automated generation picks its own pauses: 3 seconds for install, build, test and deploy, one second for ls, pwd and echo. Flags cover theme, font size, terminal width and height, plus --bootstrap for hidden setup and --filter to strip noisy output lines.
The VHS parser is where things break. Type strings reject $, \" and backticks, so any command carrying those has to be base64-encoded and decoded inside the tape. VHS itself is required (brew install charmbracelet/tap/vhs); gifsicle, asciinema and ffmpeg are optional, for speeding up a recording, capturing a live session and checking frames.
What it helps with
- record a package install and build into one README GIF
- generate several demos from a single YAML config
- keep environment setup out of the viewer's sight
- strip noisy progress lines from command output
- speed up an existing recording without re-recording
Example prompts for the agent
- Make a GIF demo: run
npm install my-package, thennpm run build, save it asdemo.gif - Record an interactive terminal session to
output.gifwith the Catppuccin Latte theme - Build the demos from
demos.yamlinto./gifs
How to install cli-demo-generator
1Skills CLI (Vercel)
npx skills add daymade/claude-code-skills --skill cli-demo-generator -a claude-code2Manually: put the files in place
~/.claude/skills/cli-demo-generator/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/cli-demo-generator/
1Skills CLI (Vercel)
npx skills add daymade/claude-code-skills --skill cli-demo-generator -a codex2Manually: put the files in place
.agents/skills/cli-demo-generator/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add daymade/claude-code-skills --skill cli-demo-generator -a cursor2Manually: put the files in place
.cursor/skills/cli-demo-generator/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install daymade/claude-code-skills cli-demo-generator2Manually: put the files in place
.github/skills/cli-demo-generator/SKILL.md1Skills CLI (Vercel)
npx skills add daymade/claude-code-skills --skill cli-demo-generator -a gemini-cli2Platform CLI
gemini skills install https://github.com/daymade/claude-code-skills --path cli-demo-generatorManually: put the files in place
.devin/skills/cli-demo-generator/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add daymade/claude-code-skills --skill cli-demo-generator -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about cli-demo-generator
How do I install cli-demo-generator in Claude?
Run npx skills add daymade/claude-code-skills --skill cli-demo-generator -a claude-code. The skill lands at ~/.claude/skills/cli-demo-generator/SKILL.md.
What does cli-demo-generator do?
It records command-line sessions through VHS and saves them as an animated GIF. Built for README demos and CLI documentation.
Why does VHS fail to parse my command?
VHS Type strings reject $, \" and backticks. Encode a command containing them as base64 and decode it inside the tape file.
Source text
SKILL.md · MIT
---
name: cli-demo-generator
description: >-
Generates professional animated CLI demos as GIFs using VHS terminal recordings. Use to create
terminal demos, record CLI workflows as GIFs, generate animated documentation, build demo tapes
for README files, or showcase any command-line tool visually: record terminal / VHS tape / demo
GIF / animate my CLI.
---
# CLI Demo Generator
Create professional animated CLI demos. Four approaches, from fully automated to pixel-precise manual control.
## Quick Start
**Simplest path** — give commands, get GIF:
```bash
python3 ${CLAUDE_SKILL_DIR}/scripts/auto_generate_demo.py \
-c "npm install my-package" \
-c "npm run build" \
-o demo.gif
```
**Self-bootstrapping demo** — for repeatable recordings that clean their own state:
```bash
python3 ${CLAUDE_SKILL_DIR}/scripts/auto_generate_demo.py \
-c "npm install my-package" \
-c "npm run build" \
-o demo.gif \
--bootstrap "npm uninstall my-package 2>/dev/null" \
--speed 2
```
## Critical: VHS Parser Limitations
VHS `Type` strings cannot contain `$`, `\"`, or backticks. These cause parse errors:
```tape
# FAILS — VHS parser rejects special chars
Type "echo \"hello $USER\""
Type "claude() { command claude \"$@\"; }"
```
**Workaround: base64 encode the command**, decode at runtime:
```bash
# 1. Encode your complex command
echo 'claude() { command claude "$@" 2>&1 | grep -v "noise"; }' | base64
# Output: Y2xhdWRlKCkgey4uLn0K
# 2. Use in tape
Type "echo Y2xhdWRlKCkgey4uLn0K | base64 -d > /tmp/wrapper.sh && source /tmp/wrapper.sh"
```
This pattern is essential for output filtering, function definitions, and any command with shell special characters.
## Approaches
### 1. Automated Generation (Recommended)
```bash
python3 ${CLAUDE_SKILL_DIR}/scripts/auto_generate_demo.py \
-c "command1" -c "command2" \
-o output.gif \
--title "My Demo" \
--theme "Catppuccin Latte" \
--font-size 24 \
--width 1400 --height 600
```
| Flag | Default | Description |
|------|---------|-------------|
| `-c` | required | Command to include (repeatable) |
| `-o` | required | Output GIF path |
| `--title` | none | Title shown at start |
| `--theme` | Dracula | VHS theme name |
| `--font-size` | 16 | Font size in pt |
| `--width` | 1400 | Terminal width px |
| `--height` | 700 | Terminal height px |
| `--bootstrap` | none | Hidden setup command (repeatable) |
| `--filter` | none | Regex pattern to filter from output |
| `--speed` | 1 | Playback speed multiplier (uses gifsicle) |
| `--no-execute` | false | Generate .tape only |
Smart timing: `install`/`build`/`test`/`deploy` → 3s, `ls`/`pwd`/`echo` → 1s, others → 2s.
### 2. Batch Generation
Create multiple demos from one config:
```yaml
# demos.yaml
demos:
- name: "Install"
output: "install.gif"
commands: ["npm install my-package"]
- name: "Usage"
output: "usage.gif"
commands: ["my-package --help", "my-package run"]
```
```bash
python3 ${CLAUDE_SKILL_DIR}/scripts/batch_generate.py demos.yaml --output-dir ./gifs
```
### 3. Interactive Recording
Record a live terminal session:
```bash
bash ${CLAUDE_SKILL_DIR}/scripts/record_interactive.sh output.gif --theme "Catppuccin Latte"
# Type commands naturally, Ctrl+D when done
```
Requires asciinema (`brew install asciinema`).
### 4. Manual Tape File
For maximum control, write a tape directly. Templates in `assets/templates/`:
- `basic.tape` — simple command sequence
- `interactive.tape` — typing simulation
- `self-bootstrap.tape` — **self-cleaning demo with hidden setup** (recommended for repeatable demos)
## Advanced Patterns
These patterns come from production use. See `references/advanced_patterns.md` for full details.
### Self-Bootstrapping Demos
Demos that clean previous state, set up environment, and hide all of it from the viewer:
```tape
Hide
Type "cleanup-previous-state 2>/dev/null"
Enter
Sleep 2s
Type "clear"
Enter
Sleep 500ms
Show
Type "the-command-users-see"
Enter
Sleep 3s
```
The `Hide` → commands → `clear` → `Show` sequence is critical. `clear` wipes the terminal buffer so hidden commands don't leak into the GIF.
### Output Noise Filtering
Filter noisy progress lines from commands that produce verbose output:
```tape
# Hidden: create a wrapper function that filters noise
Hide
Type "echo <base64-encoded-wrapper> | base64 -d > /tmp/w.sh && source /tmp/w.sh"
Enter
Sleep 500ms
Type "clear"
Enter
Sleep 500ms
Show
# Visible: clean command, filtered output
Type "my-noisy-command"
Enter
Sleep 3s
```
### Frame Verification
After recording, verify GIF content by extracting key frames:
```bash
# Extract frames at specific positions
ffmpeg -i demo.gif -vf "select=eq(n\,100)" -frames:v 1 /tmp/frame.png -y 2>/dev/null
# View the frame (Claude can read images)
# Use Read tool on /tmp/frame.png to verify content
```
### Post-Processing Speed-Up
Use gifsicle to speed up recordings without re-recording:
```bash
# 2x speed (halve frame delay)
gifsicle -d2 original.gif "#0-" > fast.gif
# 1.5x speed
gifsicle -d4 original.gif "#0-" > faster.gif
```
### Template Placeholder Pattern
Keep tape files generic with placeholders, replace at build time:
```tape
# In tape file
Type "claude plugin marketplace add MARKETPLACE_REPO"
# In build script
sed "s|MARKETPLACE_REPO|$DETECTED_REPO|g" template.tape > rendered.tape
vhs rendered.tape
```
## Timing & Sizing Reference
| Context | Width | Height | Font | Duration |
|---------|-------|--------|------|----------|
| README/docs | 1400 | 600 | 16-20 | 10-20s |
| Presentation | 1800 | 900 | 24 | 15-30s |
| Compact embed | 1200 | 600 | 14-16 | 10-15s |
| Wide output | 1600 | 800 | 16 | 15-30s |
See `references/best_practices.md` for detailed guidelines.
## Troubleshooting
| Problem | Solution |
|---------|----------|
| VHS not installed | `brew install charmbracelet/tap/vhs` |
| gifsicle not installed | `brew install gifsicle` |
| GIF too large | Reduce dimensions, sleep times, or use `--speed 2` |
| Text wraps/breaks | Increase `--width` or decrease `--font-size` |
| VHS parse error on `$` or `\"` | Use base64 encoding (see Critical section above) |
| Hidden commands leak into GIF | Add `clear` + `Sleep 500ms` before `Show` |
| Commands execute before previous finishes | Increase `Sleep` duration |
## Tape File Syntax
`references/vhs_syntax.md` is the full VHS tape-file reference — every command,
setting, and key name, with the argument forms each accepts. Read it when writing
a tape by hand, when a tape parses but behaves unexpectedly, or when you need a
command this SKILL.md does not show an example of.
## Dependencies
**Required:** VHS (`brew install charmbracelet/tap/vhs`)
**Optional:** gifsicle (speed-up), asciinema (interactive recording), ffmpeg (frame verification), PyYAML (batch YAML configs)
© daymade · MIT · daymade/claude-code-skills