Loading...
How D3Designs started: a friend's loaded question, the stack I already knew, and the shape of a 3D canvas before it was a D&D tool.
A friend asked me if an all-in-one D&D tool existed.
It was a loaded question. Roll20 does maps and dice. D&D Beyond does character sheets. Foundry does VTT. Owlbear does light maps. World Anvil does worldbuilding. Notion does whatever you decide Notion does. Every one of them is good at the part they're good at, and the seams between them are where DMs lose their evenings.
I didn't start D3Designs that night. But I started thinking about it.
I should be honest about what this was, because the polished version of this story would say I had a grand vision and chose my tools deliberately. I didn't. I wanted to get into the 3D space, and I wanted to build a micro-SaaS. Those were the two real goals. The product itself was still fuzzy: I was building toward something STL-export-shaped, where you'd design a thing in voxels and print it, but I couldn't have described the product in one sentence.
What I was sure about was the stack.
I picked what I was already comfortable with:
This isn't research-backed advice. It's what comes out when a developer ten years in needs to start a thing on a Wednesday. The tradeoff with picking what you know is you skip a lot of debate and ship the first feature faster, and the cost is you don't notice when something better has emerged. I'm fine with the tradeoff for a project I might abandon.
The first thing that needed to exist was the data model.
A user owns projects. A project owns canvases. A canvas owns layers. A layer owns objects. Objects have geometry: at first, voxel data and uploaded GLB models. That's the whole tree, and it carried for months before I had to bend it. Drizzle schemas, tRPC routers, and Zustand slices all mirrored the same five-level shape, which meant adding a new entity type was a half-day of plumbing rather than a refactor.
The 3D canvas itself was a React Three Fiber scene with a camera, a grid, and a list of objects mapped to mesh primitives. The voxel grid was a fixed-size 3D array, with each cell tracking a color and an "occupied" boolean. Painting a voxel meant updating one cell in the array and triggering a re-render: Zustand handled the store, R3F handled the geometry, and the layers panel listened to both.
Voxel-to-GLTF conversion was the first piece of actual 3D engineering. The naive version creates one cube mesh per voxel, which works until you have a few hundred voxels and the frame rate dies. The version that shipped does mesh merging: adjacent voxels of the same color collapse into a single buffer geometry, and it runs through a small worker so the main thread doesn't stall during export. None of it elegant. Most of it works.
The layers panel was where the UX started to feel like a tool instead of a demo. Object visibility toggles, drag-to-reorder, click-to-select, auto-select on add, and labels distinguishing "voxel object" from "uploaded model": small features individually, but together they're what made the canvas feel inhabited.
Auth. Projects. Canvases attached to projects. A dashboard. Billing scaffolding nobody was paying for. A 3D scene I could put a cube in. A voxel editor I could paint with. A layers panel that didn't lie about what was on the canvas. A GLTF export that didn't melt the browser.
Not a product. Not yet a business. Just enough infrastructure that if a product showed up, it'd have somewhere to land.
The friend who asked the loaded question hadn't seen any of this yet. The D&D pivot was still ahead. I was just a guy with a working canvas and a vague idea about STL exports.
That turned out to be enough.

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

A dedicated app for Mac and Windows, with the session view that wants to live outside a browser tab. Public beta, both platforms, available today.

Picking voxels as the editing primitive, building a layers panel that didn't lie, and the UX fixes that made a 3D scene feel like a tool.