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.
