README demos that keep up with your app.
Write the demo once as a script. matinee performs it against the real program, with seeded data and checked steps,
and records light and dark GIFs with a camera that follows the action. Terminals, desktop apps, or both, on Linux.
Install · Quick start · Examples · Storyboards · Web pages · X11 apps · Support
expect is checked. A demo that no longer matches the app
stops, and --artifacts saves the screen it stopped on.<picture> element like the one above.Hand-recorded demos go stale the day the interface changes, take a steady hand to redo, and are never quite the same twice. Terminal tools have VHS for this. Desktop apps, and projects that are part terminal, part GUI, have had nothing comparable. matinee is one storyboard format and one command for both.
Like infrastructure as code, the demo is rebuilt rather than patched by hand. Reproducible means the same steps, performed the same way, with their outcomes checked. It does not mean byte-identical GIFs: live time labels, live sites, and font rendering vary from run to run.
matinee runs on Linux with unprivileged user namespaces (on Ubuntu, see
kernel.apparmor_restrict_unprivileged_userns). It also needs what any desktop
that runs GTK or Qt already has: dbus-daemon, at-spi2-core, libpixman, and
libxkbcommon.
Download the latest release for x86_64 Linux (glibc 2.35 or newer):
base=https://github.com/RagingRedRiot/matinee/releases/latest/download
curl -fLO "$base/matinee-x86_64-linux.tar.gz" -O "$base/matinee-x86_64-linux.tar.gz.sha256"
sha256sum -c matinee-x86_64-linux.tar.gz.sha256
tar -xzf matinee-x86_64-linux.tar.gz matinee
install -D -m 755 -t ~/.local/bin matinee
Or build from source with Rust 1.87 or newer:
git clone https://github.com/RagingRedRiot/matinee
cd matinee
cargo install --path . --locked
Two dependencies are optional. Stories that opt into network access need
pasta, from the passt package, and apps launched with x11 = true need
Xwayland. Where user namespaces are not allowed, such as some CI runners,
--no-isolation runs stories on the host: they still get a fresh home,
environment, display, and buses, but can read your files and use the network.
A storyboard launches the app, then plays scenes of steps. This one, trimmed
from examples/calculator, clicks through a sum in
GNOME Calculator and checks the answer:
[demo]
output = "calculator"
size = [800, 600]
[launch]
app = "gnome-calculator"
wait_for = "="
[[scene]]
caption = "Click the buttons"
steps = [
{ click = "7" },
{ click = "+" },
{ click = "8" },
{ click = "=", hold = "1s" },
{ expect = "15", role = "text box" },
]
matinee check demo.toml # read the storyboard and report mistakes, without running it
matinee run demo.toml # perform it and check every step, without recording
matinee run --view demo.toml # the same, watching the session and camera in a window
matinee record demo.toml # perform it and write calculator-light.gif and calculator-dark.gif
matinee record # record every storyboard under this folder
When a step can't find its target, matinee probe demo.toml lists the windows
and the controls steps can name in them. STORYBOARD.md covers
every step, the camera, and terminal stories.
matinee check demo.toml # report storyboard mistakes without running
matinee probe demo.toml # list windows and what steps can target in them
matinee run demo.toml # perform and check every step, without recording
matinee record demo.toml # perform it and write a GIF per theme
matinee record # record every storyboard under this folder
matinee snapshot demo.toml shot.png # a picture of the screen once it settles
matinee shell demo.toml # a shell inside the isolated session the demo gets
--view # run, record: watch the session and camera in a window
--artifacts <dir> # run, record: save a still at each check, and the failed screen
--fixed-too # record: also write a fixed-camera GIF per theme
--no-isolation # run on the host where user namespaces are unavailable
![]() calculator: clicks and typing in GNOME Calculator | ![]() terminal: a staged gh command backed by a fixture |
![]() mixed: a terminal pane below an app window | ![]() cued: a release pipeline with a loop, a rollback, and a success |
More in examples/:
--view, and the viewport shows that
run with its camera outlined.The callboard, cued, and matinee examples need those projects built in checkouts beside this one.
matinee runs each demo in an isolated session so that personal and identifying details about you and your machine cannot end up in a recording: your files, home folder, user and host names, other apps' windows, open sessions, and logins. A demo shows only the project and what the storyboard sets up.
The isolation is not a sandbox for running untrusted or dangerous software. Do not use matinee to detonate malware or contain anything malicious. It is not built or tested to withstand a program trying to escape, and it would not hold up as a safety net.
| Storyboards | Writing and checking a demo: sessions, launches, steps, assertions, the camera, and output |
| Web pages | Recording a live site through a browser, with tested launch flags for Firefox, Chrome, Vivaldi, and Brave |
| X11 apps | Tk, Motif, and Qt apps through Xwayland, and Qt 5 accessibility on Wayland |
| Agent skill | Teaches an AI agent to write storyboards and run the check, probe, run, and record loop |
| Support | Which toolkits and themes are verified, and the evidence behind each |
| Vision | Philosophy, goals, and what comes later |
| Build decisions | Working contracts, experiment results, and the architecture |
Linux x86_64 is the validated platform. See the release notes for what each version changed. Video output and crates.io publication are deferred.
Bug reports, focused fixes, example storyboards, support evidence for more toolkits, and documentation improvements are welcome, including AI-assisted contributions. Read the contribution guide for checks, submission guidance, and review expectations. If something from your machine shows up in a session or recording, follow the security policy and report it privately.
cargo fmt --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked
cargo test --locked -- --ignored --test-threads=1 # integration tests that need GTK, Xwayland, and pasta
CI runs these on every pull request, then records the terminal, calculator,
and mixed examples in both themes and saves the recordings, stills, and visual
differences for review. controls.yml holds back a pull request that changes
workflows, scripts, build files, the isolation boundary, or existing tests
until a maintainer applies the reviewed-controls label. The
contribution guide covers reviewing
recordings locally.
Releases are cut from the Actions tab, and pull requests never change the
version. Notes for the next release collect under ## Unreleased in
CHANGELOG.md. Prepare release bumps the version to the next
patch, minor, or major on a release/vX.Y.Z branch, dates those notes, and
links to a pull request for it. Merging that pull request makes Publish
release tag the commit and start the release build, which checks that the
binary performs a story in a real isolated session before attaching it to a
GitHub release with the notes.
README demos that keep up with your app.
Write the demo once as a script. matinee performs it against the real program, with seeded data and checked steps,
and records light and dark GIFs with a camera that follows the action. Terminals, desktop apps, or both, on Linux.
Install · Quick start · Examples · Storyboards · Web pages · X11 apps · Support
expect is checked. A demo that no longer matches the app
stops, and --artifacts saves the screen it stopped on.<picture> element like the one above.Hand-recorded demos go stale the day the interface changes, take a steady hand to redo, and are never quite the same twice. Terminal tools have VHS for this. Desktop apps, and projects that are part terminal, part GUI, have had nothing comparable. matinee is one storyboard format and one command for both.
Like infrastructure as code, the demo is rebuilt rather than patched by hand. Reproducible means the same steps, performed the same way, with their outcomes checked. It does not mean byte-identical GIFs: live time labels, live sites, and font rendering vary from run to run.
matinee runs on Linux with unprivileged user namespaces (on Ubuntu, see
kernel.apparmor_restrict_unprivileged_userns). It also needs what any desktop
that runs GTK or Qt already has: dbus-daemon, at-spi2-core, libpixman, and
libxkbcommon.
Download the latest release for x86_64 Linux (glibc 2.35 or newer):
base=https://github.com/RagingRedRiot/matinee/releases/latest/download
curl -fLO "$base/matinee-x86_64-linux.tar.gz" -O "$base/matinee-x86_64-linux.tar.gz.sha256"
sha256sum -c matinee-x86_64-linux.tar.gz.sha256
tar -xzf matinee-x86_64-linux.tar.gz matinee
install -D -m 755 -t ~/.local/bin matinee
Or build from source with Rust 1.87 or newer:
git clone https://github.com/RagingRedRiot/matinee
cd matinee
cargo install --path . --locked
Two dependencies are optional. Stories that opt into network access need
pasta, from the passt package, and apps launched with x11 = true need
Xwayland. Where user namespaces are not allowed, such as some CI runners,
--no-isolation runs stories on the host: they still get a fresh home,
environment, display, and buses, but can read your files and use the network.
A storyboard launches the app, then plays scenes of steps. This one, trimmed
from examples/calculator, clicks through a sum in
GNOME Calculator and checks the answer:
[demo]
output = "calculator"
size = [800, 600]
[launch]
app = "gnome-calculator"
wait_for = "="
[[scene]]
caption = "Click the buttons"
steps = [
{ click = "7" },
{ click = "+" },
{ click = "8" },
{ click = "=", hold = "1s" },
{ expect = "15", role = "text box" },
]
matinee check demo.toml # read the storyboard and report mistakes, without running it
matinee run demo.toml # perform it and check every step, without recording
matinee run --view demo.toml # the same, watching the session and camera in a window
matinee record demo.toml # perform it and write calculator-light.gif and calculator-dark.gif
matinee record # record every storyboard under this folder
When a step can't find its target, matinee probe demo.toml lists the windows
and the controls steps can name in them. STORYBOARD.md covers
every step, the camera, and terminal stories.
matinee check demo.toml # report storyboard mistakes without running
matinee probe demo.toml # list windows and what steps can target in them
matinee run demo.toml # perform and check every step, without recording
matinee record demo.toml # perform it and write a GIF per theme
matinee record # record every storyboard under this folder
matinee snapshot demo.toml shot.png # a picture of the screen once it settles
matinee shell demo.toml # a shell inside the isolated session the demo gets
--view # run, record: watch the session and camera in a window
--artifacts <dir> # run, record: save a still at each check, and the failed screen
--fixed-too # record: also write a fixed-camera GIF per theme
--no-isolation # run on the host where user namespaces are unavailable
![]() calculator: clicks and typing in GNOME Calculator | ![]() terminal: a staged gh command backed by a fixture |
![]() mixed: a terminal pane below an app window | ![]() cued: a release pipeline with a loop, a rollback, and a success |
More in examples/:
--view, and the viewport shows that
run with its camera outlined.The callboard, cued, and matinee examples need those projects built in checkouts beside this one.
matinee runs each demo in an isolated session so that personal and identifying details about you and your machine cannot end up in a recording: your files, home folder, user and host names, other apps' windows, open sessions, and logins. A demo shows only the project and what the storyboard sets up.
The isolation is not a sandbox for running untrusted or dangerous software. Do not use matinee to detonate malware or contain anything malicious. It is not built or tested to withstand a program trying to escape, and it would not hold up as a safety net.
| Storyboards | Writing and checking a demo: sessions, launches, steps, assertions, the camera, and output |
| Web pages | Recording a live site through a browser, with tested launch flags for Firefox, Chrome, Vivaldi, and Brave |
| X11 apps | Tk, Motif, and Qt apps through Xwayland, and Qt 5 accessibility on Wayland |
| Agent skill | Teaches an AI agent to write storyboards and run the check, probe, run, and record loop |
| Support | Which toolkits and themes are verified, and the evidence behind each |
| Vision | Philosophy, goals, and what comes later |
| Build decisions | Working contracts, experiment results, and the architecture |
Linux x86_64 is the validated platform. See the release notes for what each version changed. Video output and crates.io publication are deferred.
Bug reports, focused fixes, example storyboards, support evidence for more toolkits, and documentation improvements are welcome, including AI-assisted contributions. Read the contribution guide for checks, submission guidance, and review expectations. If something from your machine shows up in a session or recording, follow the security policy and report it privately.
cargo fmt --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked
cargo test --locked -- --ignored --test-threads=1 # integration tests that need GTK, Xwayland, and pasta
CI runs these on every pull request, then records the terminal, calculator,
and mixed examples in both themes and saves the recordings, stills, and visual
differences for review. controls.yml holds back a pull request that changes
workflows, scripts, build files, the isolation boundary, or existing tests
until a maintainer applies the reviewed-controls label. The
contribution guide covers reviewing
recordings locally.
Releases are cut from the Actions tab, and pull requests never change the
version. Notes for the next release collect under ## Unreleased in
CHANGELOG.md. Prepare release bumps the version to the next
patch, minor, or major on a release/vX.Y.Z branch, dates those notes, and
links to a pull request for it. Merging that pull request makes Publish
release tag the commit and start the release build, which checks that the
binary performs a story in a real isolated session before attaching it to a
GitHub release with the notes.