Technical write-ups from building Neon Drift — a solo-developed arcade game that runs on HTML5 canvas, shipped on Google Play and the open web.
These are longer pieces about specific problems I hit and how I measured my way out of them. Everything here comes with the actual numbers, including the times I got it wrong. If you build browser games, some of this may save you a week.
Shorter, more frequent build notes live in the devlog.
Three unrelated performance reports from three players turned out to be the same
mistake. Why shadowBlur is billed per fill() rather than per
path, how to count blurred draw calls instead of timing them, and the numbers before
and after: 615 blurred fills a frame down to 2, 185 down to 0.
My game ran at 75% speed on 90 Hz displays and 80% on 144 Hz ones, and nobody reported it — because a slower simulation doesn't feel broken, it feels easier. The two mistakes that only cause damage together, and a fixed-timestep accumulator with render interpolation that fixes both.
A player reported a stutter on every tap. I was confidently wrong four times. The control experiment that would have ended it on day one, why a null result was the most useful data I got, and the moment an offhand remark invalidated my best theory.
Neon Drift is built by one person. There is no engine underneath it — it is a single HTML file, vanilla JavaScript, and a 2D canvas, with a small serverless backend for leaderboards and daily challenges. That constraint is why these problems are interesting: there is no framework absorbing the mistakes, so every one of them is visible and attributable.
The through-line in all three pieces is the same. Every time I diagnosed a problem by reading code and reasoning about it, I was wrong. Every time I built a way to measure it, I got an answer — sometimes an answer I didn't want, like "this isn't your bug at all".