Guide

How Wheel Cue Picks a Random Winner

The full method, in order, with nothing hand-waved — plus a fairness test you can run in this page.

The short version

  1. You press spin.
  2. Wheel Cue asks your browser's cryptographic random number generator for a 32-bit number, using crypto.getRandomValues().
  3. If that number falls in a range that would bias the result, it is thrown away and a new one is drawn. This repeats until a usable number comes up.
  4. The number is turned into a ticket, and the ticket is matched against the entries' cumulative weights to find the winner.
  5. Only then does the wheel start turning. The animation is aimed at the entry that has already won.

The winner is decided before the first frame of animation. Nothing about the spin — how long you hold the button, where you click, how long the animation runs, the order of your list, the colours — has any influence on it.

Where the randomness comes from

Wheel Cue uses crypto.getRandomValues(), the Web Crypto API's random source. It is provided by your browser and, underneath that, by your operating system's entropy pool — the same source used for cryptographic keys.

It does not use Math.random(). That function is fine for animations and useless for anything anyone might audit: it is seeded per-page, its output is predictable given enough samples, and browsers make no guarantees about its quality.

The practical difference for a wheel with twelve names is small. The difference in what you can honestly claim is not, which is why the more careful source is worth using even for a food wheel.

You can check this yourself. Open your browser's developer tools on any wheel page, look at /assets/js/random.js, and read the whole thing — it is about a hundred lines with comments, and draw32() is the only place a random number enters the system.

Run the fairness test yourself

This runs real draws through the same code a spin uses — not a model of it. Nothing is sent anywhere; the whole test happens in this tab.

Press Run the simulation to draw 10,000 results and see how evenly they land.

Why some draws get thrown away

This is the part most spinners skip, and it is the only genuinely subtle thing here.

A 32-bit draw gives a whole number from 0 to 4,294,967,295 — that is 2³² possible values. To turn that into "one of 12 names", the obvious move is a remainder: draw % 12.

The problem is that 2³² is not divisible by 12. Dividing 4,294,967,296 by 12 leaves a remainder of 4, which means four of the twelve names would come up very slightly more often than the other eight. The bias is tiny — around one part in 350 million — but it is real, it always favours the low-numbered entries, and it is avoidable.

So Wheel Cue computes the largest exact multiple of 12 below 2³² and discards any draw at or above it, then draws again. Every remaining value maps to exactly one name, and the mapping is perfectly even.

That is called rejection sampling. The result window reports how many draws were discarded on your spin — usually zero, occasionally one. The relevant code:

function below(n) {

var limit = Math.floor(POW32 / n) * n; var raw, rejected = 0; do { raw = draw32(); if (raw >= limit) rejected++; } while (raw >= limit); return { raw, limit, modulus: n, index: raw % n, rejected }; }

How weights change the odds

With equal entries, every name gets one ticket and the ticket count equals the number of names.

With Weighted choices on, an entry marked *3 gets three tickets. The tickets are laid end to end into a cumulative table, one unbiased draw picks a ticket number, and whichever entry owns that number wins.

An entry's probability is exactly its weight divided by the total weight. With Maria *3, Daniel, Priya *2, Chen the total is 7, so Maria has 3/7 (42.9%), Priya 2/7 (28.6%), and Daniel and Chen 1/7 (14.3%) each.

The slice sizes on the wheel are drawn from the same weights, so what you see is what the odds are. The strip under the wheel switches from "1 in n" to the total weight as soon as weighting is on, and the result window always reports the actual probability the winner had.

More on weighted picking →

Why the animation cannot cheat

It is a fair question, because it would be easy to build it the other way round — let the wheel spin, see where it stops, declare that the winner. A spinner built like that could be nudged by an animation bug, a dropped frame or a rounding error at the boundary between two slices.

Wheel Cue works in the opposite order. The winner is chosen first. Then the code calculates the exact rotation that puts that slice under the pointer, adds five full turns for the look of it, and eases to that angle. The landing position is an output of the result, not an input to it.

There is one small piece of randomness in the animation, and it is cosmetic: the wheel lands at a random point *within* the winning slice rather than dead centre, so consecutive wins by the same entry do not look identical. It cannot change which slice.

If the animation were interrupted — you close the tab, the browser throttles a background tab — the result was already decided. Nothing about stopping the animation early changes it.

Independent spins, and why streaks happen

Every spin is independent. The wheel keeps no history that affects future draws, does not avoid recent winners and does not "even things out".

This surprises people, because a genuinely random sequence looks less even than most people expect. With a 12-name wheel, spinning twelve times will typically produce three or four repeats and leave three or four names unpicked. That is normal. A sequence that gave each name exactly one win would be evidence that the wheel was *not* random.

The same applies to the yes or no wheel: five identical answers in a row happens about one time in sixteen.

If you want no repeats, that is a different question — one you should answer with the Remove the winner after each spin option rather than by hoping the randomness does it for you. That is sampling without replacement, and it is a genuinely different procedure.

What you can check yourself

Every result. Open How this result was picked in any result window. You get the raw 32-bit draw, the rejection threshold, how many draws were discarded, the modulo arithmetic, and which slice the ticket landed in. Redo the arithmetic on paper if you like.

The distribution. Run the simulation above. It performs real draws through exactly the same code path a spin uses — not a model of it — and reports the counts, the spread and a chi-squared statistic.

The source. /assets/js/random.js is unminified and commented. So is /assets/js/wheel.js, where spinTo() shows the animation being aimed at an already-chosen winner.

What you cannot check: that the page you loaded is the page we published. That is true of every website, and no client-side claim can fix it.

What we do not claim

Being exact about the limits is more useful than a badge.

  • This is not an audited draw. Everything happens in your browser. There is no independent record and no third party attesting to anything.
  • It cannot stop a determined organiser cheating. Someone running a giveaway could edit the entrant list between spins, or simply not show you the spins they did not like. No client-side tool can prevent that.
  • It is not certified for regulated draws. If your jurisdiction has rules about how a prize draw must be conducted, follow those rules.
  • We do not publish usage statistics. Wheel Cue is new. When we have numbers worth citing we will cite them; inventing them would undermine the point of this page.

What is left is still worth something: an unbiased draw from a cryptographic source, with the working shown for every result and the source code readable.

Frequently asked questions

Does Wheel Cue use Math.random()?

No. It uses crypto.getRandomValues(), the Web Crypto API's random source. Math.random() is not used for any selection.

Is the winner chosen before or during the animation?

Before. The result is drawn first and the animation is then aimed at the slice that already won.

Why does the same name keep coming up?

Because spins are independent. Genuine randomness produces clusters — a sequence with no repeats would be evidence against randomness. Use Remove the winner after each spin if you need unique results.

What is modulo bias and does it matter here?

Mapping a 32-bit number onto n entries with a remainder slightly favours low-numbered entries when 2³² is not divisible by n. Wheel Cue removes it by discarding draws in the incomplete final block and drawing again.

Can I verify an individual spin?

Yes. How this result was picked in the result window shows the raw draw, the rejection limit, the discard count and the arithmetic. You can recompute it by hand.

Is this suitable for a legally regulated draw?

It is unbiased and transparent, but it is not an audited service and there is no independent record. For a regulated draw, use a process your regulator accepts.

Make your own wheel

Add your choices, spin once and let Wheel Cue make the pick.