This guide walks you through creating a demo GIF from start to finish using VHS.
Prerequisites
Before starting, ensure you have:
- ✅ VHS installed and configured
- ✅ ffmpeg and ttyd dependencies installed
- ✅ Local clone of
strike48-labsrepository - ✅ Familiarity with the feature you're demoing
Workflow Overview
Estimated time: 20-40 minutes for a simple demo
Step 1: Plan Your Demo
Before writing any VHS script, plan what you want to show.
Identify the Feature
Pick a MediaCard from the documentation that currently shows "Coming Soon":
Define the Story
Answer these questions:
- What does this demo show? (One sentence)
- Who is the audience? (End user? Developer?)
- What commands will be run? (List them)
- What output is important? (What should viewers notice?)
- How long should it be? (10-30 seconds target)
Example:
Feature: SDK-rs Quick Start
Audience: Developers new to Strike48 SDK
Commands: cargo new, add dependency, cargo build
Key Output: Successful build message
Duration: ~15 seconds
Prepare Your Environment
If the demo requires:
- Real commands: Set up a clean test environment
- Simulated output: Prepare the text you'll type
- Specific state: Document what needs to exist beforehand
Step 2: Write the VHS Tape Script
Create a new file in vhs-scripts/:
cd strike48-labs/vhs-scripts
touch your-product-feature.tape
Basic Template
# Product Name - Feature Name
# Brief description of what this demo shows
Output ../public/gifs/your-product-feature.gif
Require echo
Set FontSize 14
Set Width 1200
Set Height 600
Set Padding 20
Set Theme "Dracula"
Set TypingSpeed 50ms
Set PlaybackSpeed 1.0
# Title card
Type "# Strike48 Product - Feature Name"
Sleep 1s
Enter
Enter
# Demo commands here
Type "your-command"
Sleep 300ms
Enter
Sleep 1.5s
# End card
Type "# ✨ Done!"
Sleep 2s
VHS Command Reference
| Command | Purpose | Example |
|---|---|---|
Type "text" |
Type text into terminal | Type "cargo build" |
Enter |
Press Enter key | Enter |
Sleep <duration> |
Pause for duration | Sleep 1s, Sleep 500ms |
Set <setting> <value> |
Configure VHS | Set Width 1200 |
Output <path> |
Specify output file | Output ../public/gifs/demo.gif |
Require <cmd> |
Ensure command exists | Require cargo |
Full reference: VHS documentation
Timing Guidelines
Use these timing patterns for natural flow:
# After typing a command (before Enter)
Type "command"
Sleep 300ms # Brief pause (user thinking)
Enter
# After Enter (let output render)
Enter
Sleep 1.5s # Short output
Sleep 2s # Medium output
Sleep 3s # Long output or multiple lines
# Between unrelated commands
Type "first command"
Enter
Sleep 1.5s
Type "second command" # Natural transition
# Title/end cards
Type "# Title"
Sleep 1s # Reading time
Enter
Quoting Rules
VHS has specific quoting requirements:
Single quotes for strings with double quotes inside:
Type 'echo "Hello World"'
Type 'strike48-sdk = "0.1.0"'
Double quotes for simple strings:
Type "cargo build"
Type "cd my-project"
Escape sequences - avoid if possible; use single quotes instead:
# ❌ Problematic
Type "echo \"quoted\""
# ✅ Better
Type 'echo "quoted"'
Step 3: Generate the GIF
Run VHS to generate your GIF:
cd strike48-labs/vhs-scripts
vhs your-product-feature.tape
What VHS does:
- Launches a terminal emulator (ttyd)
- Executes your commands in sequence
- Records the terminal output
- Encodes to GIF using ffmpeg
- Saves to
../public/gifs/your-product-feature.gif
First run takes longer (~30-60 seconds) as VHS initializes.
Troubleshooting Generation
Error: "command not found"
# Your script tries to run a command that doesn't exist
# Either install the tool or simulate the output
Error: "Invalid command"
# Usually a quoting issue
# Check your Type statements for proper quotes
Error: "ffmpeg failed"
# ffmpeg isn't installed or isn't in PATH
sudo apt install ffmpeg # Ubuntu/Debian
brew install ffmpeg # macOS
Script hangs:
# A command is waiting for input or not exiting
# Use Ctrl+C and review your tape script
# May need to add timeouts or simulate output instead
Step 4: Optimize the GIF
Check the file size:
ls -lh ../public/gifs/your-product-feature.gif
Target: Under 500KB Maximum: 1MB
If Size is Too Large
Try these optimizations in order:
1. Reduce timing
# Before
Sleep 2s
# After
Sleep 1s
2. Reduce dimensions
# Before
Set Width 1200
Set Height 600
# After
Set Width 1000
Set Height 500
3. Simplify the demo
- Fewer commands
- Less output
- Shorter duration
4. Use gifsicle (external tool)
# Install
sudo apt install gifsicle # Ubuntu/Debian
brew install gifsicle # macOS
# Optimize (lossy)
gifsicle -O3 --lossy=80 -o optimized.gif original.gif
# Check savings
ls -lh original.gif optimized.gif
Validate Quality
Watch your GIF to ensure:
- [ ] Commands are readable (not too fast)
- [ ] Output is visible (not cut off)
- [ ] Timing feels natural
- [ ] No flickering or glitches
- [ ] Loops smoothly
View in browser:
open ../public/gifs/your-product-feature.gif # macOS
xdg-open ../public/gifs/your-product-feature.gif # Linux
Step 5: Embed in Documentation
Update the relevant MediaCard to display your GIF.
Find the MediaCard
Locate the placeholder in the appropriate media page:
/src/content/docs/media/strikehub.mdx/src/content/docs/media/kubestudio.mdx/src/content/docs/media/pick.mdx/src/content/docs/media/sdk-rs.mdx/src/content/docs/media/strikekit.mdx/src/content/docs/media/dioxus-connector.mdx
Update the MediaCard
Before:
**Your Feature**
Brief description of the feature.
After:
<MediaCard
title="Your Feature"
description="Detailed step-by-step description: command 1, command 2, expected output."
iconName="some-icon"
status="available"
mediaSrc="/gifs/your-product-feature.gif"
mediaType="image"
/>
Key changes:
- Add
status="available"- removes "Coming Soon" badge - Add
mediaSrc="/gifs/your-product-feature.gif"- path to your GIF - Add
mediaType="image"- tells component it's an image (GIF) - Enhance description - make it descriptive for accessibility
Test Locally
Build and run the dev server:
cd strike48-labs
npm run build
npm run dev
Navigate to the media page and verify:
- [ ] GIF displays correctly
- [ ] GIF auto-plays
- [ ] GIF loops smoothly
- [ ] Card layout looks good
- [ ] No console errors
Step 6: Commit and Push
Once everything looks good, commit your changes:
cd strike48-labs
# Check what's changed
git status
# Stage your files
git add vhs-scripts/your-product-feature.tape
git add public/gifs/your-product-feature.gif
git add src/content/docs/media/product-name.mdx
# Commit
git commit -m "$(cat <<'EOF'
Add [Product] [Feature] demo GIF
Created demo GIF using VHS showing [brief description].
Changes:
- vhs-scripts/your-product-feature.tape - VHS recording script
- public/gifs/your-product-feature.gif - Generated GIF (XXX KB)
- src/content/docs/media/product-name.mdx - Updated MediaCard
Related: #92
EOF
)"
# Push
git push
Build will run on GitHub Actions to validate everything still builds.
Quick Reference
Common VHS Patterns
Simple command with output:
Type "command"
Sleep 300ms
Enter
Sleep 1.5s
Multi-line command (using &&):
Type "command1 && command2"
Sleep 300ms
Enter
Sleep 2s
Simulated output:
Type "long-running-command"
Enter
Sleep 500ms
Type " Processing..."
Sleep 800ms
Type " ✓ Done"
Sleep 1s
Changing directories:
Type "cd my-directory"
Enter
Sleep 500ms
Type "ls -la"
Enter
Sleep 1.5s
Showing file contents (simulated):
Type "cat config.toml"
Enter
Sleep 300ms
Type "[section]"
Type "key = \"value\""
Sleep 1.5s
File Size Targets
| Duration | Target Size | Max Size |
|---|---|---|
| 10s | 150-250KB | 400KB |
| 15s | 200-350KB | 500KB |
| 20s | 300-450KB | 700KB |
| 30s | 400-600KB | 1MB |
Troubleshooting
GIF is Blurry
- Increase dimensions:
Set Width 1400/Set Height 700 - Check if theme colors have good contrast
GIF is Jerky/Choppy
- VHS may be running on slow hardware
- Try reducing terminal dimensions
- Simplify the demo (fewer commands)
Commands Don't Execute
- Ensure commands are available in PATH
- Use
Require <command>to verify availability - Consider simulating output instead
GIF Loops Awkwardly
- Add
Sleep 2sat the end before loop restarts - Ensure final state is stable (not mid-command)
Build Artifacts in Git
- VHS creates real files when running commands
- Ensure
vhs-scripts/.gitignoreexcludes working directories - Only commit
.tapescripts, not generated artifacts
Tips and Tricks
Speed Up Iteration
While developing your tape script:
# Edit tape
vim your-demo.tape
# Generate GIF
vhs your-demo.tape
# View immediately
xdg-open ../public/gifs/your-demo.gif
# Repeat until satisfied
Reuse Common Patterns
Create a templates/ directory with reusable snippets:
vhs-scripts/
├── templates/
│ ├── title-card.tape
│ ├── end-card.tape
│ └── settings.tape
└── your-demos.tape
Then copy-paste into your scripts as needed.
Batch Generate GIFs
Create multiple tape scripts and generate all at once:
for tape in *.tape; do
echo "Generating $tape..."
vhs "$tape"
done
Next Steps
- GIF Guidelines → - Technical specifications and standards
- VHS Examples → - Reference tape scripts and patterns
- Issue #92 - Track progress on GIF pipeline