9 ms·
Show HN: Make 3D art in your browser using Lisp and math
Bauble is a toy that I've been working on for a few weeks, and I think it's reached the point where other people could have fun with it!
Bauble is based on raymarching signed distance functions, which are kind of like... 3D vector art? They're pretty common in the procedural art community and you can do some amazing things with them, but normally writing SDFs means writing low-level shader code.
I wanted to play with SDFs, but I found it very frustrating to translate "I want to rotate this" into "okay, that means I have to construct a rotation matrix, and then apply it to the current point, and then evaluate the shape...". So I made a high-level Janet DSL that compiles down to GLSL shader code so I could more easily play with mathematically defined shapes.
For more about SDFs, this mind-blowing video is what got me interested in the first place, and shows you what they're capable of in the hands of an expert: https://www.youtube.com/watch?v=8--5LwHRhjk https://www.youtube.com/watch?v=8--5LwHRhjk
- billconan 4y agoIs there a good framework for creating the same online ide/code demo as yours? I want to make a live tutorial, I'm thinking about creating a static site generator to generate the same kind of demo you have here.
- ianthehenry 4y agoI'm using https://codemirror.net/ https://codemirror.net/ as the editor, and I'm basically just running an onchange event on every keystroke. Not very fancy or sophisticated. The details of what exactly happens in that event are very specific to WASM/Janet/Bauble, but I think you could do something similar with JavaScript code pretty trivially. Long-term I think I'd rather break this out into a separate page with multiple canvases inline in the text -- so you can more easily scan through it/go back to previous sections -- but I was lazy and this was the easiest way to get it done. Also, this is just a static site. With hand-written HTML because I've been too lazy to configure a static site generator yet...
- deleted 4y ago[deleted]
- icu 4y agoThis is awesome, how did you implement the live code editor?
- ianthehenry 4y agoIt's CodeMirror! All I had to do was write a Janet grammar for it -- very easy to do. CodeMirror is pretty amazing -- I was able to implement the "edit values with your mouse" by just asking CodeMirror for the syntax node under the cursor, checking if it parsed as a number, and if so replacing it with a different string. https://codemirror.net/ https://codemirror.net/ https://github.com/ianthehenry/codemirror-lang-janet https://github.com/ianthehenry/codemirror-lang-janet I went with CodeMirror after reading this post: https://blog.replit.com/codemirror https://blog.replit.com/codemirror and I've been super happy with it.
- fros1y 4y agoYou should check out libfive! https://libfive.com/studio/ https://libfive.com/studio/. Previously discussed here: https://news.ycombinator.com/item?id=26930822 https://news.ycombinator.com/item?id=26930822. It is the child of Ao, previously discussed here: https://news.ycombinator.com/item?id=12319406 https://news.ycombinator.com/item?id=12319406.
- ianthehenry 4y agolibfive is great! And if you're into SDFs, libfive will give you something Bauble probably never will: the ability to export shapes as meshes, so you can 3D print them or import them into Blender or whatever. libfive is only concerned with geometry, though, so you can't do any of the coloring/shading/procedural graphics stuff. And no animations. I think of Bauble as closer to Shadertoy than libfive in purpose, although they appear very similar.
- deleted 4y ago[deleted]
- chaosprint 4y agoWow, this is so beautiful! Your web app demo is very neat. Do you think this can be used for live coding visuals? I'd love to use it together with Glicol(https://glicol.org https://glicol.org). So far I have tested Hydra and p5.js; they can be used as CDN link or NPM packages. Look forward to its progress.
- ianthehenry 4y agoThanks! I'm not really sure how to make it work with Glicol -- I don't know anything about the livecoding world. But in theory it would be easy to add a new "magic variable" (shader uniform) for like "mean root squared audio sample amplitude over the last frame..."? You'd just need some way for Glicol to tell Bauble what the value should be. I don't know how they'd communicate or if there's some standard for integrating music and visuals...? Apart from that big question mark I think it would be very suitable for livecoding visuals, as you can write some impressive effects with very little code. Easy CSS change to make the canvas full-screen and like overlay the code on top of it. That's a thing that livecoders do, right?
- chaosprint 4y agoSomething like this: https://youtu.be/iKj7IibG0OU https://youtu.be/iKj7IibG0OU I think both Hydra and p5.js render things to a <canvas>, which is probably the same as what your demo does, right? Then we just need to set some CSS for the Canvas to make it full screen and hide behind the code editor.
- ianthehenry 4y agoOhhh I think I misunderstood how this works. You write the visualization ahead of time, and then you livecode the music only? Bauble would work well for that -- you could just grab the compiled shader source and integrate it into your livecoding environment; wouldn't even need to integrate the Bauble runtime. All you'd need to do is set a few uniforms and issue a draw call. I was imagining something where you switch between coding audio and visuals on the fly -- which is still totally possible, but would require a bit of work to get them talking to each other.
- dejongh 4y agoNice!
- averysmallbird 4y agoThis is beautiful. My apologies if I missed it, but is it possible to download the produced figure as an STL (or something equivalent)?
- ianthehenry 4y agoNo; Bauble doesn't know how to "rasterize" SDFs into meshes; it only knows how to raymarch them. It's theoretically possible, but it's a pretty complex problem that would take me much too long to figure out and implement. So Bauble is relegated to just making pretty pictures for now. If you want to produce meshes using SDFs, check out https://libfive.com/ https://libfive.com/
- averysmallbird 4y agoThanks!
- gnramires 4y agoThere's also ImplicitCAD (https://github.com/Haskell-Things/ImplicitCAD https://github.com/Haskell-Things/ImplicitCAD) which produces STLs, as it is designed for CAD. It uses implicit functions, which I believe are similar to SDFs (I believe the idea is not to necessarily correspond to the distance function).
- frabert 4y agoI think that would be quite difficult, as raymarching does not produce polygons, so you'd need a way to polygonize the resulting sdf. Maybe marching cubes?
- jcynix 4y agoSurely not "something equivalent" that you are expecting, but my smartphone can do screen recordings, so here's a cropped version of what's displayed in its browser: http://www.cynix.net/2022/screenrecording-baubel.mp4 I cropped the screen recording to square format with the online service at clideo.com so they added their watermark.
- andrewstuart 4y agoIf you like this sort of thing then also https://www.glslsandbox.com/?page=4 https://www.glslsandbox.com/?page=4 and https://www.shadertoy.com https://www.shadertoy.com Unfortunately glslsanbox is not moderated very well so there's lots of spammy garbage there but also lots of really great stuff.
- anhner 4y agoSorry for my ignorance, but what kind of lisp has piping? Or what is the vertical line operator called? (torus :z 60 30 | twist :y 0.07 | rotate-pi :y t :z 0.05 ...
- ianthehenry 4y agoThis is described later in the tutorial (ctrl-f "lisp heresy"). It's a macro that I wrote, not something built into Janet -- I'm sure I'm not the first person to do this, but I'm not aware of any lisps that have such a construct built-in.
- spapas82 4y agoClojure has the thread first/last macros -> and ->> which pipes each result to the next form.
- ianthehenry 4y agoYeah, and Janet copies Clojure's threading macros (that's how I implemented pipe syntax -- split on pipes, add some parens, and stick them into a -> form). I've just never seen it done infix like this -- it's very convenient when you don't have something like paredit to quickly wrap an expression.
- eyelidlessness 4y agoAnd this is why Lisp is amazing. Seeing the question I immediately thought “this looks like a really nice convenience macro for the author’s preferred formatting”!
- tehsauce 4y agoShamelessly mentioning our project shaderpark, which is also a live-coding interface for working with SDFs but using javascript! https://shaderpark.com/ https://shaderpark.com/
- chaosprint 4y agolooks nice
- stasilo 4y agocool! never heard of your project, I've actually written something a bit similar :D https://github.com/stasilo/retrace.gl https://github.com/stasilo/retrace.gl
- tehsauce 4y agoOh cool, that looks really nice! One of the fun things that our library does is that while it has built-in abstractions for SDFs, you can also just write pretty much whatever kind of shader (2D or anything) you want.
- xrd 4y agoThis demo and the comments makes me wish for a button underneath the original link that says "upvote everything here." What an incredible project and what great comments. Thanks everyone.
- eyelidlessness 4y agoThis is awesome and I will avail myself of it pretty quickly. I may not use it directly for my project (I’m targeting SVG), but it already feels like I can benefit from the high level DSL as a glossary rather than the much more arduous journey of learning whole mathematical implementations of something just to find the next related term that’s closer to what I want to achieve. I’ll probably learn the maths too but it really helps not having to know the entire universe just to ask what I’m looking for :)
- shadytrees 4y agobut what about your novel, ian