I Vibe-Coded a Merch Store To See If I Could Sell a Dad Cap
Every blog I have ever loved had merch.
CSS-Tricks. The Rust ones. The little indie design journals that taught me more than school did. The good ones always had a store — and I never bought any of it.
Not because I didn't want to support them. Because the merch never matched the work. The writing would be meticulous, the demos pixel-perfect, every gradient agonized over — and then the store was a default Shopify theme with a heather-grey tee and a logo slapped on the chest. The care stopped right at the storefront.
So I had a dumb question. Could I make merch that felt as considered as the thing it was selling? And — funnier question — could I actually get a stranger to buy it?
Funny enough: while I was building this, I went to pull up the CSS-Tricks store for old times' sake. They took it down. The canonical blog-with-merch doesn't have merch anymore.
Perfect. The lane is open.
Want to skip the story and just see the thing? shop.engmanager.xyz
Why a Store Is the Right Brick
This isn't a random side quest. It's the cheapest possible test of an idea I actually care about.
Project FootTraffic is the bigger swing: treat overlooked local plazas like real estate, raise the value of the place, and fund a compounding product platform one small business at a time. Booking flows. Quoting. A point-of-sale extension. A checkout a nail salon would never be priced into otherwise.
The whole thesis leans on a question I had never honestly stress-tested: can one person, with AI, stand up a genuinely good store — design, product, payments, the works — at a low enough effort that it's worth doing for a business that small?
A merch store for my own blog is the lowest-stakes way to find out. Low barrier to entry. Nobody's livelihood on the line. If I can sell a dad cap that says SCRUM MASTER to someone on the internet, then the checkout and POS modules FootTraffic needs stop being theoretical and start being a thing I have shipped.
Also it's just funny. Both things are allowed to be true.
The Bar: Yeezy
I took the UI almost entirely from Yeezy.
YZY SPLY — conceived by Kanye West, designed by Nick Knight — is the most reductive storefront in fashion. The brief was, roughly, make it beautiful in its simplicity: no words where words weren't needed, nothing trapped inside boxes, everything as large as it could be, the product allowed to be the entire interface. Earlier versions leaned on the lo-fi aesthetic of sites that sell medical supplies and camping gear — almost defiantly plain — and let the goods carry the page.
I'm not selling three-hundred-dollar foam shoes. I'm selling dad caps with engineering-manager in-jokes embroidered on the front. But the posture is the same: strip the chrome, set the type big and uppercase, and let the cap be the whole experience. No mega-nav. No carousel of trust badges. No cookie wall fistfight. A grid of caps, and then one cap.
That restraint is a feature, not laziness. Every element I didn't add is a thing that can't get in the way of the product.
The Whole Thing Is a Rust Macro
There is no React here. No SPA, no hydration, no client framework tax.
The entire store is server-rendered HTML strings, produced by a JSX-like templating macro I have been chipping away at in Rust. I wrote up step one of that experiment a while back — a tiny htm! macro built with macro_rules!. It has since grown teeth: a view! macro that reads like JSX ({ expr } to splice, "text" for text nodes, real components as plain functions) and compiles straight down to a String.
Axum serves that string. Assets are embedded into the binary at compile time, minified (lightningcss for CSS, oxc for JS), and given content-hashed URLs. The whole shop ships as one Rust binary — no node_modules, no build server, no runtime framework to babysit.
The trade I like: I get the developer experience of JSX and the output of a static string. The HTML is just there on first paint. The thing that makes it feel modern isn't a framework — it's the macro and the animation work sitting on top of plain, fast, boring HTML.
Checkout That Never Leaves
The one rule I refused to break: never take you off the site.
So many small stores hand you a beautiful experience and then yeet you to a hosted checkout page on a different domain with different fonts. The spell breaks. I wanted the buy to feel like part of the same room.
That meant inline Stripe Elements, mounted right inside the bag's own pane — not a redirect. Add a cap, the bag slides over, and the payment + address fields are there, themed to match whatever color theme you've picked (there's a little bridge that resolves the site's oklch design tokens into a Stripe Appearance object so the inputs match the rest of the UI). A deferred PaymentIntent keeps the flow snappy; the cart is always priced on the server, because you never trust a price the browser hands you; and the only time you'd ever leave the page is a 3-D Secure challenge, which is the bank's call, not mine.
Keeping it inline is the kind of detail nobody consciously notices and everybody feels. That's the bar I'm trying to hold the whole way through.
I've been talking around it for half an article. Let me just put it here, loud:
The Part I'm Proud Of: A Camera That Zooms Into the Grid
Tap a cap in the grid and the grid appears to zoom — like a camera dollying in — until that one cap fills the screen as the product view. Tap back and it pulls out. It feels physical, like the product was always there and you just moved toward it.
The naive way to build that is to animate the real grid. Don't. The grid is a lot of real DOM, and transforming it means the browser is doing layout and paint work on every frame — which is exactly where cheap phones fall apart.
Here's the trick instead: I never animate the real grid at all.
When you tap, I clone a snapshot of the visible cards into an off-screen "world" and split it into two layers: a focus layer holding just the tapped cap, and a background layer holding everyone else (off-screen cards are culled — no point cloning what you can't see). Then a single translate3d(...) scale(...) on the world zooms it so the tapped card's rectangle lands exactly on the product image's final rectangle — a FLIP-style match. The GPU composites that one transform; nothing in the document reflows.
As the world zooms, the background layer fades out, the focus cap stays crisp on its own layer, and the real product panel fades in right as the zoom lands. The real grid stays hidden behind all of it the entire time, so it never paints during the animation. The reverse — the close — is pre-built during idle time, so backing out snaps instantly instead of stuttering.
Layers are the whole game. Separating the subject from the background lets each one move and fade on its own cheap timeline, and cloning lets the expensive, real DOM sit perfectly still while a throwaway copy does the theatrics. It's the same instinct as a film camera: the actor and the backdrop are different planes, and the camera moves through both.
Is It Vibe-Coded? Obviously.
Yes. Completely. I built most of this by talking to Claude Code, not typing — which is its own whole story.
I'm not hiding that, and I'd argue it's part of the allure. The point was never "I hand-crafted every line of this by candlelight." The point is that one person can now ship something that looks hand-crafted — the camera zoom, the inline checkout, the theme-matched Stripe inputs — in the time it used to take to argue about a CSS reset. The floor is rising. A blog's merch store has no excuse to feel cheap anymore, because the effort it takes to make it feel expensive has collapsed.
Is every line how I'd have written it by hand? No. Does the cap arrive embroidered and real? Also yes. That gap — between "vibe-coded" and "actually works and actually ships a physical object to your door" — is exactly the thing I wanted to measure.
Now the Real Test
The store is live: a grid of eighteen embroidered dad caps, each one an engineering-manager bit — SCRUM MASTER, VELOCITY, LGTM +2 — for about the price of a nice lunch. Tap one, watch the camera zoom, check out without ever leaving the page.
The honest experiment is whether anyone buys one. I genuinely don't know yet, and that's the fun part.
Help me find out if I can actually sell this thing. Brick by brick.
Comments
Select text in the article to leave an inline comment.