4x smaller, 50x faster Published on 22 Nov 2021 by Marcin Kulik

It’s been a while since asciinema-player 2.6 was released and a lot has changed since. Version 3.0 is around the corner with so much good stuff, that even though it’s not released yet, I couldn’t wait any longer to share.

Long story short: asciinema-player has been reimplemented from scratch in JavaScript and Rust, resulting in 50x faster virtual terminal interpreter, while at the same time, reducing the size of the JS bundle 4x.

You may wonder what prompted the move from the previous ClojureScript implementation. As much as I love Clojure/ClojureScript there were several major and minor problems I couldn’t solve, mostly around these 3 areas:

Btw, special shout out to Ryan Carniato, the author of SolidJS, for focusing on speed and simplicity, while not compromising on usability. Thanks Ryan!

Now, on top of all the above, I had fun building terminal control sequence interpreter in Rust, using excellent resource for that - Paul Williams' parser for ANSI-compatible video terminals. Special shout out to Paul Williams!

But back to speed. It used to be good enough, which is no longer good enough for me. The old player used to be sufficiently fast for probably 90% of the recordings people host on asciinema.org. It exercised many types of optimizations, like memoization (trading memory for CPU time) and run-ahead (which used a lot of memory by precomputing terminal contents for each future frame).

At first I planned to implement the terminal emulation part in Rust without any optimizations, just write idiomatic Rust code, then revisit the tricks from the old implementation. The initial benchmarks blew my mind though, showing that spending additional time on optimizing the emulation part is absolutely unnecessary.

The numbers show how many megabytes of text the terminal emulator can process in each player version (tested on Chrome 88):

recording v2.6 (MB/s) v3.0 (MB/s) ratio
https://asciinema.org/a/20055 0.61 35.41 58x
https://asciinema.org/a/153907 0.33 24.27 73x
https://asciinema.org/a/44648 0.51 26.81 52x
https://asciinema.org/a/117813 0.82 37.73 46x
https://asciinema.org/a/325730 0.58 26.13 45x

50 times faster on average!

Note that the above benchmark represents the speed of text stream parsing (including control sequences), as well as updating emulator’s internal, virtual screen buffer. This has been the bottleneck in the previous implementation of the player. The benchmark doesn’t measure rendering of the buffer to the actual screen (DOM), therefore the rendering speed improvements coming from React.js->SolidJS transition are not included here. However, SolidJS has been benchmarked against React.js and other libs many times already, so I didn’t bother proving it’s faster.

I still thought I may need to implement some form of terminal state snapshot/restore to support the “seeking” feature. This feature requires feeding the terminal emulator with the whole text stream between the current position and the desired position, or in the worst case when you’re seeking back, feeding the emulator with the whole text from the very beginning of the recording up to the desired position. Optimizing this could be done, for example, by keeping snapshot of the terminal emulator state at multiple time points, sort of like having key-frames every couple of seconds. In ClojureScript implementation this came for free, thanks to the immutable data structures. In the new JS+Rust implementation this would have required extra work, but it turned out, that’s not needed either - clicking on the progress bar in the new player, to jump to the desired time in the recording, results in instantaneous jump, even when it has to feed the emulator with megabytes of data to parse and interpret.

Other than the speed and size improvements, the new version of the player brings more nice things, like automatic scaling of the player to fill its container (as seen above), as well as WebSocket and custom “drivers”. More on these in the upcoming posts.

Archival of unclaimed recordings Published on 30 Dec 2018 by Marcin Kulik

Since asciinema’s inception in 2012 there were over 200,000 asciicasts uploaded to asciinema.org 🎉😻.

As of today (end of 2018) there are ~85,000 unclaimed recordings, which are ones that have been uploaded by anonymous users, who never linked their installation to their asciinema.org account.

Most of these unclaimed recordings are “abandoned” (recorded, watched once, forgotten), therefore we’re going to archive them, and enable daily auto-archival (related PR) on asciinema.org soon.

What’s auto-archival?

The idea behind this feature is to automatically “garbage collect” all unclaimed recordings. It will ensure the recordings that are preserved are linked to real user accounts, and these users can potentially be reached by email (abuse reports etc). This will eventually also clean up the storage (save some bucks on hosting).

How does this affect me?

If you haven’t linked your local installation to asciinema.org account (via asciinema auth command), on each upload you’re going to see this message printed in the terminal:

View the recording at:


This installation of asciinema recorder hasn't been linked to any asciinema.org
account. All unclaimed recordings (from unknown installations like this one)
are automatically archived 7 days after upload.

If you want to preserve all recordings made on this machine, connect this
installation with asciinema.org account by opening the following link:


Archived recordings won’t be deleted, they’ll be hidden from listings and inaccessible via direct link. Actual removal from database and file store will happen some time after archival, but probably not sooner than few weeks/months after archival. For the time being we’re gonna keep them for a while, and figure out what’s a reasonable TTL for pruning them.

Schedule for enabling auto-archival on asciinema.org

The above warning message is already active on asciinema.org, however actual archival is not enabled yet. We’re planning to enable archival on 31st January 2019. On that day all existing unclaimed recordings will be archived, and all new ones that are not claimed within 7 days from upload will be auto-archived (daily).

How can I make sure I don’t lose my recordings?

First thing to do is to run asciinema auth today, to link your installation to asciinema.org account (especially if you have embedded your recordings in a place like your project documentation, publicly shared slide deck etc).

Linking your installation to online account will ensure no recording uploaded from this machine will be subject to archival. It will not un-archive already archived recordings, but it will prevent archival of the already uploaded ones which are less than 7 days old.

If after doing the above you don’t see the recording(s) on your profile page then most likely they were uploaded from a different machine (or different local system account). More about this here. In such case send email to admin@asciinema.org and we’ll help you restore it.

2.0 Published on 18 Feb 2018 by Marcin Kulik

I’m very happy to announce the release of asciinema 2.0!

It’s been 3 years since 1.0 (time flies!), and during this period many ideas have been brought to life through series of minor releases. This time the scope and importance of the changes required major version bump.

Below we’ll go through all the changes in detail, you can also read the CHANGELOG for a shorter version.

asciicast v2 file format

asciinema 2.0 saves recordings in new asciicast v2 format. It’s based on newline-delimited JSON spec, and enables incremental writing and reading of the recording.

It solves several problems which couldn’t be easily fixed in the old format. Mainly:

Due to file structure change (standard JSON => newline-delimited JSON) version 2 is not backwards compatible with version 1. Support for v2 recordings has already been added in asciinema web player (2.6.0) and asciinema server (v20171105 tag in git repository). These will handle both v1 and v2 playback nicely, older versions of the recorder, player and server won’t be able to play v2 recordings though.

asciinema.org is now running the latest server and web player code and thus it fully supports this new format.

Terminal-to-terminal streaming

Previous versions of asciinema supported in-terminal playback by piping in the recording to its stdin:

cat /path/to/asciicast.json | asciinema play -
ssh user@host cat asciicast.json | asciinema play -

While useful in some scenarios, the whole recording had to be read into memory before starting the playback (you can’t easily parse JSON partially). New format, being stream friendly, allows starting the playback immediately after receiving the header line.

For example, you can now do terminal-to-terminal streaming via a named Unix pipe:

mkfifo /tmp/demo.pipe

# viewing terminal
asciinema play /tmp/demo.pipe

# recording terminal
asciinema rec /tmp/demo.pipe

Or stream terminal over the network with netcat:

# viewing terminal (hostname: node123)
asciinema play <(nc -l localhost 9999)

# recording terminal
asciinema rec >(nc node123 9999)

With new --raw recording mode (more on that below) you don’t even need asciinema installed on the viewing machine:

# viewing terminal (hostname: node123)
nc -l localhost 9999

# recording terminal
asciinema rec --raw >(nc node123 9999)

Appending to existing recording

You can now append new session to an existing asciicast file. This can be useful when you want to take a break when recording.

Start recording:

asciinema rec demo.cast

When you need a break, press <ctrl+d> to finish recording. Then when you’re ready to continue run:

asciinema rec --append demo.cast

You can do this as many times as you want.

Raw recording mode

You can now save raw stdout output, without timing information or other metadata, to a file:

asciinema rec --raw output.txt

The output file produced in this case is not in asciicast format, and is exactly like the one produced by script command (without timing file).

You can then use cat to print the result of the whole session:

cat output.txt

Stdin (keystroke) recording

Stdin recording allows for capturing of all characters typed in by the user in the currently recorded shell:

asciinema rec --stdin demo.cast

This may be used to display pressed keys during playback in asciinema-player (not implemented yet!). Because it’s basically a key-logging (scoped to a single shell instance), it’s disabled by default, and has to be explicitly enabled via --stdin option.

Pausing playback

When replaying the asciicast in terminal with asciinema play demo.cast, you can now press space to pause/resume. When paused, you can use . (dot key) to step through the recording, a frame at a time, which can be very useful during presentations! And, as before, ctrl+c will exit.

New cat command

While asciinema play <filename> replays the recorded session using timing information saved in the asciicast, asciinema cat <filename> dumps the full output (including all escape sequences) of the recording to a terminal immediately.

When you have existing recording, this command:

asciinema cat existing.cast >output.txt

produces the same result as recording raw output with:

asciinema rec --raw output.txt


I’m especially happy about the first class support for real-time, incremental recording. It’s not only important for the features introduced with this release, but it nicely prepares the ground for other live streaming options (directly to web player, or indirectly to web player via asciinema-server). This will most likely be an area where the most focus will go in the future.

Some of the native packages have already been updated (thanks to awesome package maintainers!), the rest will hopefully follow soon. See installation docs for detailed instructions for you system.

Enjoy better terminal recording and sharing!

<asciinema-player> HTML5 element Published on 02 Oct 2016 by Marcin Kulik

We have just released asciinema web player v2.3.0. Since v2.0.0 there were two smaller releases bringing lots of improvements (see the CHANGELOG), but this one definitely deserves a post of its own.

This new version makes self-hosting of the player even simpler. Let’s see an example.


<div id="player-container"></div>
  asciinema.player.js.CreatePlayer('player-container', '/demo.json');


<asciinema-player src="/demo.json"></asciinema-player>

Awesome, right?

This is possible thanks to HTML5 Custom Elements, which allow web developers to define new types of HTML elements. New asciinema-player.js includes definition of new AsciinemaPlayer element type and its associated <asciinema-player> tag. The .js bundle also provides Custom Element polyfill which makes the new element working in browsers which don’t support this feature yet.

The element supports several attributes known from <video> element like loop, autoplay, preload, as well as asciinema-specific ones like speed, theme, font-size.

See README for a quick “getting started with self-hosting” guide and a description of all supported attributes.


1.3 aka "And Now for Something Completely Different" Published on 13 Jul 2016 by Marcin Kulik

I’m very happy to announce the release of asciinema 1.3, which is kind of a special release. It brings several bug fixes and improvements for end users, and at the same time it makes life of asciinema developers (mostly me) and package maintainers (many people!) way easier.

See CHANGELOG for a detailed list of changes, continue reading for motivation on transitioning back to Python.

Wait, what? Back to Python? Yes, asciinema 1.3 brings back the original Python implementation of asciinema. It’s based on 0.9.8 codebase and adds all features and bug fixes that have been implemented in asciinema’s Go version between 0.9.8 and 1.2.0. We’ll keep the Go implementation in golang branch, it won’t be maintained though.

While Go definitely has its strengths (easy concurrency, runtime speed, startup speed, stand-alone binary), this project didn’t really benefit from any of these (and suffered from Go’s pain points). Here is a (not exhaustive) list of things that contributed to the decision of dropping Go for Python:

asciinema recorder codebase (and feature set) is relatively small (under 900 LOC currently) so it wasn’t a big effort to port all newer features on top of the old Python implementation.

Note, that the above list applies specifically to asciinema recorder. There are great use cases for Go (like IPFS) and if I was to build system-level software, protocol implementation or any kind of network daemon (proxy for example) I’d definitely consider Go. Also, asciinema is a cli app distributed to end users. If you’re building in-house software that has to run only on single platform then many of the above points may become non-issue for you.

Anyway, it feels good to be back on Python!

2016-07-14 update: Many people raised a question: why was it ported from Python to Go in the first place? There were several reasons. First, Go’s static binaries nicely solve the packaging problem (we didn’t have that many native packages then and pip install asciinema wasn’t always reliable due to the fact that it supported both Python 2 and 3). It later appeared that majority of people prefer native packages so distributing precompiled binaries wasn’t a big win for this type of project in the end. Second, Go was initially advertised as a “systems language”, and if your program does system stuff like select/signal/ioctl then Go should be perfect, right? Well, it appears that Go excels (and was built for) slightly different things (multi-core concurrency, networking, distributed systems). It is no longer advertised as a “systems language” by its authors. Third, Go’s static type system with type inference and functions as first class citizens felt like a nice bonus. In reality, the lack of generics forces you to write lots of boilerplate and repetitive code. 20 lines of boilerplate, imperative code is not simpler and easier to understand (like some Go defendants claim) than 2 lines of higher level code because it adds noise to the essence of algorithm. When reading code you don’t need that level of granularity in most cases. Well, at least I don’t need it :) Fourth, it was interesting to apply my knowledge of this domain to a language with different qualities. I would lie if I said having fun wasn’t part of the thing.

Self-hosting Published on 06 Jan 2016 by Marcin Kulik

I’m very happy to announce version 2.0 of the asciinema web player. There are several exciting aspects of this release so let’s get straight to the point.

First, the new player directly supports asciicast v1 format. In other words, there is no need to pre-process the recording upfront, before passing it to the player. This is possible thanks to built-in terminal emulator based on Paul Williams' parser for ANSI-compatible video terminals. It covers only the display part of the emulation, as this is what the player is all about (input is handled by your terminal+shell at the time of recording anyway). Handling of escape sequences is fully compatible with most modern terminal emulators like xterm, Gnome Terminal, iTerm, mosh etc.

This is cool in itself, but the best part of it is that it enables self-hosting of the recordings on your own website, without depending on asciinema.org. If you’re not comfortable keeping your recordings on asciinema.org (“in the cloud” == “other people’s computers”), or you simply prefer to own and fully control your content, this release solves this problem for you. Just place player’s .js + .css files together with .json file of your recording in your web assets directory, and insert short <script> tag in your HTML. Take a look at README for quick start.

It’s also worth mentioning that this version of the player (including terminal emulator part) has been implemented in ClojureScript. If you were sceptical about performance of compile-to-javascript languages and/or performance of immutable data structures then this will hopefully convince you that there’s no need to worry about it. ClojureScript compiler does a wonderful job of converting high level Clojure code into highly optimized, fast JavaScript code. If it’s possible to build a performant player like this one in ClojureScript then you can build anything in ClojureScript. Look at the source if you’re curious how it looks like.

Check asciinema/asciinema-player on Github for API documentation and usage examples.


Private asciicasts Published on 11 May 2015 by Marcin Kulik

The core idea behind asciinema.org is to allow anyone to share the recording of their terminal session by simply sharing a link to your asciicast page. Since the inception of asciinema all recordings has been public. We wanted to encourage you to share your knowledge, show off your tricks, and allow others to learn from it.

It appears though that the nature of the asciicasts is often semi-private. Many of you would like to record something and share it with a selected group of people only, your team-mates for example. There were requests for private asciicasts. There were some ideas to workaround the fact that everything on asciinema.org was public. asciinema would be way more useful if it allowed you to decide if and with whom you share the recordings, wouldn’t it?

The good news is as of today all new recorded asciicasts are private by default. They get unique, secret URLs (like Github’s gists) which means you can share them with selected people as easy as before. Whoever gets the secret link can view the asciicast. Private asciicasts are not listed on the Browse page or anywhere else on the site.

Public asciicasts are still a thing though, and you can publish any of your recordings by clicking “Make public” in gear dropdown menu on an asciicast page. If you’d rather have all your new recordings public by default you can change the visibility policy on your asciinema.org account settings page.

It’s possible that next version of asciinema recorder will have -p and -P switches for asciinema rec and asciinema upload commands, which will force private (-p) or public (-P) visibility for a single asciicast, overriding the default account policy.


New ways of asciicast embedding Published on 31 Mar 2015 by Marcin Kulik

Support for embedding asciicasts just got way more awesome. See embedding docs for details, read on for examples.

Embedding on your site

In addition to the existing support for embedding full player widget on your page, you can now use image link to display a screenshot linking to your recording on asciinema.org. This is useful in places where script tags are not allowed, for example in Github README files.

You can get the embed snippets for a specific asciicast by clicking on “Embed” link on asciicast page.

Here’s an example of how the image link looks like:

Embedding on Slack, Twitter and Facebook

asciinema.org supports oEmbed, Open Graph and Twitter Card protocols now. When you share an asciicast on Twitter, Slack, Facebook, Google+ or any other site which supports one of these APIs, the asciicast is presented in a rich form (usually with a title, author, description and a thumbnail image), linking to your recording on asciinema.org.

Here’s how it looks on Slack:

And here’s my tweet including a link to the same asciicast:

1.0 Published on 13 Mar 2015 by Marcin Kulik

I’m very happy to announce the release of asciinema 1.0, which brings many long-awaited features and settles the ground for even more awesome features and improvements coming in the future.

See CHANGELOG for a detailed list of changes, continue reading for highlights of this important release.

Idle time optimization

Did you ever wish you had more powerful machine because this software compilation you’re recording takes long time? Or maybe you wanted to pause the recording process, plan your next steps, and then resume recording? If you said “yes!” to any of the above then you may like asciinema’s new option.

asciinema rec command learned new option: --max-wait. It allows limiting idle time, by replacing long pauses (terminal inactivity) with shorter ones.

You use it like this:

asciinema rec --max-wait=2

This starts recording session in which all pauses longer than 2 seconds are replaced with exactly 2 second ones.

An asciicast is worth a thousand words, so let’s compare recording with and without --max-wait. First, let’s look at the result of recording with plain asciinema rec:

Now, let’s look at the result of recording the same thing, this time with asciinema rec --max-wait=2:

Using this new option will make you look like you always know what to do next, you’re confident, and last but not least - you own a super computer that can compile the biggest project in a matter of seconds. How cool is that?

Local workflow

Another improvement to asciinema rec is its ability to save the recording to a local file.

asciinema rec demo.json

This saves the session to demo.json file. Now, you can replay it directly in your terminal:

asciinema play demo.json

Finally, if you’re happy about it and you want to share it on asciinema.org just run:

asciinema upload demo.json

Let’s see it in action:

If you don’t need to keep your recording local and just want to record and upload in one step, you can still asciinema rec without a filename.

New, simple asciicast format

Due to the fact that previous versions of asciinema recorder didn’t allow saving recordings locally, there was no stable and documented “asciicast format”.

This changes with 1.0. The file produced with asciinema rec <filename> is a simple JSON file with a strict set of attributes. The format is versioned to allow future extensions while preserving backwards compatibility. See asciicast file format version 1.

If you know how to deal with ansi escape sequences you can manually edit your recordings with a text editor, or build a tool that can post-process them.

Configuration file

There are several new options that can be set in ~/.asciinema/config file. See README for a description of all of them.

Here’s an example of setting --max-wait permanently, so you don’t need to pass it manually on each invocation of asciinema rec:

maxwait = 2


All available installation methods can be found on installation page.

Note: not all native packages may be updated yet. If you want to make sure you’re getting the latest version of asciinema download a binary for you platform here.

The future

The changes introduced in this release, in addition to being valuable by themselves, enable even more awesomeness in the future. For example, the upcoming ability to self host (yes!) your recordings (without depending on asciinema.org) wouldn’t be possible without having a way to record to a file with a well defined format.

I hope you’ll enjoy the future. Meanwhile, enjoy asciinema 1.0!

asciinema switching to Mozilla Persona for login Published on 24 Oct 2013 by Marcin Kulik

So far you could log in to asciinema using your Github or Twitter account via OAuth. The idea behind this was twofold:

Passwords are insecure, inconvenient and annoying. Inconvenience of passwords was nicely summed up by Xavier in his tweet saying “password reset is the new login”. So the OAuth flow, being very simple for the user (given he/she is already logged in at the provider), helped achieving the initial goals.

And while OAuth based login worked totally fine it made asciinema dependent on commercial vendors for no good reason. OAuth was designed for API authorization between applications, not for user authentication. asciinema doesn’t need access to user’s Github repositories nor user’s tweets. It just needs the ability to authenticate a user. Also, the assumption that everyone has either Github or Twitter account is simply wrong.

The assumption that everyone has an email address is a correct one though. E-mail is ubiquitous and everyone remembers his/her own address. Can’t we just use it as an ID on the web? Mozilla believes we can and we should. Mozilla Persona, a reference implementation of BrowserID protocol, puts the email address at the center of authentication and gives us simple, privacy-sensitive single sign-in solution.

asciinema team believes in Mozilla’s mission for promoting openness and innovation on the web, and thus we switch to Persona based authentication, replacing the existing OAuth based flow. If you have an existing asciinema account then fear not, you won’t lose access to it. When signing in just use the same email address that you assigned to your account. If you don’t remember which one you have used (or you haven’t set the email address at all) then sign in (with your preferred email address) and you’ll be given an option to locate your existing account by doing the OAuth dance for one last time.

Let us know what you think about this change. Enjoy!