From Terminal to SVG - Arthur Dick

Monday, August 11th, 2025

If you've ever tried to explain how a command-line tool works, you know the struggle. A static screenshot is worth a thousand words, but it often fails to capture the interactive, dynamic nature of the terminal. A full-blown video recording or a GIF can do the trick, but they come with their own set of problems: large file sizes, blurry text, and no way for the viewer to pause and inspect the content.

I recently found myself in this very predicament. I was putting the finishing touches on a personal project I've been using for years, a command-line task manager called Perennial Task. It's a simple, file-based tool I built to help me manage recurring responsibilities, those tasks that, like the name suggests, come back recurringly. I wanted to showcase its features in the README file on GitHub, but I felt that a simple block of text wouldn't do it justice. I needed something better.

That's when I had an idea: what if I could record my terminal session and play it back as a lightweight, crisp, and interactive animation? This led me down a rabbit hole, and after a lot of tinkering, I’m excited to introduce my solution: term-to-svg.

What is term-to-svg?

term-to-svg is a command-line tool that records your terminal sessions and converts them into animated Scalable Vector Graphics (SVG) files. Unlike GIFs, which are raster-based and can become pixelated, SVGs are vector-based, which means they look sharp at any resolution, have incredibly small file sizes, and can even be styled and manipulated with CSS and JavaScript.

In short, term-to-svg allows you to create beautiful, high-fidelity animations of your terminal sessions that are perfect for embedding in documentation, blog posts, or anywhere on the web.

Features

I designed term-to-svg to be both powerful and easy to use. Here are some of its key features:

How it Works

The process is simple. First, you record your terminal session using the standard script command with the --timing flag:

script --timing=rec.time rec.log

Then, you perform whatever actions you want to record in the new subshell that appears. When you're done, just type exit.

Finally, you use term-to-svg to convert the two generated files (rec.log and rec.time) into an animated SVG:

./term-to-svg -t rec.log -i rec.time -o output.svg

And that's it! You now have a beautiful, animated SVG of your terminal session.

Why I Built This

As I mentioned, the initial spark for term-to-svg came from my work on Perennial Task. Perennial Task is a command-line tool for people who want a simple, local-first way to manage their tasks, especially the recurring ones. All tasks are stored as individual XML files that you own and control. It has features like flexible rescheduling, task prioritization, and both interactive and non-interactive modes. I needed a way to show how all of this worked, not just tell. Now, with term-to-svg, I can create demos like this one:

Terminal Session Recording user@devvm:~$ # start in the past to make date diffenrences clearuser@devvm:~$ sudo date -s !"2000-01-01"[sudo] password for user: Sat Jan 1 12:00:00 AM MST 2000user@devvm:~$ prn helpPerennial Task - A simple command-line task manager.Usage: prn [command] [argument]Commands: create Interactively or non-interactively create a new task. edit [task_file] Edit a task. Select from a list or specify a file. complete [task_file] Mark a task as complete. describe [task_file] Show a detailed description of a task. history [task_file] Show the full completion history of a single task. report [date] Show a report of all due and upcoming tasks. help [command] Show this help message, or help for a specific command. version Display the application version.user@devvm:~$ user@devvm:~$ user@devvm:~$ prn createNotice: A new configuration file has been created at '/home/user/.config/perennial-task/config.ini'.--- Create a New Task ---Enter the task name: Buy a new domain nameSelect task type: (n) Normal (a simple, one-off task) (s) Scheduled (a task with a due date that may repeat)Enter your choice: nEnter priority (e.g., -2, 0, 10), press Enter for default (0): 5Success! Task file created at: /home/user/.config/perennial-task/tasks/buy_a_new_domain_name.xmluser@devvm:~$ prn create--- Create a New Task ---Enter the task name: Water the plantsSelect task type: (n) Normal (a simple, one-off task) (s) Scheduled (a task with a due date that may repeat)Enter your choice: sEnter due date (YYYY-MM-DD): 2000-01-07Does this task reschedule automatically? (y/N): yReschedule interval (e.g., '30 days', '1 month'): user@devvm:~$ # move time forward a few days7 daysReschedule from?user@devvmuser@devvmuser@devvm:::~~~$ $ $ s##ul denoto 'wds a jtgueom p-p sat so"t 2 t0th0he0e - b0di1ul-el0 '4ds"a tdeu ef odra tweatering the plants (d) From its previous due date (for fixed schedules like rent)Tue Jan 4 12:00:00 AM MST 2000user@devvmuser@devvm::~~$ $ ssuuddoo ddaattee --ss ""22000000--0011--0185"" (c) From its completion date (for flexible tasks like cleaning the gutters)user@devvm[sudo] password for user: [sudo] password for user: :~$ Enter your choice: user@devvmSat Jan 8 12:00:00 AM MST 2000Sat Jan 15 12:00:00 AM MST 2000:~$ pron rceportPreview days in advance? (optional, press Enter to skip): --- Task Report ---user@devvmuser@devvm::~~$ $ pprrnn rceopmoprltete /home/user/.config/perennial-task/tasks/3pay_monthly_sEnter priority (e.g., -2, 0, 10), press Enter for default (0): ---------------------- Task Report ---erver_bill.xml Success! Task file created at: /home/user/.config/perennial-task/tasks/water_theUPCOMINGOVERDUETask 'Pay monthly server bill' was completed on 2000-01-15.: Water the plants (was due 1 day ago): Water the plants (due in 3 days)_plants.xmluser@devvmuser@devvmTask has been rescheduled to 2000-02-15.::~~$ $ pprrnn ccoommppllete ete/home/user/.config/perennial-task/tasks/water_the_plauser@devvm--- Complete a Task ---nts.xml Task file for 'Pay monthly server bill' updated successfully.:~$ prn create --name "Pay monthly server bill " --due 2000-01-15 --reschedule---- Complete a Task ---user@devvminterval :~$ # w"e1 cmaonn tehd"i t- -ar etschedule-askfrom due_date --priority 10--- Creating New Task (Non-Interactive) ------ Select a task to complete --- Filter: ReportableTask 'Water the plants' was completed on 2000-01-08.user@devvm:~$ prn edit /home/user/.config/perennial-task/tasks/pay_monthly_serveSuccess! Task file created at: /home/user/.config/perennial-task/tasks/pay_month [2] Water the plantsTask file for 'Water the plants' updated successfully.--- Editing Task (Non-Interactive) ---ly_server_bill.xmlEnter #, (f)ilter, (q)uit: user@devvmDue date set to: 2000-02-01:~$ prn report1user@devvmTask 'Buy a new domain name' has been marked as complete on 2000-01-04.--- Task Report ---:~$ user@devvmTask file for 'Buy a new domain name' updated successfully.-------------------Success! Task file updated at: /home/user/.config/perennial-task/tasks/pay_month:~$ user@devvmuser@devvmNo tasks to report on at this time.ly_server_bill.xml::~~$ $ p#r nn orwe ptohret report should look different--- Task Report ---user@devvmuser@devvmuser@devvm:::~~~$ $ $ pcrlne arreport---------------------- Task Report ---user@devvm:~$ prn describe /home/user/.config/perennial-task/tasks/pay_monthly_sDUE TODAY-------------------erver_bill.xml : Buy a new domain nameuser@devvmUPCOMING--- Describe a Task ---: Water the plants (due in 3 days):~$ clearDUE TODAY---------------------- Complete a Task ---: Buy a new domain name [1] Buy a new domain nameTask has been rescheduled to 2000-01-15.r_bill.xml --set-due 2000-02-01user@devvmTask: Pay monthly server bill:~$ clearType: ScheduledPriority: 10Details: Due on 2000-02-01.Reschedule: Automatically, every 1 month.Basis: Calculated from the due date.Status: Due in 17 days.History: 1 completion logged.user@devvm:~$ prn history /home/user/.config/perennial-task/tasks/pay_monthly_server_bill.xml --- Task Completion History ---History for task: Pay monthly server bill------------------------- 2000-01-15------------------------user@devvm:~$ user@devvm:~$ prn report--- Task Report ----------------------DUE TODAY: Water the plantsuser@devvm:~$ user@devvm:~$ user@devvm:~$ # thanks for watching!user@devvm:~$ logout 0.00s / 382.19s

Give it a Try!

I'm really happy with how term-to-svg turned out, and I hope you'll find it as useful as I do. It’s open-source and licensed under the MIT License, so you're free to use and modify it as you see fit. You can find the source code and more detailed installation instructions on the GitHub repository.

I can't wait to see what you create with it!

Tags: software developmentcommand line

← Perennial Task Just Got More FlexibleBlog Index ↑