· 5 min read
How I built Kitted's infrastructure
Kitted went live on November 1 with a store and a 3D Armory. Here's how the pieces fit together - from licensed 3D models to a GPU that renders each print after checkout - and what I'd do the same way again.
- kitted
- infrastructure
- building
Kitted went live on November 1: a store with 76 curated designs, and the 3D Armory, where anyone can build their own gun part by part and order it printed on a tee, hoodie, desk mat, mug or sticker. I wrote about why I’m building it. This post is the how.
It’s one person and a lot of Claude Code. The repo’s first commit was September 27. By launch it had 776 commits and 164 merged pull requests.
The shape of it
Kitted is really two businesses sharing one set of 3D models. The curated catalog is ordinary print-on-demand: designs I render ahead of time, listed in Shopify and printed by Printful. The 3D Armory is the hard part, because every order is a design nobody has seen until the customer pays.
Build
The 3D Armory
Customers kit out a gun in the browser. They get display-only versions of the parts; the full models never leave the server.
- three.js
- Next.js
- Vercel
Save
A build becomes a short code
Every build packs into a short share code. It powers share links, saved builds and the leaderboard, and later rides along with the order.
- Supabase
Buy
Checkout on Shopify
The cart and checkout are plain Shopify, with Shop Pay, Apple Pay and Google Pay. The build code travels on the line item.
- Shopify
Render
A GPU renders the print
Only after payment does a cloud GPU render the build in Blender at print size. A minute or two and a few cents per print.
- Modal
- Blender Cycles
Print
Printful prints and ships
The finished files go straight to Printful, which prints and ships in the US. Tracking flows back to the customer automatically.
- Printful
Starting with the 3D models
Everything starts with licensed 3D models of real parts - receivers, handguards, optics, grips, stocks. Each one gets cleaned up in Blender at real-world scale, with its origin at the point where it attaches. That convention is what makes assembly simple: a part snaps onto a named socket on another part with no offsets to fiddle with.
They’re visual models only. They have the outside shape and nothing that works.
Every part and every camo pattern has a license record in the database before it can go live, and the database itself refuses to publish a part until its logos are stripped and its scale is checked. I’d rather have the rule fail a query than trust myself to remember it.
The 3D Armory
The builder runs in the browser with three.js, on phones as well as desktops. Most of the work there went into two things:
- Phones. A 3D builder that works on a laptop can still fall apart on an iPhone. I tested in the iOS Simulator throughout and tuned until all four launch platforms turned smoothly in mobile Safari.
- Protecting the models. Customers get display-only versions of the parts, good enough to look right on screen. The full models never leave the server, and there is no way to download a model. The licenses I buy require that, and it’s also just the right call.
A build packs down into a short code. That code is the whole design: it reopens the build from a share link, saves it, puts it on the community leaderboard, and later rides along with the order.
Checkout stays boring
I didn’t build a cart. When someone taps Buy, the build code goes onto a Shopify line item and the customer checks out like any other Shopify store, with Shop Pay, Apple Pay and Google Pay. Shopify handles payments, tax and receipts, which are exactly the things I don’t want to get creative with.
Rendering the print after payment
This is the part I’m proudest of. Nothing gets rendered for print until an order is paid. Then the order webhook queues a job, and a cloud GPU on Modal renders that exact build in Blender’s Cycles renderer at full print size - a minute or two, and a few cents.
Doing it after payment means I never pay for GPU time on carts that don’t buy, and the print is rendered from the full-quality models instead of whatever the customer’s phone could draw. The files then go to Printful automatically, and shipping updates flow back to the customer.
The curated catalog uses the same render setup ahead of time, so a curated shirt and a custom one look like they came from the same studio. Because they did.
The community side
Saved builds, a leaderboard, votes, ranks and squads all live in Supabase, the database. There’s almost no free text anywhere a customer can type. The one exception is usernames, and every one goes through a word filter and an AI moderation check before anyone else can see it. Anything borderline waits for me.
Running it
- Hosting: Next.js on Vercel, with a firewall in front for bots and scrapers.
- Data: Supabase for the database, sign-in and file storage.
- Analytics: PostHog on both the app and the store.
- Email: Cloudflare routes the inboxes, Resend sends the mail.
- Support: an AI drafts replies to common questions, and I read them before they go out.
Each business I run gets its own accounts with these services, so a traffic spike or a billing problem on one can’t take down the other.
What I’d do the same way again
- Write the rules down first. Before any code, I wrote a rules file for Claude Code: what Kitted will never do, the brand, how 3D parts are named and assembled. Every session starts from it, and it has saved me from more mistakes than any test.
- Put guardrails in the database. Rules about licensing and publishing live as database constraints, not just in my head.
- Spend money after the customer does. GPU renders, print files and fulfillment all wait for payment.
- Use boring tools for money. Shopify for checkout, Printful for printing. My time goes into the part nobody else sells.
- Keep changes small. 164 pull requests in five weeks sounds like a lot. Each one was small enough to read, test and roll back.
I’ve left out the security specifics on purpose. How the models are protected and how the site handles abuse work better when they aren’t written down in public.
If you want to see it working, build something at kittedbuilds.com.