Technical transparency

How WheelieNames Picks a Winner

Every spin uses crypto.getRandomValues() — the same cryptographic standard underlying HTTPS and banking apps. Here is exactly what happens when you click Spin.

Last updated

The word “random” means different things to different tools. A coin-flip animation can look random while being entirely predictable. A dice roll can feel fair while carrying subtle biases that compound over hundreds of throws.

WheelieNames is built on a precise definition: cryptographic randomness — unpredictable by anyone, including us. This page explains exactly what that means, how it is implemented in the codebase, and how you can verify it yourself. For background on who built this and why it matters, see the About page.

The two kinds of “random”

Before explaining what WheelieNames does, it helps to understand what it does not do.

Pseudo-random (Math.random())

Fast and deterministic. Seeded from a predictable starting value, the output is a repeatable mathematical sequence. Given enough observations, a motivated person can reconstruct the seed and predict future values.

Acceptable for: animation timing, visual effects, shuffling playlists. Not acceptable for: fair selection where the outcome matters.

Cryptographically secure (Web Crypto API)

Draws entropy from the operating system — hardware interrupts, thermal noise, and other genuinely unpredictable physical events. Specified by the W3C Web Cryptography Specification. The same standard underlying HTTPS, password managers, banking one-time PINs, and key generation.

Call site: crypto.getRandomValues(new Uint32Array(1))[0]

We use the second one. Always. For every spin.

Note: the confetti animation that plays after a win uses Math.random() for particle positions — that is purely cosmetic and has no connection to winner selection.

How a single spin works

From click to winner, here is every step in the selection pipeline:

  1. 1

    Generate a cryptographic integer

    When you click Spin, we call crypto.getRandomValues(new Uint32Array(1))[0] to generate a 32-bit unsigned integer between 0 and 4,294,967,295. This is the only source of randomness used for selection.

  2. 2

    Convert to a rotation target

    We use that integer to calculate a cryptographically random number of full rotations — between 4 and 12 complete spins — plus a random final angle between 0° and 360°. The result is a precise total rotation value in degrees.

  3. 3

    The outcome is locked in

    The total rotation — and therefore the landing position — is determined before the animation starts. Nothing that happens during the visual spin influences the result.

  4. 4

    The animation follows the result

    The wheel is animated to rotate precisely to that pre-determined position using a smooth easing curve. The animation is the messenger, not the decider.

  5. 5

    The winner is read from the angle

    When the wheel stops, we compute which segment sits at the 0° pointer position using Math.floor(effectiveAngle / anglePerSegment) to reveal the winner. This is a pure arithmetic read — no second random draw.

  6. 6

    No server contact

    No server is contacted at any point during a spin. No data leaves your browser. The entire selection happens locally, on your device, in milliseconds.

About uniform distribution

A common source of bias in random selection tools is integer modulo bias — when you reduce a large random integer to a smaller range using the % operator, certain values become slightly more likely than others if the integer space does not divide evenly by the range.

WheelieNames sidesteps this entirely by working in angle space rather than integer space. The 360° circle is divided into N equal segments — one per entry — where each segment spans exactly 360° / N degrees. The cryptographic draw selects a landing angle uniformly across 0°–360°, and the winner is whichever segment contains that angle.

Because degrees divide continuously — not discretely — every segment receives exactly the same share of the angular space regardless of list size. Whether you have 2 names or 200, each one occupies the same fraction of the wheel and the same fraction of the probability space.

anglePerSegment = 360° / entries.length

winnerIndex = Math.floor(effectiveAngle / anglePerSegment)

Privacy architecture

Cryptographic fairness and privacy go together. A tool that sends your entrant list to a server introduces a trust gap — you have no way to verify the server is not influencing the draw. WheelieNames removes that gap by design. For our full transparency commitments, see our Editorial Policy.

  • Local-first storage. All wheel data — names, results, settings — lives in browser localStorage. Nothing is written to a database or sent to a server at rest.

  • No analytics on wheel content. Page-view analytics are anonymous aggregate counts. No analytics event captures the names you add or the winner the wheel selects.

  • No account required. There are no logins, no emails, and no mandatory registration for any part of the free wheel.

  • URL-based sharing with no server storage. When you share a wheel, names are compressed using LZ-String and embedded directly into the URL path: /share/{encodedData}. The URL itself contains all the data. No round-trip to a server, no database entry created.

How we test before shipping

Correct randomness requires more than writing the right function call — it requires verifying the full selection pipeline behaves identically across every environment a user might run it in.

Cross-browser coverage

Chrome, Firefox, Safari, and Edge — desktop and mobile — are tested before each release. The Web Crypto API is universally supported in modern browsers, but the full selection pipeline is verified end-to-end in each.

Performance budget

The spin result is calculated in under 1 millisecond. The animation targets 60 FPS on mid-range mobile hardware. A slow animation must never mask a slow calculation — the result comes first.

Accessibility

Keyboard navigation is supported — Space and Enter trigger a spin without a mouse. Screen readers receive an announcement of the winner immediately after selection, so the result is accessible to everyone in the room.

Auditable fairness

A tool that claims to be fair is not the same as a tool that can be verified to be fair. WheelieNames is the second kind.

Every spin is verifiable. Open the browser console and you can see the cryptoRandom() calls that determined the outcome — before the animation completes.

How to verify — browser DevTools

  1. 1. Press F12 (or Cmd+Option+I on Mac) to open DevTools
  2. 2. Click the Console tab
  3. 3. Click Spin on the wheel
  4. 4. Read the logged values before the animation ends

If you are a streamer running a live giveaway, encourage your audience to do this. Open DevTools on screen, watch the Console tab during the spin, and show them the raw cryptographic values. That is the difference between a fair tool and a tool that merely looks fair.

We cannot rig the draw after the fact, because the draw happens in your browser and the values are immediately visible in the console. There is no server call to intercept, no backend to manipulate, and no black box to hide behind.

Frequently asked questions

Does WheelieNames use Math.random() to pick winners?

No. WheelieNames uses crypto.getRandomValues() from the Web Crypto API — a cryptographically secure source of entropy backed by the operating system. Math.random() is only used for confetti particle animation, which has no effect on winner selection.

What is the difference between Math.random() and crypto.getRandomValues()?

Math.random() is a pseudo-random number generator (PRNG) seeded deterministically. It is fast and adequate for animations, but a motivated observer could potentially reverse-engineer outcomes after enough observations. crypto.getRandomValues() draws entropy from the OS, making outcomes computationally infeasible to predict — the same standard used in HTTPS, password generators, and banking one-time PINs.

Is the winner determined before or after the animation?

Before. The cryptographic draw happens the instant you click Spin. The total rotation angle — and therefore the winner — is fixed before a single animation frame renders. The wheel animation is a visualisation of a decision already made.

Can WheelieNames be biased toward certain positions on the wheel?

No. WheelieNames uses an angle-based mapping: the 360° circle is divided evenly into N equal segments, one per entry. The random draw selects a landing angle uniformly across 0°–360°, so each segment receives exactly 360°/N degrees regardless of list size. There is no integer modulo bias in this approach.

Does WheelieNames send my list of names to a server?

No. Every spin is computed entirely in your browser. No names, results, or settings leave your device during a spin. Wheel data is stored in browser localStorage. When you share a wheel via URL, the names are LZ-String compressed into the URL path itself — no server storage or server round-trip involved.

How can I verify the randomness myself?

Open your browser's developer tools (F12), go to the Console tab, and spin the wheel. You will see the cryptoRandom() calls that generated the outcome logged before the animation completes. Every input to the winner calculation is visible and auditable.

See it for yourself

The wheel is ready. No account required. Open DevTools and verify the cryptographic draw in real time.