How I Accidentally Made a Game I Couldn't Stop Playing

I wanted to make something fun for Halloween. Nothing big, just a game I could build in an afternoon. So I vibe coded a clicker game called Candy Hoarder, where you knock on doors for candy, hire help, and eventually trick-or-treat the moon.

Then I played the first version for two and a half hours.

That wasn’t the plan. A clicker is supposed to be a quick, silly thing. But I got pulled in, and figuring out why, and then fixing it so a full game takes about five minutes, turned out to be the most interesting part of the project.

You can play Candy Hoarder in your browser, and the source code is on GitHub.

Picking the idea

I knew I wanted another TypeScript browser game, like Obsolete, my Ludum Dare 60 entry. I also knew I wanted something a little funny but simple. A clicker fit that. The whole game is one button and a growing number, and everything else is decoration on top.

I asked Claude for a few Halloween clicker concepts. There was a ghost haunting a neighborhood, pumpkins that slowly become self-aware, and a cauldron where every upgrade causes a ridiculous side effect. I picked the candy one. You trick-or-treat, spend candy on helpers that collect candy for you, and the helpers escalate from a bigger pillowcase to a little sibling in a dinosaur costume, a minivan route, a haunted candy shop, and a candy factory. The final purchase is trick-or-treating the moon.

I also didn’t want it to look as rough as Obsolete. We settled on a paper-cutout style: flat shapes with drop shadows so they look layered, in deep purple, orange, black, and cream. I couldn’t picture what you’d actually click on until Claude described a front door on a porch with a jack-o’-lantern. You knock, the door pops open, and a hand drops candy into your pillowcase. Each helper you hire shows up on the street, and the moon hangs in the sky the whole game, slowly getting bigger.

Building it from my phone

The plan was to have Claude write a short brief that I could hand to Claude Code. The brief covered the core loop, the seven helpers, the visuals, the tech, and an accessibility section. Helper prices go up about 15% with each purchase, a few one-time upgrades double your knocks or a helper’s output, and buying the moon ends the game.

Then I realized I couldn’t get to Claude Code from my phone. So I asked Claude to build it right there in the chat instead. It set up a TypeScript and Vite project, wrote the game rules as plain logic with no page code mixed in, added Vitest tests, drew the whole street as inline SVG, and published a playable version I could open on my phone. It also gave me the source as a zip so I could keep going in Claude Code later.

I didn’t write any of the code. To be honest, I didn’t even read the brief. I made the big calls along the way: what the game was, how it should look, and what it had to do for screen reader users. After that, I played it and changed whatever I didn’t like. That’s what vibe coding meant here.

Two and a half hours

I opened the first version to try it out. Two and a half hours later, I had trick-or-treated the moon.

I’d like to say that was research. I’m a bit of a completionist, so once there was a moon to reach, I was going to reach it. I may also have been procrastinating. There were plenty of things I could have been doing, and probably should have. None of them were urgent enough to stop me.

Mostly, I got lost in the numbers. Watching them go up is the whole appeal of a clicker, and it worked on me. The part I didn’t expect to enjoy was the shopping. At every stage I was working out which upgrade was actually worth it. Is it better to double your siblings now or save for the next minivan? The answer changes as the game goes on, and figuring it out kept pulling me back.

So the game worked. It was just far too long. Nobody else was going to give it two and a half hours.

Balancing by simulation, again

I wanted a full game to take about five minutes. I borrowed that from Ludum Dare 60. If I was going to share this, I wanted it to be a complete experience in a reasonable amount of time.

Later that afternoon I opened the project in Claude Code, and we balanced it the same way I balanced Obsolete: by letting simulated players do the playing. The balance test plays the real game rules and fails if a full game drifts away from five minutes. The README has the details.

Sound and phones

The first version was silent. In Claude Code we added background music and sound effects, and none of it uses audio files. Everything is synthesized in the browser with Web Audio. The music is generative: a low drone, some wind, and a music box wandering around a minor scale.

Each helper also makes its own noise. The little sibling does a tiny “rawr,” the kid crew giggles, the minivan goes beep beep, the haunted shop has a door bell and a ghostly “whoo,” and the factory clanks and blows a steam whistle. Music, helper noises, and sound effects each have their own on and off button, and the game remembers your choices.

The other big change was the phone layout. On a narrow screen, the street and the shop now become tabs along the bottom, and the Shop tab shows a badge with how many things you can afford. The moon changed too. Its ring fills as you save toward the price, and when it closes, you click the moon itself to finish the game. Progress saves in your browser, so you can close the page and pick up where you left off.

My accessibility baseline

My target for everything I build is WCAG 2.2 AA, and it was in the brief from the start. I wanted the important parts of the game to be real controls.

The door is a real button, named “Knock! Trick or treat at the door.” When the moon is ready, it becomes a button too. The rest of the street is decoration and hidden from screen readers. Shop cards use aria-disabled instead of disabled when you can’t afford them, so they stay focusable, and pressing one tells you how much more candy you need. Each card’s name includes its cost, what it produces, and how many you own.

The trickiest part of a clicker for screen readers is that the numbers change constantly. Announcing every knock or every second of income would be noise. So the game has one polite live region that only speaks up for purchases, milestones, bonus events, and the moon being ready. When you want your total, the C key reads it out, and K knocks. Both shortcuts can be turned off. Numbers are read as words, so you hear “1.2 thousand” instead of “1.2K.” The tabs follow the standard arrow key pattern, the sound buttons are toggles, and all the animation stops if you’ve asked your device to reduce motion.

Then I tested it with VoiceOver on my phone, and it’s actually really hard to play. Double tapping the door over and over is hard to keep up. The balance test doesn’t account for that either: its simulated players knock three to five times a second. The controls are labeled correctly, but the core mechanic doesn’t work well with a screen reader yet, so I still need to fix it.

Where it ended up

Candy Hoarder went from an idea to a finished, deployed game in one afternoon. It has music, sound, a phone layout, and a test that guards the pacing. For someone who doesn’t have a process for finishing games, that’s a nice change.

The lesson I’m taking from it is about balance. The first version was fun. It just had no sense of how long fun should last. I only found that out by playing it, and I only fixed it by turning “about five minutes” into a test that fails.

It’s not done, though. Double tapping the door with VoiceOver isn’t a good way to play, and the balance needs to account for that. On my iPhone, the game is silent when the ringer is off, even with headphones, and after I turn the ringer back on, sounds don’t come back until I reload the page. The helper sounds should also tell you where each helper is on the street, and right now they don’t.

For now, it’s a Halloween game, and it takes five minutes. Go trick-or-treat the moon.

Get in touch

Questions, feedback, or just want to say hi? Send me an email.

Email me