← Back to Blog

Dev Blog · June 11, 2026

Monster Punch: Reinventing Whack-a-Mole for the Browser

Monster Punch

When I started building Monster Punch, I told myself it would take a weekend. It took three. The concept sounds simple enough — monsters pop up, you click them before they disappear, you score points. Whack-a-mole has been done a thousand times. But every time I thought I had it finished, something felt off. The timing, the feedback, the escalation. Each piece had its own hidden complexity, and I kept pulling on the thread.

The Core Loop and Why Timing Is Everything

The first version I built had a fixed window — each monster appeared for exactly 800 milliseconds. It felt boring after about 30 seconds. Too predictable. I started experimenting with randomized display windows between 400ms and 1100ms, and something interesting happened: the game immediately became more stressful in a good way. Players couldn't fall into a rhythm. They actually had to watch the grid. I also learned that the gap between monsters disappearing and the next one appearing is just as important as how long they stay visible. If the grid goes quiet for too long, you lose momentum. Too short, and it becomes random noise. I landed on a 60–180ms inter-spawn delay that kept the action feeling connected without overwhelming the player. Getting those two numbers right took more iteration than I expected from something so invisible.

Punch Feedback: The Thing I Underestimated

My first pass had a click handler that removed the monster and added to the score. That was it. It felt terrible. Clicking a monster and having it just disappear gave no satisfaction at all — it felt like missing, even when you hit. I added a CSS scale-down animation, then a brief flash, then a little star burst drawn with absolutely-positioned divs. Each addition made it feel better, but the real unlock was sound. I was hesitant to add audio because browser autoplay policies are a pain, but even a short 40ms synthesized thud on click changed everything. I ended up generating it with the Web Audio API so there were no file dependencies. It's literally three lines of code but it makes the hit feel physical. That was the moment the game felt like a game and not a UI test.

Escalation and the "Unfair" Difficulty Curve

I wanted the game to get harder over time, but I had to be careful about how that happened. My first escalation model increased spawn rate linearly — every 10 seconds, a new monster was added to the pool. By 40 seconds in, it was genuinely unbeatable. Players weren't failing because of skill; they were failing because the math was against them. I switched to a curve that increases speed and frequency together but caps out rather than spiraling infinitely. Past a certain point, the game doesn't get harder — it just stays at peak intensity. That shift made a real difference in playability. People now chase high scores instead of quitting out of frustration. Difficulty should feel like a challenge you might actually meet, not a wall you're guaranteed to hit. That lesson will travel with me to every project going forward.

Browse All Games