How a daily puzzle picks its answer
A daily puzzle has an awkward set of requirements: the answer must be identical for every player, impossible to discover early, and it must never run out. Storing a list fails all three eventually. Here's what we do instead.
Huedle is our daily colour puzzle: one secret colour per day, six guesses, a hint after each one. Simple to describe, and the interesting engineering is entirely in a question you'd never think to ask as a player — where does today's colour actually come from?
The obvious answer, and why we didn't use it
The obvious approach is a list. Write out a few hundred colours, put them in a table with dates, and look up today's. Plenty of daily games do exactly this, and for a hand-curated word game it's the right call, because the answers need to be words a human vetted.
For a colour puzzle it's all downside:
- It runs out. Whatever you write, there's a date after which the game breaks unless somebody remembers to top it up.
- It's sitting right there. A list of future answers exists somewhere — in a database, in a file, in the repository history. Anything that exists can leak, and for a daily puzzle a leak isn't a bug, it's the end of the game.
- It's work forever. Someone has to keep feeding it.
Deriving the answer instead of storing it
Huedle's colour isn't stored anywhere. It's computed, on demand, from two things: today's date and a secret key that only the server has.
The recipe is a keyed hash — HMAC-SHA256 — of the string huedle:2026-08-13,
using the server's secret as the key. That produces 32 bytes of output that look completely
random but are perfectly repeatable: same date and same key, same bytes, every time, forever.
Then we simply read the colour out of those bytes. The first two bytes become the hue, the
next two the saturation, the next two the lightness.
That's the whole mechanism, and it satisfies all three requirements at once. Every player asking on the same UTC day gets the same colour, because the input is the same. Nobody can work out tomorrow's colour, because without the secret key the output of an HMAC is not predictable from the input — that's precisely the property HMAC is built to have. And it never runs out, because there's always another date.
The part that needed actual taste
Raw randomness makes a bad puzzle. If you take those bytes at face value you'll eventually serve a colour that's almost black, or almost white, or a washed-out grey — and on those days the game is broken, because when saturation is near zero or lightness is near either extreme, hue stops being visible. The player is asked to guess a property the colour doesn't meaningfully have, and no amount of skill helps.
So the ranges are deliberately narrowed. Hue gets the full circle, 0–359, because that's the interesting axis. But saturation is constrained to roughly 35–90, and lightness to roughly 25–75. Every possible Huedle answer is a colour with a hue you can actually perceive.
It's a small thing — three lines of arithmetic — but it's the difference between a puzzle that's fair every day and one that's fair most days. We'd rather have a slightly smaller space of answers than a game that occasionally hands somebody an unwinnable one.
Hints that guide without giving it away
The other design problem is feedback. Tell the player too little and they're guessing blind; tell them too much and the puzzle collapses in two moves.
Huedle answers three questions after each guess, once per axis: are you too high or too low, and how far off are you? The "how far" is bucketed rather than exact — spot on, close, off, or way off — so you learn the shape of your error without being handed the number. You also get a single overall match percentage, which is what makes the last guess of a close run so agonising.
The distances behind those buckets aren't the same for each axis, which surprised us. The eye is far more forgiving about saturation and lightness than about hue, so the hue bands are much wider in raw units than the saturation and lightness bands are. The overall match score weights hue at double the other two for the same reason: if you're 20 degrees off in hue, you got the colour wrong. If you're 20 points off in lightness, you got it slightly wrong.
Scoring, and why an unsolved run can never beat a solved one
Scores in a daily game have a job beyond ranking: they have to make the leaderboard readable at a glance. Ours is arranged so that solving is worth more than not solving, always — every solve starts from a floor that no unsolved run can reach, no matter how close it got.
Above that floor, two things earn more: solving in fewer guesses, which is worth a large fixed jump per guess saved, and solving precisely, which adds a smaller bonus for landing very close rather than just inside the tolerance. So a first-guess bullseye is the theoretical maximum, and a sixth-guess scrape is worth clearly less — but still more than the best near-miss.
The important structural point is the one from our piece on leaderboard cheating: the browser never computes any of this. Your client sends colours; the server holds the answer, produces the feedback, and works out the score. There's no score field in the request to tamper with, because the score doesn't exist until the run is over and the server decides what it was.
The catch worth knowing about
Deriving the answer from a secret key has one sharp edge: the key can never change. Because the colour is a function of the secret, rotating that secret changes the colour of the day — and if it happens mid-day, it changes the answer underneath everyone who has already made three guesses. Their hints suddenly describe a colour that no longer exists.
With a stored list this would be a non-issue. With a derived answer it's the one operational rule you have to hold onto, and it means the game secret has to be treated as permanent infrastructure rather than a rotatable credential. That's a real trade, and worth knowing about before you build something this way.
Would we recommend it?
For anything where the answer is generated rather than authored, yes. A keyed hash of the date gives you unpredictability, perfect reproducibility across every player and server, and an infinite supply, for about five lines of code and no ongoing maintenance.
For a word game, or anything where each answer needs a human to check it's actually good — no. Curation is the whole product there, and you should store the list and guard it properly. The technique is only right when you genuinely don't mind what tomorrow's answer is, as long as it's fair.