People draw raffle winners with these, so this is held to the password generator’s standard rather than a toy’s.
Two things are wrong in almost every picker on the web, and both are invisible unless you count.
First, Math.random. It is not cryptographic — its internal state can be recovered from a short run of outputs, after which every past and future value is known.
Second, modulo bias. byte % 6 looks fair and is not: 256 does not divide by 6, so four of the six faces come up about 2% more often. Here a draw landing in the incomplete last block is discarded and redrawn — a few bytes of cost, and every outcome exactly as likely as every other.
And sort(() => Math.random() - 0.5) is not a shuffle. The result depends on the browser’s sort algorithm and some orders come up far more often than others. This uses Fisher-Yates.
It draws from crypto.getRandomValues, the browser's cryptographic random source — the same one the password generator on this site uses. Math.random is deliberately not used anywhere here: it is a non-cryptographic generator whose internal state can be recovered from a short run of outputs, after which every past and future value is known. For a raffle that matters.
It is the bug in almost every picker on the web, and it is invisible unless you count. Taking a random byte and doing "byte % 6" looks fair but is not: 256 does not divide by 6, so four of the six faces come up about 2% more often than the other two. The fix is to discard any draw that falls in the incomplete last block and try again, which costs a few bytes and makes every outcome exactly equally likely. That is what this does.
Because a comparator that answers inconsistently breaks the contract every sort algorithm relies on. The result depends on which algorithm your browser uses and how the list was ordered to begin with, and some arrangements come up several times more often than others. The one-liner is famous and wrong. This uses Fisher-Yates, which visits each position once and is provably uniform.
Both stay in the draw, and the page tells you there is a duplicate. Two people really can be called Maria, and quietly collapsing them into one would halve her chance of winning. It is the sort of thing that only comes to light after the prize has been handed over, so it is said up front instead — you can delete one yourself if it was a typo.
It shuffles the whole list, then deals it out one at a time across the groups, like cards. That matters when the numbers do not divide: dealing keeps every group within one member of every other, whereas slicing the shuffled list into blocks dumps the entire remainder on the last group.
No, and that is deliberate. A reproducible draw needs a seed, and a seed that anyone can set is a draw that anyone can steer — which is exactly what you do not want for a raffle. If you need to evidence a result, record it as it happens: screenshot the list and the outcome together, or draw in front of the people involved.
Runs entirely in your browser; nothing is transmitted. Draws come from crypto.getRandomValues with rejection sampling — never Math.random, and never a random sort comparator. Duplicates in your list are reported, not removed. Nothing you type here is sent to our servers — the calculation runs entirely in your browser.