Become a Creator today!Start creating today - Share your story with the world!
Start for free
00:00:00
00:00:01
Asciinema: Terminal Recording Done Right (with Marcin Kulik) image

Asciinema: Terminal Recording Done Right (with Marcin Kulik)

Developer Voices
Avatar
0 Plays2 seconds ago

I have a theory that only bad projects get finished — good ones keep finding new things to do. Asciinema is a case in point. What started as a way to share terminal sessions with friends has, over 14 years, grown into a full suite of tools covering recording, hosting, playback, and live streaming — and been rebuilt multiple times along the way. So what does it actually take to record and replay a terminal session faithfully in a browser?

Joining us for this conversation is Marcin Kulik, Asciinema's creator. The project's architecture has passed through almost every interesting corner of software engineering: a Python recorder built around pseudo-terminals (PTY), a ClojureScript terminal emulator for the browser that hit performance limits with immutable data structures and garbage collection pressure, a move to Rust compiled to WebAssembly, a Go experiment that didn't last, and a new Rust CLI for concurrent live streaming backed by an Elixir/Phoenix server that calls Rust code via NIFs. The same Rust terminal emulator library now powers all three components — the browser player, the server, and the CLI.

If you've ever looked at those terminal animations embedded in a README and wondered what's underneath them, or if you're interested in how a passionate open-source developer navigates 14 years of language changes and rewrites, this conversation has plenty to offer.

---

Support Developer Voices on Patreon: https://patreon.com/DeveloperVoices

Support Developer Voices on YouTube: https://www.youtube.com/@DeveloperVoices/join

Asciinema: https://asciinema.org

Asciinema Docs: https://docs.asciinema.org

Asciinema CLI (GitHub): https://github.com/asciinema/asciinema

Asciinema Player (GitHub): https://github.com/asciinema/asciinema-player

Asciinema Server (GitHub): https://github.com/asciinema/asciinema-server

AVT - Rust terminal emulator library: https://github.com/asciinema/avt

vt-clj - the original ClojureScript terminal emulator: https://github.com/asciinema/vt-clj

Paul Williams' ANSI/VT100 State Machine Parser: https://vt100.net/emu/dec_ansi_parser

Rust: https://www.rust-lang.org

WebAssembly: https://webassembly.org

SolidJS: https://www.solidjs.com

Elixir: https://elixir-lang.org

Phoenix Framework: https://www.phoenixframework.org

Rustler (Rust NIFs for Elixir/Erlang): https://github.com/rusterlium/rustler

Clojure: https://clojure.org

ClojureScript: https://clojurescript.org

cmatrix: https://github.com/abishekvashok/cmatrix

Marcin Kulik on GitHub: https://github.com/ku1ik

Marcin Kulik on Mastodon: https://hachyderm.io/@ku1ik

Marcin Kulik on asciinema.org: https://asciinema.org/~ku1ik

"They're Made Out of Meat" demo: https://asciinema.org/a/746358

Kris on Bluesky: https://bsky.app/profile/krisajenkins.bsky.social

Kris on Mastodon: http://mastodon.social/@krisajenkins

Kris on LinkedIn: https://www.linkedin.com/in/krisjenkins/

---

0:00 Intro

2:28 What Is Asciinema?

4:48 How Asciinema Started

9:51 The Problem of Parsing Terminal Output

14:07 Building a Cross-Platform Recorder

17:01 Rewriting the Parser in ClojureScript

22:19 The Hidden Complexity of Terminals

29:28 Rendering Terminals in the Browser

39:47 When ClojureScript Can't Keep Up

45:28 Moving to Rust and WebAssembly

52:01 The Go Experiment

57:43 Adding Live Terminal Streaming

1:07:12 Can You Scrub Back in a Live Stream?

1:14:40 Editing Recordings

1:25:27 Outro

Recommended
Transcript

Good Projects vs Bad Projects

00:00:00
Speaker
I have a pet theory that only bad projects get finished because a bad project, right, you do it, doesn't really go anywhere. But a good project, if you build it and like it and you use it, it sparks more ideas.
00:00:16
Speaker
When you're using it, you see what's missing, you see what more you could have added. Something in your brain says, this is good, but it'd be even better if we added this or that, and off you go. Good projects have a life of their own. They have legs, and you're forced to run with them.

Introduction to ASCII Cinema

00:00:35
Speaker
And so it is with Marcin Kulik's 14-year-long project Ask Inamar. It's a project that can record and play back anything from a quick demo of how to use the command line to a live streamed coding session to an entire movie, provided that movie can be rendered in a monospace font.
00:00:56
Speaker
It's the ASCII Cinema, hence the name, and it started life as a terminal transcript program and has grown to so much more. It's a great project. I've used it for screen recordings and demos in readmes. It's really nice for that. But today we're going to look beneath the surface because it's a fascinating project to learn from. It covers data structures, rendering techniques, an astonishing number of languages. I think we cover Python, ClojureScript, Go, Rust, Elixir, and maybe some more.
00:01:29
Speaker
And it goes through a lesson that we all have to learn in the end. Don't write a parser with regular expressions.

Meet Marcin Kulik

00:01:36
Speaker
Let's get into it. I'm your host, Chris Jenkins. This is Developer Voices, and today's voice is Marcin Kulik.
00:01:54
Speaker
Joining me today is Marcin Kulik. Marcin, how are doing? Marcin Great, great. How are you? Marcin Kulik Very well. Where are you coming in from the what in the world? Marcin Kulik I'm currently based in Poland. Marcin Poland? Marcin Yes. Marcin Kulik Okay, so we're roughly in the same time Marcin Kulik

The Evolution of ASCII Cinema

00:02:11
Speaker
Indeed, yeah. Marcin Kulik smearing it out yeahp so You've been doing this project for, i think, 14 years, if my research tells me correctly. Just about right, yeah.
00:02:23
Speaker
And I think it's brilliant. There are lots of associations I have with even older projects, but we'll get into that. But maybe we should start with, you can tell us what ASCII cinema is.
00:02:35
Speaker
sure so ascii cinema ah aka askinema that's how i pronounce it um is a ah suite of of tools for recording uh sharing streaming terminal sessions uh it's something i uh I started developing, as you said, 14 years ago, and it's been my passion project since then.
00:03:06
Speaker
um And the in a nutshell, yeah it allows you to ah record your work in a terminal, ah but just by typing a command as kinema rec, which starts a new session that gets saved into a lightweight recording file.
00:03:29
Speaker
And then this recording file can then be replayed on a web ah using a custom-built Askinema player.

Challenges and Implementations

00:03:39
Speaker
ah So you can you can embed ah this player on your own website, or you can use Askinema's hosting platform ah known as Askinema Server that you can self-host or you can use the publicly available instance that I run, which is at askinema.org.
00:04:04
Speaker
um And I've seen these all around the place. I mean, on the edge of my consciousness, I have seen Gilemar playing in lots of places where it's like, oh, this is a terminal demo of something that someone wants to explain to me. And I'd never really thought about the infrastructure that goes into making that work.
00:04:24
Speaker
So maybe i yeah maybe I first have to apologize for ignoring your work under the hood. But now we can wo up for it. So I often think with these things, when I'm trying to understand things like this, I start by thinking, what's my naive implementation? How would I try and build this?
00:04:42
Speaker
But you've been working on this for so long and you've rewritten it so many times. Maybe for a change, I'll ask you, what was your naive implementation? Where did you start? Oh, okay. That's... ah That's a fun fun story. So um somewhere around 2010, 11, I was playing with this old school ah Unix command called script, ah which has a counterpart called script replay. There are two commands, script and script replay. I didn't know that.
00:05:14
Speaker
Right. yeah And so, yeah. And so on Linux, you, and yeah, I think, yeah, that was, that was at the time on Linux, you had script and script replay where you could, uh, uh, the script command, uh, captured everything that was printed out to a terminal where you were working in it.
00:05:36
Speaker
And it was producing this lightweight text file with the whole content. And it also produced additional second file that contained a timing of every event that was printed, that there was associated timing information, like what was the delay between this print and the next print and the next print. So having those two pieces of time. Time being thing that you seeing everything at once, right?
00:06:05
Speaker
Right, exactly. yeah so so um So, script replay takes those two files and replace that. And it was it was it felt like ah like magic, like seeing terminal just moves on its own, like doing those things, typing those commands.
00:06:23
Speaker
ah That felt really, like really very cool like then. and And I thought, okay, maybe... ah I can record some tutorials using that and share this these files with friends. And then I looked into how to, ah what would be the the easiest way for me to share this with people.
00:06:44
Speaker
there those but The recording files, ah created by the script command are called types... Well, yeah, typescripts. Typescript is ah is a file. Not too confused with the... Yeah, no, hopefully no one's going to sue on that one. It's probably tight. So those typescript files... So I thought, okay, I'm going to send this over, I don't know, email to a friend and ask him, okay, can you run these commands script replay path?
00:07:13
Speaker
And um that felt rather inconvenient if I want to just show someone, if people were already used to to use sending a link to YouTube, right?
00:07:24
Speaker
Yeah. um And and they thought, okay, how can I make this simpler? so So I thought, okay, I will ah maybe try to Let me look into how to replay those files in a web browser.
00:07:43
Speaker
ah so i So I spent some time like analyzing the the the file structure. It was very simple. Just mostly, ah the there are several of flavors of those TypeScript files, but If you have those this this format where you have two separate files, the first one is just the raw binary data that was printed by ah by a program, by a shell.
00:08:08
Speaker
Everything that that program printed to standard out or standard error, then it was just appended to the file raw with no extra changes. Did it not capture standard in as well?
00:08:22
Speaker
um not the it It can do in this extended format, okay but that that came later, I think. I i don't know.
00:08:33
Speaker
It can do that as well, but then you you get additional file or this or you need to use this extended format where they were the script command uses a single file,
00:08:46
Speaker
ah with some structure where it did labels different event types. ah Very similar to to what ASCII Cast file format does.
00:08:58
Speaker
m But um back to the the story. so um ah So I looked into that and it it felt like, okay, I have timing information. I have what to print and I need to interpret this, the stream of data that was captured. And this is where the the first challenge comes in ah because you can't just like take everything and just start appending it to like some div on a page and just like incrementally add to it because it's
00:09:29
Speaker
there are some control

Web Player Development

00:09:31
Speaker
sequences uh that control colors uh text colors uh cursor movement clearing of screen all sorts of yeah and someone presses delete then the appendix exactly there's like yeah the backspace character and uh and all this stuff so so uh What I needed to do was to to build some kind of ah rough ah terminal emulator that interprets the stream of data, builds a virtual a virtual buffer of characters, just like terminal has a grid of characters, and then render those resulting characters in some loop. ah
00:10:16
Speaker
ah according to the timing uh so the the original version was very rough and i didn't really implement like a proper uh control sequence parsing or like other other like it was very like hacky thing i just ah glued together a bunch of ah regular expressions that i was like matching the matching the the the text uh like each each frame uh or like each event that that happens at a at an like
00:10:52
Speaker
next, what happens next, I was matching against a series of various irregular expressions and that was how I was making sense of it. And it kind of worked. ah it's It was very rough and, ah you know, was falling on very trivial cases where you have like, where you had like not, where you have anything much more more complicated than ah just some simple typing in in the shell, then it was all falling apart.
00:11:26
Speaker
um But um but it it showed me that it can be can be done and I thought, okay, this is cool. If I can make it and like ah the the player somehow make it work reliably, And if ah if I create ah a hosting platform for it, so people can just treat it as a terminal YouTube, they will be able to share those links to those recordings. And this will be the easiest way to share the recordings.
00:11:55
Speaker
So that's how i did that anyone who wanted to be a publisher was like using the the Unix script command.
00:12:03
Speaker
Um, and uploading those files. No, no. don So, yeah so, so that was around that time. That was the very early stages. Uh, I thought that using script command just shows me the, the, the recording part, but, uh, I, uh,
00:12:21
Speaker
I had a colleague who was, i was ah i was using Linux back then, and I had a colleague who was using Mac. ah And I approached him and and I told him, hey, I have this recording, can you replay this on your machine? I was curious like how how this will look like ah in my OS native terminal. yeah yeah And he said, well, I don't have, there's no come command such ah script replay.
00:12:46
Speaker
And I was like, what do you mean? You have script, but you don't have script replay. And he said, yes. and it's and what yeah And it turned out that ah macOS ah didn't have script replay and the script commands didn't even record any timing information in the second file.
00:13:08
Speaker
It was only able to just capture the output ah with just just like ah in full, but no additional information. so script replay made no sense. I've never heard of that. Right. So now, I believe these days it changed and they upgraded script and script replay along those like 14 years. I don't remember when.
00:13:32
Speaker
um But back then it it was not there.

Enhancing Terminal Sessions

00:13:36
Speaker
Even though ah like the yeah most of like Unix, Unixy tools on, on Mac OS comes from the BSD heritage.
00:13:51
Speaker
yeah And for example, on free BSD, it was always there. The script replay was there. So someone made a decision that it's not needed anyway. So I thought, okay, well, then here's the problem. Like I need to,
00:14:10
Speaker
create my own recorder, just get inspired by how script, uh, does it. So I opened the, the script. dot C file, uh, Reddit. It's, it's not that long, actually.
00:14:23
Speaker
It's a hand, like handful of screens. Uh, And I learned how it does it. It's pretty straightforward, right? Yeah, yeah. it's ah the the domain The main thing it uses a pseudo-terminal, PTY, which is a facility in in the Unix-like systems that allows you to...
00:14:44
Speaker
to um pretty much like become man in the middle between your terminal and the programs running in it. ah So you can ah you're responsible for transferring input and output between terminal and the and your shell.
00:15:03
Speaker
ah And this is how, ah in fact, this is how TMax works, how GNU Screen works, and even SSH uses PTY, Studio Terminals. So it's all the same mechanism.
00:15:16
Speaker
um Makes perfect sense. So I thought, okay, let me let me let me ah create my own Askinema recorder for based on on this on this script C file. And ah and then I realized Python, ah which I wasn't really like a Python developer back then, but I knew it. I used it for some things.
00:15:40
Speaker
ah Python has a built-in PTY module. module in in standard library and you can you can implement a very very rough like capture of terminal session in python in probably like not more than 20 lines maybe even less using this module so i did that and it it worked and it it it worked on on on linux and on mac os and i thought okay cool so now i just need to
00:16:12
Speaker
Save that it into a file and then it I will be able to use the file with the web player. So that's ah that's the beginning pretty much. Out of curiosity, did you when you implemented the Python version, did you keep the same file format that Script was using?
00:16:29
Speaker
um Initially... I'm asking you to remember yeah details from like 12 years ago now. Yes, I think so. ah Well, it's it it was a long time ago. But ah in the very early stages, yes, I used the TypeScript. So it was like ah actually a set of two files.
00:16:47
Speaker
um Yes, ah that was the case. And then later... ah Later came the official AsciiNema's own ASCII CAS file format.
00:17:01
Speaker
Right. At some point, you must have broken away from regular expression parsing if you wanted to catch all the corner cases. Yeah, I did. at what point does it get a genuine ANSI parser?
00:17:11
Speaker
Yes. um so um i the tool, uh, was getting popular and, uh, I was getting, more and more issues from people that, uh, something renders wrong.
00:17:28
Speaker
And, and the, it It was pretty much like a lack of proper terminal emulation and and proper anee the proper stream parsing.
00:17:44
Speaker
um So I thought, okay, um
00:17:49
Speaker
I will never and make it very reliable if I will not have a proper parser there and and perform proper terminal emulation.
00:18:01
Speaker
ah And at the time, I was ah i was doing Clojure professionally. ah Okay. And ah I thought, okay, um it could be a little...
00:18:19
Speaker
fun project to just try. ah Because you can you can ah also... ah The player, the Askinema player is a front end thing, the JavaScript library.
00:18:31
Speaker
ah it ah It was always like that. So I need something that works in the in the browser. And thankfully, Clojure has a ClojureScript compiler that can a compile Clojure code into JavaScript.
00:18:47
Speaker
ah And i thought, okay, Clojure is so much pleasure to work with and dealing with data structures in Clojure is a delight.
00:19:03
Speaker
And parsing and terminal emulation, this is pretty much all just data structures and algorithms. There's like... you know you can like if If you leave the the the like the the the input part, like a keyboard part, which a skinnema player doesn't handle at all because it just replaced what what was only you know captured.
00:19:29
Speaker
ah So the player doesn't need to to handle ah with input. yeah oh wait Is this because if I type the letter A, then you don't need to record that because the screen is about to repeat the A on the output to display it back to me.
00:19:46
Speaker
Right, of course. So that's ah the system is is doing the echo thing. So this is the echo mode of ah of a terminal.
00:19:56
Speaker
which which can be ah toggled with some syscalls, terminal control, tc, set author, et cetera. Anyway, ah by default, the echo is on. So whatever gets gets inputted gets outputted automatically. So I capture what gets outputted. Yeah, that's always that mystery. Programs like... ah or any program that asks for a password, and then when you type, it doesn't print that password, those programs typically disable eco mode.
00:20:30
Speaker
ah Makes sense. And so the input goes in, no output goes anywhere. So so this is this is why ah the the player doesn't really need to to deal with the keyboard, with, with you know, um keyboard layouts, all this all those things that that are probably like projects on their own.
00:20:50
Speaker
um Yeah. And if you if you also like ah ignore the the rendering part and just stick to like ah parsing the the the stream of captured data and ah turning that into like a grid of virtual buffer of characters with their attributes, like colors, bold, text, textile, et cetera.
00:21:16
Speaker
This is just data structures. There's like no side effects, nothing. And Clojure felt like just a right fit for that. And and and that was my my weapon of choice back then. I just enjoyed it. Do you know what's really weird is you and I must have been developing EnclosureScript professionally at roughly the same point in the historical niche?
00:21:40
Speaker
Because there weren't that many Closure EnclosureScript programmers back then. I think so. That was probably the golden age of ClosureScript. Yeah, totally. Yes.
00:21:50
Speaker
um So that was around, ah for me, that well, I started looking into this like implementation of of proper ah parser and and terminal emulator Enclosure yeah in ah I don't know, 2014, 15, probably.
00:22:10
Speaker
So I thought, okay, let me just try it. Let's see like if I can do that. And what was immensely helpful was um there's ah a guy called ah Paul Williams ah who created a fantastic ah ah state diagram ah for ah like...

Terminal Emulation Complexity

00:22:31
Speaker
VT100 compatible terminals, ah where there's there's just like a big SVG file with all those like states and transitions. Like ah basically it shows you like ah what are the states the terminal is in, what are the different like modes and which bytes, by the but particular specific byte byte values trigger which transitions. So,
00:22:59
Speaker
so So Terminal is, ah people think, like okay, it's just like a grid of like just the text and and the buffer like a buffer and then pretty much and you know just just print stuff.
00:23:11
Speaker
But Terminal is like a complex state machine. It has like probably around 10 or something different modes that can be toggled with control sequences.
00:23:23
Speaker
Right. That control everything. So ah if you so toggle some ah various modes at random, the next print may just not be visible at all.
00:23:37
Speaker
You may try to print parallel and it goes nowhere because terminal is in some some ah some state that just like... Give me you some examples because we've got echo on and echo off, I'm guessing, are two modes. I can't think of any others.
00:23:52
Speaker
Right. So, um well, there there are things like, you know, if you... Obviously, things like when ah a control sequence is not properly terminated.
00:24:09
Speaker
Uh, then you, you, you open a, you started control sequence for setting the text color to red. And at the end, you need to put the character M to like execute this, like switch the, the, the foreground color for next print operation.
00:24:27
Speaker
If you forget to put that M and just start printing like hello world. then it will not, ah it it will, it will, it may, eat so it may keep ah reading those characters as a part of a control sequence, not as a text to print, for example. until so um So that's one thing. Another ah thing, if even if you like, most programs terminate control sequences because they would not do their job very well. But for example, well ah if you move the cursor to the right edge of the screen and um you flip one of the modes, like i think...
00:25:17
Speaker
there's insert mode where instead of, ah or hold on, hold on, insert, there's replace mode. There are many modes. But um one of the modes, I think it it could be the,
00:25:32
Speaker
the insert mode, basically you move the character to to the right edge of the screen, turn on the insert mode and you start, and you start, if you want to print hello and normally, uh, in a normal mode, it would just like type age and move back to the next line and, uh, and print hello.
00:25:53
Speaker
Uh, but within third mode, um, it will just start, ah
00:26:00
Speaker
like inserting the every character of the word word hello into this one single cell. So at the end, where the cursor was originally, it will stay there and you will end up with a ah letter E in it.
00:26:15
Speaker
Sorry. Hello. O, or D. If hello works, then yeah. yeah ah So there are things like that. So it's not just like ah you take the text and you just like append it somewhere. You need to be aware of all all of those different modes and how they interact with each other.
00:26:34
Speaker
um So there are different things that are also like scrolling regions. So ah programs like Vim use that, but not only vim ah Basically, the program can say, hey, from the fifth row to the 20th row, I want this to be a scrolling region.
00:26:54
Speaker
And terminal remembers, okay, I remember that. And then next time, ah Vim says, okay, please scroll that scrolling region we talked about by two lines up.
00:27:07
Speaker
And the terminal does exactly that, just scrolls only that region, leaving ah the top and the bottom parts are like intact, which is handy for Vim to like keep the status bar in place while you are scrolling inside of a buffer, for example.
00:27:25
Speaker
yeah yeah. Is that also how it does things like split windows? um
00:27:32
Speaker
It's complicated. ah Like ah horizontally horizontal splits, ah potentially that would be useful and used. ah For vertical splits, it it gets more tricky because there is some also some um
00:27:54
Speaker
very like minimal support for... like Yeah, like the vertical ah like regions. So like yeah a typical scroll region is like that.
00:28:09
Speaker
ah and then so ah But this is not really supported by by a lot of terminals. So probably they do just some some workaround or just some... old school way of doing that yeah this okay this makes your front end seem like it's going to be a lot more sophisticated than i thought because you have to your front end isn't just a player it's actually a proper terminal emulator to some degree right yeah yeah yeah exactly Exactly, that's the case. So I... ah oh First, when i started implementing that, i I implemented this library, closure library called VTCLJ.

Optimizing Performance with VTCLJ

00:28:49
Speaker
Yeah.
00:28:51
Speaker
Obviously, the name is... strengthfor time For closureists, it's an obvious name. VTCLJ. And it was just this this thing for parsing ANSI sequences and ah having like a virtual representation of ah of a screen buffer.
00:29:10
Speaker
And then i ah implemented like a front-end UI thing that takes those um those characters from the grid and renders them with different color attributes, text styling, etc.
00:29:28
Speaker
I'm curious, it what's the what's the um implementation in the DOM? Because you could do it as never-ending stream of divs, or you could do it as a table, or you could break out a canvas tag.
00:29:40
Speaker
What's the right way? um Oh, i'm I'm still searching for the right way, actually. As we speak, as we speak. Just yesterday, I was i was trying another approach. So...
00:29:52
Speaker
so ah Well, one thing is that ah from the beginning, Askinema's value add was that you can actually pause the the the playback and select the text and copy paste it.
00:30:10
Speaker
That seems useful, yeah? Yeah, because it's text after all. And ah we we are not really like... We have the source material.
00:30:21
Speaker
well never The whole text that was printed terminal, we have that in the recording so we can actually... render that as a text that can be selected and copy pasted. So that was one of the, the, the, um, priorities for me to keep that because people really enjoyed this, this, this aspect of it.
00:30:42
Speaker
Um, so, um, Initially and up until recently, it was pretty much like a HTML pre-element with ah some child elements inside of it ah with classes for text and background applied.
00:31:03
Speaker
And that was animated using a front-end library. um At the time, that there was a... you know React style like, but the, like a data oriented one ah for Clojure.
00:31:18
Speaker
was OM, one was om ah I remember. oh but I didn't use that one. There was a different one. ah RAM? RAM or something? I don't remember. ah um Anyway, yeah, that was would used like pretty much DOM elements and applying classes. Right, so the grid is kind of maintained in memory because you're rendering to a virtual grid and then sticking that in a pre-tag.
00:31:42
Speaker
yes yes yeah yeah exactly yeah so so there's always like a uh like a source of truth in in a in the memory uh memory buffer somewhere uh and then that gets uh you conveyed to to to the dome and i i did some tricks like uh only updating lines that changed and nothing more. So like instead of redrawing, like updating everything,
00:32:12
Speaker
um that those like React style libraries help with that because they can do the diffing virtual DOM and stuff. so i I'm surprised you optimized that because i wouldn't have thought the frame rate on ah replaying a terminal was high enough that you'd need to worry about performance of it.
00:32:32
Speaker
Oh yeah. ah So I didn't really worry about it. ah ah For a long time, i still don't really worry about it because 99% of recordings are chill, just typing some stuff and getting output from commands, maybe some code editing in Vim, etc. But this is not really high you know high frame rates.
00:32:58
Speaker
ah material. yeah um But people started to you know, but because the simple things worked very well and smooth, people started and started you know doing more heavy things and running recording some ah animations like Sea Matrix and Kakafire. That's the version of the film The Matrix that's done in ASCII.
00:33:27
Speaker
Yes, exactly. And you can play that back in Ask Inima. ah Yeah, yeah, yeah. Brilliant. yeah yeah We won't talk about the copyright issues. I guess. Yeah, we should probably. um so ah So people started recording various things. even There was one one person who...
00:33:45
Speaker
um ah took the stream from their webcam and fed this into through, I think, FFmpeg.
00:33:59
Speaker
or something that that can turn this into ASCII, you know, animated a version of of yeah of a video, right? And so so he did that, replayed that, like played that stream inside Terminal and recorded with Eskinima.
00:34:19
Speaker
And then and then he uploaded and it was... ah It was choppy. So, because there was like thousands of, of you know, small DOM elements being updated and then moved around ah every second. What if you have like, ah you know, ah even like 30 FPS.
00:34:43
Speaker
Yes. Source video material. There's just like... Lots of lots going on all the time. Yeah, that's what do. So that wasn't that wasn't the very performant. So I did some optimizations over the years.
00:34:59
Speaker
Tried to do some smart caching here and there. not recalculating some things. um Doing some more focused to there' screen updates and and stuff like that.
00:35:14
Speaker
I thought that this is fairly easy to test, right? Because you've got a static input file and all you have to do is play it and check that the final view looks how you expect.
00:35:26
Speaker
Is it something like that? Yeah, yeah, yeah, exactly. yeah um So when someone sends you a bug, the bug reporting must be pretty accurate. Oh, yeah. Yeah. It's very simple.
00:35:40
Speaker
Yeah, that's a big advantage. Right. Yeah. Okay. so we are ah Yeah, just about the the like the way it's kit gets rendered. So ah another approach would be to... Well, SVG is ah kind of very would be very similar in performance to like just using some native HTML elements.
00:36:04
Speaker
ah And then there's Canvas or WebGL that could be used. So i ah i play with the idea of using Canvas or WebGL for rendering the whole thing, but then I lose the native select and copy and paste support. think in this particular case, that would be a big loss, right?
00:36:27
Speaker
Yeah, I would need re-implement that. and While it wouldn't be like super hard, then it would be probably also not that good from like ah assistive technologies point of view. Yeah. um So there's a lot of, you know, things.
00:36:46
Speaker
pros and cons for choosing like how to render stuff there. But um recently i i started like changing how I render background actually, because I can do background color ah ah Typically, it's just one color.
00:37:03
Speaker
But if you have ah you know Vim with some panels or some H-top program running with all those green and and blue highlights, this is the backgrounds background color. Yeah.
00:37:17
Speaker
ah So this stuff doesn't is doesn't like take part in selection and copy-pasting, like the background color. So I can actually like i render that on the on a separate layer below the text and make the whole rendering simpler and more efficient.
00:37:37
Speaker
So I'm playing with this stuff, just trying to to to find the right. And also at the same time, there are some solutions that I could have used and would make things ah faster, a simpler, a cleaner, but ah not every browser supports everything. And that's good I must point out that Safari is ah the new IE.
00:38:07
Speaker
it's It's just like for me, it's been always like ah it works everywhere. And then in Safari, there's always some glitch, some some weird rendering problem. ah So that was and that was like holding me back because I want to support ah not just like Chrome and nothing else.
00:38:26
Speaker
um But it is it gets better year after year. I'm patient, as you as you see by Chrome. And persistent. So I'll wait like a year or two. And and some of those APIs are like improvements to to rendering that i i would love to use.
00:38:44
Speaker
will be there and then i will I will probably upgrade. So, yeah.

Transition to Rust and WebAssembly

00:38:48
Speaker
Okay. So if I'm right, we've currently, in our point in history, we've currently got a Python recorder with a ClojureScript playback system on the web.
00:38:59
Speaker
Is that still the state of play? um No, no, that is not the state of play. That was 10 years ago. So um um so ah while we're on the players' side still, so...
00:39:17
Speaker
so i I thought, okay, those ah high frame rate animations, I really want this to to to be smooth and I want to be proud of how how this player performs.
00:39:33
Speaker
how What can I do that? How can I do that? And then I first started benchmarking and profiling how ah how it performs the Clojure Script version.
00:39:47
Speaker
And what i what I discovered is that because ClojureScript uses um immutable data structures, whenever you update ah element of a list, of a vector, or of ah of a map, you are effectively not updating it in place, but creating a new map and the moving and referencing the existing elements.
00:40:15
Speaker
ah So basically the container gets like replaced. ah But this this is a memory allocation. And so if you if you take ah like animation in a terminal where the where the grid ah constantly updates.
00:40:32
Speaker
And the grid is made of of vectors, ah is a vector of vectors. And each element of the internal vector is ah is a map with a with a character and a color attribute, etc.
00:40:47
Speaker
So if you want to just change one element in some place, you need to replace the the inner vector with a new one that has it is just like one element swapped.
00:40:58
Speaker
And then that forces you to replace the whole outer like a line lines vector. ah by you know taking the the the head and the tail and then inserting the the the the the card row between them.
00:41:16
Speaker
ah Which normally when you when you do this stuff in web apps, just shuffling some data structure, it doesn't really matter. But if you if this happens in ah in an animation, it happens like...
00:41:31
Speaker
tens of thousands of times per second, ah then a browser needs to allocate a lot of new data structures yeah just for them to be ah garbage collected one millisecond later because the new cell replaced the whole, you know,
00:41:49
Speaker
Yeah, you create lot of short-lived objects. Exactly. lot of short-lived objects. and So so the the pressure on garbage collector was was huge there. So i realized back then that, okay, ClojureScript is not the best language to have like a performant terminal emulator.
00:42:12
Speaker
hyping Yeah, high frame rate animation is maybe not great. But aren't you going to have the same problem if you go to JavaScript? Yeah. um Well, not quite. ah Well, in JavaScript, you can mutate things in place.
00:42:26
Speaker
ah So ah that that's one thing. So one one problem less, not that much ah pressure on memory allocator and garbage collection.
00:42:38
Speaker
would have thought there was still some. Oh, there There is, that yeah. there is yeah Yeah. And another another reason why the player is no longer ah written in closure script was the...
00:42:53
Speaker
the size of the library itself, because closure script compiler produces huge, uh, like, uh, bundles. Uh, that's because it includes, uh, good chunk of closures standard library, like core, uh, what, what was the closure core?
00:43:14
Speaker
Well, anyway, uh, so, ah if someone wanted to use Askinema Player on this site, they had to download this JS file and i that the they downloaded from GitHub's release page that was half a megabyte in size.
00:43:34
Speaker
That was just like yeah unacceptable for people. People were like, What's going on? JavaScript cheats because people download the standard library with the browser, right? That's that's true, yeah. But then then also, like I use various Clojure libraries in it, like core async and core...
00:43:55
Speaker
core core match i think and a few others okay and this adds up and this really adds up so it it's i thought okay no this is not like not like two reasons for like finding a better solution and even though i really didn't have to because as i said like for the majority of use cases it was fast enough ah This other argument, you know, just like the size argument was like, okay, let's start thinking about alternative.
00:44:32
Speaker
um And i thought, okay, ah there's WebAssembly now, which allows me to to write very performant uh i mean to run run code very ah very efficiently at near native speeds uh i just need to compile something to web assembly and then i will be able to embed that into the js player and um
00:45:04
Speaker
And so the idea was that this the browser and some some outer shell of the player would still be written in JavaScript, but the ah parsing of of the stream and the virtual buffer ah maintenance and the whole terminal terminal state maintenance would be written in something that that will be blazing fast.
00:45:28
Speaker
So ah I chose Rust because it had very, very good story for compiling to WebAssembly. It was one of the early, ah probably the best ah the best language to use if you wanted to target WebAssembly, ah like...
00:45:50
Speaker
eight, seven years ago. Now it's it's gotten better for many languages. But back then Rust had... Yeah, it definitely seemed to lead the way on that one, didn't it? i Yeah. Yeah. So I thought, okay. And I already been like interested in in learning Rust. So I thought, okay, ah let's try. Let's see if I can reimplement that ah terminal emulator part that I had already in ClojureScript.
00:46:18
Speaker
uh interest so the domain was known to me uh uh i just needed to to to write this in a different language uh try to to be uh idiomatic uh as much as i could but um um but yeah and it turned out very well so um uh i Actually, one thing that really helped with like ah preserving the correctness of of the parser and of the terminal emulation was that ah already in that ClojureScript version, ah the the the virtual terminal library, I i had ah a comprehensive suite of property tests that were super valuable.
00:47:11
Speaker
uh because i could as assert on various invariants like uh uh the cursor uh position never goes you know uh off the edge of uh of the screen right that the number of of lines in the in the vector that holds the the current lines is never uh smaller or bigger than ah the the number of row of of rows that I maintain. ah Yeah, or there are a whole bunch of nice automated constraints. There's so many of these invariants that must hold always.
00:47:50
Speaker
so i i and then So I used ah some generatoral generator library that allowed me to generate those random and sequences of texts intermixed with ah with control sequences ah and was like asserting that everything is is good.
00:48:17
Speaker
um So that was very helpful. And I already had like a blueprint for that. So I did the same in the Rust version. Mm-hmm. so so So, yeah. so So then I said, okay, this seems to be working. i ah The ClojureScript version was player version 2.x.
00:48:40
Speaker
And the the new one ah using Rust and WebAssembly was 3.0.
00:48:48
Speaker
So that was a new new newur rendering part in a small small amount of of JavaScript and embedded virtual terminal ah inside of it.
00:49:01
Speaker
I'm curious, what did you choose for the kind of JavaScript front of the front end? um I chose SolidJS. ah Solid JS. I don't know much about that.
00:49:15
Speaker
Yeah, it's React-inspired library, but very lean and focused on performance. And this one actually, i did a but review of of bunch of options.
00:49:30
Speaker
Svelte was another option that I thought about. ah But i I specifically looked for something that doesn't use virtual DOM. ah with and neither Svelte SolidJS they don't use Futural DOM ah Typically, React and other similar libraries, they um they keep the ah virtual DOM representation in memory, and then on every update, they rebuild the whole thing and then try to reconcile it ah with the actual DOM, which is not very like efficient.
00:50:13
Speaker
wait wait It's convenient and maybe conceptually easy. for At least for for the implementers ah of of React-like library. But it's not very efficient.
00:50:25
Speaker
Sounds to me like you've already got... Because one of the advantages of React, of virtual DOMS, is you've got a logical model before you go to rendering. right It sounds to me like you've already built your own logical model of what a terminal's current state is, so why have two?
00:50:42
Speaker
uh yeah yeah but that's true yeah just to some degree yeah um and so so then i chose solid because it seemed like at small and there was uh like size was small like the library was tiny uh and it was very performant i i i tested this and and But it's it it you use it almost that just like React. So it's familiar. You can just write some. So so the like the control bar, the... the
00:51:17
Speaker
and at at the top of a player, there are some icons that you can enter full screen, et cetera. There's some some bit of a UI or Chrome, if you will. ah So this is all those those solid JS components. And then at the heart of it is it's also one one component that ah basically maps this internal representation of the of the grid into Into DOM, into like a bunch of spans and classes, CSS classes.
00:51:54
Speaker
Yeah. yeah did you Were you then tempted to go back and revisit the Python recorder?

Recorder Development in Go and Python

00:52:01
Speaker
um I did, yeah. I did. Well, that was a a small detour, actually, 2014, where I...
00:52:12
Speaker
where i I actually re re-implemented the recorder in Go. ah And there are several reasons for that, but this this expelledling this experiment ah kind of failed.
00:52:31
Speaker
I wasn't very happy with it. like I really really didn't enjoy either working with with this code base in Go, and it didn't really... like I know. I just didn't fall in love in that in this in in this in this phase of the CLI.
00:52:54
Speaker
um Okay. Well, one of the one of the priorities for me always was the easy or eat ho easy ease of ah distribution of the recorder. ah So i I tried to avoid like ah too many external dependencies. So in fact, the the the Python recorder ah The original version and the and the version that was...
00:53:21
Speaker
still current just before last ah September, this September. um It was like zero external dependencies, only Python standard library. So it could be even like, ah it was available as a pip package on PyPy. But it could just be like a downloadable single file, Python file, because it it didn't but doesn't didn't depend on anything.
00:53:50
Speaker
And I really enjoyed that, but it was also like, okay, but it would be nice to have some ah more interactive things like terminal live streaming, but I would need to to to reach for some WebSocket libraries. Also Python is not that, in my opinion, great language for doing like concurrency and like ah and the network programming, um it's It's a nice zki starter thing for, for like you know, if if you want to
00:54:26
Speaker
the proof of concept very much. I like Python a lot, but it's not what I'd reach for if I were doing concurrency. I'll definitely agree with that. Yeah, yeah. Well, you can, but it's kind of pain and suffering. Yeah. It's just like depends on how much you can take.
00:54:45
Speaker
Yeah. There are other languages that kind of go with the grain. Right, right. Yeah. yeah but so if But you weren't happy with Go. What what took you away from Go? um um Because on the surface, good concurrency. um It's got a great multi-platform deployment story, I believe.
00:55:05
Speaker
um I think at the time was ah the... the the
00:55:13
Speaker
So the practical things, ah yes, like distributing single static binary was a win. ah But I i remember there were there were constant problems with dealing with those low level system things i across different platforms, like on yeah on on Linux and FreeBSD and Mac OS.
00:55:39
Speaker
um And I think this tired me the most, probably. i thought that this will be obstructed away ah more than I thought.
00:55:50
Speaker
ah Maybe I was just used to how Python's PTY module and various other standard library modules abstracted a lot of quirks. and And back then, this was not the case with Go.
00:56:05
Speaker
um
00:56:08
Speaker
Yeah, and... I just like felt that I just don't enjoy it anymore. And and it's just like, just a constant stream of frustration.
00:56:19
Speaker
And when it's your own project, that is totally legitimate. Yeah. And, and, and, um, my, my, uh, I just also didn't enjoy the Go as a language. like i I learned ah other languages before and after that that I feel are way more um round or more cohesive and and more... well well I don't want to like bitch here on the Go. just like It's not my cavity. its It turned out that it's just like I don't want to spend my...
00:57:00
Speaker
my ah my free time ah on my passion project with a language that I don't enjoy. It doesn't spark joy, as they say. Yeah, exactly. Yeah, yeah. So I thought, okay, I have still this, this is all working Python implementation.
00:57:19
Speaker
ah which I can still like resurrect. I needed to backport a few few few new things that landed in Go version. But yeah, so then it continued as a as a Python code base.
00:57:36
Speaker
And then recently um I had this idea that I would like to implement live terminal streaming. So not only would record session and then upload file just rewatch but you will be able share a link to session and let watch it time.
00:57:55
Speaker
you would not only be able to record a session and then upload a file and just rewatch it but you will be able to um share a link to a live session and and let people watch it in in realtime ah And so I started looking how to implement

Live Streaming Innovations

00:58:14
Speaker
that. i um the The server side, the Askinema server that would be the side in this ah live streaming ah is implemented in ah Elixir ah using Phoenix Web Framework, which is fantastic.
00:58:34
Speaker
Which is fantastic as stack for the interactive things for for all the WebSocket-y things. um Yeah, I've heard that. Right. So... um So this part was already like there and waiting for, for, for clients or a common line client to connect and stream the session in real time.
00:58:55
Speaker
I just needed to find a way what's the best way to do that. And I, I looked at how to do it in Python, but i wasn't really like satisfied. And then one thing occurred to me that,
00:59:08
Speaker
ah ah I need to solve one problem for live streaming, which is when someone joins, like you send a link to ah to a live stream to someone and they join mid mid-stream, like just later.
00:59:25
Speaker
yeah i need to ah They need to to see what's ah what's currently on the screen. Not only get new updates to the screen, but just like what's currently there. So I need to so i need to preserve a state.
00:59:42
Speaker
And couldn't can snapshot what the window currently looks like. But you're not choosing to say, well, just every second I'll just send out a whole snapshot to everyone. No, no, no, no.
00:59:54
Speaker
so So the idea was that the the CLI will connect to the Ask Inama server, just just send it to the endpoint there, and then the Ask Inama server will fan out all those updates to our connected viewers.
01:00:10
Speaker
ah which is how it is implemented right now. ah But um so the server being this this this hub there could be maintaining this state.
01:00:23
Speaker
ah So when a new viewer joins, the server can send the state, which is fine. But then I wanted to make it ah more robust, uh, in a sense that, uh, what happens when, uh, there's this network disconnection between the the producer. So the CLI and the server.
01:00:47
Speaker
So I am doing some streaming, something in my terminal, like, uh, typing something in my shell. And then my internet connection goes, uh, uh, for, you know, for a moment, just for a moment.
01:01:02
Speaker
And, How should i deal with that? like what what What should be the the recovery path here? So my my idea was that ah the client, the the CLI, should be ah should be ah buffering everything or do some other smart way of like preserving the the last state.
01:01:27
Speaker
And when it reconnects, it pushes that state to the server, which can then use to just use sets its own like state for for the viewers.
01:01:39
Speaker
um Makes sense, yeah. ah And so one thing that that was really handy to have was this ah new Rust implementation of of the terminal emulator I did for the player.
01:01:57
Speaker
ah which I was able to actually use in all three components. So it is used in in the player for ah further rendering, and for for like rip for playback.
01:02:13
Speaker
um It is also used in the server, ah which... ah uses it for generating snapshots, like periodical snapshots of live streams. So the, ah so the, like a poster image is updated in like every five seconds. If you look at the person's profile and there's a section, uh,
01:02:39
Speaker
ah listing all this person's live streams that are currently ongoing. There's a thumbnail that gets like updated like every five seconds. And this is the snapshot taken by this terminal, Rust terminal administrator that lives in the Elixir server ah there.
01:02:58
Speaker
Oh, hang on. Hold on a second. How do you make that to work? How do you run a Rust program from within Elixir? Yeah, um there's a a wonderful tool called Rustler, which allows you to ah integrate Rust code into Elixir or Erlang application. So Beam, which is a virtual machine for Elixir and Erlang, it has a concept of native implemented functions, NIFs,
01:03:33
Speaker
And and ah historically, this was mostly for to support people writing like native extensions in C that they they get they get get compiled and then yeah yeah called from the Erlang code.
01:03:47
Speaker
So they do some heavy calculation and then quickly give you a result small result. um so that it was So Rustler is this library that allows you to take a ah Rust code and call it from from Elixir.
01:04:03
Speaker
ah So this is how it's done. ah the yeah Brilliant. Okay, so you've got the Rust code running on the back end, and you were about to tell me it's also got it running in in the recorder?
01:04:15
Speaker
Yes, yes. That's the that's the third final final place where where where i have that... the terminal emulator. um So ah the reason for that is ah that twofold actually, well, threefold, there are many new reasons, but but but the ah the the the end result is that I rewrote the CLI from Python to Rust because I could just embrace this terminal emulator library that I already had. And also Rust allowed me to
01:04:50
Speaker
to go you know not go crazy but but uh uh sanely approach uh uh all those uh concurrency problems that i that i have with uh um with like yeah like live streaming and WebSocket connections running in the background while in the foreground you are actually doing stuff in your terminal and Kinema recorder is not supposed to block you or print anything to your terminal or you know ah just not interfere. But in ah in in the back somewhere there's various things going on in different threads.
01:05:33
Speaker
um connections to the server, et cetera. um So yes, so the CLI version 3.0 was released in September this year.
01:05:44
Speaker
And it embraces the the terminal emulator library, and which is called AVT, by the way. AVT. And it uses it, yeah, and it uses it for a few things.
01:05:56
Speaker
ah One thing, it really helps with the like maintaining state and ah help with those... ah points in time where there's a reconnection to the server or all stuff like that. Also, the CLI has a actually two streaming modes. There is a remote mode and a local mode.
01:06:18
Speaker
So the remote mode is what we've been talking about. that It connects to the Askinema server that ah publishes it to the viewers on the internet somewhere. ah But there's a local mode where ah the CLI actually opens a local port ah ah and launches a web server, ah its own built-in web server with an embedded player.
01:06:39
Speaker
ah So you can actually share a link to to your local ah machine ah to for someone on the la on your on your own network or if you're on some VPN.
01:06:53
Speaker
that that should work as well. And then it will just go straight from the browser to your own CLI, to your own terminal and be streamed directly without like being, you know,
01:07:05
Speaker
forwarded by the proxy. I have to ask you a question for my, actually for my job here. If someone street, like is the client of a live stream, can they pause and scrub back and scrub forward and catch up?
01:07:19
Speaker
Cause I could actually use the ability to broadcast my terminal around the room quite handily. Right. Right. Uh, so now the, at the moment, uh, ah the live stream is,
01:07:32
Speaker
just just live there's no pause or rewind at the moment uh there's there's a couple of challenges like this is probably one of the major uh topics i would like to tackle in the future
01:07:50
Speaker
uh there there are few like i had like a list of major things that the project was missing and i've been like feeling like checking off the the list uh gradually and this one is probably one of the here remaining points so the the challenge here is that um uh because this is not a real video and we we can't really use existing solutions that that were ah built for for the big video use case for like buffering and other you know things around that.
01:08:30
Speaker
um I need to invent how I do buffering. I need to invent how I do i rewind and how this works. Because ah the naive naive way would be to to just ah collect every event every event session event that that got delivered over WebSocket to the player in some memory array and have it handy there. So if someone wants to rewind, stick back, I have it, I can just use that information.
01:09:05
Speaker
But ah that could potentially use a lot of memory. It really depends on how much how long is the stream, how for how long someone is planning to stream. Some streams are could run for forever, like in infinitely.
01:09:24
Speaker
I've certainly had streams running for more than a day, fairly being fairly common, yeah. Right. So right now, there's ah if you go to AskInima.org and there's a profile called AskInima,
01:09:38
Speaker
if on that profile, you will you can see that there's an ongoing live stream that streams the ASCII ah version of Star Wars Episode four And it's and it's it's streaming for two weeks in a loop pretty much right now. I started it two weeks ago. And I plan to to just keep it like up and streaming forever. so um So that's an example of of ah of a case where just buffering everything ah doesn't work. So how much would we buffer? Like last one hour or something?
01:10:11
Speaker
But then in ah those terminal events are not ah uniform in size. they are not like They don't have a constant bitrate because they really depend on how much was printed out.
01:10:26
Speaker
to a terminal so ah like for any given like change that happened so because asking a marocorder doesn't really like take snapshots every like 30 every 30 you know 30 times a second it just captures events that happen whenever they happen and the print events can happen when the program decides to print something.
01:10:51
Speaker
So for example, if, if, if I leave my shell session, like for one hour and like, just like open, uh, while recording and go for a walk and I go back, then the the the actual file size of the recording will increase by zero bytes because nothing happened that between, you know, while I was away, right? Yeah, you've got some interesting time calculations there because if you if the user were to scrub back by 35 minutes, the correct answer is absolutely nothing changed.
01:11:26
Speaker
But you've whole kind of stream of events plus stream of time model to resolve. Oh, yes. Yeah, yeah exactly. so so um So then if I wanted to like ah buff for live streams, buffer last hour,
01:11:41
Speaker
how how much entries, how much bytes is one hour. like this This really is a wrong question here. So you need a variable buffer. Yeah, okay, I can see why it's not something you can easily drop in.
01:11:53
Speaker
Right, right. So then I could just fix size buffer for like and count the bytes, and so 10 megabytes. ah I also want to be like i am considered for ah the people who actually watch those recordings on various websites or on Askinema.org or on different personal sites where people use the player.
01:12:16
Speaker
ah Because this this would take lot of memory and, you know, ah i don't want to use a few gigs of memory for just replaying text text thing, right?
01:12:29
Speaker
um So say I would use 10 megabytes for for the the buffer. So then what happens if someone wants to go back farther back? than this, right? Where do I get this information? So that there are many options. that like This is a topic for ah for a whole separate conversation that didn't can go on for yeah for for hours.
01:12:53
Speaker
I predict sometime in the future you're going to end up writing something that can store long sessions on S3 or something. Yeah, that's that's actually one of the options. um That's one of the options, just ah segmenting them and then keeping index of of segments with with like time ranges.
01:13:15
Speaker
ah this is similar The idea is similar to what HTTP live streaming does, HLS. that this This also like is... m that there's uh some some work prior work in the video space that i could uh take some inspiration from but but you can see like that it's not the most straightforward thing to to implement because you need to there are some uh know trade-offs and questions and decisions made and uh
01:13:52
Speaker
I'm just wildly speculating here, but I wonder if um a source of inspiration might be the security camera industry. Because surely they've dealt with the problem of the camera image not changing at all for hours and people needing to scrub back to find the yeah five minute window where someone broke it. Maybe someone at the the Louvre would like to speak to you. Yeah.
01:14:14
Speaker
ah yeah They recently had those kinds of problems. and Okay. I want to pull it back into user space a bit because of course yeah I'm keen to use this. So one thing i found tricky as a user, and this is entirely my problem, but I'm hoping you might have some solutions, is I try and record a terminal session that I want to share with people and I mistype something.

Editing and Community Tools

01:14:36
Speaker
And, you know, it's like ah you get five minutes in, you make a mistake and you wish you could edit it. Is there any editing support for the sessions? Will there be? Can I snip out my mistakes?
01:14:49
Speaker
So, yes, there actually is in the form of some ah community projects. Okay. ah So the natively, there's no no real thing that I implemented for editing other than just making the the file format easy for people to just mess with. Because ah actually the asq as ASCII Cast format is is a new line delimited JSON format.
01:15:22
Speaker
where every event is ah it's just like a three-element array of, like you're presenting an event, where first element is ah is a time, second is a type of event. Usually that's O, what goes for output, which is printing. And the third is the payload, what gets what should get printed. So you can just open that ah file in the in your editor,
01:15:48
Speaker
and fix the typos there. It's not very yeah helpful if you have like a ah a lot of control sequences there because they can really abstract what you're looking for.
01:16:01
Speaker
ah but But you will find it there. Everything that that got printed is in the file and it's in plain text. So ah that's one way. Another is like there's a bunch of tools that people made.
01:16:16
Speaker
ah You can go to docs.askinema.org and in the about on the About page there's section called, I think, ah Integrations.
01:16:29
Speaker
There's a bunch of, ah it's not a complete list, but just like what I was able to gather, ah of tools that that can work with Askinema and some of them are actually ah useful for editing. ah various aspects of of so there there are tools um that can uh replace some text sensitive text for example that if you if you have some yeah you realize oh i have some password there like a aws secret key then it can find it that easily and replace it there are tools that can uh modify timing so like speed it up or like remove long pauses or
01:17:13
Speaker
are of various things. um one One thing that are ah you can do with with the Askinema CLI actually is concatenate multiple recordings.
01:17:26
Speaker
So if you can, for example, record in multiple takes, a few parts of of what you want to show, into separate recordings and then concatenate those files into a single recording. And it will just like make sure the timing is like properly, you know, stuck on top of each other. And then everything is as well. Presumably you have to make, you have to be really careful to make sure that the end state of the first file looks sufficiently similar to the start state of the next one or it renders weirdly.
01:17:59
Speaker
Um, Not really, um because ah
01:18:07
Speaker
the recording doesn't take the the snapshot of ah of ah of a terminal window. It takes you know it records the events. So um in fact, if you would be, ah say you're You run command A, hit enter, and then get some output.
01:18:28
Speaker
And then type command B, enter, get some output. And then you have a file, recording file from that. ah If you did that in two steps, so like type A, enter, get output, exit the session, end the session, and and then do the same for B and co and concatenate them,
01:18:47
Speaker
you will most likely end up with it almost exactly the same same ah file contents, except the the timestamp of time timing, of course, because that is very yeah precise. But um the reason is that ah for for that second recording, it only recorded what got ah printed since it's since you started recording, not what was in your terminal before.
01:19:19
Speaker
So this is this is this is one tricky part that people kind kind there can't wrap their head head around ah because um for Another example of of the funny thing is that, say you you do some stuff in your terminal and you your cursor is at the very bottom. You have a full terminal of of just some some stuff there. And then at the very bottom, you you start recording.
01:19:47
Speaker
So what will get recorded is only the stuff that starts now. everything Everything above it is not visible to the new recorded session.
01:19:59
Speaker
Okay, yeah, i can see I can see that. But then that raises the question, when I start a new recording session, does it start with no prompt at the start? Yeah, well, well um well if you when you start a new recording session, like the the initial like the initial state of the of the virtual terminal that will that they would be used for for interpreting those recorded events is blank. The cursor at the zero zero and it's blank.
01:20:32
Speaker
But ah when you start a new session, Askinema launches a new shell, like an embedded inner shell, which itself prints this initial,
01:20:48
Speaker
ah prompt yes of course of course it does okay yeah yeah i've missed that yeah cool so where um before i before i leave you and go and uh record and try and edit some of my mistakes out in a new version um where where do you want to take it next what is the next priority like people being able to scrub back and forth across streams um well I don't think this will be the next thing.
01:21:16
Speaker
Well, the the thing is that this is still something that that I do when I have free time. So, um, uh, it's not my, not my full-time job.
01:21:27
Speaker
Uh, so, uh, what I typically do is like, I work on something that's either useful for me because I said, okay, now this would be useful for me right now.
01:21:38
Speaker
Maybe I'll work on that. Or, uh, I just feel like doing it because I think this will be so much fun. ah Or there's a major, major demand from the community.
01:21:53
Speaker
And I agree with that. Because there may be a major demand for something. And if I think, okay, this will be a pain in the ass to maintain for next 10 years, I don't want to be doing that. So that that's what what happened a few times. But I try to bring features that are useful to people anyway.
01:22:14
Speaker
so So I don't know, well and probably that the life life advanced live mode with scrubbing, not sure. Well, it's still somewhere in the plans, but I'm not sure when. ah Recently, I added actually, the ah this was a long-standing point on my to-do list, which was a full-text search on the...

Future Plans and Improvements

01:22:39
Speaker
on ascianemo.org so oh you basically can search for recordings that were uploaded by users by their full content everything that happens in a terminal is indexed so yeah you can try it out so that that was one one cool thing that was a long time coming but it it it's it's it's now there i'm i'm super happy about it um And yeah, I just like now, probably the next next next thing when I will have time will be some improvements they already started playing with to the performance of the player and the the whole like canvas background rendering.
01:23:28
Speaker
Just like, I want this to be super efficient and performance. Just just like...
01:23:37
Speaker
it makes me happy if when the software is, uh, it's performing because we have super fast computers and I just like hate, uh, inefficiency. Uh, so, so this is my jam. So probably probably I will, I will spend some time in the player area. Um,
01:23:56
Speaker
I guess. Who knows? We'll see. We'll see. We'll see. well yeah When you've got the um all singing live stream um multi-client server architecture running in a way I can play back and edit, we'll get you back into the podcast. All right.
01:24:12
Speaker
but For now, if someone wants to get started, it's askinamar.org, right? Yes, askinamar.org. Yeah.
01:24:21
Speaker
A good way to start is, of course, watch the introductory recording on the on the front page, but also go to the docs. there There's a link in that in the header and follow the getting started guide, which is if you yeah it pretty much is a great overview of of all the pieces of of the of the project cli the player the server it shows you how you can do various things and that you can also self-host your own server how you can self-host the player on your website and um yeah just like the getting started is probably a good jump start
01:25:04
Speaker
Awesome. I should go and record some demos that I've been meaning to publish for a while. On that note, Marcin, thank you very much for taking me through nearly a 15-year history. I'll join you for the celebration party. Oh, yes.
01:25:18
Speaker
And to the next 15. Absolutely. Cheers. Cheers, cheers. Thank you. Thanks for having me. Pleasure. Thank you, Martin. As usual, I'll put links to everything we discussed in the show notes. I think the place to start with a project like this, if you're interested, is sprucing up some of your old read-mes, because it's a great way to use it. And it's also a great way to show other people how to use your stuff. It really brings it to life. It can do, in a quick animated GIF, what it takes several paragraphs to explain.
01:25:52
Speaker
I'll leave you with one other link in the show notes. Marcin has put together a few fun demos of quite how far he can push this project. And one of them is a radio play called They're Made Out of Meat. And I'm not going to say any more about it because I don't want spoil anything. But if you like sci-fi, it is definitely worth your next five minutes.
01:26:12
Speaker
Or maybe five and a half, because before you go and listen to that, please take a moment to like, rate, or share this episode with a friend or a social network. Helps people find us. And make sure you're subscribed, because we'll be back soon with another interesting voice from the software world.
01:26:28
Speaker
But until then, I've been your host, Chris Jenkins. This has been Developer Voices with Marcin Kulik. Thanks for listening.