# \[ANN\] Asciicast.jl

**URL:** <https://discourse.julialang.org/t/ann-asciicast-jl/107529>\
**Category:** Package Announcements\
**Created:** [December 12, 2023, 10:09pm UTC](https://discourse.julialang.org/t/ann-asciicast-jl/107529 "2023-12-12T22:09:38Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [December 12, 2023, 10:09pm UTC](https://discourse.julialang.org/t/ann-asciicast-jl/107529/1 "2023-12-12T22:09:39Z")

</div>

[Asciicast.jl](https://github.com/ericphanson/Asciicast.jl) makes it easy to include and maintain animated gifs of Julia REPL sessions in documents (like package READMEs) and in documentation.

[![Screenshot 2023-12-12 at 23.09.12](https://global.discourse-cdn.com/julialang/original/3X/a/d/ad2281fa131bba276ab9ac5ce9214245c029ade5.png)](https://ericphanson.github.io/Asciicast.jl/dev/)

With Asciicast, in Documenter docs, you can use `@cast` blocks similar to `@repl` ones. For example

````markdown
```@cast
using Pkg
Pkg.status()
1 + 1
```

````

generates and embeds an animation of the code executing. The [Documenter Usage](https://ericphanson.github.io/Asciicast.jl/dev/documenter_usage/) section of the docs shows all of the options, as well as some examples.

Likewise, in documents like READMEs, you can include blocks like

````markdown
```julia {cast="true"}
using Pkg
Pkg.status()
```

````

Then run `Asciicast.cast_document`. It will parse the document using `pandoc`, identify these blocks, execute the Julia code, generate a gif, save it to disk, then add an image link to the gif into the document, writing it back out. This makes it easy to update and maintain these gifs. The [Markdown Usage](https://ericphanson.github.io/Asciicast.jl/dev/markdown_usage/) section of the docs goes into all the details there. Also, as an aside from the animations, I think this same technique could be used to ensure README examples stay fresh, e.g. by calling something similar in the tests to execute the code.

One caveat is that we lack a precise markdown parser that maintains syntax trivia like whitespace etc, so when pandoc writes the document back out, it will effectively re-format it (in ways that should not change the rendered output, but can change the markdown file itself quite a bit).

Additionally, Asciicast.jl provides macros and other functionality to generate animations directly. They also support VSCode, to show animations in the plot pane (using the js asciinema-player, not gifs, meaning they are high resolution always).

I developed the first version of this code a few years ago to add animations to my toy package [TravelingSalesmanExact](https://github.com/ericphanson/TravelingSalesmanExact.jl#examples), but recently expanded and updated it quite a bit, and registered it in General (it can be useful as a test dependency at least). I also [tested it out on ProgressMeter.jl](https://github.com/timholy/ProgressMeter.jl/pull/289), and documented [some limitations of my approach](https://ericphanson.github.io/Asciicast.jl/dev/limitations/).

Asciicast.jl also builds on Documenter, and relies heavily on some of its internals (reusing some of it’s functionality for code parsing and execution). But perhaps it can be stable with the help of some [integration tests in Documenter](https://github.com/JuliaDocs/Documenter.jl/pull/2376).

I hope it can be useful!

---

<div class="post-metadata">

**Author:** ![Storopoli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/storopoli/32/209278_2.png) [@Storopoli](https://discourse.julialang.org/u/Storopoli)\
**Post date:** [December 12, 2023, 10:11pm UTC](https://discourse.julialang.org/t/ann-asciicast-jl/107529/2 "2023-12-12T22:11:31Z")

</div>

Wow this is awesome. Thank you!

---

<div class="post-metadata">

**Author:** ![quinnj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/quinnj/32/11_2.png) [@quinnj](https://discourse.julialang.org/u/quinnj)\
**Post date:** [December 13, 2023, 12:29am UTC](https://discourse.julialang.org/t/ann-asciicast-jl/107529/3 "2023-12-13T00:29:30Z")

</div>

Very cool!

---

<div class="post-metadata">

**Author:** ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)\
**Post date:** [December 14, 2023, 5:22am UTC](https://discourse.julialang.org/t/ann-asciicast-jl/107529/4 "2023-12-14T05:22:43Z")

</div>

Very nice! It would be cool to also emulate keystroke delay when typing input via some sort of stochastic delay.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [December 14, 2023, 8:30am UTC](https://discourse.julialang.org/t/ann-asciicast-jl/107529/5 "2023-12-14T08:30:10Z")

</div>

Nice! But from the name I thought it would be a package that converted unicode to ascii, or something, such as `α` to `a`, `ü` to `u`, etc.

I guess it works for unicode characters as well?

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [December 14, 2023, 10:45am UTC](https://discourse.julialang.org/t/ann-asciicast-jl/107529/6 "2023-12-14T10:45:19Z")

</div>

Yeah, the name comes from the [asciicast file format](https://github.com/asciinema/asciinema/blob/main/doc/asciicast-v2.md). This package mostly just generates asciicast files, then hands then off to compatible software in the `show` method or to make the gifs. Unicode should be fine.

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [December 14, 2023, 10:46am UTC](https://discourse.julialang.org/t/ann-asciicast-jl/107529/7 "2023-12-14T10:46:21Z")

</div>

I have a delay per line but not while typing each line. I think Replay.jl does something like that though. Would be cool to add!

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [December 14, 2023, 12:13pm UTC](https://discourse.julialang.org/t/ann-asciicast-jl/107529/8 "2023-12-14T12:13:57Z")

</div>

As an aside because you mention readmes, is there any way to actually keep those up to date in CI without making things really messy? That the readme is part of the repo and not a CI artifact complicates things

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [December 14, 2023, 12:26pm UTC](https://discourse.julialang.org/t/ann-asciicast-jl/107529/9 "2023-12-14T12:26:14Z")

</div>

I haven’t setup anything for that currently; in Asciicast.jl itself, I check in the tests that calling `Asciicast.cast_readme` does not change the current readme; if it does, sometimes that means I’ve changed the example, but often it means the formatting changed, so it’s not super satisfying. A better option would be to save the `.cast` files next to the gifs, then in the tests regenerate them, then compare the `.cast` files loosely (e.g. timings may be different), and fail if it seems they are stale. I started thinking about this but haven’t implemented much yet.

In terms of autogenerating the gifs in CI, one thing I can think of there is storing them on a different branch, like documenter does with github-pages, and then having the image links reference them from github on that branch, rather than a local reference. However that doesn’t help if the image links in the readme itself are out of date. (E.g. this can work if you always have 3 examples in the same order and just want the gifs to be up-to-date).

Another option is a periodic github workflow that just PRs the readme / assets directory with the contents of `Asciicast.cast_readme(MyPackage)`. That would be easy to implement at least.

Personally I don’t really mind regenerating them manually, as long as the CI only fails when they are actually stale as opposed to unrelated formatting changes in the readme.
