Methodology
The exact algorithms behind every draw on this site, written out so you can check them.
Entropy source
All randomness comes from crypto.getRandomValues(), the browser’s cryptographically secure random number generator, which draws from the operating system’s entropy pool. Every tool page shows a badge stating which source is active.
If a browser does not expose the Web Crypto API, the site falls back to Math.random() and displays a warning explaining the limitation. The fallback is never used silently.
Uniform integers: rejection sampling
To produce an integer in [0, n): take a 32-bit unsigned value from getRandomValues(); compute limit = floor(2³² / n) × n; if the value is at or above limit, discard it and draw again; otherwise return value mod n.
Discarding the tail is what removes modulo bias. Without it, when n does not divide 2³² evenly, the lowest outcomes would be marginally more likely. The expected number of retries is less than one.
Uniform floats
Decimal values are built from two 32-bit draws, using 27 bits and 26 bits, to fill the full 53-bit mantissa of a JavaScript number: (hi × 2²⁶ + lo) / 2⁵³. This gives a uniform value in [0, 1) with full double precision, which is then scaled to the requested range.
Weighted selection
Weights are multiplied by 1,000 and rounded to integers, so three decimal places are supported exactly. The integers are summed to give a total, one ticket is drawn uniformly in [0, total) using rejection sampling, and the tool walks the cumulative sums to find the owning entry.
Weights must be greater than zero and at most 1,000. Wheel slice angles are computed from the same integer weights, so the visual proportions always match the actual probabilities.
Shuffling: Fisher-Yates
For i from length−1 down to 1: draw j uniformly in [0, i]; swap elements i and j. Every permutation is equally likely. A random comparison function passed to sort() is never used, because it produces a biased ordering.
Drawing several without repeats
For k unweighted draws from n entries, a partial Fisher-Yates pass resolves only the first k positions: position i is swapped with a uniformly chosen position in [i, n), and the entry at i is taken. This is equivalent to drawing without replacement and is O(k) rather than O(n).
For weighted draws without repeats, one weighted selection is made, the chosen entry is removed from the pool, and the weights are recomputed before the next draw.
A request for more unique entries than exist is refused with an explicit message. It is never silently downgraded to allow repeats.
Wheel stop angle
Angles are measured in canvas space where 0 points right and angles increase clockwise. The pointer is fixed at −π/2 (12 o’clock). Segment i occupies [start_i, end_i) before rotation, sized proportionally to its weight.
The entry under the pointer at any rotation r is the segment containing normalise(−π/2 − r). To stop on a chosen segment, the tool solves that equation for r: it takes the segment centre, offsets it by at most 40% of the half-width (so rounding can never cross a boundary), computes the required rotation, and adds four to seven full turns.
After the animation the tool recomputes which segment sits under the pointer and compares it with the chosen winner, logging an error if they disagree. In normal operation they never do.
Animation and result separation
The winner is always selected before any frame is drawn. Animation progress is derived from wall-clock time rather than accumulated frame deltas, so a throttled background tab resumes at the correct position instead of extending the spin. Easing, duration and frame rate cannot change the outcome.
A lock prevents a second draw while one is running, and the completion handler is written to fire exactly once so no result is recorded twice.
Team balancing
Keep-together groups are merged into single units with a union-find pass. Units are shuffled with Fisher-Yates. In equal mode each unit goes to the team with the fewest members; in score mode units are sorted by average score descending and each goes to the team with the lowest running total; in random mode each unit goes to a uniformly chosen team.
Keep-apart rules filter the candidate teams before selection. If no candidate remains, the unit is placed in the best available team and the unmet rule is reported. This is a greedy algorithm and does not guarantee an optimal partition.
Seating placement
Front and back requests are placed first from the appropriate end of the room; everyone else is shuffled and dropped into the remaining seats. When adjacency rules exist, up to 250 randomised placements are generated, each scored by counting violations, and the best is kept — stopping early on a perfect layout. Adjacency includes diagonals.
Browser compatibility
The site targets current versions of Chrome, Edge, Firefox and Safari, on desktop and mobile. It uses ES modules, Canvas 2D, CSS custom properties and CSS Grid. Optional features degrade cleanly: the Fullscreen API falls back to a CSS zoom mode, Web Share and speech synthesis are hidden when unsupported, and localStorage failures are caught so a private-mode session still works.
Known limitations
Statistical testing can reveal obvious implementation bias but cannot prove randomness. This site is not certified for regulated gambling, licensed lotteries or clinical randomisation, and must not be used for them.
Results cannot be reproduced, because each draw uses fresh entropy and nothing is stored server-side. Export or print a record at the time if you need one.
Greedy team balancing and bounded seating search are approximations by design, chosen so the tools stay fast and never hang on an impossible constraint set.