◄ NEON PONG

How Neon Pong Was Built

A solo-developer devlog — the tech, the decisions, and the hard parts.

Neon Pong looks simple, and that's the point. But getting a fifty-year-old idea to feel good in a modern browser — with power-ups, three CPU difficulties, and real-time online multiplayer — took more engineering than the clean front end lets on. This is the story of how it came together, written for anyone curious about building browser games solo.

No engine, on purpose

Neon Pong is written in plain vanilla JavaScript and drawn on the HTML5 Canvas — no Unity, no Godot, no framework. For a game this size, an engine would be more weight than help. The entire game ships as a tiny bundle that loads almost instantly, which matters enormously for a web game: players decide whether to stay within the first second or two, and every megabyte you make them download is a chance for them to leave.

The core is a classic game loop driven by requestAnimationFrame: read input, advance the simulation by the elapsed time, resolve collisions, draw the frame, repeat. Movement is time-based rather than frame-based, so the game runs at the same speed whether your screen refreshes at 60Hz or 144Hz.

Making the ball feel right

The difference between a dull Pong and a fun one is almost entirely in the ball. Two rules do the heavy lifting. First, the ball accelerates slightly every time it strikes a paddle, so rallies build tension instead of settling into a rhythm. Second, the contact point matters: hitting the ball with the edge of the paddle deflects it at a steeper angle than hitting it dead center. That single mechanic turns a reflex test into a game of placement and mind games, and it's the thing that makes beating the Hard CPU satisfying rather than tedious.

The CPU opponent

The computer player isn't psychic — that would be no fun. Instead it tracks the ball with a capped reaction speed and a small margin of error, and those two numbers are what the Easy / Normal / Hard setting actually changes. Easy reacts slowly and drifts; Hard moves fast and rarely misjudges. Tuning those values to feel fair but beatable took more playtesting than any other part of the game.

The hard part: online multiplayer

Adding online play is where a weekend project becomes a real one. The naïve approach — let one player's browser run the game and tell the other what happened — falls apart immediately, because browsers throttle background tabs. The moment a host tab loses focus, its game loop slows to a crawl and both players desync.

The fix was to make the match server-authoritative. The game simulation runs on a Cloudflare Durable Object — a tiny stateful server at the edge — at a fixed 30 ticks per second. Each player's browser only sends its paddle position and renders the authoritative state the server streams back over a WebSocket. Because the server never sleeps, a backgrounded tab can't break the match. The same backend handles two modes: a global "Quick Match" lobby that pairs the next two players searching anywhere in the world, and private four-letter room codes for playing a specific friend.

Shipping everywhere

The web build runs on Vercel. The same codebase is wrapped with Capacitor to produce a native Android app, and adapts to different ad providers through a small interface so the web, mobile, and game-portal versions can each plug in their own monetization without touching the game code. Responsive scaling keeps the play field the right pace on a phone, a tablet, and a desktop monitor.

What I'd tell another solo dev

Start with the thing players touch most — here, the ball — and make it feel great before adding features. Keep the build tiny. And don't add online multiplayer unless you're ready to think like a netcode engineer, because "just sync the two browsers" is a trap. Small games can still have deep technical corners; that's what makes them worth building.

▶ Play Neon Pong now
Home About How to Play Making Of Pong History Strategy Privacy