Vai al contenuto
RandoKit
IT

How randomness works in your browser

Every RandoKit result comes from the same short pipeline: entropy collected by your operating system, a cryptographic generator, unbiased mapping onto your entries, and a shuffle that treats every ordering equally. Here is what each of those steps does.

A computer is a deterministic machine

Run the same program twice with the same inputs and you get the same output. That is the whole point of a processor, and it is why software cannot conjure randomness out of arithmetic alone. What it can do is measure the messy physical world it lives in: the exact microsecond a network packet arrived, jitter between hardware clocks, noise from a dedicated on-chip source, the timing of key presses. These measurements are unpredictable in their low bits, and the operating system mixes them into a pool of entropy.

That pool is small and slow to refill, so it is not handed out directly. Instead it seeds a cryptographically secure pseudorandom number generator (CSPRNG), which stretches a few hundred bits of genuine unpredictability into as much output as you need. The guarantee a CSPRNG makes is precise and worth stating carefully: given any amount of its previous output, no practical computation recovers the internal state or predicts the next value.

Two random APIs, two very different jobs

Browsers expose randomness twice. Math.random() is a fast, ordinary pseudorandom generator. It is perfect for scattering particles in an animation and unsuitable for anything a person might contest, because its internal state can be inferred from enough observed output.

crypto.getRandomValues() is the one RandoKit uses. It fills a typed array with bytes from the platform CSPRNG:

const buf = new Uint32Array(4);
crypto.getRandomValues(buf);
// Uint32Array(4) [ 2419513288, 771049255, 4084221171, 33920617 ]
Four unbiased 32-bit values, straight from the platform generator.

The full comparison, including performance and when the cheaper API is genuinely the right call, is in the guide on Math.random versus crypto.getRandomValues.

Turning random bytes into a fair pick

Random bytes are uniform over 0–255. Your wheel has six names. The obvious conversion is the wrong one:

const index = randomByte % 6; // don't do this
Convenient, and quietly unfair.

There are 256 possible bytes and 256 divided by 6 is 42 remainder 4. Indices 0, 1, 2 and 3 are produced by 43 different bytes each; indices 4 and 5 by only 42. That is a 2.4% edge for four of your six names — invisible on a single spin, and exactly the kind of thing that makes a repeated draw indefensible.

The fix is rejection sampling: throw away the unbalanced tail.

  1. Compute the largest multiple of 6 that fits in the range: 252.
  2. Draw a byte. If it is 252 or higher, discard it and draw again.
  3. Otherwise return the byte modulo 6.

Each remaining index now corresponds to exactly 42 byte values, so every name has an identical chance. Roughly 1.6% of draws are discarded, which costs microseconds. RandoKit applies this to every integer it generates, from a d20 roll to a range on the random number generator.

Shuffling: why the algorithm matters

Ordering a list is a different problem from picking one item, and it has a famous wrong answer. Sorting a list by a random comparator — sort(() => Math.random() - 0.5) — is not a shuffle. The result depends on the sorting algorithm’s internals and produces measurably lopsided distributions, with items near their starting position far too often.

The correct method is the Fisher-Yates shuffle. Walk the list from the end to the start; at each position, swap the current item with an item chosen uniformly from the part of the list not yet fixed. Each of the n! possible orderings comes out with equal probability, provided the index at each step is drawn without bias — which is why the two halves of this page belong together.

What that means in practice

  • Running orders. One shuffle gives you a complete, repeat-free order — see randomizing presentation order.
  • Multiple winners. Shuffle once and take the first three names rather than re-running a single-winner draw, which can hand the prize to the same person twice. Picking without repeats covers the trade-offs.
  • Teams. Shuffle, then deal the list out like cards, which distributes any remainder evenly. That is exactly what the team generator does.

What fairness actually requires

A correct generator is necessary and not sufficient. The people affected by a draw judge it by the process around it, and that part is yours to design.

Be honest about the limits, too. A browser-side draw stores no seed and produces no receipt, so a determined sceptic cannot replay it and confirm the number that came out. What they can verify is that you announced the rules first, drew once, and published the result. For a classroom or a prize draw that is enough; for a regulated lottery it is not, and you should be using an audited provider. The giveaway guide walks through the difference.

Where your list goes

Nowhere. All of the above happens in the tab you have open. Entries stay in memory and in your browser’s local storage so a refresh does not wipe them, and nothing you type is transmitted to us. More detail is on the about page and in the privacy policy.

Common questions about randomness

Is a computer capable of true randomness?

Not on its own. A processor executes deterministic instructions, so any sequence it computes is reproducible given the same starting state. What modern operating systems do instead is collect unpredictable physical measurements — interrupt timings, hardware noise, device events — into an entropy pool, then use that pool to seed a cryptographic generator. The output is not random in a philosophical sense, but nobody can predict it without the internal state.

What does crypto.getRandomValues() actually give me?

It fills a typed array with bytes produced by the platform's cryptographically secure pseudorandom generator, seeded from the operating system's entropy pool. Unlike Math.random(), its internal state cannot be recovered from the values you have already seen, so a person watching earlier draws gains no advantage in predicting the next one.

What is modulo bias and why does it matter for a name picker?

If you take a random byte from 0 to 255 and reduce it with % 6, the results 0 through 3 can each occur 43 times while 4 and 5 occur only 42 times, because 256 is not divisible by 6. On a six-name wheel that is a small but real advantage for four of the names. RandoKit avoids it by discarding the values in the unbalanced tail and drawing again, so every entry maps to exactly the same number of possible inputs.

Why shuffle a list instead of picking one name at a time?

A single Fisher-Yates shuffle produces each of the possible orderings with equal probability and guarantees nobody appears twice. Repeatedly drawing one name and hoping for no repeats gives a different, messier distribution and eventually produces duplicates. For running orders and multi-winner draws, shuffle once and read down the list.

Can I verify that a RandoKit draw was fair?

You can verify the method but not replay the specific draw, because no seed is stored anywhere. In practice, fairness in front of an audience comes from process: publish the entrant list and the rules before you draw, draw once on screen, and record the result. That is true of any browser-based picker, ours included.

Does the wheel animation affect the result?

No. The winning entry is selected before the animation begins; the spin is presentation, and the wheel is rotated to land on the result that was already drawn. Reduced-motion settings shorten or skip the animation without changing the outcome in any way.