0:00 thought I was um I was talking. Sorry. It turns out I I was muted. So, hello. Is is is is the 0:08 screen readable? If you could make it a little larger, 0:14 that might be helpful. But yes, we can see it. We can read it. Uh making it a 0:19 little larger might be a bit difficult now because I had to font. Okay. No 0:25 worries. On with the show. Okay. Great. Thanks. It's it's fine as it is. 0:30 Great. Thanks. So, um, hello everybody. My name is Onat and, um, I've been 0:36 working on this language for the last decade. And, um, what you're looking at 0:42 is a, um, blockbased for I mean, I'm I'm not 0:48 actually really like, you know, good at presentations and I haven't really prepared for the talk. So, excuse if if 0:55 the talk is like a little bit um anyway a train wreck, but let's see. Let's see 1:01 what happens, you know. So, um the thing is this is actually like a 1:09 Ford editor that's encoded in another Ford editor that look like um hold up 1:17 that look like this. So um this is a previous version of of 1:24 that um editor and this is a text base for it. Um so you can just type anywhere 1:31 on the screen. This is like just um 4K blocks per screen. um 64 by 1:40 64 and um text base for takes about 60 1:46 milliseconds to compile the editor which you're looking at here. So that's number 1:53 that you're seeing here. That's like 17 um 8 millisecond. That's the textbased 2:00 performance like you know when you're um processing text uh to 2:07 compile and this takes 8.24 24 milliseconds for 2:14 uh two platforms Windows and Linux and I 2:20 can I cannot I can say like okay let's um let's see let's yeah it takes four 2:28 milliseconds per uh platform as you can see here um if I don't compile for Windows 2:36 and 8.2 two milliseconds for the entire program that's looks like this. 2:45 So um this is vamp and this is the first series program that I um coded in for 2:53 that's like um you know beyond a certain complexity that like okay this editor uh 3:01 that we were looking at um was manageable uh in text based for but to 3:07 do this in text would have been much more difficult for uh a lot of reasons 3:13 that we're going to get into and um yeah this this is based on uh a binary 3:19 encoding which is why this is so fast and it gets translated directly into 3:25 machine code. So um yeah 3:31 um let's let's start with like why fort uh is actually not um you know um I mean 3:42 fort does a lot of stuff right but it's actually still um I'm going to create it 3:48 as a runtime opinionated language and that means the language is u has a 3:55 defined runtime which is in the case of forge it's it's a data stack and a uh 4:01 return stack right and um you know anything that you 4:07 could configure um per your own for of course um like um you know I I like to 4:16 have global memory for instance so um the thing is how do you run a fort on 4:23 on a GPU right because like this program that we're looking here, it also has like shaders and like it's it's actually 4:30 just compute shaders and um rendering text like this and running Fort on the 4:38 GPU um in the traditional sense is kind of like impossible because um you have 4:45 to maintain that stack with registers and it it's it's not that you know it's 4:52 it's not that good. um versus um 4:57 like because I mean I I've been I I've been uh programming this for 10 years uh 5:04 more than 10 years actually and um the thing is it it had to be the most 5:12 performant language ever also and um the fourth overhead just by this example uh 5:19 the um 16 like 60 milliseconds versus 5:24 like 4 milliseconds. That's like for difference between using data stack 5:30 versus using registers only, right? So this for is uh like the stack is just 5:37 two uh there's there's only two uh items on the stack. So um and you can see the 5:43 stack is visible on the top left corner here. Um so you can go anywhere in code 5:49 and say okay what does the stack look like here um or here for instance it's like um all 5:59 the instances that this definition is is being called from um the stack is 6:05 visualized but why why do we need stacks right 6:12 stacks are there so that we can pass information in a convenient way. 6:17 Otherwise, we would have to use variables and having to name variables all the time is a lot of well, a lot of 6:24 bookkeeping that you have to do versus just using stacks, right? And um let's 6:30 see um I mean this 6:36 is in instead of using stacks, we can just use global memory. Um, for 6:43 instance, we don't have to use stacks even at the runtime, but I use stacks at 6:48 the compile time uh because it makes passing arguments a lot easier. 6:56 Um, sorry. I'm just scrolling through the code to find like 7:02 um an interesting place, but cuz cuz this this subject is actually like um uh 7:08 maybe we should just stay on this screen for a while. Um 7:14 I because this is like the uh the first screen of of this environment and um 7:22 there's a bunch of numbers here and um like a structure here. So um in in in my 7:33 in an old forge I I made there was this um like begin and end definitions like 7:41 um begin definition and end definition like that versus 7:46 uh this means the beginning of the definition and end of the previous 7:52 definition. Right? So you don't have to um remember to close your words, right? 8:00 Uh the definition closes each definition closes itself or if there's no 8:05 definition, if there's just space um then that means that's an execution which we're going to get also um you 8:14 know later. Um so actually this is the perfect place to mention execution. 8:22 So um I think we have to code in the 8:29 simplest way and I don't think it involves a lot of abstractions right so 8:36 um I think we should just code everything in assembly including the language and the editor itself um and 8:44 how do we write that assembly is um of course we don't have to write it like uh 8:50 we don't have to write it instruction by instruction Actually, we can use a macro language uh like this for to 8:58 implement that other fort core if we wanted to or other u language extensions 9:05 if we wanted to because that's the other point, right? Like it it has to be a foundational language that's um that can 9:13 last um forever because uh it's it's the simplest that it gets. And um the the 9:21 design space for that um is like two 9:27 registers is I think the optimal point because if you have four registers that's a lot of shuffling 9:34 and most operations are like they they just use two um operands. So two 9:42 registers for stack size at compile time is enough for a program of this 9:48 complexity. Oh yeah, I could just open this of course. 9:53 um for for like the um and um this program is 10:01 um so I can basically title the screen anyway I want and 10:07 um it does not use stacks at all like I mean it uses stacks at some places but 10:15 not in the way that you would think like you know uh there there is no like the stack overhead of like you know uh 10:23 traditional forge it's all compiled down to assembly because in a way it's all programmed in assembly but you know the 10:30 assembly is um highle macro uh for style and I got uh basically anywhere uh 10:39 anywhere I have um like okay there we go 10:45 uh I have like exact assembly output that I'm interested in for the architecture that 10:51 I'm compiling compiling to. So, um this is x64 for now, but um you could compile 10:58 to ARM 64 or any of the microcontrollers or whatever. Um you could use any 11:04 computer to transpile to any other computer. So as long as you can communicate with that other computer via 11:12 like sending the compiled code that you just wrote uh I mean that you just generated via execution which is like 11:20 the um yeah the subject that that I wanted to get to is like we don't have to think 11:28 code as like some complicated um you know like structure. It's it's 11:36 just pure execution uh that generates a very simple that 11:42 maps to very simple assembly and then you execute that code. So you have um 11:48 exact definitions and simple definitions and the execution is also very efficient 11:53 and um so a question about your your screen is the um the the color is is is 12:00 uh highlighting or is there is there some encoding for the coloring? Oh yeah, there is um there's semantics 12:08 associated with color. It's it's like color for but you know um it's it's 12:14 compile time color for like I mean color for is as far as I know it's still uh 12:20 text encoding based which is still uh valid by the way it's like it's just 12:26 slower and it has some disadvantages also but you might want to do text based 12:31 color for it instead of like this index based color for so the index based part 12:36 is there is a dictionary that maps each word to you know each of those words is 12:42 like I mean I could I could just go to this loop and I could call this like uh loop for instance and it will change 12:49 everywhere because um it's it's like I see so you're storing you're storing a 12:54 central index for each for each uh word in the I see interesting exactly exactly 13:00 and how many how many how big are how how big are each is is each word like 13:06 how big is the index space um Well, there is 24bit indices because 13:12 I want to pack each instruction to four bytes. So 24 bits of that four bytes is 13:17 dedicated to that. But in the next iteration actually I'm going to do four bytes for indices and then I'm going to 13:24 store one byte tag in a separate block. So you have like I mean this is going to 13:31 get faster you know this is just back baseline. I see. So so it's so it's it's 13:36 a index and then a tag. Got it. Got it. Thanks. Yes. Yes. Exactly. And um 13:42 because if you're if you don't have that index, that means you're hashing and then you had to do that hash lookup 13:49 which gives you like uh dynamic local context. But I I like global context 13:56 more than local context because I have exact mappings, you know, exact semantics instead of like, oh, maybe I 14:03 called this word in a different context. So that word has like a different that 14:08 word maps to a different cell like different index and like you know that kind of like problems I don't want to 14:14 have to deal with like with text space but uh like still text base is uh valid 14:21 in certain context like maybe you want to do I don't know 14:28 um it's I mean it's it maybe you want to do like free form 14:35 programming I mean without having to require a complex editor because instead 14:40 of like having the complexity of text in the language, you've embedded that complexity in the editor. Uh because um 14:48 you know when you're writing you you're like looking up this um you know word 14:53 like loop for instance and um that's I'm I'm pulling from this concept that I 14:59 call the deck. So I have like a deck of cards and I have a bunch of words that are like for these are my walcon words 15:07 for instance and these are ffmpeg words when I'm like dealing with ffmpeg and like a lot of words now I put in a to-do 15:13 list to implement later and I just never got around to it's not even like a 15:18 problem and this is just one encoding right this is not central to the 15:24 execution this is just for printing this is not the core language so In the 15:30 future, if you're like doing open source for instance, you you have the option to say like um just ship the source but not 15:39 the symbols, not this like dictionary part. So um in a sense you still have 15:44 the source and the numbers and um you know but you can still protect your IP 15:51 and like you know symbols for instance uh for like I don't know and um there is 15:59 also the possibility of um embedding this whole thing into the program 16:04 itself. So the core language is 2 to 4 kilobytes. It's actually should be two 16:11 kilobytes. I haven't checked recently, but yeah. Um it's it's very simple 16:16 because what I'm doing is I'm just looking um like I'm just generating a 16:23 template based like um code so that I can execute it 16:29 efficiently instead of like having to incur the um interpreter cost, right? So 16:36 um I mean that's like also happening in this textbased language and that's why 16:42 it's 16 milliseconds. I mean it's still fast but you know having to hash and 16:48 having to look up that overhead is like easily like yeah 16:54 uh easily um yeah eight like 12 milliseconds of cost. How how how do you 17:02 manage the the index space? Like that's the main thing that's kept me from going down that road is sort of like is there 17:09 a lot of complexity in managing? Yeah, that was um that grew to be a 17:15 problem because like um after a while there is just a lot of words and like um 17:21 so I I solved that via like tags. So I have these 16 uh word scrolls and I can 17:30 paint them with tags and then I can select tags um over here while a deck. 17:36 So each of those are like tags. I mean it's it's kind of complex. I'm not going 17:42 to do four tags in the next iteration. I'm going to do just 16 bit index plus some predefined tags instead like API 17:51 implementation you know uh that sort of thing like um you know this is not the 17:57 um end iteration I mean there's a lot of UX improvements 18:03 uh to be you know to to be imagined right there's to 18:10 be explored I mean that's that's very exciting about this language is like um 18:15 it's it's also going to run on Steam Deck and also uh VR and also phones and 18:21 tablets, right? Um because um why not? We we're not like constrained to the 18:28 keyboard keyboard anymore. It's it's just like picking up symbols. I mean you 18:33 could essentially draw on the screen instead of like typing on the keyboard. And you said like how do you manage I 18:39 mean you can just type words like you know let's say ABC 18:44 DF I mean you could just uh like define words like this you can move them around 18:52 um you know and then when you when you insert them into the into the source base then you you you have to use the 18:59 selection on the left or you you can type you do the lookup at that point to yeah I mean um you can actually I mean 19:07 you used to be able I mean I I used to be uh I used to just have this 19:12 dictionary space and now I just type something and if I need like something 19:18 like uh index for instance index for something I just press control space and 19:24 that gets redefined wherever uh it gets redefined which is like uh configurable 19:30 like you know I I want to define index ABC here for instance and then it gets 19:36 defined here. You're kind of consciously pl managing the index space as you place new add new 19:43 things. And I I see Yeah. Yeah. I mean, it's it's like you you can move stuff 19:49 around and the only thing that you have to do is like walk through the whole source and patch, you know, numbers. 19:56 It's it's simple. I mean the editor is also very simple which is um you know 20:02 important if you want to import the editor for open source programs like you know you don't have to install 4 GB of 20:09 Visual Studio like 200 megabytes of PHP or whatever it's just 64 kilobytes of 20:15 editor if even that like and um you know 20:20 it's it's portable to anywhere because it's it's so simple. Um so yeah there is 20:28 a lot of stuff here that makes programming easier which you can see as structure in the code um like um a new 20:37 syntax for like conditionals and loops and like like this loop for instance how 20:44 it's implemented is like I can jump I got like um jump to definition right so 20:52 let me what this loop does is like it increments depth by one and whatever 20:57 depth is like it's usually zeros as you can see over here it's it's like um and 21:04 then you plus one that and then you see like oh it's plus one I mean you can 21:10 just see all the code flowing um at compile time right and that's the stack 21:18 uh over here and what's interesting about this um 21:24 Like another interesting thing about this language is like um you should be 21:30 also able to see the data flow as it's happening at runtime right so that's 21:36 also possible with with this language so I'm just like iterating through 21:42 um like okay what what was with play um for instance at setup here when I click 21:50 previous for instance I want to record like uh this with play uh index, right? 21:57 Uh so and that shows up over here just by by this um corner. So um that's like 22:06 68 for instance or um we could 22:12 say okay let's let's let's for instance run this and then like press like 22:18 previous or next uh three four times I think I pressed five six okay let's 22:25 let's count it how many times we pressed so okay so let's see one two three four 22:34 five six seven here we press seven times and you can see like the data flow as 22:41 it's happening through runtime um and you know this is the most basic form you could imagine like moving over 22:49 the mouse and seeing the full data flow which I'm going to implement for the next editor and so on but you know it 22:54 works um and you can even embed more met metadata there and I mean this is 23:02 essentially free printf like um you don't even have to type print f you just 23:07 say like okay what was like hot slot as like this code was running and if I'm 23:14 like creating some stuff then I'm going to 23:20 yeah so the hotspot was like 3D for instance like you know or 31 3D 23:31 3D you know it's it's like it's when when you're debugging it's 23:36 it's instant visualization which is um all you need essentially for fast 23:43 debugging the um so for the the the index indexes into some sort of a 23:50 some sort of like a name table. What's do you have how how is how is that built like is it a fixed fixed sized space for 23:59 the the names or what how do you manage that piece of oh yeah that's eight bytes 24:04 per um like cell I mean I I I call them cells uh like they have indices right 24:12 but they're essentially like uh compile time cells right um and you know you're 24:19 just defining names here you treat them as memory essentially. Uh, 24:25 and they're eight bytes per cell. Got it. And when you also but the name you 24:31 could make like 16 bytes if you want and it doesn't have to be but the definition of the language says that each cell is 24:39 going to be eight bytes per like you know because that's that's the one that 24:44 uh you know I think that makes sense because u I mean you could put in type 24:49 information into eight bytes if you you know um take care of it in many ways. I 24:55 mean um you don't need 16 bytes I think but 16 bytes names I mean sure maybe if 25:01 you want to let's see and and is the um um let's see when you when you 25:09 uh what about for like comments are you how do you 25:18 right um so comments are um I'm so there's 24 bits of data per instruction 25:25 on this iteration. So it's three characters. So I can just write comments like this. They're essentially like 25:32 strings, you know, they're just like encoding the string in in the U bite instead of like using like an external 25:39 string table. I see. So those are stored direct in instead of Right. Right. I see. Yeah. Because you don't want to you 25:45 don't want to pollute your your dictionary space with I I see. Yeah. Yeah. I mean you could store it in the 25:50 dictionary also if you want or you could pull it externally. I mean this language is free form. It's implemented in the 25:57 Sony. So whatever you want to do, you're free. I mean and um it doesn't have to 26:03 like I mean um I see like you know um I I I didn't want the language to be 26:11 like rigid like all the other languages out there. Like Rust for instance is is 26:16 a very rigid language that says like okay you know what this is the language and like you have to fill out these tax 26:22 forms and these all rules and if you don't abide we don't even compile your code or whatever like it's it's versus 26:30 you're free to do whatever you want and um you know it's it's like there's so 26:37 little abstractions that you can implement your own abstractions or like 26:42 your own um extensions if if you want. I mean it's 26:48 it's it's like yeah it's it's super simple compared to like all those 26:53 runtime opinionated languages that are like um that have to cater to all kinds 26:59 of um concerns, right? versus um 27:04 defining like a simple language that can still solve all those problems by being flexible enough by thinking about the 27:12 output instead of like you know being dogmatic about the runtime right 27:19 um so yeah I mean 27:24 um there is let's see let's see um there's a lot to talk 27:32 about for like you know how to program an assembly and um I mean how to like 27:41 program an assembly efficiently right um assembly for what for 27:48 well that's what processor are you on um X64 for for this iteration but that's 27:56 actually like a great question I mean for what is like it could be ARM 64 also 28:02 And um the portability is one of the um you know concerns in this like style is 28:10 like um you know each of like all of this is like programmed in x64 assembly 28:17 but through these um highle words. So I could replace those highle words for ARM 28:23 64 or Commodore 64 if I had to and emulate uh somehow. On Commodore X64 I'd 28:31 had to emulate the registers through dedicated memory. On ARM 64 you have so 28:37 much registers that emulating is not a problem and you're still like you know 28:43 um within that register budget. So you're still as fast as like 28:48 um you know uh as if you had like all those registers. It's it's like it 28:55 doesn't really cost you to not use registers, right? It's so are you are 29:01 you wanting to uh release this to to uh others or 29:07 uh Sure. Um I mean um at some like I think 29:14 um I'm gonna start a stream soon um where I'm going to build this language 29:21 uh again and this editor uh again for um 29:26 all kinds of like different stuff like Steam Deck and VR and you know desktop 29:33 of course and tablets too. Um so yeah this is like 29:40 um you know it's it's not ready for prime time. There's a lot of like UX 29:46 improvements to be made to this whole thing is is like you know the the situation but u as also like a 29:56 um you know proof of concept for like how fast you could compile and how fast you could run. I mean um and also how 30:05 expressive uh it is and um how debugable it is, how scalable it is, right? This 30:12 is like a very um I mean it's it's it 30:18 takes about thousand times more times to compile this program in C 30:25 um than in this language. So, and also it's more code in C even 30:33 though C has like all those pre-ompiled headers for walcon 30:39 ffmpeg and so on. um because this is a um for instance I'm just going to say 30:46 like um this is a macro language so I can say 30:53 div I can just have like say 29 device 30:59 to say we wk device which means like okay what does it mean it means get swap 31:06 chain images you know which is which gives you the images for the uh you know 31:13 for the swap chain. So uh in C I would have to write 31:18 this as like we can get image swap chain get swap chain 31:25 images car etc etc um and then I would have to say like 31:31 um GPU because like it's not global and then device versus just you know just 31:39 device I mean the difference in usability and 31:44 also readability is u huge compared to like all those other languages that are 31:50 bound by um having to be text based right instead of like execution based um 31:57 you know this have you started uh have you started making a manual or documentation 32:04 well uh the documentation will be the streams that I'm going to do uh as I built the language and the editor you 32:11 know that's the documentation that's going to be happening that's it's going to be happening live 32:18 you know um and it it doesn't even need that much documentation the whole thing 32:24 is so simple so um the thing is okay let's get to the language semantics 32:29 right so we said like oops there's a here's a bug that sometimes crashes the 32:35 editor when I go to the top like you know It's It's a stupid thing, but you 32:41 know, sometimes it happens. I haven't had the motiv motivation to fix it. So, 32:47 um anyway, oh yeah, there it happened again. 32:53 Funny. Think I'm not doing like balance checking, which is like happens when you're programming in assembly. 32:58 Sometimes you forget to do balance checking on somewhere after some subtracting or whatever which is again 33:06 um you know dependent on how you program assembly right so okay let's let's read 33:14 this so this means defining right so I'm defining like call first I seem to lost 33:20 your screen there uh oh okay 33:26 you still sharing oh Yeah, I think it's okay. It's back, 33:31 right? Okay, cool. Thanks. Thanks for reminding. I mean, I I thought we were sharing screen still, but yeah. 33:39 So, Oh, okay. Okay. I think I I know what happened there. It crashes and then 33:46 I I quit and then that closes the share. So, after Yeah, if you share just the if 33:52 you share the whole the whole screen then it'll get then it'll stick. But if you skip share just the one window then 33:58 when that window goes away it will Yeah. Yeah. I I So um so call is like 34:06 FF0. So what does FF0 right? Let's see. XX 34:12 FF0. Oops. Oh yeah. I see FFE0. That's jump to racks, right? Um, 34:21 so call becomes jump to racks because there's already a return address on the 34:27 stack. So I don't want to call I just want to jump to the top of the stack like that I want to call. So um it means 34:35 that we're passing um at every word the top of the stack is going to be racks 34:43 right and the second item on the stack is going to be RDX. So out at looks like 34:50 48.92. So that's like exchange RDX racks. So that's a 34:58 trick actually uh that's occurs um everywhere in this um in this code 35:06 generation. Before I start the definition, I say exchange racks 35:13 RDX. So depending on which like 35:19 um which one you're calling which um like 35:27 um depending on whether RDX is on top of the stack or whether rax is on top of 35:32 the stack you call um you know just before or just after exchange RDX 35:39 racks. So that means that each calls are just single instructions instead of requiring a potential exchange 35:46 instruction to align the racks and RDX for top of stack, 35:52 right? So um so yeah, all of this is like extremely efficient and 35:58 um yeah, I mean this is also like in the definition of the language, right? And all of this is like public domain by the 36:05 way. Um I'm not going to like you know encumber this like with patents and I 36:10 ask you not to also like this is just pure foundational stuff relates to like 36:17 public domain for like public uh you know knowledge. I mean uh as far as I 36:23 know this is like the most fundamental way of like writing in a um JIT style 36:31 assembly because um yeah every instruction just compiles 36:36 to a single instruction right like this um load for instance these green words 36:43 are like just um load from this cell 36:48 index um into racks or RDX depending on whether RAX is on top of stack or RDX is 36:55 on top of stack. So, um, 37:01 yeah. Does that make sense in terms of like semantics, language 37:07 semantics? I'm a little little fuzzy on on so you're saying you're just you have 37:13 a two element stack that you're alternating. Maybe I'm not understanding the what if you could go through the 37:18 register what what the how you're using each register that would be helpful. Uh, yeah. So um racks and RDX are used for 37:27 um you know those the it's the stack registers and um like 37:35 top of the stack and a and a stack pointer or some other arrangement. Oh no, they're they're just those two uh 37:42 stack items. You know there's only two items on the stack. Got it. Got it. 37:48 And um you know this compiles move rax 256 and this compiles move rdx 512 and 37:56 this compiles move racks 1024 you know and uh when it's like when you read this 38:05 um then you know this becomes top of stack and then you can do another like you know uh write into like salt for 38:13 example or whatever and you know that's I mean it it works you know um it's just 38:19 you can do this by just using one bit actually is our racks on top of stack or 38:25 not that's the one bit that you're interested in like it's it's super efficient 38:34 um so yeah so sorry still not quite get following it you're saying that the so 38:39 you're keep you're keeping a single bit to keep track of whether rax or rdx is is the top of stack is that Yes. So then 38:47 so then you you've got a two and you've got a two element stack basically. Is it? Yes. Exactly. Exactly. Got it. Okay. 38:54 Yeah. I mean um two element stack because uh four elements gets very um 39:02 yeah I mean if if you're calling with four elements you have to deal with a lot of permutations to align the stack 39:10 layout you know as you expected. Um, or maybe you could run like two parallel 39:16 stacks, but I don't see the point. It just makes everything so much more complex than like just having two items. 39:22 And most of the time, I mean, two two items is just enough for um all the 39:28 things that you might want to express with this language. And if you need more 39:34 than two items then you read it into I mean you write it into a variable and then you read it uh when you need it you 39:42 know like um for example the uh for example there's like this uh free 39:49 list definition right let's see I think I'm using free list for example oh 39:56 there it is so um the free list for example uses 40:03 this variable called stride which is stride in shifts you know uh so you have 40:10 to define it before you call this word and other than that it takes like okay 40:16 how much free list items that I'm going to have and that's like 32 kilobytes for directory entries for example and then 40:23 like free list I define as like I'm going to read into the max like uh I'm 40:29 going to read top of stack onto max right which is this 33 kilobytes and 40:36 then into base which is directory entries and then I generate code like 40:42 for allocation free previous index and append. So that's like five items that I 40:47 don't have to pass on top of stack that I can read anytime, you know, if if I 40:52 care to, you know, I don't even have to like deal with it. It's just there if I if I care to like I might care about 40:59 allocation of free, but maybe not other stuff or whatever for particular um free 41:06 list, for example. And it it would be helpful if you could go through the the tags that you're using because that's 41:12 also challenging to Oh yeah, sorry. Sorry. Yeah, that's like um so green is 41:18 load and red is store. So I'm loading 41:24 previous onto like or say I'm loading the allocation um function on top of 41:31 stack and then I'm uh writing that to plus tab which allocates like a tab for 41:37 instance right which are like you know which happens when you roll a new tab 41:44 like uh you know like this it allocates like a new tab and we can like verify 41:52 that when it when this runs by like saying like okay you know what let's look at those variables and 41:59 see what happens if I allocate one two and three 42:05 tabs and you know yeah you got like three times 42:14 the and cx is like one dx is five and 42:19 you know etc etc So, um, yeah. 42:27 What about the other? So, red is red is read and and green is or green is right. 42:33 What what are the other Oh, yeah. Yeah. Sorry. Um, so white is call. So, call 42:40 means that you compile a call instruction literally uh at uh JIT time 42:48 though. So um whatever address that you had inside grow like you know which is 42:55 like eight bytes uh which you can jump to the definition right. So um this 43:01 address gets compiled in the instruction stream in here 43:07 and the the the pipe the pipe in front of the definition. So magenta is is uh 43:15 is definition is is the pipe just styling or is that 43:21 so that also gets compiled you know that's the definition beginning so that gets compiled to a return because it 43:28 needs to return from the previous instruction which is setup you know I mean the previous definition which is 43:35 setup and um and then there's exchange racks rdx X and then um you know that's 43:44 the definition uh beginning right so and then you compile these you jit these 43:50 other uh instructions one by one so this this is a compile this is a load this is 43:55 a number like uh this is a call call and like numbers and this is 44:03 um this compiles and and sorry the the the number so the the the numbers is 44:09 there a single the the numbers are the cyan numbers are compile of the number or some 44:16 other sorry they're compile move into into rax or or rdx depending on 44:23 who's top of stack oh yeah I mean for example this stuff they generate nothing 44:29 at the output right but when they get compiled this like this gets translated 44:35 to uh move rax 4 move rdx 104 for and 44:40 move rax 32 and then this is like puts cx which is defined here you know it's 44:47 just um some number that's like 1,003 which is like the 44:54 type and then like the register which is one you know um and then sorry the 45:01 yellow the yellow is what again oh the yellow is um runtime okay so 45:09 That's like runtime store. So that generates a move RCX020 if if you can like you know is 45:16 there is there a comp is there runtime read? Is that the the blue or no? 45:22 Uh sorry can you repeat that? U so yellow is runtime runtime write. What's 45:28 the run is there runtime read? Oh yeah, runtime read is uh CX dot like the dot 45:35 syntax. Or you could just say CX at you know it's it says like move racks to RDX 45:42 uh move racks to RCX like or you could say 45:49 um move RDX or CX if you want like CX at the you know sorry I said run I meant I 45:56 meant at at u sorry yellow is yellow is is is execute time read or is it it's 46:03 compile time read? Uh, I'm getting them mixed up. I'm 46:09 sorry. No, it would be helpful if you could go through each tag one by one so that we Yes. Yes. Yes. Yes. Um, sorry 46:16 about that because like you know the it can be a bit confusing. Uh, I just got 46:21 used to it like you know the way it looks. Um, so uh each so 46:28 if so yeah the the red ones the these are like calls, right? The white ones 46:33 are calls uh at and they are compile time calls and the red ones are compile 46:38 time writes. Okay. And green ones are compile time read and yellow ones are 46:46 execution or rather like runtime uh you know uh so it's so this is indexing. So 46:55 uh each directory path is like 256 256 characters for instance and um I'm 47:03 indexing directory path which I've defined here as like maxers which is 47:08 sorry the yellow the yellow the yellow is execute time read is that is that right or execute time 47:16 invocation call yellow is used for a bunch of stuff I mean sometimes it's uh 47:23 there's also So um a prefix like this equals here, you know. Mhm. So or this 47:30 dot here or postfix when it's a load or it's a prefix. I see. So okay, you've 47:35 got the color the color is overload. Is that is that all different tags or is that Yes, they're all different. Okay, 47:42 got it. Okay, so you got you've got several several things that are yellow that depend on the t on the Yes. Yes. 47:48 Sorry about that. Ran out of colors. Okay. Some Yes. When it's like yellow, then uh 47:55 if there's like nothing, then that's a um like runtime uh call, you know. So if 48:05 if if it's like a um so there was like plus tab that Oh, there's also like undo for by the way because you really need 48:12 undo if you're like doing like a custom editor, right? Yeah. So, so, so why 48:17 didn't you use the I'm surprised that you use color for compile time read and write, but then you use different 48:24 prefixes and suffixes for the for execute time. 48:29 Yeah, because I mean execute time code like you know has to kind of stick out 48:36 you know because I want to see at a glance which pieces of code are generating code versus like which are 48:43 like you know um I mean these are all generating code at some point right oh 48:51 sorry I had to I was doing some steam integration yesterday so that's like 48:56 undo and and you Haven't Let's see. So, you uh you haven't explained the blue yet. 49:03 Sorry. You haven't explained blue yet. What's blue? The blue's comments. The blue's comments. Blue 49:09 comments. Okay. Like um and the green the orange reds are uh 49:19 strings, right? So, comments and strings can be converted 49:24 um you know. So this would be like a string um but it's not a runtime string 49:30 because um I cannot assume anything about the runtime. This is a pure compile time language that you can use 49:37 to implement any kind of logic to implement whatever you need to generate for at runtime 49:45 like um so it's omniflexible right like you can um just say like I mean this 49:53 won't generate anything at all like no assembly you can just you know be 49:59 irresponsible on the stack and like it won't matter like you can just 50:05 um you know um let's see and what what are the what 50:12 are the uh the hard brackets? Oh yeah, the hard brackets are um the 50:18 notation that I have for managing uh basic blocks as I call them. I mean 50:24 they're also like terminology but yeah um so the basic blocks are defined here 50:31 and they're like um they define 50:38 um ranges of code that like um that you 50:43 can have like you know a beginning and a link and a end jump targets for. So 50:51 yeah, so um with this notation, you don't need ifs anymore because you can have an if 51:00 like conditional anywhere, right? So um let's see a place where 51:09 um say like a conditional say um for example I'm here decoding like 51:17 each vi packet at if I'm calling like I'm def okay okay let's look at this actually this is an interesting piece of 51:23 code like what happens when you flush a video for instance when you have to like flush a video um which means like when 51:31 you're changing in the video you had to like go through the remaining like uh packets and stuff that ffmpeg has to um 51:40 you know and release them. Mhm. So what happens here is like I'm looping forever 51:46 basically which what this loop does until I break and I call V packet decode 51:54 you know which is like um a Q which gives me a video packet and I assign 52:01 that to uh video v V packet uh variable you know which generates this code here. 52:08 Mhm. So, um I'm sorry, what are the curly the curly braces and why are they yellow? 52:17 So, yeah, these are uh these are lambdas. That's that's a great question 52:22 actually. Thank you for I mean I haven't I'm doing like a terrible job explaining the language. This is like very all over 52:31 the place, but thanks for asking these questions about like you know I mean these are lambdas and um you know if you 52:38 you can call you can choose to call them or not. I mean lambdas in the sense that 52:44 they that they they they do they bind any variables or they just they're just they're just an invocable thing that 52:51 leaves an address. Yeah, it's it's just an invocable thing that's an address like you know it jumps over. Got it. Got 52:57 it. That and like I don't like locals. It's it's everything is global, you 53:03 know. I mean, got it. Got it. I I figured I just thought I'd ask because L means things to people. Does does the um 53:10 And sorry, why I'm confused why in that lambda why are you using a yellow a 53:15 yellow symbol there? Isn't that it that doesn't get happen at runtime because it's in a lambda or what's the 53:22 uh so yellow is also used for I mean it's not that much stuff you know it's 53:27 also used for immediate time words I mean um so that's when you invoke that 53:36 definition when it's like jitting you know and that's like defined outside in the language itself it's it's very 53:43 simple assembly code you know it's just like appending that um you know um panning like what this 53:51 does is um basically um say like I want to execute 53:56 this piece of code um otherwise nothing executes you know only the things that 54:02 that are like uh within this yellow execute and all of the other ones are like uh definitions right so you know 54:09 exactly what you're executing if it's like following this um yellow um bar 54:16 here. Yeah. So, it's either definition or execution. I see. And yeah, I mean 54:23 you could got a lot of stuff overloaded on the yellow there. Okay. 54:28 Yeah. I mean, uh I don't know. I I like the color, but you can choose color, you 54:34 know, it's I mean, if when the editor is released, you'll be able to 54:39 um well, you'll be able to uh attend 54:45 like within code, you know? I mean, we can just ditch Zoom and just attend the 54:51 meeting in inside the code editor, right? Like because you can integrate 54:58 multiplayer here. um easily and you know um also a multiplayer version control 55:04 system that's like um you know that's scalable to any kind of users like git 55:12 is not the end all of like version control systems I think like 55:17 um but yeah we were looking at with flesh here and like the the code and I 55:24 mean this calls you know this is just a single call and then this is Um and then 55:30 the result of that is stored in rax and I move that to we packet and then if rax 55:36 is zero I break and I move that we packet because ffmpeg requires me to 55:43 pass it in a pointer. So I have to pass it in a pointer and 18 is like you know 55:49 what is 18 18 is a packet free which frees the packet right. So I mean I I could just and sir 55:58 how are you how are you actually hooking you're hooking into to to AV codec and and ffmpeg and stuff like how is that 56:05 binding how are you how are you bridging that divide? Yeah. Yeah. Well I assume 56:10 that I don't have any uh floating point arguments. So uh the calling convention 56:18 is like um just this. So um implement is 56:24 this. So you have to align the SP which I do by reading SP like the old stack 56:30 pointer into B. Like this is so stupid you know having to align the SP but you have to do it because the operating 56:38 system requires you to um I I don't even use stack pointer like for any data 56:45 anymore. Um I just use it as a call stack. And you know when you think about 56:51 it um that could have tremendous benefits. You just eliminate a lot of like stack overflow like um uh return 57:01 oriented programming like right there right. Um it's it's 57:07 like I this whole program runs without any runtime stacks. It's it's totally 57:13 possible to program without having to use any stacks at runtime at all. Um 57:21 yeah, I mean way we could open some demos 57:27 maybe. So yeah this whole program I mean it's 57:32 not just also CPU side code right there is also u GPU code which is 57:40 um like which most other languages for most other languages it's an afterthought right 57:47 um and in this language it's it's so expressive that you 57:53 can like define the whole spare wheel like generation in 58:01 like just this much code essentially like 58:09 it's it's not that much and by the way even even like the fonts are defined in this language is is my screen showing by 58:15 the way or is oh okay it's like stuck on my screen so I wasn't sure 58:22 I'd be curious to to to see that how you define the fonts it looks like they're kind of a bit of a vector something that 58:29 yes yes so um say we're redefining m for 58:34 example to be like you know um so m is here so 58:40 um I start from bottom left right to top left to center to top right to bottom 58:48 right so what if I went to bottom center but I had to switch to the other uh deck 58:56 you know. So, yeah. Yeah. So, now it's like, can you 59:03 see the difference? Maybe I can make it change the font size 59:10 here. So, yeah, it looks um like this now. Or, you know, I could I could 59:17 just make it something entirely different. Denmos like it's it's just um encoding stuff at 59:28 um you know it's it's so simple it's it's like it's just this much code 59:34 to yeah it's it's just all this code is like this much for for that 59:41 language and you know yeah and that's like the font definition 59:48 right I'm going to undo do that. Okay. So, um and that's Are you hitting 59:55 something to rebuild the system each time? Is that Oh, yeah. It's that's the enter. Okay. Whenever I I press enter, 1:00:02 uh it rebuilds. You know, you you you get like you get very 1:00:08 um how to say it, you know, you get very used to it. Like 8 milliseconds is so 1:00:14 fast. I I I can't even like wait for C to compile anymore. Yeah. It's but yeah 1:00:21 um it's also includes all this shader stuff also that I'm defining inside the language Paul says he can't Paul can you 1:00:29 see the screen you were indicating in the chat you couldn't I can currently see it but 1:00:36 I can't see those on my other stream okay never mind so um yeah I mean that rendering code 1:00:44 looks like this you know it's a bunch of shader codes which uh um which is not 1:00:50 that hard to write actually you know and you can do um you know the the the cool thing about 1:00:58 this language is you can redefine stuff like this for instance and there I just redefined 1:01:05 filter you know there can be two definitions that's fine and I can say like okay um you know what if I did this 1:01:14 instead or okay that didn't change anything 1:01:20 because what if I didn't do okay crash but I 1:01:25 shouldn't. Yeah, it doesn't look on the stream because like the difference is 1:01:30 very subtle. Maybe I should see like look at it more. Oh yeah, I I know. I 1:01:36 know. Hold on. There's like the dark modes here. I can show you dark 1:01:44 modes which 1:01:50 or how to implement the dark mode. And this is I assume that little 1:01:55 green dot is your curs is your mouse cursor. Yes. Yes, that's mouse 1:02:01 cursor. Where is the dark mode? I'm looking for a comment that looks like 1:02:06 Oh, there it is. Dark mode. There we go. So, it's not exposed yet, but I just 1:02:13 enabled dark mode. So I'm going to open graphics conference talks like the 1:02:20 um you know and if I close dark modes it looks 1:02:26 like this for instance like a lot brighter you know versus 1:02:34 um versus with the dark mode. So the way that this dark loop 1:02:42 works is um I've defined like I have this 1:02:47 floating um point constant here you know 32 bits but I have 24 bits currently so I have 1:02:54 to encoded with two items on the stack you know I swap and shift by eight and or oh I was gonna clarify so for for 1:03:03 compiled numbers you're you're you're just using the one the one 24bit the 1:03:08 cell with 24 bits of of Yes. Yes. Yes. That means also 24bit floats which has 1:03:15 precision issues unfortunately but you know whatever it's fine it's um 1:03:23 so yeah I I I sample from four planes like y u vi and um you know I had 1:03:31 defined samplers here um as like zero sampler into sampler Y and one sampler 1:03:37 into sampler U and sampler V and you The sampler at requires a sampler ID you 1:03:45 know. So uh because you know you have to like like the sampler handler rather. So 1:03:52 you have to set that and the results like that samples from that 1:03:59 um like Y plane right the luma plane and the UV chroma planes uh separately. And 1:04:08 if the chroma is like I mean sorry if the luma is 1:04:13 um beyond some threshold. Oh wait hold on there it is. 1:04:21 I'm looking like where wait that that's not that code. So if the luma is beyond 1:04:27 some threshold if the luma is greater than 0.6 six um which you had to assign as like 1:04:36 condition. You know in this language before you call ifs you had to assign the conditionals to this condition 1:04:43 variable. Um you know instead of if you could also call if else but you have to 1:04:49 pass like two lambdas. Oh okay. So your your your conditional is taking a taking 1:04:54 lambda's the thing to conditionally. I see. Yes. And the condition is this 1:05:00 variable here that I read into the condition you know and the the the the 1:05:06 like GT question for example like that's what can you explain what that's taking where is it where is it doing the 1:05:12 comparison between and where is it putting its result. Oh yeah. So um the 1:05:18 same syntax that we used before like the dot syntax I'm reading from the luma 1:05:23 variable luma dot and then 0.599 f. So in this language you have to 1:05:30 define your floats. So um f does that and then if luma is greater than 0.6 six 1:05:39 that generates like this variable you know uh 26E uh that's say uh ID uh and 1:05:47 that's the condition variable and then you know 1:05:53 um if if that condition is true this this code gets run which is like inverse 1:05:58 the luma essentially and sorry the the the red the red is 1:06:06 reading from the condition variable and then putting it in rx or dx depending on 1:06:11 the oh the red is re the red is uh storing into the condition variable 1:06:18 sorry storing into I see and then I see and then if you consumes that yes yes 1:06:23 yes it consumes the result of the greater than which is like uh generates 1:06:28 like a spare result and all of that is defined as like you know this is just um 1:06:35 a binary instruction All right. And I read into source and destination, you 1:06:40 know, always two stuff like two items on top of stack. And um if I need more than 1:06:47 that then like condition for example that's fine you know or maybe sampler ID 1:06:53 that's that's like uh that's actually better because like um you can like 1:07:02 define this condition programmatically at compile time if you care to without 1:07:07 having to pass it on stack even right like 1:07:12 um I the restriction of two stack items is 1:07:19 definitely worth it. Um in the worst case you just read in I mean you just 1:07:24 write it into another variable and read it when you have 1:07:30 to which makes also the code a lot more readable. So 1:07:35 um so yeah that's like you know a bit about how you can also program shaders 1:07:42 in this and you know and and and sorry you didn't quite maybe I didn't quite 1:07:48 follow so you're you're targeting Vulcan um how are you how are you actually getting getting into the formats that 1:07:54 Vulcan uses and like yeah um the formats that Vulcan 1:08:01 uses as like like are You are you using a um what what kind of 1:08:08 a you're you're compiling to to one of the Vulcan shading languages or what's the what's the problem? Oh yeah, this is 1:08:15 compiling directly into spare. So um okay so you're generating raw spir uh 1:08:22 bits. Got it. Yes. Otherwise I would depend on another tool the gllang 1:08:28 compiler which is huge. I mean that's like at least 100 megabytes. I think a 1:08:34 lot more than that now with all the debug symbols and so on and all of that is unnecessary. The rules are so big 1:08:40 now. Yeah. I mean in in C only like even though you 1:08:50 have all those headers and like for you know all those struck 1:08:56 definitions all all that convenience stuff that you have in C. It was like um 1:09:03 I think 150 kilobytes of C code for a much more early prototype version of 1:09:09 this idea. And um this is now around 200 256 kilobytes 1:09:16 of code including the shader stuff like all that font definition shaders the 1:09:22 ffmpeg vulcan uh initialization the UI and you know um 1:09:30 the interaction the folder iteration stuff etc like you know a lot of stuff 1:09:36 actually in 200 kilobytes I mean the expressivity of fort is insane at 1:09:44 compile time. It's it's a lot better than like you know um the restraints of 1:09:50 like runtime for it right which is like I mean it has to pass through the stack 1:09:55 and like question is like h how how can it run on the GPU right there is like um 1:10:02 a lot of like expressivity loss just because we want to pass through a stack but that information passing um I mean 1:10:10 you could also achieve that through like global variables Um and with that it 1:10:16 becomes much more simpler, faster and it also becomes you know more um how to say 1:10:26 I forgot it's it's easily it's it's much 1:10:32 more easily debugable because like um the state is just laid bare you know 1:10:37 that's that's just like um global state that's not like um you know you're not 1:10:43 try to uh juggle like local state space at all. So it becomes a lot more 1:10:50 manageable compared to like you know all the other languages. So um I don't know what else 1:10:58 can I say actually um the fort stuff for instance for uh sorry the welcome stuff 1:11:05 is like um Vulcan is walcon usage is mostly like 1:11:10 filling uh forms right so if I if I look at some walcon stuff 1:11:17 um like okay for instance I'm creating like images for each um for like 420 20 1:11:25 YUV 420 format. 1:11:30 Nice. So, um the way that I generate this is like 1:11:37 14 info which is like um which fills the information structure. I mean it selects 1:11:44 it and then fills the information structure with the type and then what's a dollar what's a dollar sign? 1:11:51 Um the dollar sign that's just a variable. Okay. Yeah, it's it's all it's 1:11:57 all cells here, you know. If it's not a string or if it's not in number, then it 1:12:02 has to be like a cell and the tag is like, you know, if it's red, then it's 1:12:08 um it's reading into that uh you know, whatever it is. There there's no single 1:12:16 like end all definition for anything any of this. You know, it's not going to complain like, oh, this was a definition 1:12:22 before. You can't read it. No, I just I just wasn't quite following like in in this context though, you're so you're 1:12:27 you're um writing into it. Why are you writing into it at at you're defining these and 1:12:35 then you're read and then you're reading out of it one like on that lock lock inc 1:12:40 one? Oh, sure. Yeah. So, let's see. Let's read this code. Uh I was up up at 1:12:46 the top of the block on Yes. Yes. So uh if I press enter we can 1:12:52 see like okay it's reading zero mostly and then dollar is like whatever information ID it's it is you know 1:12:59 because in walcon you have these okay hold on you have these um 1:13:05 w say so can create info for instance or 1:13:14 or create info oh wait types populating one of the 1:13:21 structures that they use and then yes so 14 would be image create info right so 1:13:27 instead of having to type all of that like we can I I you don't have to import 1:13:32 that it's just an ID right um I mean this these kind of binary interfaces 1:13:39 simplify a lot versus like having to you know if if this was like a string based 1:13:46 interface like open XR that would be awful, right? Could be worse. Could be goods or something, but 1:13:53 yeah. I mean, uh, in Vulcan, you had to always do this shenanigan where you you 1:13:59 go like we image create info info equals and then you 1:14:07 copy this structure type, you know, and then zero. You had to do this for every 1:14:13 single time versus uh I can just say if in zero for first information or if one 1:14:22 for the second one. Mhm. Or if because sometimes you need more than one information structures that are 1:14:28 referring to each other and they're like 256 bytes apart and you know they're 1:14:35 just a bunch of words. And the last one is info which is like okay if you want any kind of info like you know any kind 1:14:42 of offset for this like structure that I defined here as like 8 kilobytes you 1:14:48 know that's all this is like 8 kilobytes of globally accessible data from anywhere essentially and um what I'm 1:14:56 saying is like okay let's get the in info ID which is mostly zero right so 1:15:02 and then add that to that address and then load that load that to uh RDI which 1:15:09 generates this Leah RDI bit here you know and then it writes some index which 1:15:18 is like in this in this case it's 3B 9A cde 9 you know uh which is like the type 1:15:26 information what is that 3B 9B 1:15:31 9 wait what that's weird 1:15:37 Oh, that's that's interesting actually. What am I even writing here? 1:15:47 Okay, you're searching in the header for is it is it is it in decimal instead or 1:15:52 maybe it's in another header. It's but it should be there. Oh, sorry. Did we 1:15:58 lose? Okay, we lose the screen. Okay. So, 1:16:04 um, info. So, so actually I when I was asking about the dollar sign, I was actually looking up. Can you go back to 1:16:11 block 50? I think it was block 54 there with the 1:16:17 There we go. Yeah. So, up at the very top that lock inc bang uh word. What 1:16:23 What's going on with the the red dollar sign and the green? Like why why are you you're reading you're you're writing 1:16:28 into dollars from the and then oh I mean yeah it doesn't have to be it could be 1:16:34 just this oh okay yeah I see okay 1:16:40 yeah I was surprised that you needed that seemed like an unnecessary step that was why I was yeah yeah yeah totally totally um and 1:16:48 just like like it seems like you've got a convention like convention for how you're using dollar sign in several of 1:16:53 these words is that maybe I'm not getting the the idiom. It's just a temporary variable that I really don't 1:16:59 care about, you know. Got it. You're good. 1:17:04 Temporary just just for temporary contextes. And um you know, sometimes that causes troubles too like that 1:17:11 happened. If you call like two of those words that are like using those variables at the same time, then you 1:17:18 know it's it could be trouble. But you know, you just define another one. There's there's so many of them like 1:17:24 those Yeah. And it it really doesn't matter like you can they're essentially free. I mean um if if you were to be 1:17:31 like um it it doesn't cost anything at runtime. So you can have as many 1:17:38 variables as you need it. Um and this is also interesting. So this is compile 1:17:46 like this is defining memory for runtime but all that memory is global 1:17:52 memory. So uh I dedicate a single register to be able to access all memory 1:17:57 of the program that are stored in this single register which gives you like 1:18:03 gigabytes of state which is huge. I mean you shouldn't have to need like 1:18:08 gigabytes of space actually. Um or you could uh allocate like you know virtual 1:18:14 memory if you needed to um instead of like using this global 1:18:20 space which is anti antithetical to all conventional programming wisdom which 1:18:26 says like don't use globals I mean you know as if like if if if you're like 1:18:34 accessing them in a responsible manner like I can just say like okay where am I using upload buffers for instance 1:18:41 And suddenly it's not that like scary, you know, because like I know exactly 1:18:46 where I'm using those. And um it's not like I mean I I'm very 1:18:53 critical of Rust's memory safe attitude where you have to fill tax forms to be able to access a piece of memory which 1:19:00 is just there. Like it's free to access and you don't even have to pass anything on a register to be able to access it. 1:19:06 It's just like it's just there and somehow like you know people are like oh 1:19:13 that's unsafe you know pass it in a functional context or whatever. So you 1:19:19 end up having these like stacks of state you know pass through like 20 30 layers 1:19:27 of call stack like the same state over and over again which is insane. So, so 1:19:32 for you're you're going to target uh Sphere V like um I haven't looked deeply 1:19:38 the how bad is the encoding like is it it it's a fairly simple instruction 1:19:43 encoding or what how bad is sphere v? Uh sorry what what is encoding for what 1:19:50 exactly? For for you were going to encode sphere v instructions right? Oh 1:19:55 yeah. Are are they like I I don't have a good sense. Are they are they hard to encode or is it a fairly straightforward 1:20:02 format? I mean uh they're they're kind of hard to encode but not really. I mean 1:20:08 you just have to like define it in a um you know you read the spir spec uh which 1:20:15 is like spir which looks like 1:20:21 this. I'm going to save your eyes. So it it defines the whole thing here you know 1:20:28 uh the binary encoding and all the instructions. So um say like how would 1:20:34 you encode um an instruction? Let's see bit instructions 1:20:40 for example shift right logical right let's 1:20:45 see where are where is shift right 1:20:51 logical okay there it is so 194 194 not too bad so it's just a it's just a bite 1:20:58 code kind of okay yes yes I mean once you have like those words it's just like 1:21:03 194 binary I mean I I get I don't know how much header header header and footer and what all you got to wrap around it. 1:21:09 But yeah, I mean binary is just this oneliner, right? And vector is just that 1:21:17 four lines. I mean it's it's very simple code really like and that vector stuff 1:21:24 is for when you have for instance um when you want to shift right four item 1:21:30 vectors you know uh by MD vector or by one it like by like uh just a single I 1:21:40 mean four component vectors by a single component like float for I mean uh single component integer sorry we can't 1:21:46 shift by float of course got it got like like ver. Yeah, I see. Yeah. Yeah. Yeah. 1:21:52 And this ve thing is like just that abstraction for that, you know, like reading um like it's just com comparing 1:21:59 like destination component count with source component count and if they're not equal like I mean that state gets 1:22:06 written to C CX and this if else works on this condition CX, you know, so 1:22:12 that's why it's there or like actually that's is is that running even? Oh yeah, 1:22:17 it's it's a if false within and if else of course. So yeah, how are how are you um 1:22:25 displaying the state when you're on top of a word? Like what how do you how do you have the opportunity to hook that 1:22:32 in? Uh sorry, how do you mean you were 1:22:38 showing this? you're showing the state of the the stacks of the plate when you're sitting on top of a word like 1:22:43 what how do you actually do that injection of the the instrumentation or 1:22:49 oh uh well it's the state is just sorting racks and rdx so if you store that in an array you know you you can 1:22:56 visualize that um in reverse order and you get this but but I mean how are you 1:23:03 you're doing that only when that word is getting executed right like how do you are you modifying how you compiled it to 1:23:09 have a moment to update the this update. Oh, right. Right. I forgot. I I've had 1:23:16 to look how I implemented it, but I'm probably doing like um yeah, code 1:23:21 injection where if the cursor is here, like the active cursor, 1:23:26 um do a code injection where you're recording racks and RDX into this global array that's like storing the state of 1:23:33 the stack. Okay, that that should be it. But I'd have to read the code now. Okay. 1:23:39 Okay. I was just curious if you were if you 1:23:44 had some But it's it's all like it's all straight line assembly that's coming out. So you're like you're not actually 1:23:49 you must something to get get in there, right? Yeah, it's it's all straightforward assembly. Very 1:23:55 straightforward assembly. It's it's just generating the required instructions in JIT which is compiles to a single call 1:24:03 for those white words and like you know a return exchange racks RDX for 1:24:09 definitions and for these it's just a single jump and for loads it's just a 1:24:15 single move uh to racks or RDX or for writes it's again back to the global 1:24:20 memory uh a single move um you know it's it's it's all very simple 1:24:27 So, how do you um how do you keep how do you keep uh flaws and bugs from entering 1:24:34 your codebase? Do you have tests around it or do you have asserts? I mean, what do you do to to try to um Yeah, don't 1:24:43 make bugs. That's that's the like um when you have 1:24:49 bugs uh what I do is like I um I triage 1:24:54 the bug first by okay let's say like I'm triaging why a shader would be crashing 1:25:01 you know uh say here so this shader crashes I disabled this and does it still crash uh yes it still crashes okay 1:25:09 and then I disable this too does it still crash no okay that must be in in color you know does that make sense? I 1:25:17 mean that's uh the fastest way that I can like there's no reliable way to 1:25:22 prevent bugs is is like you know my experience you just have to 1:25:29 um I mean there there are ways that you can use like um I had memory overflows 1:25:35 um you know where I was corrupting memory and or sometimes I passed the wrong stride or wrong number or whatever 1:25:44 and it's you learn to discover it at some point. I mean, um, and you fix it. 1:25:53 Trying to prevent it is more effort than it's worth in my opinion. And a lot of languages try and fail at that because 1:26:00 like at the end of the day, who's going to prevent logic box? You know, there's no compiler that can execute your code 1:26:07 for you and tell you like, oh, you know what, that's not what you meant. I mean you just have to 1:26:12 um you know write simple code and think simple data transformations to express 1:26:18 your uh code and most of the time you'll be fine and if something goes wrong um 1:26:24 usually it goes wrong immediately and you know you can just undo and see like okay you know um as as as soon as you 1:26:31 can replicate the bug then you just do a triage where you can just undo or you can just uh enable disable stuff uh and 1:26:39 you find uh the source like you know fast and sometimes yeah in uh in um 1:26:48 sometimes the bugs are like so hard to find it it persists for a while but they're there they're still fixable I 1:26:55 mean it just I've had good experiences with uh design by contract which is in 1:27:01 the Eiffel language so um you you you document you you 1:27:09 basically ally um you do mathematical things with okay what does 1:27:16 this code need the preconditions and the postcond conditions and the invariance 1:27:22 and then if something's violated it tells you right away and then uh it's it's a way of 1:27:31 um injecting integrity into the code that where the code actually sort of 1:27:36 fixes itself in many ways So, I've had good experiences with that. And I was just wondering if uh anybody 1:27:44 else did that. So, I mean, if you wanted to, you could still do that kind of stuff also in in this style of 1:27:51 programming, right? You could just do checks that are like you express with 1:27:56 macros. Um, and you can compress that whatever you're going to write with this 1:28:02 very efficiently. And, um, if you want to do contracts, sure, go ahead. I mean this is a um metarogramming language 1:28:09 that doesn't impose you anything. I mean um you can say like okay you know what 1:28:16 these are like I have for instance um say these are my 1:28:25 constraints constraints you know um had to like compress that down to nine 1:28:31 characters. So um and you can say like okay you know 1:28:38 the constraint is um a x should be like this b should be that or like you know 1:28:44 should could be like v 0 should be zero and v1 should be always 1:28:52 um should be 14 or whatever you know 1:28:58 like we should be like whatever less than 64. You know, like if if this 1:29:06 was like your constraint space, you you just like 1:29:11 um condensed that like constraint that contract stuff that you were talking 1:29:16 about into work that you can use where you're like, you know, using those 1:29:22 contracts if if you want to. Um for me, I I just Thank you. I just try to not 1:29:29 make that many um you know errors instead like and try to maintain the 1:29:35 state consistent uh all the time instead of like relying on like you know checks 1:29:41 everywhere like because relying on checks is like you know it's it's kind 1:29:46 of like uh safe programming um but yeah I mean I I really like L safe 1:29:52 programming rather than safe programming. I I had a question about the um the 1:29:59 dictionary visualizer on the left. Um you you said that the the capacity you've got is for eight eight characters 1:30:05 in the current system. I'm curious why you only show the six the six characters. Is that just a space 1:30:10 constraint or Yeah, space constraint like uh nine it's actually nine characters and nine characters by seven 1:30:18 bit and there Yeah. And there are uh other like encodings also that I've um 1:30:26 come up with that that's not present in this language which is um say 16 bit 1:30:34 plus 16 bit plus 16 bit plus 15 bit. So that's like that gives you 64k words and 1:30:42 you can concatenate up to four of them together in just 64 bits like um that's should be a much 1:30:49 more efficient and much more expressive. Um and the thing is you can also since 1:30:57 you have defined all words from concatenation of four words that opens 1:31:02 up the possibility of doing say like voice recognition in the editor. So you can just bring the words on the screen 1:31:09 and say like oh I want say um instead of having to like say sampler 1:31:17 ID for instance and then I don't have to go to sampler ID it just selects it and which becomes important because it's not 1:31:24 going to be um keyboard only or desktop only and also I I also want to port this 1:31:30 to um phones tablets steam deck likes you know hand handhelds 1:31:36 um VR headsets everywhere and um even watches or like smart glasses or 1:31:43 whatever like um you know and it is portable to everywhere I think um just 1:31:49 the UX changes but the codes and the whole idea remains simple for all kinds 1:31:55 of environments is um I I'm also curious how how often do you end up using the 1:32:01 facility to to uh rename uh to rename name words as you refactor things. Oh, 1:32:09 renaming, right? Yeah. So, um for instance, non ouiji is like nonwork 1:32:16 groups, but it's like, you know, non work G, let's say. It's just as simple 1:32:22 as that. I'm curious how often you find yourself using that. I It's a new facility. Like, 1:32:29 is it Right. Right. Sometimes, I mean, sometimes I come up with a better um 1:32:35 like better name. You know, naming is hard and you can say like, "Okay, you 1:32:40 know, I'm just going to name this temporarily and then come up with a better name later." But yeah, it doesn't 1:32:45 happen that often. You're right. Well, yeah. I was I was curious because it it seems like a neat facility that Yeah. I 1:32:52 I guess you on the other hand, like once you're used to a name, you're used to a name. Cool. Yeah. Yeah. It's that's the 1:32:58 thing. I mean um it has downsides to compare to text. I mean text would be contextual right? So you can just type 1:33:05 anywhere. So um and with this you had to bring up like the dictionary that you 1:33:12 want because like otherwise it's a huge search space that you have to search through like at scale right if you build 1:33:19 like more and more complex software with this. I mean um you're going to need more dictionary space or maybe not even 1:33:26 that. I mean, all of this is like how many words? It's not even that many 1:33:31 words. I mean, I noticed you very carefully kind of curated the layout of it. How much do you find yourself 1:33:37 fussing fussing with that? That's actually It's kind of interesting stylistically, though, to be that 1:33:43 they're laid out in in an ordered way. Oh, yeah. Yeah, that was intentional. 1:33:49 Um, so 16 per scroll, 16 words per scroll, which is like this. And 1:33:56 um so thing is I I I I'm not really sure about any of this. 1:34:04 So this is uh where it's it's like you know more open to um imagination, 1:34:10 reimagination perhaps. And um the way that I like the way that I 1:34:17 organize those scrolls is like I have tags per scroll. So this is like packs 1:34:24 and to-do and I can just go around and say like what are XAs words which are 1:34:30 like uh the x64 assembly and these are X assembly API words for instance right 1:34:37 and what are like the free rewards are here for instance like this uh yeah it's 1:34:45 surprisingly organized like I I I think when I've thought of using indexes before I've always feared that it if I 1:34:51 just sort of randomly dump dump them in in the order I created things that would be disorganized, but this idea of 1:34:56 placing them explicitly is is pretty cool. That's that's really neat idea. Oh, thanks. Yeah, I mean, um, 1:35:03 organization with indexing is like, you know, the the hard part. I I thought a 1:35:09 lot about this problem. Uh, it's it's it's I was thinking about 64 verse 1:35:14 scrolls and maybe I will go back to 64 scrolls. I mean, it gets a lot of like 1:35:22 Maybe this was too granular. I I don't know. All all of this is like open to 1:35:28 you know re reimagination basically by anyone. Uh because the language doesn't 1:35:33 depend on it. The specific editor does right. So you can have as many editors 1:35:39 as you want and code interrupt without having to explicitly say like okay you 1:35:44 know uh this has to be that and that. If you're like mixing source, I mean, uh, 1:35:50 they can interrupt at the source level, but not at the editor level. But that's fine. I mean, you know, 1:35:56 um, I I think, um, this language can 1:36:01 host any kind of like language um because it offers u pure assembly 1:36:08 execution, right? there's no um blocks there that you have to like go through 1:36:14 or that I have to define uh so that you can do whatever you want if you can 1:36:20 express that logic in assembly then which is like you know which you compile through this macro assembly right uh so 1:36:26 it's not like you know pure like hardcore assembly that we're used to it's much more uh approachable and 1:36:35 um yeah what was I saying I I forgot That's where I was going with this. I I 1:36:41 I think I I asked a question. I I had a different question. I'm curious how you bootstrapped the system. 1:36:47 All right. Um bootstrap the system. I mean, it used to be this and then um 1:36:57 from that system I I mean it still uses C unfortunately, but the next version is 1:37:03 going to be standalone and entirely self uh Bootstrap. So um this is this 1:37:09 compiles into assembly um and I host that in a C project to uh 1:37:18 make this editor which compiles uh you know web and all the other stuff and uh 1:37:26 the next version is going to be also programmed in this and like it's we're going to program 1:37:32 program it live basically uh all of it so that um you know it can 1:37:39 a something that can be like passed on from generation to generation, you know, 1:37:44 like as foundational bootstrapping knowledge like okay, you know, this is how you can build this uh editor uh if 1:37:51 you had to. It's it's so simple. Um and language is much simpler than the editor 1:37:57 of course like all the complexity is just just editor. Uh and you know um other 1:38:05 than that like um yeah the the font 1:38:10 rendering but you can also have the editor stand alone which means like if 1:38:16 you want to embed the editor to say into a game you can have the game have its own 1:38:23 text rendering and just expose the editor and its interaction and so on. So 1:38:28 yeah, I mean I expect a ton of editors for this programming language for sure. Like 1:38:34 hopefully I mean if people find it 1:38:39 interesting. So what else I can say like about so what have you built games or or 1:38:46 like what what are the things that you build with this? So I built before vamp I built um this 1:38:55 going to go back and wait did I open the tab there? No sorry. So I built those u 1:39:04 biological um stuff um that's going to ship also in web. So 1:39:13 um this was also done in the previous iteration. So which looks like this. 1:39:28 Okay, hold on. All 1:39:35 right. Okay. So, yeah, 1:39:41 it's it's like this galaxy like structure that expands. Um, it's it's 1:39:48 just a shader. Um, unfortunately, it's it's running a bit slow because I'm trying to stream it 1:39:54 at the same time. So, sorry about that. Maybe I can open 1:40:00 up. And other than other than that, the editor itself like this. So, this was 1:40:05 the previous version. And you can see like I don't know if you can read the text, but I was still opening and 1:40:12 closing definitions back then. So, there's that. And if I change this to something much 1:40:22 more dynamic so that we don't have to wait so much. Oh, okay. Let's 1:40:30 this. So, yeah. Is that 1:40:39 Yeah. So, you can use this philosophy for any kind of like coding I think. 1:40:46 Um it's like what you can do with this is boundless. You just think about 1:40:52 what's the code that I want to generate and what's the logic that's required to 1:40:57 generate that code. You know that's that's all that's required. That's all this is. Uh all the rest is just 1:41:04 implementation details. I mean you could still have a stack larger than two. it's 1:41:09 going to run slower because you have to manage all that stack back and forth all 1:41:14 the time versus you could have it in global memory which works a lot better in my opinion. 1:41:22 um like just do exact opposite of programming knowledge and you know 1:41:30 um you you'll do fine basically like uh 1:41:35 don't do locals or don't do like I mean you can still do locals if you had to 1:41:40 but um yeah I just like passing stuff globally instead of 1:41:47 um having to red like reaccess the in context locally all the time and you 1:41:55 know programming assembly gives you a lot of uh freedom. So compared to like 1:42:03 um so that's that's like the new stuff and that's the older stuff 1:42:09 basically. So um assembly is essentially much more 1:42:16 free form than uh dealing with compilers. So, Spurby is dealing with 1:42:21 compilers, right? So, I had to be explicit about everything. I had to read stuff into variables and I had to um you 1:42:30 know, if I had to use a result, there is no implicit place I can go for that 1:42:36 result versus an assembly um all the registers are passed all the time. So, 1:42:42 you don't have to pass stuff on the stack. it's implicitly passed for you by 1:42:47 the processor for free. Right? So, um that's the major difference between a 1:42:53 server and compiler. Like apart from the whole complexity difference, 1:42:59 um there's also a lot of implicitness uh intrinsic to the assembly language 1:43:06 for you know I mean I target x64 you could target another architecture. 1:43:12 Ultimately, it depends on where you're going to run this code. Like I highly doubt that I'm going to run the same 1:43:18 code on a like a Commodore 64 on a 6502 or like you know um but if I had to I 1:43:26 could totally emulate it you know um it's just like going to be slower than 1:43:33 having like programming directly to the specific architecture. Um but you know 1:43:40 you can do binary retargeting or in this case execution retargeting because you 1:43:46 haven't produced the binary yet. you're like you can execute logic before you produce the binary uh instead of like 1:43:53 having to translate back from you know binary and um so yeah there is that 1:44:00 implicitness about assembly and um it makes stuff a lot less code than uh if 1:44:08 you had to write everything with a compiler where you had to pass all all 1:44:13 the values explicitly instead of like in assembly 1:44:18 I can just say cursor at b and then bx greater than oh I know that I read bx 1:44:24 here I don't I didn't have to pass it you know I didn't have to define like a new variable it's just bx I mean and 1:44:32 that generates like just a compare and a jump um it's all super efficient 1:44:40 um yeah I mean let me look at my notes to see if if we miss something uh I 1:44:47 think we got to the most important stuff. Anyway, do we have questions, comments? You know, 1:44:56 it's it it's a really neat system. I a lot of cool ideas, a lot of uh stuff 1:45:01 that it's very thoughtprovoking. Thank you. Thank you. Oh, I just thought 1:45:07 something that we didn't get to was conditionals, right? How do conditionals with the block like basic block? I love 1:45:14 the look of it. It's uh it's a really cool system and I like how responsive it is. Thank you. I mean 1:45:23 um it's I I didn't actual motivation was 1:45:29 I I wanted like a system that looked super cool when I was um you know dropping acid 1:45:37 basically. I mean um like it had to be simple enough. It had to be like, you 1:45:43 know, um it had to also look cool. And this is 1:45:48 going to look even cooler than this. I mean, this is um like the the font 1:45:55 here. It looks like, you know, you can get many different 1:46:00 looks. This style of like, you know, font design or my favorite look is like 1:46:07 this. There you go. Yeah, kind of 1:46:17 like and um okay, how do we do 1:46:23 conditionals? So um the conditionals work within basic 1:46:29 blocks and um so you can open up a basic block and 1:46:35 it will constrain the um it will constrain the assembly output 1:46:41 to that basic block. So for instance here I'm loading the temporary address 1:46:46 which is just this top me layout to rax and then I'm reading that into R11. Um, 1:46:56 and if if I didn't have this, then the assembly output would get like very 1:47:03 um I mean the like it's it's it's nice you know because you can see within a 1:47:09 single basic block what's what's the generate assembly for this basic block right and 1:47:15 um within a basic block as soon as you do a conditional if that conditional 1:47:22 passes then the block continues, you know. So, um let's 1:47:28 see. For instance, if okay, let's let's find a conditional. 1:47:35 It's like 1:47:45 okay. Okay. Yeah. Let's let's go back here. So if the packet is not zero then 1:47:52 I free that packet you know if if there was like more conditionals after this 1:47:58 um you know I I I see that if it if it's 1:48:03 not if the focus video is not zero then I execute this rest of the code until I 1:48:11 encounter this here which is the link you know which is the else part. So 1:48:17 instead of else's I have these uh you know links here that are like all across 1:48:23 the code actually um that can be also used for se calls 1:48:28 can be used for conditionals uh they can be overridden um you know hold on I'm going 1:48:35 to try to find like a conditional most of the time it's used for C calls which 1:48:41 is which confuses right now but yeah so right Here for example I'm I'm saying 1:48:48 like if I'm full screen I'm not going to do anything and if I'm not full screen I'm going to call this function called 1:48:54 UI tally and then I'm going to call setup which sets the slot ID to zero and 1:49:00 then slot live count to zero and then it iterates through all the slots and then 1:49:06 it does a check you know and the check is like if this is live you know if this 1:49:11 slot is live uh you increment the slots live count by one and 1:49:18 then if this slot is a leaf you know so you keep filtering. So if this is live 1:49:24 then it's it's passed this filter you know and then you check for leaf and you 1:49:31 know uh if that if it's also leaf then I check uh I decode the balance you know I 1:49:38 I get the balance of the slot and then I decode it which um you know reads it 1:49:43 into local variables and then um and then I do a hot check which is like 1:49:50 doing like a mouse check for between the mouse and the slots bounce you know and 1:49:57 um if if it's hot then the hot slot index is the slot ID which I passed 1:50:04 implicitly by the way this is R12D you know it's R12 passed implicitly I didn't 1:50:11 have to define the slot index for this function um it's it's just there it's global and 1:50:18 this hot slot is also global so Um you don't have to define these you know 1:50:26 arguments all the time. You can just you know um use stuff anywhere use memory any 1:50:33 memory anywhere basically. And so yeah I set the hot slot and then I get the video of the 1:50:39 slot and then I set it as a hot bit and then I return one in a or zero if if it 1:50:47 was not hot you know. So yeah, it it basically checks 1:50:53 all the slots if I'm not full screen and so I can get the hot slot index which 1:50:58 gives me like what my mouse is hovering, right? So I can do stuff with it. But I 1:51:04 I don't have to pass that like everywhere in code, you know, all the time. It's it's it's just free. I mean 1:51:12 um it's it's a lot faster and simpler to pass it globally unlike you know what 1:51:19 everybody else does um you know C rust um 1:51:25 yeah so yeah that's that's uh basically how I do conditionals 1:51:32 um and how I pass state around I mean like using uh state everywhere I can um 1:51:40 you know and yes you had to care about lifetimes. If you modify the same states 1:51:46 from like multiple threads, you're going to have troubles, especially on like 1:51:51 platforms where you have to synchronize that access. But you know, I I care 1:51:56 about lifetimes. I'm just accessing this data from a single thread. there cannot be like a um race condition because like 1:52:05 I'm not writing it from two threads like reads from multiple threads is fine but 1:52:12 as soon as it's right from multiple threads then you have to use like um locks and you know stuff like that um 1:52:21 you know locks as in just this keyword called lock I 1:52:28 mean wait what where's lock. Oh, I'm I'm looking at I still have the square. Um 1:52:35 yeah, so lock is just a single um bite on x64 and you can use it on a bunch of 1:52:42 instructions including bit test reset. So if you have to set or reset like a single bit from multiple uh threads then 1:52:50 yeah that's totally possible. Um I mean in C you would have to like 1:52:58 ask the compiler specifically to generate it or use like intrinsics. 1:53:03 Um, yeah. I like I like being able to just say like Oh, not this. Sorry. I 1:53:09 like being able to just say like lock just being able to append like you know 1:53:14 if if I append this then it becomes a lock lock ad you 1:53:20 know if I don't call that then it's just a single ad. 1:53:29 So yeah, it's it's very powerful, but you're responsible for all the code 1:53:36 generated. Um, you know, you can still use compilers like uh like in spare. Um, 1:53:43 but yeah, I I prefer to use assembly because I like the full control and the freedom that assembly gives instead of 1:53:49 like compilers and explicit parameter passing. So yeah, that was a lot of 1:53:57 stuff. Let me check my notes if we missed anything. Um, I have like I have like a word here 1:54:05 called stack fetishism which we didn't get to like I 1:54:12 I just don't use any stack juggling words except for swap which you need. Right. So you're you're releasing it 1:54:19 tomorrow. Is that what you said? Um, not tomorrow. Um, I'm gonna start a 1:54:27 live stream where we build live on live stream and then we're going to release it after we're building we're building 1:54:34 it on live stream, you know, because it's it's not uh like I just need one 1:54:40 last iteration, but I can I can u maybe release it earlier than like it's it's 1:54:48 going to take one month I think to recode this uh live. Maybe a lot less 1:54:54 than that. I don't know. We'll we'll see. Not too 1:55:02 long. And the application itself is Yeah, right now I'm waiting for Steam to 1:55:08 review it. Um but yeah, um the thing 1:55:14 is there are like when I like this is not the final 1:55:20 form also. This is the 24-bit version. Uh but it's going to be 32 bits plus uh 1:55:27 8 bits for tags and you know um stuff. Um, 1:55:33 so yeah, there there you know it it wasn't the final form like this this was 1:55:41 I knew that I this wouldn't be the final form and like because this was my first 1:55:46 binary attempt um before this I had like two other text fors and this this was 1:55:53 the first like binary form and I thought 24 bits would be enough but you know uh 1:55:59 in the end it's slower. than using 32 bits. Um, and the reason 1:56:06 for that is if you have tags together side by side like compact on an array, 1:56:13 single bite tags, um, then you get fast skips, you know, so empty blocks you can 1:56:20 skip super fast by just reading eight eight tags at a time and check for a zero. Like read eight bytes and check 1:56:27 for a zero and if it's zero, then you can skip it. There are no instructions there versus you had to read 32 bytes 1:56:33 and do like eight compares to see at least if this was like a um yeah comment 1:56:39 or not, you know, basically because tag zero is essentially comments. Yeah. 1:56:49 Cool. Well, that that was really awesome. Um thank you. All right. Um 1:56:55 well, I I think that concludes our our meeting. I I'm going to hit the stop button on the recording and uh see you 1:57:03 all next month.