You write a .tape file and run evp my_sript.tape to produce smooth, high quality, portable GIF or SVG demos.
EVP is a rewrite of VHS with some key improvements.
See it in action at flyline or below:
EVP is extends VHS in these ways:
- Significantly faster. No more skipped frames when creating demos in GHA!
- Animated SVGs:
- Super crisp demos
- You can select and copy text from the SVG as it is playing!
- Fonts are embedded into the SVG so the demos are portable (fonts are subsetted before embedding)
- SVG screenshots
- Box-drawing chars are rendered as SVG shapes. Don't worry, an invisible character is written to the SVG so selecting and copying text works as expected.
- Supports Kitty extended keycodes. e.g:
Ctrl+Shift+Alt+LeftCommand+Alt+PageUp
- Specify full shell path with arguments. e.g.:
Set Shell bash --init-file test.rcSet Shell yaziyou can specify and program, not just a shell!
- EVP has no runtime dependencies
- It is a statically linked musl binary
- A collection of useful fonts are embedded into EVP
- Mouse support: you can script mouse input (clicking, dragging, mouse moving)
- Set the terminal size by number of rows / cols or by number of pixels.
- Coming soon: resize support
- Coming soon: snapshot process metrics to help debug interactive use
- Coming soon: key event name overlay
EVP runs a shell inside an embedded libghostty terminal. This allows us to support advanced terminal features in a headless environment such as: complex key combinations; key press and key release events; mouse input support; legacy escape codes.
The SVG animations are done using SMIL.
Fonts are embedded into the SVG using this method.
A custom optimizer reduces the file size and complexity.
All the text on one terminal row is rendered inside of a <text> span which helps the browser copy the right text when you select and copy from the SVG.
GIF rendering is powered by gifski.
Tip
No sudo required!
curl -sSfL https://raw.githubusercontent.com/HalFrgrd/evp/master/install.sh | sh> docker bake extract-libghostty
> cargo build # Start from a base script:
> evp print-ref-script > demo.tape
# Modify the script then run it!
> evp demo.tapeOr if you already have a VHS script:
> evp --mimic-vhs demo.tapeTODO: make it possible to record user input and generate a tape from that.
evp record --output demo.gif, type away, use the mouse, then exit. Maybe we should automatically cut put the "exit + enter" part after a Hide.
The script should have a the refernece at the top.
TODO
TODO
EVP supports a superset of VHS .tape script language. Below is a complete template of all supported commands, settings, and events in the EVP .tape script language:
# --- Output & Dependencies ---
Output demo.gif # Target output file (supports .gif, .svg, .svgz, .json, .stats)
Output demo.json # Multiple outputs are supported. You can use the `--ouput demo.svg` flag also.
Output demo.svg # Recommended
Output demo.svgz # gzip-compressed svg, less widely supported
Output demo.stats # Reports some stats about the rendering process
Require curl # Assert that curl is available on system PATH
Source common.tape # Inline another tape file
# --- Window & Font Settings ---
Set Shell bash # Configure shell execution path (e.g. bash, zsh, fish)
Set Shell bash --norc # EVP supports any command as the "shell"
Set Shell yazi # You can boot right into your TUI
Set Theme "Catppuccin Mocha" # Apply a predefined colour theme (run `evp themes` to discover themes)
Set Font "JetBrains Mono" # Monospace font family name
Set FontSize 20 # Font size in pixels
Set LineHeight 1.2 # Line spacing multiplier
Set LetterSpacing 0 # Letter spacing adjustment
Set Width 800 # Terminal window width in pixels
Set Height 400 # Terminal window height in pixels
Set Cols 100 # Set terminal width in rows (Set Width has precedence)
Set Rows 30 # Set terminal height in rows (Set Height has precedence)
Set Padding 10 # Inner padding between terminal grid and window frame
Set Margin 20 # Outer margin around window frame
Set MarginFill "#6B50FF" # Background colour of outer margin area
Set Framerate 30 # Recording framerate in FPS
Set TypingSpeed 50ms # Default speed/interval for typed text
# --- Child Process Environment ---
Env PS1 "$ " # Set environment variables for the shell process
# --- Playback & Timeline Controls ---
Sleep 1s # Pause playback for a duration (e.g. 500ms, 1.5s, 2m)
Hide # Hide subsequent commands from recording output
Show # Resume recording commands to output files
Screenshot frame.png # Capture the current terminal window frame as a PNG, SVG, or JSON
Screenshot frame.svg
Screenshot frame.json
# --- Clipboard Controls ---
Copy "text to clipboard" # Copy a string into the system clipboard
Paste # Paste current clipboard contents into terminal
# --- Keyboard & Input Events ---
Type "echo 'hello'" # Type text at the current default TypingSpeed
Type@10ms "fast typing" # Type text at an overridden speed of 10ms
Enter # Press key alias (equivalent to Key "Enter" / Key "Return")
Backspace 5 # Repeat a key alias N times (press Backspace 5 times)
Ctrl+C # Press key combination modifier
Ctrl+Shift+Alt+Left # Even complex key codes are possible.
Press Down # Explicitly hold a key down
Release Down # Explicitly release a held key
# --- Mouse Controls ---
Click 10 20 # Left click at column 10, row 20
RightClick 10 20 # Right click at column 10, row 20
DoubleClick 10 20 # Double click at column 10, row 20
MouseMove@100ms 0 0 10 10 # Move cursor from (0,0) to (10,10) using default sigmoid (EaseInOutCubic) easing
MouseMove@100ms@EaseInOutElastic 0 0 10 10 # Move cursor with EaseInOutElastic easing curve override
MouseDrag@EaseInOutQuad 0 0 10 10 # Left click and drag with EaseInOutQuad easing curve
MouseScroll 10 20 Up # Scroll mouse wheel Up or Down at column 10, row 20
# --- Wait / Synchronization ---
Wait "Ready" # Wait for output matching text pattern
Wait /regex/ # Wait for output matching regular expression
Wait+Screen /regex/ # Wait scanning full screen instead of only the last line
Wait+Line /regex/ # Explicitly wait scanning last line only (default)
Wait@1s /regex/ # Wait with an overridden timeout of 1s (default is 15s)
Wait+Line@1s /regex/ # Wait scanning last line with 1s timeout override
Wait+Screen@1s /regex/ # Wait scanning full screen with 1s timeout overrideEVP is based on the vhs project.
They share little code but EVP does try use the same .tape file format.
The colour themes in assets/vhs-themes.json are taken from the VHS project and are licensed under the MIT License. See licenses/VHS-MIT.txt for the full license text.
Some fonts are embedded inside the EVP binary. See licenses in license for the full license text.