Skip to main content

termtosvg

Record a terminal session and get a standalone SVG animation you can drop into any web page.

No video encoding, no player to embed, no JavaScript. The output is a single vector file where the text is still text.

CI PyPI Python License

Maintained by Gabor Lepsenyi ยท gaborl.hu

Example


Why SVG

The animation above is a 26-second session at 82ร—19 characters, in 50 KB. That is one file, and the properties that come with it are not available from a screen recording:

The text is real text Readers can select, copy and search the commands in your demo. Search engines index them.
Resolution independent Vector output stays crisp on a 4K display and at any zoom level. There is no "recorded at the wrong size" problem.
Themeable after the fact Colours are CSS classes, not baked pixels. Restyle a finished animation by editing its stylesheet.
Self-contained One .svg file. No player script, no external assets, no network requests. Works from file://.
Diff-friendly enough to commit Plain XML in your repository, embedded with a relative Markdown link.

Installation

termtosvg runs on Linux, macOS and the BSDs, and requires Python 3.10 or later.

python3 -m venv .venv
source .venv/bin/activate
pip install termtosvg-ng

Three equivalent ways to run it โ€” use whichever reads best to you:

termtosvg          # the historical command name
termtosvg-ng       # matches the name you installed
python3 -m termtosvg

[!IMPORTANT] Why the install name carries -ng. The plain termtosvg name on PyPI belongs to the original author and last shipped 1.1.0 in January 2020. That release predates the removal of pkg_resources from setuptools, so on Python 3.12 and later it fails at import with ModuleNotFoundError: No module named 'pkg_resources' โ€” every command, --version included, dies immediately. termtosvg-ng is the same tool with that fixed.

The termtosvg command is kept so that existing scripts, tutorials and distro packaging continue to work unchanged. The import package is termtosvg as well.

Installing straight from source
pip install git+https://github.com/gaborini/termtosvg.git@develop
OS packages maintained by the community

These package the original termtosvg distribution, so they carry 1.1.0 and the caveat above applies to them.

OS Repository Command
Arch Linux extra/termtosvg pacman -S termtosvg
FreeBSD graphics/py-termtosvg
Gentoo media-gfx/termtosvg emerge media-gfx/termtosvg
macOS Homebrew brew install termtosvg
NixOS nixpkgs
OpenBSD graphics/termtosvg

Quick start

Start recording. You land in a subshell โ€” type as you normally would.

$ termtosvg
Recording started, enter "exit" command or Control-D to end

Leave the shell to finish:

$ exit
Recording ended, file is /tmp/termtosvg_exp5nsr4.svg

Open it in a browser to watch it, then embed it with a relative link:

![My demo](./demo.svg)

How it works

termtosvg separates capturing from drawing, which is what makes the output editable and reproducible:

                  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   your shell โ”€โ”€โ–บ โ”‚    record    โ”‚ โ”€โ”€โ–บ .cast file โ”€โ”€โ–บ โ”‚    render    โ”‚ โ”€โ”€โ–บ .svg
                  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   (asciicast v2)   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                            โ–ฒ                โ–ฒ
                                     hand-editable      SVG template
                                     timings & text     (theme + chrome)

Running termtosvg with no sub-command does both in one pass. Splitting them is useful because the intermediate .cast file is plain text: you can fix a typo, retime a pause, or re-render the same recording with a different theme without performing the session again.

termtosvg record demo.cast          # capture only
termtosvg render demo.cast out.svg  # draw, as often as you like

Because render reads the asciicast format (v1 and v2), it also renders recordings made with asciinema.

Command line reference

Three forms. The default records and renders in one go:

termtosvg [output_path] [-c COMMAND] [-D DELAY] [-g GEOMETRY] [-m MIN_DURATION]
          [-M MAX_DURATION] [-s] [-t TEMPLATE] [-v] [-h]

termtosvg record [output_path] [-c COMMAND] [-g GEOMETRY] [-v] [-h]

termtosvg render input_file [output_path] [-D DELAY] [-m MIN_DURATION]
                 [-M MAX_DURATION] [-s] [-t TEMPLATE] [-h]

Not every option applies to every form โ€” render takes its geometry from the recording, so it has no -g:

Option Default default form record render What it does
-c, --command COMMAND $SHELL, else sh โœ… โœ… โ€” Program to record, with arguments: -c 'ipython --pprint'.
-g, --screen-geometry COLSxROWS your terminal, else 80x24 โœ… โœ… โ€” Screen size to record at, e.g. 82x19.
-t, --template TEMPLATE powershell โœ… โ€” โœ… Built-in name (see below) or a path to your own template.
--theme THEME the template's own palette โœ… โ€” โœ… Override just the colours: auto to use the palette stored in the recording, a built-in name, or a path to a JSON palette.
-m, --min-frame-duration MS 1 โœ… โ€” โœ… Merge frames shorter than this. Raise it to shrink output from commands that redraw constantly.
-M, --max-frame-duration MS noneยน โœ… โ€” โœ… Clamp long pauses, so thinking time does not stall the animation.
-D, --loop-delay MS 1000 โœ… โ€” โœ… Pause before the animation loops.
-s, --still-frames off โœ… โ€” โœ… Write one SVG per frame into a directory instead of one animation.
-v, --version โœ… โœ… โ€” Print the version.
-h, --help โœ… โœ… โœ… Print usage.

ยน Unless the recording's header carries idle_time_limit, which is then used.

Durations accept a bare integer or an ms suffix โ€” -m 17 and -m 17ms are the same. output_path is optional everywhere; a temporary file is generated when it is omitted (a directory, with --still-frames).

Templates

A template supplies the colour theme, the font, any window chrome, and how the animation is driven. Pass one by name with -t:

Template Look Animation
powershell (default) Windows PowerShell palette CSS
base16_default_dark Base16 default dark CSS
dracula Dracula CSS
gjm8 Understated dark, no chrome CSS
gjm8_single_loop gjm8, plays once instead of looping CSS
gjm8_play gjm8 with a play-icon drawn over the screen CSS
progress_bar Adds a progress bar tracking the animation CSS
putty PuTTY palette CSS
solarized_dark / solarized_light Solarized CSS
terminal_app macOS Terminal.app CSS
ubuntu Ubuntu terminal CSS
xterm xterm palette CSS
window_frame Adds a terminal window frame CSS
window_frame_powershell Window frame, PowerShell palette CSS
window_frame_js Window frame with play/pause buttons JavaScript

Colours separately from chrome

A template bundles two independent things: the colour palette and the terminal chrome (window frame, play button, progress bar). --theme lets you vary the colours without authoring a template, so any palette combines with any chrome:

termtosvg render demo.cast out.svg -t window_frame --theme dracula

--theme accepts:

Value Meaning
a built-in name the palette from that template, e.g. --theme solarized_light
auto the palette stored in the recording's own header
a path a JSON file with fg, bg and palette attributes

auto is useful for recordings made with asciinema, which store the terminal's palette in the cast file. Recordings made by termtosvg record do not store one, so auto warns and keeps the template's colours.

A palette file uses the same shape as the asciicast theme object, so it can be copied straight out of a .cast header:

{
  "fg": "#839496",
  "bg": "#002b36",
  "palette": "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5"
}

Eight or sixteen colours are both accepted. With eight, the bright half is left as the template defined it rather than being guessed at.

Names are resolved in a fixed order โ€” auto, then a built-in name, then a path โ€” so an argument never means something different depending on your working directory. To load a file called dracula, write ./dracula.

Embedding, and one caveat worth knowing

Fifteen of the sixteen templates animate through pure CSS, so they play when loaded as an ordinary image โ€” including from a Markdown ![...]() in a GitHub README.

window_frame_js is the exception: its play/pause controls need JavaScript, and browsers do not execute scripts inside an SVG loaded via <img>. Embed that one with <object> or <iframe>, or link to the file directly:

<object type="image/svg+xml" data="demo.svg"></object>

Writing your own template is documented in termtosvg-templates(5). The shipped templates under termtosvg/data/templates/ are the best starting point โ€” copy one and edit its palette.

Recipes

# Record a specific program instead of a shell
termtosvg -c 'ipython --pprint' demo.svg

# Pin the geometry so the animation is not tied to your window size
termtosvg -g 82x19 demo.svg

# Tame a chatty command: coalesce sub-17ms frames, cap pauses at 2s
termtosvg -m 17 -M 2000 demo.svg

# Re-theme an existing recording โ€” no need to perform it again
termtosvg render demo.cast dracula.svg -t dracula

# Keep the chrome, swap only the colours
termtosvg render demo.cast out.svg -t window_frame --theme solarized_light

# Use the palette the recording was made with (asciinema casts store one)
termtosvg render downloaded.cast out.svg --theme auto

# Render someone else's asciinema recording
termtosvg render downloaded.cast out.svg

# Still frames, e.g. to pick a thumbnail
termtosvg render demo.cast frames/ --still-frames

# Two seconds of breathing room between loops
termtosvg -D 2000 demo.svg

Compatibility

Python 3.10 โ€“ 3.14
Operating systems Linux, macOS, FreeBSD, OpenBSD (anything with a POSIX pty)
Not supported Windows, which has no pty module. WSL works.
Dependencies pyte (terminal emulation), lxml (SVG), wcwidth (wide-character widths)

Windows shells can still be recorded โ€” the powershell template exists for styling such recordings โ€” but termtosvg itself must run on a POSIX host.

Development

make install   # editable install with dev extras
make tests     # unit tests with coverage
make lint      # ruff
make build     # sdist + wheel into dist/
make html      # regenerate the example gallery

make lint runs ruff check. The formatter is intentionally not enforced; see the note in pyproject.toml for why.

Rendering is deterministic, which makes it easy to prove a change did not alter output: render the casts in docs/examples/casts/ before and after, and compare bytes.

Bug reports and pull requests are welcome at github.com/gaborini/termtosvg.

Maintainer

Gabor Lepsenyi โ€” gaborl.hu ยท github.com/gaborini

Licensed under the BSD 3-Clause License.

Originally created by Nicolas Bedos, who wrote the recorder, the rendering engine and the template system. Copyright is retained as required by the license.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

termtosvg_ng-1.4.1.tar.gz (85.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

termtosvg_ng-1.4.1-py3-none-any.whl (86.1 kB view details)

Uploaded Python 3

File details

Details for the file termtosvg_ng-1.4.1.tar.gz.

File metadata

  • Download URL: termtosvg_ng-1.4.1.tar.gz
  • Upload date:
  • Size: 85.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for termtosvg_ng-1.4.1.tar.gz
Algorithm Hash digest
SHA256 0c35b0a62ab8c825228716f5051b771c04765ce327ffc21fcc20dd9891141e4e
MD5 ca053e20f3da975bcbd0216dddc847a1
BLAKE2b-256 a602824d27b1d0b9ed793b0138c7ee7bac66219634d3d39b24959b813a2492e2

See more details on using hashes here.

Provenance

The following attestation bundles were made for termtosvg_ng-1.4.1.tar.gz:

Publisher: release.yml on gaborini/termtosvg

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file termtosvg_ng-1.4.1-py3-none-any.whl.

File metadata

  • Download URL: termtosvg_ng-1.4.1-py3-none-any.whl
  • Upload date:
  • Size: 86.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for termtosvg_ng-1.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a725b4b575db775def9c6ca207a91f3d906ca619ab45e41a5b6ac838eeea6620
MD5 c465bf22b0da9388849a6734e048da17
BLAKE2b-256 e22770587d37f57fe7b06cb2435c7f5b4f0b07f40019b7add63d536160786ff7

See more details on using hashes here.

Provenance

The following attestation bundles were made for termtosvg_ng-1.4.1-py3-none-any.whl:

Publisher: release.yml on gaborini/termtosvg

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page