Skip to content
TeamPickerWheel
Methodology

How Team Picker Wheel Picks a Winner

The random number source, why the modulo is guarded, why the animation cannot affect the result, and how to test all of it yourself in about a minute.

Every spinner on the internet claims to be random. This page shows the actual method, names its limits, and gives you the code to check the claim without taking our word for anything.

The Short Version

The winner is chosen by the browser’s cryptographic random number generator before the wheel starts turning. The animation is then drawn so that it lands on the already-decided result. No server is involved, nothing is logged, and there is no house, no weighting and no memory of what you spun before.

Where the Randomness Comes From

The site uses window.crypto.getRandomValues(), the browser’s cryptographically secure random number generator. It is the same primitive browsers use to generate encryption key material, and it draws from entropy the operating system collects from physical sources.

It is not Math.random(). That function is a fast pseudo-random generator that is seeded once and is explicitly documented as unsuitable for anything security related; in some engines its output is predictable from a handful of prior values. The only place Math.random() appears here is a fallback for a browser so old it lacks the crypto API, which in practice means it never runs.

The Modulo Trap, and Why the Loop Is There

This is the part most wheels get wrong, and it is worth understanding because it is the difference between “we used a random number” and “every entry has an equal chance”.

A generator gives you a number from a huge range — here 0 to 4,294,967,295. To turn that into a segment on a ten-entry wheel, the obvious move is random % 10. That is subtly biased. The range 0 to 4,294,967,295 has 4,294,967,296 values in it, and 4,294,967,296 does not divide evenly by 10. Six of the ten remainders occur one extra time across the range, so six entries on the wheel are very slightly more likely to win than the other four.

The fix is rejection sampling: work out the largest multiple of the entry count that fits in the range, and throw away any draw at or above it, drawing again. Discarded draws cost nothing and the remaining range divides perfectly. Here is the whole function, exactly as it ships:

function randInt( max ) {
    if ( window.crypto && window.crypto.getRandomValues && max > 0 ) {
        var limit = Math.floor( 0xffffffff / max ) * max;
        var buf = new Uint32Array( 1 );
        do { window.crypto.getRandomValues( buf ); } while ( buf[ 0 ] >= limit );
        return buf[ 0 ] % max;
    }
    return Math.floor( Math.random() * max );
}

The do ... while loop is the guard. On a ten-entry wheel it rejects a draw roughly once in 715 million, so it almost never runs — but it is what makes the result provably uniform rather than approximately uniform.

The effect of the guard on a 10-entry wheel
ApproachChance per entryVerdict
Math.random() scaledEqual, but from a predictable generatorFine for a game, wrong for a draw people are watching
getRandomValues then plain % 10Six entries very slightly favouredBiased, and the bias is invisible without testing
getRandomValues with rejection samplingExactly 10% eachWhat this site does

Why the Animation Cannot Change Anything

The order of operations matters more than it looks. The winning segment is selected first. Only then does the code work out what rotation would put that segment under the pointer, and animate toward it.

So none of the following has any effect on who wins: how long the wheel spins, how hard or where you click, whether you hold the button, whether you use the spin button, the hub, the space bar or Instant pick, and whether the animation is skipped entirely because your device is set to reduce motion. Instant pick and a full five-second spin run the same two lines of code to choose the winner.

This also means the wheel cannot be nudged or timed. There is no skill component to find.

What Each Setting Does to the Odds

How the controls affect the probabilities
SettingEffect on the draw
Switching an entry offIt is excluded. The remaining entries share 100% equally
Remove entry after it is pickedEach winner leaves the wheel, so the odds rise for those left, exactly as slips leaving a hat would
Hide names on the wheelNone whatsoever. It changes only what is painted on the segments
Sound effectsNone
The same name entered twiceIt occupies two segments and has double the chance. This is how you weight a raffle by ticket count

The last row is a deliberate feature rather than a bug, and it is explained on the name hat page, where weighting a raffle by ticket count actually comes up.

Test It Yourself

You do not have to believe any of the above. The same generator the wheel uses is available in your browser console, so you can run the draw tens of thousands of times in a second and look at the distribution.

  1. Open any tool page on this site.
  2. Open your browser’s developer console. On Chrome, Edge or Firefox that is F12, then the Console tab. On Safari, enable the Develop menu first.
  3. Paste the code below and press Enter.
  4. Read the table. Every segment should sit close to 10 percent, and the chi-squared figure should land somewhere around 9.
// Paste into the browser console on any tool page.
// Counts where 12,000 draws from a 10-entry wheel actually land.
const n = 10, runs = 12000, hits = new Array(n).fill(0);
const buf = new Uint32Array(1);
const limit = Math.floor(0xffffffff / n) * n;
for (let i = 0; i < runs; i++) {
  do { crypto.getRandomValues(buf); } while (buf[0] >= limit);
  hits[buf[0] % n]++;
}
const expected = runs / n;
const chi2 = hits.reduce((s, o) => s + (o - expected) ** 2 / expected, 0);
console.table(hits.map((count, i) => ({
  segment: i + 1, count, pct: (count / runs * 100).toFixed(2) + '%'
})));
console.log('chi-squared:', chi2.toFixed(2), '- expect roughly 9 for 9 degrees of freedom');

Run it a few times. You will see the counts wobble — that is what randomness looks like, and a wheel that produced exactly 1,200 hits per segment every time would be the suspicious one. A chi-squared value around 9 with nine degrees of freedom is what a fair ten-way draw produces. Values above about 21 would happen less than one run in a hundred by chance, so a generator that consistently returned those would be worth doubting.

What We Never Do

  • No server-side draw. The result is computed in your browser. Our host never sees it, because it is never sent anywhere.
  • No logging of results. There is no record of any spin on any server. The results list and the CSV export are built in your browser from what happened in that session.
  • No house, no sponsored outcome. No entry has ever been weighted for any commercial reason, and there is no mechanism in the code that could do it.
  • No memory between spins. Except for the removal setting, which you control and can see, each spin is independent. The wheel does not know or care what came up last time.
  • No profiling. The site does not know who you are, so it could not treat you differently even if it wanted to.

The Honest Limits

Three things this page is not claiming.

Where the method stops
LimitWhat it means for you
Not a certified RNGRegulated gambling and licensed lotteries require audited, tested and certified systems. This is a free web page and is not one. The terms of service say so explicitly
No independent recordBecause nothing is stored on a server, you cannot later prove to a third party what a draw produced. For a giveaway, record the screen while you spin
Trust in the browserThe randomness is only as good as your browser and operating system implementation. That is the same primitive your banking session depends on, but it is not something this site controls
Trust in the code shipped to youYou are running our JavaScript. The console test above uses the browser generator directly rather than our function, so it checks the method independently of us

Related Reading

For the mechanics of the buttons rather than the mathematics, see the walkthrough of the controls. What the site does and does not collect is in the privacy notice, and the parts of the site that are hard to use with assistive technology are listed honestly in the accessibility statement.