A domain-specific language for doing 3d modelling. As in, you write code, and it spits out a 3d model.
If you want to make 3d stuff, there’s “CAD” (Computer-Aided Design) software for making machinable, functional parts (like gears or brackets or cases or adapters) and then there’s software for making art for game assets or animated shorts or whatever.
Another way to divide the space: there’s software where you make the result directly using a pointing device (think “MS Paint” or something where you can “freehand” stuff), and then there’s software for making 3d shapes by writing code.
(This is entirely a tangent, but I think of the “pointing-device” way of doing things as the “potter paradigm” which connects your fingers as much as possible to the digital space that is your medium so you can manipulate the thing you’re making. And the latter is the “dark factory paradigm” named after “dark factories” – manufacturing facilities populated only by robots doing manufacturing where they don’t even need to keep the lights or HVAC on because the robots don’t need them. In the “dark factory paradigm”, you externalize a portion of your brain in the form of a program/script and it acts on your behalf on the digital medium. And these paradigms aren’t limited to just making 3d files. Graphviz is another good example of something in the more “dark factory” way of doing things. And the project I’m working on now isn’t the first one I’ve undertaken to expand availability of “dark factory” pattern asset creation tools available. I really feel like the world needs a lot more of that. Not to say the “dark factory” pattern is “superior” per se, but it’s a lot better for the way my brain works and I’d like for way more of such tools to exist. So I guess I’m being the change I want to see in the world.)
Just some examples of software for making 3d models sorted on those two axes:
| CAD | Artistic 3d Modeling ---------+-------------+---------------------- Pointing | FreeCAD | Blender Device | TinkerCAD | Autodesk Maya ---------+-------------+---------------------- Writing | OpenSCAD | Code | ImplicitCAD |Notice that bottom-right box is empty? I’m working to fix that.
The working name for what I’m working on now is “Modelgen”. Not 100% sure that’ll be the final name, but it works for now.
(And to be fair, I think some of the tools in the top box may have built-in tools for doing things by writing code, but I want something where the writing-code way of doing things is the “bones” of the project, not something kindof tacked on after the fact as an afterthought.)
Just to tease it in some slightly more concrete terms, following is kindof a “hello world” sort of program that will display (pop up a window with an OpenGL viewer in it) a low-poly sphere. (The sphere in this example will consist of 8 times 16 equals 128 faces, some square/rectangular ones with 4 vertices, some triangular with 3.)
import "mg/prim" import "mg/util" sphere := prim.Sphere(8, 16) util.Display(sphere)The result looks like this:

Outputting that sphere to a file (in GLTF format) instead of just displaying it looks like this:
import "mg/prim" import "mg/format/gltf" sphere := prim.Sphere(8, 16) gltf.Encode(@{ Filename: "sphere.gltf", VertexSets: [@{ Vertices: sphere, }], })For a much more complex example, here’s a desk fan I modeled with my language just to test it out and provide an example to users:

And the corresponding source code can be found here. (It was too big to paste into a Lemmy comment.)
Everything I’ve showed here is actual. Like, not potential future state stuff, but works today on my computer. (I haven’t published it anywhere yet, but that’s coming… sometime. Heh. It’ll be FOSS when I do. AGPL license.)
Right now, it only supports vertices and faces, and has some helpers for doing some helpful geometry-generation kind of manipulations. It doesn’t yet support textures, normals, normal maps, armatures, morph targets, animations, etc but all of that is planned to happen at some point. It’s still early on. (It’s nearly 25,000 lines of Go code (plus a little HTML/JS/CSS that tips the total over 25,000 according to cloc) and I’ve been working on it for many months (not sure exactly how long) and I’m calling it “early on”. Lol.)
Just some miscellaneous stuff:
- It has a functional “playground”. As in, a webpage where you can go (or where you’ll be able to go once I put it out there somewhere), write Modelgen code in a text box, hit the “run” button, and it will run that Modelgen code in your browser. (Not on the server. Actually in your browser using WASM and WebGL for the displayer.) Think Go’s Playground or something like JSFiddle, only for Modelgen.
- Right now, it’s an interpreted language, but I’m planning to support automated transpilation from Modelgen to Go as well. Picture this. You’re writing a game, right. A largely procedurally-generated game maybe similar, let’s say, to Spore. Your game needs to generate creatures on the fly at runtime. So you build a function in Modelgen that takes some parameters – maybe biome kind of stuff like aridity that might affect how reptilian the creature is and maybe gravity level that would affect how “stocky” the creature was or whatever – you transpile that Modelgen function into Go, you write your game in Go and include that function in the code, and when your game needs a new creature, it just calls the function, which uses the parameters and maybe some PRNG and gets a fully functional model complete with textures and animations. (I probably won’t bother making facilities for transpiling to other languages other than Go, but it’ll be FOSS. If someone contributes code for transpiling to C or JavaSript or whatever, I’d probably be open to adopting it into Modelgen if they wanted that.)
- It only supports two file formats so far: STL and GLTF. And it only supports outputting to those file formats, not importing. But I definitely plan to support as many formats as possible and to support importing from files.
- It is written in a way such that Modelgen can be used just as a Go library without involving the DSL. And I plan for that to continue to be the case moving forward.
- Modelgen supports faces with any number of vertices more than 3. But the displayer and many of the functions that output to files require 3-vertex faces. But there’s stuff built into Modelgen to split more-than-three-vertex faces into three-vertex faces automatically.
Ok. I think I’ve said enough at this point. Lol.
Anti-mouse is not quite my thing, though the look is interesting. You might consider vertex color support at-least for part color and at-most for face color (/face loops). Though I also have been tinkering with my own 3-digit hex color palette and VC-friendly Godot materials* so I might be biased. It’s also too bad that NURBS isn’t more supported (SDF models are the closest modern equivalent).
I have thought about making my own editor, with more focus on flat mesh editing (not excluding simple operations like extrusion, revolve etc). I haven’t started, other than a text format/loader I made (via Raylib+Nim-lang bindings) which isn’t quite as capable as what I have in mind.
I’m not sure if ‘modelgen’ is a good name, it sounds AI-related.
* generally untextured. though I’m not entirely against general-use textures especially via normal maps, for instance metal is pretty fun even just via built-in noise
You might consider vertex color support at-least for part color and at-most for face color (/face loops).
Yeah, kindof my guiding principle for what features I want it to support is “support whatever GLTF supports”, and GLTF has something called “COLOR_0” which is basically vertex colors. So, yeah. It’s on the roadmap. How high up the priority list? No clue at this point. Lol. (Right now I’m tweaking the OpenGL 3d viewer built into it, and I think probably one of the next things I’ll tackle is per-vertex normals. But yeah.) If folks want per-face colors, I’ll probably just make users split vertices as necessary. Like, if they have something like the following:
* / \ / \ / Red \ / \ *---------* \ Blue / \ / \ / \ / *And they want the whole top face to be red and the whole bottom face to be blue (or, say, if they want a hard crease normals-wise at the junction there rather than a smooth transition), they’ll just have to have 6 separate vertices (though some of them will share the same location in space.) If that makes any sense.
I’m not sure if ‘modelgen’ is a good name, it sounds AI-related.
Yeah, that’s good feedback to have, and you’re not wrong. I don’t know. I haven’t thought of a better name yet. Heh.
It has what I’ve heard called a “Swiss Army knife” CLI. If you think of how Git works, for instance, where you have “git log”, “git commit”, “git revert”, “git show”, “git diff”, etc, that’s a “Swiss Army knife” pattern. So I want the executable to have an easy short version. I was thinking “mg” for “Modelgen”. (And it would have “mg run” for running a script and “mg shell” for an interactive REPL and “mg help” for usage information (all three of these preceding examples already exist and work) and “mg transpile” for transpiling a script to Go (when transpilation to Go is supported in the future) etc.) So I kindof want that to be a consideration of the name. If I renamed it to “Enmodelerator” or whatever, it’d be harder to come up with a short version for that. Heh.
Anyway! I’m rambling. But I do want to avoid any appearance of it being connected to anything GenAI. (And I do specifically intend for it never to include any LLM-generated code or anything.)
if folks want per-face colors, I’ll probably just make users split vertices as necessary
they’ll just have to have 6 separate vertices
If that makes any sense.Sure, this is the approach I believe was used for Mt. Crumpit in the VC skybox in the PS1 Grinch game (see the image in my post). Basically cut-and-paste into new mesh (‘separate>selection’ in Blender*), then paint. Perfectly fine for final assets, but can complicate mesh changes.
Another trick is to instead just add edge loops to contain the transition, so not exactly a hard edge but pretty close with a small enough face (this was Spyro’s trick for mountains/clouds/celestial-bodies etc in its VC skyboxes, also Homeworld 2 see explanation).
Technically gltf does support face corner domain (as called by Blender* color attribute), though I can understand the multiple reasons you might not go that route especially early on. Basic VC does cover a lot of use-cases, and I’m not sure if your modelling method will have that sort of work-flow where it’s simple+common to work with faces/topology directly like that (like for character design).
When you do get to textures/UV stuff you can also go that route for color via a palette as well. Assigning the entire UV map of a part onto the middle of a single pixel would also be the easiest first step to code, and a palette would make a lot of sense for this type of tool.
* I also am not so comfortable with Blender. It’s not impossible for the low-poly stuff that I do, but I’m not a master with shortcuts and the modifiers bother me with errors or I-should-not-have-done-that moments.
This is great information! I’m definitely no expert at 3d graphics and I’m mostly learning as I go, and this all gives me a lot to look into. Thanks much!
I’m not sure if ‘modelgen’ is a good name, it sounds AI-related.
3DCode, 4DCode, Next3D, OrganicCode, 3Gee, 3DKode, Object-Code, AnimatreeD, 3DFormat, ThreeDee (I like making up names for things)
Good stuff! I am likely to change the name, and this is good inspiration. I kinda like “3Gee”. Might have to think and maybe riff on that and see if there’s good option related to that or maybe just go with “3Gee”, heh. We’ll see.
Hey!
Thank you for sharing your project details with us. I like it. If you make this available to the public, please share it with us. I do have a question though, how fast is it rendering an image (for example the desk fan)?
It doesn’t yet support textures, normals, normal maps, armatures, morph targets, animations, etc but all of that is planned to happen at some point. This. I’m hyped to see this!
I’m impressed tbh, and 100% a future user of your software. You wouldn’t believe me if I tell you this but a couple of weeks ago I had a similar idea but I never worked on it. There must be a reason why I crossed your path (and vice versa). I tried to create a CGI video project, and I thought it would be way faster and easier to create it with code than manually creating it
Out of curiosity, what is your personal opinion on Blender?
I do have a question though, how fast is it rendering an image (for example the desk fan)?
Great question!
First off, keep in mind this is interpreted and I haven’t really had performance that front-and-centered in my mind so far. As I mentioned, I intend to implement transpilation to Go, and I expect way better performance when that’s an option. (I do want to keep the interpreter, though, just because I don’t want the Go runtime to be a hard dependency for users.)
Second, when I first saw your response, I happened to be on a Raspberry Pi 4 (8GB model), so I figured why not test out performance there.
Oh, and one other thing. The images I’ve been posting are screenshots of an OpenGL 3d viewer built into the program. If you call
util.Display(...)from the DSL it pops up a window with the model you passed to it displayed in it and you can rotate it, zoom in or out, turn on edge highlighting (“wireframe”-like) and such.So, I did a quick, completely unscientific benchmark. For this benchmark, I edited the desk fan script in a couple of ways. First, I removed the command that displays the fan. (That display command hangs the program until exit it, so if I benchmarked that, it’d only really be benchmarking my reflex speed – how fast I could close the viewer.) Second, just to give you an idea of how big/detailed/complex the model was, I printed the number of vertices. This test also doesn’t try to save the model to a file or anything, but does fully generate the geometry in memory. Here’s the result, again on a Raspberry Pi 4:
$ time ./modelgen run examples/deskfan/deskfan.mg 1343 real 0m0.880s user 0m0.260s sys 0m0.051sThat script was written with a “smoothness factor” parameter. Higher produces a model with more faces (a “smoother” model, if you will) and lower produces a model with fewer. The above test was with a smoothness of 1.0. I tried with 8.0 and here are the results:
$ time ./modelgen run examples/deskfan/deskfan.mg 70031 real 0m2.941s user 0m3.318s sys 0m0.185sSo, more than 50x the number of vertices, about 3.3x the amount of time required.
Oh, and in case you’re curious, here’s what the 8.0-smoothness desk fan looks like:

Here are the same two tests on my much beefier desktop system with a 3.4GHZ AMD Ryzen 3 1300X Quad-Core Processor.
$ time ./modelgen run examples/deskfan/deskfan.mg 1343 real 0m0.203s user 0m0.091s sys 0m0.009sAnd with smoothness factor of 8.0:
$ time ./modelgen run examples/deskfan/deskfan.mg 70031 real 0m0.810s user 0m0.915s sys 0m0.045sSo, there you go. That’s roughly the performance one could expect. At least until Go transpilation is completed.
Out of curiosity, what is your personal opinion on Blender?
My experience with Blender is just that I find it super frustrating. (And that likely says a lot more about me than about Blender, and totally no shade on Blender fans. A lot of what people do with Blender is extremely impressive.) Every time I have occasion to use it, I learn enough to do whatever I’m trying to do, but I definitely don’t like it, and that kind of information just doesn’t stick in my brain. (“Press such-and-such key and then such-and-such key and select such-and-such from the menu and then drag this there… etc” just slips out. Anything I’ve done in code, I can refer back to easily. I suppose I could make a video for my future self every time I learn how to do some particular thing in Blender, but with code, you get the ability to just see how you did something later for free.)
Plus it feels inefficient to tweak models after the fact. If I decide I wish I’d done some step 5 steps ago differently, it can be very difficult to make that change in a precise, perfect sort of way. What do you do, undo 5 times, do the step you wanted to do differently, and then re apply the other 4 steps? Can you reapply the other 4 steps on top of an altered fifth-back step? For right-brained artist types (respect!), I suspect such a thing mostly doesn’t matter. They’d tweak until it looked right, and the route they took to get there wouldn’t really bother them any. They’re not going for perfection. Perfection (or at least the… perhaps imperceptible, high-effort-low-payoff sort of mathematical precision I’m talking about) may be antithetical to their process and methods. But my brain very much rebels against any attempts to force it into the proper shape to be ok with that.
I do quite a lot of work in OpenSCAD. (I’ve got a 3d printing addiction and most of what I print is stuff I design myself in OpenSCAD.) I don’t intend for my DSL to change that. OpenSCAD is great for what OpenSCAD is great at, and what I’m building is for something different. OpenSCAD fits my brain very well, and was definitely a big source of inspiration for my DSL.
Also, I should definitely admit I haven’t used Blender very much. I’ve made a few rudimentary models. (Like… two or so?) I fixed up a model once for 3d printing. But that’s about it. I haven’t even gotten into texturing or rigging or anything in Blender.


