I finally tried vibe coding

I've leaned on autocomplete for as long as I've been writing code, so when GitHub Copilot came along with suggestions that actually understood the surrounding file, I was interested. But I was late to the "vibe coding" party. When work handed out Cursor licenses I mostly ignored mine. I felt faster doing things the way I always had, and I wasn't going to gamble a deadline on a tool I didn't trust yet.

Paternity leave changed that. With some time and no deadlines, I decided to properly learn how to work with an AI agent instead of just tab-completing. It went better than I expected. Here's what I built and what I ran into.

Project 1: Personal website (React, GitHub Pages)

I started with my personal website, a small React app on GitHub Pages. The first prompt got me hooked:

"This is my personal website; it looks a bit dated. Can we make it look modern and cool? Specifically, I would like a retro-futuristic theme and a dark mode/light mode button."

The result was... fine. A bit cartoonish, and "retro-futuristic" turned out not to be my thing. But I could already see where this was going. So I tried again:

"Actually, make it more professional, minimalistic, and concise, while still surfacing the most relevant information."

And then kept nudging:

  • "this section is unnecessary"
  • "make the experience part card-based"
  • "let's try a dark style"

A few rounds later I had something I liked. What stuck with me was how fun it was. Trying a style, throwing it away, trying another one: that used to be expensive enough that I'd never bother.

BeforeAfter

Project 2: Wordle clone (React, Firebase)

Next up was my Wordle clone, a React and Firebase app with a bit more going on. This time I wanted real features, not just a facelift (though it got one of those too). The original was bare-bones: one word a day, five guesses, everything in browser storage. With the agent I added:

  • Profiles: sign in with a Google account.
  • Stats: games played, current streak, win rate, guess distribution.
  • Leaderboard: rankings across those stats.
  • Info: how to play, and an About section.

It even walked me through which Firebase settings to change for the new login flow, which I hadn't expected.

BeforeAfter

This is also where the cracks started to show:

  • CSS glitches. Dark mode worked, until I zoomed out and white bars appeared where the dark background should have been.
  • Fiddly features. Redesigning the keyboard took several tries. First it landed outside the card, then I had two keyboards.
  • Wrong data. The stats were buggy; the guess distribution always showed five guesses no matter what I'd actually played.
  • Performance. Moving state to Firebase so it would sync across devices made everything sluggish. I reverted and now only write on submit or refresh.
  • Design drift. Every new card, modal, or tab had slightly different shadows, corner radii, padding, or margins.

Every feature got there eventually, but each one needed a few rounds of back-and-forth.


Project 3: ESP32 Wi-Fi clock (C++, PlatformIO)

The last test was my ESP32 dot matrix Wi-Fi clock: C++ on PlatformIO, driving a dot matrix display, with a settings page written in plain HTML and JS.

This was a lot harder. Most changes broke something and I had to go in and debug by hand:

  • Web page changes that no longer matched the server config.
  • Boot sequence edits that stopped the device from turning on at all.
  • Settings struct changes that wiped saved data.
  • Styling on new elements that didn't match the rest of the page.

Still, I got a lot done:

  • Web page: light and dark modes.
  • New screens: a countdown, a Matrix-style rain effect, and the device's IP address.
  • Display options: screen order and duration, flipped orientation.
  • System stuff: mDNS, timezone and weather via the Open-Meteo API, a system info page, reboot and factory reset.
BeforeAfter

What I took away

Where it shines:

  • Starting from zero. Bootstrapping a new project or feature is where it feels like magic.
  • Small, well-defined changes. Point it at the right file and it usually nails it.
  • Cleanup. Removing dead code and unused dependencies, safely.

Where it struggles:

  • Consistency. It reinvents patterns unless you tell it exactly which ones to follow.
  • Big features. Anything sprawling needs a very specific prompt, and usually a few of them.
  • Code quality. The output can be brittle and narrowly fitted to the exact thing you asked for.

A few habits that helped:

  • Start a fresh chat often. Long threads drift.
  • When it goes sideways, revert and rephrase instead of patching the patch.
  • Give it context: name the files and entry points.
  • Be very specific. Vague prompts get vague code.
  • Put project conventions in .cursor/rules so you don't have to repeat them.
  • Have fun with it. Getting good at this takes some playing around.

Back to posts