Skip to content

ASCII Animation Workbench

Builds an animation of character grids from a video, a GIF, a frame-by-frame editor, moving text or a procedural effect, and exports plain frames, ANSI, asciicast v2, an animated GIF and a self-contained HTML player.

This is a workbench rather than a converter. The document is a sequence of character grids with a delay on each, and there are four ways to fill it — a video or GIF, drawing the frames yourself with the previous one showing through, moving a banner around, or one of the procedural effects — and four ways to get it out, including a real animated GIF and a single HTML file that plays it with no network at all.

🔒 Runs entirely in your browserasciiartanimationvideoterminal
Where the frames come from

Andy Sloane’s donut.c (2006): a z-buffered torus shaded by the surface normal against a fixed light.

The same seed always gives the same frames, so a result can be reproduced and re-exported identically.

Frame 1 of 1

1 frame, 0.1 s, about 7.5 kB in memory

Export
























For MP4 or WebM, save the GIF and hand it to the GIF → video tool, which already encodes with WebCodecs and muxes H.264 into MP4 and VP9 into WebM. Writing a second encoder here would be a worse copy of that one. There is no APNG export: it needs the acTL/fcTL/fdAT chunks on top of the PNG writer, and it is not built.
Frames are capped at 600 and the total grid at 2.4 million cells — about 230 MB of colour in flight. At this size that is 600 frames. Past it a phone tab is killed with no message at all, which is worse than a refusal.
asciicast v2 is JSON lines: a header object, then one [time, "o", data] array per frame. Times are absolute seconds from the start rather than per-frame delays, every frame homes the cursor and erases below it so a short frame does not leave the tail of a long one behind, and lines end with CRLF — a bare newline in raw terminal output produces the classic staircase. Implemented here from the published spec.
Frame count times grid size is where all the memory goes, so both are capped and the cap is stated rather than discovered. Conversion runs in a worker with a cancel that reaches the loop, so a 300-frame job neither freezes the tab nor keeps running after you stop it.

How to use it

  1. Watch the frame budget, not the file size

    Everything here costs frames times grid cells, and the page prints how many frames fit at the width you have chosen. Widening the output from 80 to 160 characters quarters the number of frames you can hold. The cap exists because the alternative is a phone tab being killed with no message at all.

  2. Set the delays before you export

    Each frame carries its own delay and every exporter reads it, so what you see in the preview is what the GIF and the asciicast will do. Set one frame and press “apply to every frame” for a constant rate, or leave individual frames longer to hold on a pose.

  3. Choose the export by where it is going

    asciicast v2 for asciinema and for anyone who will play it in a terminal. GIF for a chat window or a README. The HTML player for an embed — it is one file with the frames inside it and no CDN. Plain text frames if something else is going to read them.

Common questions

What is asciicast v2 and why not just a GIF?

It is the format asciinema records terminals in — JSON lines, a header object then one [time, "o", data] array per frame — and it stays *text*, so it is a few kilobytes where the GIF is a few megabytes, and the viewer can select and copy what is on screen. Implemented here from the published spec. A GIF is the right answer when the destination cannot play a terminal recording, which is most places.

The procedural effects — did you write those?

The code, yes; the techniques are older and are credited on the page. The spinning torus is Andy Sloane’s donut.c method — a z-buffer so the near surface wins, and the surface normal dotted with a fixed light to index the ramp — and the fire is the demoscene effect Fabien Sanglard documented. Plasma, the rain and the sine scroller are folklore with no single author, and are named as such. Every effect is a pure function of the frame number and the seed, so the same seed always gives the same animation.

Can I stop a long conversion?

Yes, and it actually stops. The conversion runs in a worker that checks between frames, so cancelling ends the work rather than hiding the result — which matters on a phone, where the difference is another minute of the fan running.

Feed it from

Next

These accept what this tool produces, so the result can go straight in.