 Hello, I'm Ella Heppner, and today I'm going to be talking about Vloger. Vloger is a web app that I've been developing for the past couple of months. And it's essentially a visual interface for programming in ClosureScript. And what that means is that Vloger gives you a kind of drag-and-drop interface for viewing and editing ClosureScript code rather than a more traditional text-based interface. So the core feature of Vloger is a new strategy for visualizing EDN expressions that relies on a kind of nested circular structure rather than using text. In addition to this visualization tool, Vloger also acts as a drag-and-drop tool for editing these visualized EDN expressions. So Vloger's basic strategy for visualizing EDN relies on treating lists as circles and the elements of those lists as smaller circles within side and in closing circle. So here I have a couple of different lists as examples. Here we have an empty list. And in Vloger, that just gets represented as an empty circle. Here we have a list of one element and in Vloger, that looks like a circle with a smaller circle inside. And here we have a list of three elements. And when there are multiple elements, the first goes at the top of the enclosing circle and the remainder get organized in a counterclockwise pattern. Now, the reason I went with a counterclockwise pattern rather than a clockwise pattern is that the counterclockwise pattern produces really nice and intuitive results when you're writing out a function call with just a couple of arguments. Here we have some function calls as an example. Here we have increment being called on X. And you can see that the increment symbol ends up at the top, half of the enclosing circle and the arguments down in the bottom. Here we have a function call of two arguments. And you can see that, as always, the function call will be at top. And the two arguments are down here in the bottom half of the circle. And the nice thing is that you can read them left to right. If these were organized in a clockwise pattern instead, then this X would be on the right and this Y would be on the left. So you'd have to read it right to left, which would be really confusing. Here's a function call of three arguments. And you can still kind of see that it's a bit left to right. But as the number of arguments to a function call increases, it becomes kind of less and less obviously, less and less obviously left to right. Like here it's not even strictly left to right anymore. You know, again, it goes right to left for the first couple of arguments. So you have to keep in mind that things are organized in a counterclockwise way. Now, one of the great things about closure is that it supplements the normal Lisp syntax with some new types of forms that represent different built-in data structures. For instance, we have vectors which are represented by square brackets normally. And in closure, those get represented as octagons. Whereas, you know, parentheses get translated into kind of smooth circles. These pointy square brackets get translated into like a pointy octagon. Closure also has maps which are represented with curly braces. And in closure, maps are represented as circles with little spikes coming out of each side, reminiscent of the spikes on the sides of the curly braces. Here we have function literals which are not technically their own data type, but they do have special syntax in closure. And so in closure, that's reflected by having a circle with little lines coming out of each side. And finally, we have sets which syntactically are kind of like a combination between maps and function literals. And so in closure, these get represented as a circle that has both the spikes from the map and the lines from the function literal. And just like lists, all the elements inside these structures get represented with the first element up top in the remainder in a counterclockwise order. The real power of closure comes in that you can nest these shapes together inside one another. And by doing this, you can represent any EDN expression that you might want to, including closure script code. So here we have a little function definition, a function of one argument that takes, or it takes in one argument and multiplies it by itself. And in closure, that wouldn't end up looking like this. We have the fn up here, declaring that this is a function, our argument vector here, and finally the function body where the argument gets multiplied by itself. Here we have another example of a closure script expression calling the map b function on two arguments. And here's what it looks like in closure. And you can see the function literal syntax fits in very nicely, just to circle with these lines came out of the side. And then you just use the normal percentage sign symbol inside to reference the argument. So at this point, I'm actually gonna switch over to the app itself so you can see how it works. Here I have that expression that was in that last slide, but there's a bunch of other stuff on the screen that I'll also explain. So one of the most important things on the screen is this bottom right hand corner right here, which is called the eval zone. And the idea of the eval zone is that it's basically like a REPL. Any form that you see on the screen here, you can click and drag into the eval zone and it will evaluate it. And you clicked and drag six, which obviously leads to evaluates to six. If I grab this vector here and evaluate it, then that will just evaluate to itself. And if I grab this whole expression here with the map b and this function, then that will evaluate to the result of applying this function to these arguments just like you'd expect. You can also edit programs by dragging things around in here. If I wanted to add a new vector to this map b call, I could click and drag this and it would get duplicated here. I can also change the order of things by clicking and dragging and then dragging the thing that I don't want anymore to the discard corner, which is down here. This is how you discard things in Bloger. And you can also drag things back out of the discard corner or out of the eval zone. Anyways, that's it for the discard corner in the eval zone. Up on the right hand side of the screen, this might be obscured by my camera, but trust me, it's there. There is a text button. And when you click on that, you will see a page that has all of the code that you wrote on the previous screen displayed in a text form like normal. So if you write something in Bloger and you're done with it and you want to pull it out and use it in some other Closerscript project, you can go in here to copy your code out. On the sides of the screen, you'll see these form bars. And form bars are basically just a place where you can store forms in a more long-term way that you might find useful in the future. So here I've got a bunch of different arithmetic and function stuff here. I mean, I can drag any of these out anywhere into my program to use them whenever I feel like. And these are completely dynamic, meaning that any form you have in your code, you can just drag into the form bar and it'll stay there until you drag it to the discard corner to get rid of it. So these form bars act as kind of like a combination of like a normal tool bar with some tools on it that you can use to do stuff and also like a clipboard. You can use this as kind of a way to copy and paste stuff by dragging something onto a form bar going to elsewhere in your program and then dragging it back out. So now I'll talk about these tools that are up on the top half of the screen and the bottom side. We have the undo and redo tools, which are kind of self-explanatory. Here we have a tool that when you drag it onto a form, it encapsulates that form in a surrounding circle. And this is really useful if you wanna surround something with another function call and that's a great tool for that. And we have other tools here. Here's a tool that kind of takes something that takes a form you drag it onto and surrounds it in like a function definition. So that's really useful too. Now let's go ahead and take a look at Vloser's settings. To get to the settings page, you just click on this little icon up here. Here on the main page of the settings, we have the project selector. You can see all the different projects that you have in Vloser. I just have this one right now. You can make a new one by clicking this button. You can duplicate an existing one with this button. You can delete programs with this button and you can rename them with this button. Over on the right side of the main page, we have some various visual settings. You can change the size of kind of like the zoom level of your forms. As you can see, you can change the size of the form bars on the sides of the screen, including the tools. And you can also change the camera speed, the speed at which you kind of jump around when clicking on stuff. And then over here, there's also a couple of different color schemes that you can choose from. We'll stick with the default. Here we have the save form bars page. And the idea of this is that, like I mentioned earlier, these form bars on the side of the page are very dynamic and that you can constantly kind of remove and add stuff to them, but that makes them kind of transient. And so the save form bars page is a way to kind of store a form bar that you like that you think you might want to use in the future in a more long-term way. Like say if I really like all the features that I have on this form bar, I can drag that in here and then at any time in the future, I can come back and that form bar will be saved right here. And this works like cross-project too, so you can kind of transfer different form bars between different projects. Here we have the tools page and this is where all of these tools that I was showing off before live. There's all the ones that I showed and some more. Here's one that encloses a form in a vector, the one that encloses a form in a lead expression, et cetera. And then additionally, I'd like to show you that you can edit the positions of all of these form bars on the settings page. If I grab one of these and drag it, then it will snap to wherever I place it. You can also create entirely new forms or more new form bars by clicking on these circles. These start out empty, but then if you go out into the main program and start dragging stuff onto them, then you can fill them up with whatever you like. You can also delete form bars that you've created by dragging them into the bottom left-hand corner. And so all of what you're seeing on the sides of the screen here is completely configurable. This isn't like fixed. You can move these around, have whatever tools and whatever form bars you want. So with that out of the way, I'm gonna go ahead and kind of write a little program in loader so you can see how it works in practice. And in particular, I'm gonna write a little expression for determining whether some given number is a prime number. So to start out, let me just create an empty let expression which I have in my form bar here and I'll delete this map call that we had earlier. So in this let expression, let's go ahead and define a binding in and that will be kind of the number that we're checking for primality. Let's set it to six, I guess. And one thing I didn't mention is that you're not just stuck at kind of this level of zoom. If you're kind of getting too deep to see things at this level, you can click on any form and zoom in to get more detail. So here I'll click on this. And the way we're gonna check for primality is by just checking every number less than in and seeing if it's divisible or if in is divisible by it. So we're gonna use the sum function to do that. I'll use a function literal inside here. And what we're gonna be checking is a, we're gonna be using the range function. To get all the numbers between two and in, we're starting at two because one doesn't really count when it comes to prime numbers. And so inside this literal function here, we're going to check if this, if in is divisible by the current number. And so we'll do that by checking if the mod of in with respect to the argument is zero. And as you can see, if there's some literal and you want to change what it says, you can just click on it and edit it will. So there's a little bit of text editing involved in closure, but much less than any normal closure script workflow. So I think this should work. Let's go ahead and run this expression. Got an error there. Not sure what I did wrong mod in. Oh, there we go. That was supposed to be inside. All right. Now if I run this and you'll see that it's telling me true for six, it's actually giving me the opposite answer of what I want here. Whether this is not prime, not checking whether it is prime. So to fix that, I'll just wrap this form here in a not call. And then this expression should be working. So here we have in of six and it tells us that six is not prime. If I change this to seven, then it should tell us that it is. Yep. We go to say another number 14 seems to be working. Yep. And so if we wanted to change this into a function rather than just a let expression, we can just get rid of that and change this to a function. And so now this is a function that takes in a number and determines whether or not it's prime. And you can see that that evaluates to kind of the function result that you'd expect. We can also make this a named function just by kind of changing this and giving it a name. We can call it prime question mark. And that will also evaluate just fine and then prove that this works. Let me go ahead and try to invoke this prime function and see what we get. There's prime 10 should be false. Yep. Or prime 29 should be true. And it seems to be working. So that's the basic overview of what editing a program in Glowshare looks like. Now at this point, I'm actually going to switch over to a local server rather than the production server because I'd like to show you a feature that isn't available on production yet that I'm still working on. And this feature is called quill mode. So if you're not familiar with quill, it is a cross-platform graphics library for closure and closure script that leverages processing and P5.js for the JVM and JavaScript specifically. And essentially, it just gives you a very nice, simple straight forward graphics library that you can use to draw animations in closure or closure script. And in this case, obviously we're going to be using the P5.js version that runs in a browser. So to activate quill mode in this development branch, you open up the settings and on the main project page, you'll see that there's this new quill mode button. When you click on that, it will move a lojure off to just one side of the screen and create a new canvas here that quill can use to draw on. So when you're in quill mode, there is a special function, start sketch that gets exposed by lojure. And start sketch basically takes in a draw function and then draws whatever that draw function says to draw on this canvas. And so we'll go ahead and run it to give you an example. Here we have just a black background with a red ellipse in the center. And to see how this animation is defined, we can zoom into this function here. It's a function of two arguments, W and H, representing the width and height of the canvas. And all functions that you pass to start sketch should take these two arguments. So the first thing that this function does is it calls q slash background. And this q namespace is actually the quill.core namespace, by the way, just something that lojure automatically provides when you're in quill mode. So here we have a q slash background called the zero. And that basically just tells quill to set the whole canvas here to black. Here we have q slash no stroke, which basically tells it that we don't want any outline on this shape that we're about to draw. Here we have q slash fill, which we're using to tell it that the inside of the shape should be red. And then finally here, we have the call the q slash ellipse that actually draws the ellipse. The first two arguments that it takes are an x and y coordinate for the center of the ellipse. And we're getting those x and y coordinate by multiplying the width and height that we're getting as an argument by 0.5, which places it in the center of the canvas. And then the remaining two arguments are the width and height respectively. So if I were to change any of this and then rerun this start sketch expression, then it will update as you'd expect. Now quill is not just meant for drawing static shapes. It's meant primarily for animations. But right now, our draw function does the same thing every time it's called. So this animation doesn't have any movement to it. But if we wanna introduce some state, then we can go ahead and make this change over time. And to introduce some state, I'm gonna use an atom that will change inside this function call each time. And to do that, I'm gonna use this tool here, which wraps a form in a let expression. I'll drag this onto closure. And here you can see that what was previously, there is now in this kind of body of the let expression and we have a space to add bindings here. So to give our image some animation, I'm gonna define an atom called t. And this atom is gonna just start out with a value of zero. And one thing that I wanna show off here is that when you're typing in a literal or an assemble in closure, you can actually just write out full EDN expressions. And once you put out of that circle, a closure will kind of translate it into the sub hierarchy visual thing automatically. So rather than dragging the form for typing atom and stuff or dragging in a circle and putting a smaller atom circle inside, I can just write out atom zero. And once I click out of that, it'll automatically get translated to this. So closure kind of allows for kind of a mix of sort of text-based and visual programming styles. So here we have t being initialized to zero. And inside this function, we now need to increment t each time this function is called. And to do that, we will call the swap function on t and we will call it with the increment function. So now each time this draw call is made, t will go up by one. And to actually make t do something or to make our animation respond to t, we will use t in the definition of this ellipse here. So for instance, we can make it so the width of the ellipse is equal to t. And to do that, I can just write out at t. In closure, dereferences get represented as these little circles, this kind of little circle of circles. So this circle of circles around t just re-reads as like at t, dereferencing t. And so with that, I think that we can go ahead and run this sketch again. And we should see that the ellipse increases in size as that runs as you'd expect. And so if you're familiar with Quill or any other graphics library, then I'm sure that you can see that with the tools here, you could create some very interesting and complex animations. But this is enough to kind of give you an overview for the purposes of this talk. So at this point, I'd like to switch back to my presentation. And I'd like to go ahead and address the question of why somebody would ever be interested in using closure over an existing closure script workflow. Now, one of the big benefits of closure is that it natively encourages and in fact kind of requires structural editing. So structural editing is kind of this idea of editing closure or closure script code or really list code in general in a way that kind of pays attention to its tree-based nature. List programs are really best thought of as these kind of nested tree structures rather than as pieces of text. And when you're using a text-based editor and you wanna do structural editing, you need all kinds of text editor plugins and stuff to get your text editor to kind of pretend that you're editing a tree rather than editing text. But in closure, this is sort of a tree-first interface from the ground up. So like I was showing before, you interact with the program by just dragging whole forms around. You're never gonna have a hanging parentheses or anything because the structure that closure gives you is just a direct representation of the tree structure of your program. Another benefit of closure is that it's meant to be optimized for touchscreens. So right now, I'm mainly working on closure for web browsers and there's no official mobile app or anything yet. You can try the web browser version on your phone and it kind of works, but there's some significant UX issues that I haven't managed to solve yet. I'm kind of trying to work on getting the basic web browser version working before worrying about mobile compatibility. But from the very start, I've been designing closure with the idea of eventually porting it to mobile devices because I think that this kind of drag-and-drop interface would be a really powerful way to program on a mobile device that would be way more powerful than any kind of text editor on a mobile device. So that is one potential big advantage of closure. Another big hope that I have for closure is that it can be used as an educational tool for beginners. And I think that there are a couple of things that can potentially make closure more approachable for beginners than just kind of a normal closure script environment. There are a lot of other visual programming environments like Scratch that just kind of use their own sort of made-up programming language. But one of the great things about closure is that if you were to learn programming through a visual interface like closure, then it translates directly to a real programming language, closure script. If you learn programming through Scratch, then you eventually have to realize like, oh, this language isn't like, something I can use to get a job or whatever. This is just kind of a toy. So I'm gonna have to give up this language and go learn something else. But if you learn programming via closure, then you are just learning closure script from the very start. There's no point in what you have to say, okay, I'll have to give up on this language and go learn something new. And so if you learned closure script through closure, I expect that you'll have a very easy time kind of transitioning over to a normal closure or closure script workflow once you've learned with closure. Because once you kind of understand how to translate between the text representation of stuff and the closure representation, it's just completely the same language. Another benefit for beginners is that, like I said, there's no way to have a hanging parentheses or anything. closure forces you to have valid syntax. There's no way to produce a syntactically invalid program in closure. And additionally, for people who already know some programming languages, oftentimes when they look at LISPs, they'll say, there are so many parentheses here. This looks so ugly. And once you understand the syntax of LISP, you realize that that kind of simplicity of just having parentheses and stuff gives you a lot of power in that it makes the program so kind of easily amenable to like analysis, which allows for things like structural editing and metaprogramming in the form of macros. And so an interface like Vloater can allow you to enjoy all those benefits of LISPs, but without seeing any parentheses at all, right? There were very few parentheses listed during this talk, even though I was just programming in closure script, right? The parentheses just get translated to circles. And so somebody can look at a bit of LISP code and not even have to worry about all the parentheses. So that won't scare people off anymore if you're using closure. There's also some significant limitations with closure as it exists right now. And one of the biggest limitations in principle is the information density of the code that you're seeing. So one thing that's great about text-based interfaces is that you can see a lot of text on a screen at once if you have a reasonable zoom level. In closure, it's hard to see more than three layers deep into a hierarchy without the text becoming so small that it's impossible to read. Now, thankfully, closure makes it very easy to jump around in the hierarchy and zoom to different levels. And so if you're actively clicking around or tapping around, then the information density problem is solved to some extent. But if you're just looking at like a static screen, then you can't see as much code at once with closure as you could with a text-based interface. Another limitation with closure right now is that it doesn't really do much in the way of handling errors. When an error happens in your closure script code, oftentimes it'll just crash the closure web app itself. And even when that doesn't happen, it might just fail silently and not really give you any kind of useful information. Eventually, I do plan to fix this. I plan to add some more tools for kind of exploring closure errors in a visual way. But right now, closure doesn't really have any way to do that. The only way to see what's gone wrong when you're at your code crashes is to look at the development console. And even then, the results that it produces can be kind of hard to understand given that it's operating in a bootstrapped environment. And another big limitation of closure is that right now, there's not really any way to use it on an existing code base. If closure just lives as a web app and if you want to edit something in closure, you'd have to copy all your code into this web app and then copy it back out when you're done, which obviously isn't very practical. I'd like to also address this limitation used to join existing code bases by eventually making a port of closure that works as kind of like an in-repl plugin. And there's a project called Gorilla Repl that I'm aiming to base this off of that creates kind of a web browser-based interface as a kind of rebel for a running like JBM closure project. And so in the future, I'd like to eventually develop something like that for closure as well. So anyways, that's my talk. Thank you for listening. Here's my contact information if you'd like to get in touch with me. And I hope that you find closure useful or at least interesting. Thank you.