BE AWESOME
Settings
Games
📅 April 21, 2026 · ⏱️ 4 min read

Perfect Time: Designing a Game With No Feedback Loop

A timer that runs and vanishes, and why removing the one thing every other reflex game relies on was the actual design.

This post is about Perfect Time: Designing a Game With No Feedback Loop
Play Perfect Time →

This one took a month longer to ship than the last few, and it's because the actual design problem is a strange one: how do you build a game around a timer, and then remove the timer from the screen. Perfect Time starts a pulse, that pulse disappears from view almost immediately, and you have to guess when it would have stopped using nothing but your own internal sense of elapsed time. There's no visual clock running while you wait. That's not a bug or a missing feature — the entire game is designed around not having one.

Every other game gives you feedback. This one can't.

Every reflex game I've built so far gives you something to react to in real time — a target, a path, a color on screen. Perfect Time can't do that, because the entire premise depends on you not being able to see the thing you're being tested on. That constraint made it genuinely harder to design than anything else I've shipped, because I couldn't lean on visual juice or on-screen state to make waiting feel interesting. The only real feedback loop is the one you build for yourself, silently counting in your head, and then the reveal at the end telling you how close your internal clock actually was.

Millisecond scoring, but not evenly weighted

Accuracy is measured down to the millisecond, and I went through a few passes on how to turn a raw millisecond gap into a score tier before landing on something that isn't linear. Being 50 milliseconds off should count for a lot more than being 500 milliseconds off counts against you, proportionally — the tiers compress at the tight end and loosen up as the gap widens, so there's real, felt separation between "excellent" and "good," while "bad" and "very bad" don't need nearly as much resolution between them. Nobody needs to know precisely how badly they missed once they've already missed badly. The tiers that matter are the close ones.

Why rounds had to stay short

Each round only lasts a few seconds, and that was a deliberate ceiling, not a technical limitation. Ask someone to hold an internal count for thirty or sixty seconds and you're not testing time perception anymore, you're testing sustained attention and whether they got distracted partway through. Keeping it to a few seconds isolates the thing I actually want to measure — can you internalize a short duration and reproduce it — from the much noisier problem of long-duration focus. It also means a round costs almost nothing to retry, which matters a lot for a game whose core skill is "get a slightly better internal count than last time." Nobody refines an internal rhythm over one attempt.

The synthesized audio cues took longer to get right than I expected too — a chrono-pulse sound at the start, chimes on a good result, a different tone for a miss. None of them are allowed to hint at timing during the actual guess window, only before it starts and after it ends, otherwise they'd quietly undermine the entire premise by giving you an audio metronome to count against instead of your own internal one. It's a small, easy-to-miss rule I had to keep enforcing on myself every time I wanted to add "just one more" bit of audio feedback mid-round.

The browser's own clock isn't as trustworthy as it sounds

There's a layer to this that has nothing to do with game design and everything to do with JavaScript timers being less precise than people assume. A naive implementation using setTimeout to mark when the "correct" answer would have landed is exposed to throttling and drift — background tabs get deprioritized by the browser, and a timer that's supposed to fire at exactly some duration can slip by enough milliseconds to matter in a game where the whole point is millisecond accuracy. I ended up timing the actual elapsed duration against a high-resolution timestamp rather than trusting a scheduled callback to fire exactly on time, which matters more here than in literally any other game on the site, because in every other game a few stray milliseconds of timer drift are invisible. Here, they're the entire scoring axis.

It's a strange thing to have spent real effort on: making sure the game is measuring itself accurately, independent of whether the player's internal clock is any good. But it felt necessary — if I'm going to tell someone their guess was forty milliseconds off, I need to actually trust that the forty milliseconds is real and not an artifact of the browser being busy doing something else at that exact moment.

The one input method this game had to get right

Submitting your guess is a single tap or click, and I thought carefully about which event actually fires it. Some pointer events on touch devices carry a small, inconsistent delay between the physical touch and the event handler running, compared to how a mouse click typically dispatches. For a game where the entire submission is "stop the count the instant you believe time's up," any inconsistency in that path becomes indistinguishable from the player just having bad timing, which isn't a fair trade. I picked the most immediate event available on each platform rather than defaulting to whichever one is more conventional to wire up, because here, "slightly more correct to code" and "measurably fairer to the player" turned out to be the same decision.

This is probably the strangest game on the site so far, if only because there's nothing to look at while you're actually playing it. Everything interesting about it happens in the gap between the pulse disappearing and your own decision to submit, which is a space I can tune and measure but can never actually see into. I find that more interesting than frustrating, but I'll understand if not everyone agrees with me on that. Every other game on the site gives you something to point at when you explain why you lost. This one just gives you a number and lets you sit with it.

Hello!