Generate terminal demos (asciinema casts & GIFs) from simple shell-like scripts.
Project description
scriptcast
Generate terminal demos (asciinema casts & GIFs) from annotated shell scripts.
scriptcast turns a shell script into a reproducible, polished terminal demo — with typing animations, multiple scenes, mocked commands, interactive sessions, output filtering, and more.
Table of Contents
Background
Terminal demos are hard to reproduce. Screen recordings drift, manual re-runs produce different output, and polishing timing or hiding sensitive paths requires video editing.
scriptcast treats demos as code. You write a shell script annotated with SC
directives — controlling scenes, typing speed, mocked commands, interactive expect
sessions, and output filters — then run a two-stage pipeline:
- Record — the script executes with shell tracing enabled; raw output is captured
and written to a JSONL
.scfile containing timestampedcmd,output,input, anddirectiveevents. - Generate — the
.scfile is read by a streaming renderer that synthesises a polished asciinema.castfile with typing animations and timing.
The .sc file is plain text, version-controllable, and diffable. Re-generating a cast
from an existing .sc is instant.
Install
pip install scriptcast
Requires Python 3.10+. For GIF output, install agg.
From source
git clone https://github.com/dacrystal/scriptcast.git
cd scriptcast
pip install -e .
Usage
scriptcast demo.sh # record → generate → export (PNG by default)
scriptcast demo.sc # generate → export (skip record)
scriptcast demo.cast # export only
scriptcast --no-export demo.sh # record + generate only, no image
scriptcast --format gif demo.sh # export as GIF (requires agg)
scriptcast install # install agg binary and fonts
Key flags:
| Flag | Default | Description |
|---|---|---|
--output-dir PATH |
same dir as input | Where to write output files |
--no-export |
off | Stop after generating .cast; skip image export |
--format [gif|png] |
png |
Export format |
--theme TEXT |
dark |
Built-in theme name or path to .sh theme file |
--directive-prefix PREFIX |
SC |
Directive prefix used in scripts |
--trace-prefix CHAR |
+ |
PS4/xtrace prefix |
--shell PATH |
$SHELL |
Shell used for recording |
--split-scenes |
off | Write one .cast file per scene |
--xtrace-log |
off | Save raw xtrace capture to <stem>.xtrace |
Examples
examples/showcase.sh — a realistic three-scene demo: interactive login, mocked deploy, status check with filter.
examples/tutorial.sh — one scene per directive: mock, expect, filter, comment, sleep, word_speed, record pause/resume.
Themes
Built-in themes: dark (default), aurora, light. Pass --theme <name> or a path to a custom .sh theme file.
--theme dark |
--theme aurora |
--theme light |
|---|---|---|
Script Syntax
Scripts are valid shell scripts. SC directives are embedded as shell no-ops
(: SC ...) so they execute harmlessly but appear in the xtrace output for the
recorder to process.
#!/usr/bin/env scriptcast
# Global config — applied before any scene
: SC set type_speed 40
: SC set width 80
: SC set height 24
# ── Scene: intro ──────────────────────────────
: SC scene intro
echo "Hello from scriptcast"
# ── Scene: mock ───────────────────────────────
: SC scene mock
: SC mock deploy <<'EOF'
Deploying to production...
Build: OK
Tests: OK
Deploy: OK
EOF
deploy
# ── Scene: expect ─────────────────────────────
: SC scene expect
: SC expect ./my-app <<'EOF'
expect "Password:"
send "secret\r"
expect "prompt>"
send "quit\r"
expect eof
EOF
# ── Scene: filter ─────────────────────────────
: SC scene filter
: SC filter sed 's#/home/user/projects#<project>#g'
pwd
# ── Scene: comment ────────────────────────────
: SC scene comment
: SC '\' This is a visual comment
echo "comments appear as prompt lines in the cast"
# ── Scene: setup (not recorded) ───────────────
: SC scene setup
: SC record pause
DB_URL="postgres://localhost/mydb"
: SC record resume
echo "Connecting to $DB_URL"
Recorder directives
These are consumed during recording and never appear in the .sc file.
| Directive | Description |
|---|---|
SC mock <cmd> <<'EOF' ... EOF |
Mock <cmd> so it prints fixed output during recording |
SC expect <cmd> <<'EOF' ... EOF |
Run an interactive session via expect(1) |
SC record pause |
Stop capturing output (commands still execute) |
SC record resume |
Resume capturing |
SC filter <cmd> [args...] |
Replace the current output filter with a shell command (stdin→stdout) |
SC filter-add <cmd> [args...] |
Append a command to the current filter chain |
SC '\' <text> |
Emit a # text comment line in the cast (visual annotation) |
SC helpers |
Inject ANSI color variables (RED, YELLOW, GREEN, CYAN, BOLD, RESET) silently into the script |
SC expect syntax
The heredoc body is a standard expect script. scriptcast preprocesses it to capture
typed input and clean up spawn noise. Inputs sent with send are recorded as input
events; silent inputs (e.g. passwords read with read -rs) produce silent animations.
: SC expect ./fake-db <<'EOF'
expect "Password:"
send "secret\r"
expect "mysql>"
send "show databases;\r"
expect eof
EOF
Generator directives
These are stored in the .sc file and interpreted during cast generation.
| Directive | Description |
|---|---|
SC scene <name> |
Start a new scene |
SC set <key> <value> |
Set a timing or display config key |
SC sleep <ms> |
Pause for N milliseconds |
Config keys (SC set)
| Key | Default | Description |
|---|---|---|
type_speed |
40 |
ms per character when typing commands |
cmd_wait |
80 |
ms after a command is typed, before output |
input_wait |
80 |
ms to pause before typing interactive input |
enter_wait |
80 |
ms at the start of each scene, after clearing |
exit_wait |
120 |
ms after the last output line of a scene |
width |
100 |
Terminal width (columns) |
height |
28 |
Terminal height (rows) |
prompt |
$ |
Prompt string shown before commands |
word_speed |
same as type_speed |
Extra ms pause after each space when typing |
cr_delay |
0 |
ms between \r-split segments (for progress-bar animations) |
When using ANSI escape sequences in prompt, use ANSI-C quoting so the shell
interprets the escapes before scriptcast sees them:
: SC set prompt $'\033[92m> \033[0m'
Similar Projects
- VHS — declarative
.tapeDSL for scripted terminal recordings; outputs GIF, MP4, WebM - Terminalizer — record a live terminal session and render it as a GIF or HTML player
- asciinema_automation — automate asciinema recordings using pexpect and comment directives
- demo-magic — bash function library for simulated typing in live terminal presentations
What makes scriptcast different:
- Shell-script-native — the demo source is a real, runnable
.shfile, not a DSL or config format. Directives are no-op shell comments that execute harmlessly. - Two-stage pipeline —
recordandgenerateare separate. Re-rendering with different timing or themes is instant, no re-recording needed. - Version-controllable — the
.scfile is plain JSONL, diffable and reviewable in git. - Mocking and expect —
SC mockandSC expectlet you script slow, side-effectful, or interactive commands without running the real thing. - Output filters —
SC filterpipes captured output through any shell command to scrub paths, tokens, or hostnames before they reach the cast.
Contributing
Issues and pull requests are welcome at github.com/dacrystal/scriptcast.
Before opening a PR, ensure:
- All tests pass:
uv run pytest - New behaviour is covered by tests
License
MIT © dacrystal
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scriptcast-0.2.0.tar.gz.
File metadata
- Download URL: scriptcast-0.2.0.tar.gz
- Upload date:
- Size: 900.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4b51fd087fad1ae759fd8135a8046994f356018a50befbf600da3fe965e17f60
|
|
| MD5 |
cfa540be7984cf0f34a623d98e08696b
|
|
| BLAKE2b-256 |
d7e72f155f8a5cfdfe407c94e94f2220a050f2d5360d0aead80e1a03f9525733
|
Provenance
The following attestation bundles were made for scriptcast-0.2.0.tar.gz:
Publisher:
publish-pypi.yml on dacrystal/scriptcast
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scriptcast-0.2.0.tar.gz -
Subject digest:
4b51fd087fad1ae759fd8135a8046994f356018a50befbf600da3fe965e17f60 - Sigstore transparency entry: 1244739769
- Sigstore integration time:
-
Permalink:
dacrystal/scriptcast@138deee60b3b8213d096f9d612dff6365efa928c -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/dacrystal
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@138deee60b3b8213d096f9d612dff6365efa928c -
Trigger Event:
push
-
Statement type:
File details
Details for the file scriptcast-0.2.0-py3-none-any.whl.
File metadata
- Download URL: scriptcast-0.2.0-py3-none-any.whl
- Upload date:
- Size: 216.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c9b96ab09eb3e4122f1820aa99cbc76a239348e77586c66d0f55f80c103cd25
|
|
| MD5 |
cda09617c8f990be67819f8e9c8ddf2d
|
|
| BLAKE2b-256 |
d8119aec1bafa59985049ca5741a7b2143fc916e2cc0e15b3b5d857434b10f7e
|
Provenance
The following attestation bundles were made for scriptcast-0.2.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on dacrystal/scriptcast
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scriptcast-0.2.0-py3-none-any.whl -
Subject digest:
1c9b96ab09eb3e4122f1820aa99cbc76a239348e77586c66d0f55f80c103cd25 - Sigstore transparency entry: 1244739813
- Sigstore integration time:
-
Permalink:
dacrystal/scriptcast@138deee60b3b8213d096f9d612dff6365efa928c -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/dacrystal
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@138deee60b3b8213d096f9d612dff6365efa928c -
Trigger Event:
push
-
Statement type: