Designing 3D models you cannot see
What I actually wanted
A badge that says I am partially sighted, that a stranger can read without staring, and that works when I am not in an English-speaking country.
Badges like this exist. The ones I could find were small, cost more than they should, and were almost always English only. The size is the part that irritates most: the whole purpose is to be noticed at a glance by somebody who is not looking for it, and a discreet badge is a contradiction. The language part matters at exactly the moment it is hardest to explain yourself, which is when you are somewhere you do not speak the language.
None of that is a hard engineering problem. It is a thing nobody had bothered to make, because the market for it is small and scattered across a dozen languages.
That is precisely the shape of problem a 3D printer is good at, and it is precisely the shape of problem I could not have solved a year ago, because I am not a designer and I had never used CAD.
I now have five printed objects in the house that I designed, including that badge, in five languages, and I wear it.

The interesting part is not that an AI wrote the models. It is what had to be built around it before the models were any good, and that I did not design that scaffolding either. It accumulated, one failure at a time.
The problem nobody mentions
When you ask an agent to write a web page you can look at the result. When you ask it to design a physical object, neither of you can. It emits code, the code compiles, and what comes out is a mesh: a few thousand triangles that mean nothing to a language model and nothing to me.
The failures are not syntax errors. OpenSCAD catches those. The failures are models that compile perfectly and are wrong. Letters that merged into a blob. A wall too thin to survive a nozzle. A recess that silently is not there. You find out an hour into a print, or worse, when you pick the thing up.
So the loop has to close some other way.
Starting from nothing
I began by opening a blank session and asking it to research the current state of the art for programmatically generating 3D models, and to make a case for one. It came back with OpenSCAD: models as code, parametric, scriptable from a command line, no GUI in the way.
I want to be careful about how much credit that deserves. It is a good answer, and I could not have given it. It is also the answer that suits an agent, and I had no way to judge whether it was the answer that suited me. I went with it because the reasoning was checkable, not because I knew.
That turns out to be a reasonable way to start in a field you know nothing about. Ask for the landscape and the argument, not the answer.
The instruction that mattered
The thing that actually changed the results was a standing instruction: after every modelling attempt, look at what went wrong and ask what tooling would have caught it earlier.
Not “try harder next time”. Build the check.
Almost everything useful in that repository came out of that instruction rather than out of any plan. Each script exists because something specific went wrong once, and the answer to “how would we have known” turned into code.
What accumulated
Three layers, in the order they appeared.
Look at it, from seven angles
The first failure was the dullest. A model that looked right in one render was wrong from another. So: seven orthographic views on every meaningful edit, and inspect them before showing anyone.
The bottom view earns its place more than the rest. It is the face that meets the print bed, which is where flatness, chamfers and pockets go wrong, and it is the one you never think to look at.

There is a limit, and finding it was its own failure. A straight-down render cannot show a shallow recess at all. A 0.6mm pocket in the back of the badge was invisible in the render and had to be verified by ray-casting the mesh instead. A view is evidence, not proof.
Check the mesh is a solid
Rendering shows you shape. It does not tell you the geometry is manufacturable. So the next layer runs on the exported STL and asks four questions.
Is it watertight, with no holes. Is the winding consistent, so every face points outward. Does it have positive volume, which catches an inverted solid. Is it a single body, or has something drifted loose.
Those take a second and fail before a slicer would.
Measure the features
The third layer is the one I would not have thought to build, and it is the one that has saved the most.
It measures two things on embossed text: how many separate islands there are in the mesh, and how narrow the narrowest stroke is.
Island count is a proxy for legibility. For the badge it should equal the number of glyphs plus four, being the rim and the three pieces of the eye symbol. Fewer means letters have merged into each other. More means one has fragmented, such as an accent floating free.
Stroke width is measured by morphological opening: erode the shape by half a candidate width, dilate it back, and see whether it survives. The widest width that preserves the shape is the narrowest real stroke.
The obvious approach is twice the area over the perimeter, and it is wrong. The script says so in a comment, because whoever reads it next will be tempted: for a short shape it underestimates badly, since a rectangle of width w and height h gives wh over w plus h. A short thick letter reports as a thin one and you shrink type that was fine.
The moment it paid for itself
The badge needed a Japanese version. The obvious rendering is the kanji 視覚障害.
Two independent reasons say no. Japanese low-vision practice prefers the katakana ロービジョン, because 弱視 collides with the medical sense of amblyopia. And at 58mm across, on a 0.4mm nozzle, the kanji strokes sit so close together that the gaps between them close up into an unreadable blob.

That is the katakana version, and every stroke stands clear of its neighbour. The kanji did not.
The second reason was caught by the island count, before anything was printed. The number came back far lower than the glyph count and the check said the glyphs had merged. Rendering both and comparing confirmed it.
Nobody looked at a picture and thought that looks wrong. A script counted connected components and said so.
Knowledge belongs in the checker, not the prompt
One more thing, which I think is the general lesson.
FDM printing has a widely quoted minimum feature size of about 1.2mm. An agent told that rule will apply it everywhere, and will shrink your lettering until it fits.
The rule is about free-standing walls, which have to hold themselves up and carry load. Embossed detail is a different case: it sits fully supported on solid material underneath, and prints cleanly down to roughly 0.8mm, or two extrusion widths. Below that a stroke stops being a letterform and becomes a single wandering bead.
Measured stroke widths on the finished badge run from 1.05mm to 1.37mm. All below the quoted rule. All fine, and printed.
That distinction now lives in the checker, with the reasoning written next to the number, and a note telling the next reader not to bold the type to chase 1.2mm. Putting it in a prompt would have meant relearning it every session. Putting it in a script means it is still true next year.
What transfers
Very little of this is about 3D printing.
When the model cannot see its output, build the thing that can. Not a better prompt. An actual measurement with a threshold and a reason.
Make the tooling review part of the loop. The single most productive instruction was to ask, after each attempt, what would have caught this sooner. Nearly everything useful came from that rather than from planning.
Put domain knowledge in code, with its reasoning attached. Every threshold in these scripts carries a comment explaining what it protects, because a constraint whose reason has been forgotten gets removed the first time it is inconvenient.
Trust the numbers over the picture. The renders are for you. The checks are what actually caught things.
The scripts are in the printable-badges repository, along with the badge itself.