🎡 SpinForFree

Inside the Free Wheel

August 12, 2026

The wheel on the home page runs entirely in your browser. Nothing you type into it is ever sent to a server: not the names, not the results, not a request when you press Spin. Elsewhere on this blog we make a lot of noise about draws being decided on the server, so a client-only wheel deserves an explanation. This post is that explanation, plus a couple of implementation details that turned out to be more interesting than expected.

Why browser-only is the right default

Think about what actually goes on that wheel. A class roster. The names of everyone on a team. A list of friends deciding where to eat. For most of what a name picker does all day, the list is mildly personal, the outcome is low-stakes, and the honest answer to “where should this data live?” is: nowhere.

A teacher pasting thirty children’s names into a website should not have to wonder what happens to them afterwards. In the free wheel the answer is checkable from the network tab: no request carries them anywhere. The list is stored in your browser’s local storage so it survives a page reload and is there again tomorrow, and clearing your browsing data deletes it completely. There is no account to breach and no database row to leak, because neither exists.

The same draw, minus the server

Being client-side does not mean being sloppy about the pick itself. The free wheel draws with crypto.getRandomValues, the cryptographic generator built into the browser, rather than Math.random. And it corrects modulo bias with rejection sampling, the same way the server-side draw does: random values that would land in the ragged tail of the 32-bit range are thrown away and redrawn, so every name has exactly the same chance rather than the first few having a sliver more. With eight names the difference is unmeasurable. It is corrected anyway, because the correction is three lines and “exactly equal” is a much better sentence than “equal, near enough”. The full background is in how random number generators actually work.

Weighting works too, in the most transparent form there is: list a name twice and it has two slices, which is two tickets, which is double the chance. Anyone looking at the wheel can count them.

What it deliberately does not do

Everything the free wheel refuses to send anywhere is also everything it cannot prove. It keeps no record beyond a list of recent winners in the page itself. It has no shared link, so two people opening the site see two independent wheels. And nothing stops anyone from spinning again and mentioning only the spin they liked.

None of that is a flaw. It is the trade. A browser-only wheel is private and instant precisely because no server is involved, and a draw nobody can audit is exactly what a classroom pick or a dinner decision calls for. The moment the situation changes, when there is a prize, an audience, or a result somebody might dispute next week, the requirements invert: now you want the draw decided once, on a server, written down before any screen sees it, and watchable by everyone on one link. That is the account-backed wheel, and the mechanics are in how the live spin works. The two wheels are not a free tier and a paid tier. They are two answers to two different questions, and both are free.

The elimination bug worth writing down

One detail cost us a rework, and it is a nice example of how a feature can be correct and still wrong.

The wheel has a “remove the winner after each spin” option for raffles that should not pick the same person twice. The obvious implementation removes the winner the moment the spin ends. We built that first, and it was mathematically fine: the winner was announced correctly, the next draw excluded them correctly.

It also looked broken. Removing a name changes every slice’s size, and the wheel redraws immediately, underneath a pointer that is no longer moving. So the pointer, which had just settled on the winner, was suddenly resting on somebody else entirely while the text below announced a different name. Every part of the system was right and the picture contradicted the announcement.

The fix was to defer the removal: the winner stays on the wheel, pointer resting on them, until the moment you press Spin again, and comes off just before the next draw. Same fairness, same exclusions, but the wheel never disagrees with its own result. A small note under the winner tells you it will happen. For a tool whose entire job is being trusted by the people watching it, what the picture says matters as much as what the code does.

One quirk of elimination is worth knowing if you weight names by listing them twice: a win removes the slice that won, not the person. The duplicate slice stays, so a double-listed name can win again. That is how physical raffle tickets behave, which is why we left it, but it surprises people who expected one win to take them out entirely.

The honest summary

The free wheel is the private, instant, nothing-leaves-your-browser answer, and it uses the same quality of randomness as the audited draw. What it gives up is evidence. When you need a draw you can defend afterwards, use the shared wheel and read how to run a raffle people trust first. When you just need a name picked, the home page has you covered, and your list is nobody’s business but yours.

Advertisement