Apr 9, 2026 — Clifton

A Day of Vibe Coding

Dear Founders—

Last week I gave Claude the blog. Today I gave it the rest of the repo.

Forty-two commits later, here is what 24 hours of vibe coding actually bought me.

1. Redesigned the Homepage

The old onlyplans landing page was a long scroll of links. The new one is a card grid—SVG thumbnails, animated diagrams, a unified nav strip across the top. Every card shows you what the thing is before you click it.

Time from “I want a card grid” to shipped: about an hour. The hard part wasn’t the layout. The hard part was deciding which 12 cards earned a slot above the fold. That decision is mine. The HTML is Claude’s.

2. Scaled Zoning From 4 Explorers to 119

Yesterday morning the zoning section had four interactive city explorers—Dallas, Austin, Houston, San Antonio. By tonight it has 119 across all 50 states plus DC, with 244 city profiles underneath them.

The number is the boring part. The interesting part is that the generator now reads a JSON state config and emits a standardized landing page with a shared engine.js. Every new state is a config file, not a fresh codebase. Add Oregon? Twelve lines of JSON. Add Tennessee? Twelve lines of JSON. The marginal cost of the next state went from a week to a coffee.

This is the part of vibe coding that actually compounds—the first version is the prototype, the second version is the abstraction, and the third version is the factory.

3. Then Deduplicated All Of It

Scaling fast makes a mess. Two hours after the 119-explorer push I had 207 duplicate entries scattered across state configs, plus a long tail of macOS ‘ 2’ cruft files that had been silently riding along in git for who knows how long.

One pass to delete the dupes. One pass to nuke the cruft. One pass to auto-generate the configs from a single source of truth so the dupes can’t come back. Boring work. Necessary work. Vibe coding doesn’t excuse you from cleanup—it just lets you do the cleanup in twenty minutes instead of an afternoon.

4. Templatized 173 Blog Posts Into JSON

Until this morning every blog post on this site was a hand-rolled HTML file. 173 of them. Each one carried its own copy of the navbar, the styles, the meta tags, the footer. Editing the navbar meant editing 173 files.

Now every post is a JSON record. Two templates—one for thesis posts, one for essays—render the entire archive at build time. The post you’re reading right now is one of those JSON records. I edit one template and 173 pages update.

If you have ever maintained a static blog by hand, you know exactly how much this hurt before and how good it feels now.

5. Recovered Content I Didn’t Know I’d Lost

Here is the part nobody warns you about. The templatization pass extracted the “main body” of every post into the JSON—and quietly dropped the trailing sidebars on a couple dozen of them. The kind of sidebar I’d written by hand months ago and forgotten about. Gone. No error. No warning. The build was green.

I caught it by diffing the rendered output against an old snapshot, found a stretch where the old version had a sidebar and the new version didn’t, and added a tail_html field to the schema. Then I walked back through every affected post and pulled the content back in.

The lesson: even good migrations lose things. The only way you notice is by looking. Not by trusting the test. Not by trusting the diff. By looking.

6. Optimized The Blog Assets

While I was in there: deleted the legacy post directories the templatizer had replaced, compressed 13 large PNGs to JPEG (the worst offender was 2.4MB—on a blog post), and fixed a handful of unicode bugs where curly quotes had been double-encoded somewhere along the way.

Nothing fancy. The page weight on a few posts dropped by 80%.

7. Killed 64 Idle Animation Timers

The new homepage has 61 SVG thumbnails. Every one of them was animating with SMIL on page load—subtle little loops to make the cards feel alive. Subtle enough that you didn’t notice them visually. Loud enough that the phone got warm holding it.

Converted all 61 from SMIL to hover-only CSS. The animations only run when your cursor is on the card. Idle CPU on the homepage went from 64 active timers to zero.

This one is small but I’m proud of it. The lazy answer would have been to delete the animations. The right answer was to keep them and make them cheap.

8. What Vibe Coding Actually Means In Practice

People hear “vibe coding” and picture a founder reclined in a chair while an AI types code. That isn’t the job.

The job is this: I describe the shape of what I want. Claude proposes a path. I steer at every fork. The bottleneck is no longer typing—it is deciding well, fast, all day. Which of the four approaches it just offered is the one that will still look right next month? Which abstraction is premature? Which cleanup is yak shaving and which is load-bearing?

The CEO job and the vibe-coding job converge here. Most of the cycles are spent on what NOT to do. The wins come from saying no to the 80% of suggestions that would have produced drift, and yes to the 20% that compound.

9. Where I Actually Helped

I should be honest about my role, because the temptation in posts like this is to wave hands and credit the model for everything.

I picked the cards that made the homepage cut. I decided the zoning generator should read JSON configs instead of forking the code per state—Claude would have happily forked. I named the tail_html field. I noticed the missing sidebars (by squinting at a rendered page in a browser tab, not by running a test). I called the SMIL-to-CSS conversion when I caught my own laptop fan spinning up on the homepage. I said no, repeatedly, to abstractions that wanted to exist before they’d earned their keep.

What I didn’t do: write almost any of the code. Type out the JSON for the 119 state configs. Hand-edit 173 post files. Touch the SVG markup.

The split feels right. The taste, the priorities, the “is this actually shipped or just green” check—those stayed with me. The keystrokes went somewhere else. On a good day that’s a 10x multiplier. On a bad day it’s a 2x multiplier with a side of cleanup. Today was a good day.

10. What Broke

Be honest about the misses or nobody learns anything.

Three things broke today. The Dallas, Portland, and San Antonio zoning explorers shipped with a duplicate catCol declaration that prevented the data table from rendering at all—caught it on a manual smoke test, fixed in three commits. The trailing sidebars on the templatized posts vanished, as covered above. And the first dedupe pass missed a class of edge cases that needed a second pass to clean up.

Vibe coding produces drift. The defense is the same as it always was: look at the thing. Open the page. Click the button. Diff the old against the new. The faster you ship, the more often you have to look.

11. Closing

Forty-two commits in a day across a homepage redesign, a 30x scale-up of an interactive map system, a full content migration of 173 blog posts, three rounds of cleanup, and a performance pass.

A year ago this is two weeks of work for three people. Today it is one founder, one model, one long Thursday.

The frontier moved. Again.

—Clifton

Five tools worth building on this
  1. Vibe-coding session log visualizer — commits over time, churn vs net additions, rendered as a single skyline
  2. Drift detector — diff before/after a templatization pass and surface silently dropped content
  3. Animation budget meter — count idle timers per page and flag any page over a threshold
  4. “What broke” tracker — pair every big refactor with the bug it caused, kept honest over time
  5. Repo-scale generator config viewer — surface the JSON-driven build graph so the factory is legible