D&D pivots everything: characters, the 5e API, and the first generation
The voxel work ran out of pull. The D&D pivot happened because the energy was there and the infrastructure already pointed in that direction.
The voxel work stopped pulling me forward.
Not in a dramatic way. The features were shipping, the canvas worked, the layers panel had stopped lying. But the next thing on the list was always another small UX fix, and I noticed I was reaching for the side projects tab more than the main one. That's the burnout signal I've learned to take seriously: not "I'm exhausted," but "I'm not curious about my own code anymore."
So I followed the energy.
Why D&D, specifically
Two reasons, neither of them strategic.
The friend's loaded question had been sitting in the back of my head for two months. The all-in-one D&D tool that didn't exist. I'd been building infrastructure for an STL-export-shaped product that I couldn't describe in one sentence, and the D&D framing happened to be the one I could describe in one sentence.
The other reason is simpler: voxels pivot toward D&D more cleanly than they pivot toward anything else. Terrain is voxels. Dungeons are voxels. Props are voxels. The work I'd already shipped wasn't going to waste: it was going to wait. What I needed was a feature that could land on top of it and pull users in, and "your D&D character, with art, in 3D" was a feature I could believe in.
I was also just thinking about D&D a lot. I'm not going to pretend that wasn't part of it.
The pivot looked like a sprint
The repo went quiet for most of December and then exploded in the last week. Avatar generation dialog, image handling, modal preview, character sharing, share routes with Open Graph metadata. Most of the late-December work was the pipeline that takes a character description and turns it into a portrait, plus the public share page that shows it off.
I'm going to skip the AI image generation drama. There wasn't any. The image side worked roughly first try: image generation is a solved problem in late 2024, the rough edges were the usual ones, and there's nothing in the experience worth a section in a blog post. Every other AI startup is writing that post. Mine doesn't need to.
The actual engineering challenge was somewhere else.
D&D 5e is harder than it looks
The thing I underestimated was the rules.
A "D&D character" sounds like a small data structure. Name, race, class, ability scores, a portrait. In practice it's a graph of cross-referenced rules. Race determines speed and grants abilities. Class determines proficiencies, hit dice, spellcasting, and a sub-tree of features per level. Background grants skills and equipment. Ability scores cascade into modifiers, which cascade into saving throws and attack bonuses. Levels gate everything from cantrips to extra attacks. None of this is hard individually. All of it together is a lot of paper.
If you ask a language model to "generate a level 5 half-elf bard," you'll get a character. It'll have the right vibe. The problem is it'll also have wrong proficiencies, plausible-sounding spells the bard list doesn't include, and ability scores that don't match the modifiers next to them. Models hallucinate D&D the same way they hallucinate anything else: confidently, and in a register that sounds correct unless you check.
The fix wasn't a rules engine. A real rules engine for 5e is a multi-week project, and I was building a feature, not a system of record. The fix was reference data.
The 5e SRD as ground truth
I pulled the 5e SRD into the database. Races, classes, subclasses, backgrounds, skills, feats, equipment, spells. The data lives in tables that mirror the SRD's structure, and the schema is dull on purpose: names, descriptions, level requirements, stat modifiers, proficiency lists.
The character generation flow then becomes a different shape. Instead of asking the model to invent a half-elf bard from scratch, I hand it the SRD's actual half-elf entry and the actual bard entry and ask for a character that fits inside that. Name, backstory, appearance, personality: those are creative work, the kind of thing models are good at. The mechanical structure stays grounded in real data.
This isn't a rules engine. It doesn't validate that the character is legal: if the model decides the bard somehow has a fighter's heavy armor proficiency, the system doesn't catch that. But it's enough to make characters that pass the sniff test for someone who's played D&D, and it's a foundation that can grow into validation later if the product needs it.
The SRD client itself was a few hundred lines of TypeScript. The schema migrations were uneventful. The interesting work was deciding what not to model: I skipped subclasses-of-subclasses, skipped variant rules, skipped Unearthed Arcana content, skipped anything that wasn't in the core SRD. The product's job is to make characters that feel right. Edge cases can wait until someone files a bug.
What the first stretch shipped
A character generator that takes a prompt and returns a structured character grounded in real 5e data. A portrait generation flow with a modal preview and a save path. A public share page with Open Graph cards so a generated character can be linked anywhere. The same voxel infrastructure as before, sitting underneath, no longer the headline feature.
The product still wasn't fully described in a sentence. But it was much closer.
The voxel work was the foundation. The D&D pivot was the shape. What was missing was the rest of the cast: monsters, NPCs, encounters, campaigns. That part started immediately.

Written by Jean P.
Solo builder.
Discuss this post
Join the D3 Designs Discord to share thoughts and follow along.
