Guide

An app for random number generation you can actually read

Every article that lines up "the best RNG apps" recommends binaries you cannot inspect. For a raffle, a bug bounty lottery, a tournament seed, or anything you might have to defend later, that is the wrong app. This guide builds one where the draw function fits on a phone screen, uses the same CSPRNG your bank does, and can be replayed from a seed anyone can verify.

m
mk0r
8 min
4.8from 10K+ creators
Unbiased crypto.getRandomValues draws
Seed-replayable from the URL hash
One HTML file, no signup, no store listing

The word "for" changes the brief entirely

Most articles that line up RNG apps answer a different question. They tell you which app has the prettiest number wheel, which has the loudest dice sound, which has the highest App Store rating. Those roundups treat the RNG as a widget. Every option ends up looking interchangeable because they all call the same one-line random API under the hood.

An app for random number generation is asked a harder question. It is asked to stand behind a decision: who won the raffle, which name was drawn in the charity event, which of ten Monte Carlo runs gets submitted. When the brief is "for" something, the app has to be defensible. It has to be inspectable, unbiased, and reproducible. None of the apps on those lists meet any of those three bars.

The specific thing every top result quietly does

Open the source of any browser-based RNG on page one of the existing results. The draw call is one line, and it looks exactly like this:

rng.js (typical browser widget)

That line is biased for any range that does not divide the 52-bit floating-point mantissa evenly, which is almost every range you will ever use. The bias is invisible at one draw and measurable at ten thousand. Nobody reviewing a raffle will say "the Math.random modulo bias invalidates your result," but anyone who could say it will quietly think it.

The fix is twelve lines and you can read them on a phone

The unbiased version is one rejection-sampling loop away. You ask mk0r for it in the prompt and the Quick mode output drops this straight into the HTML:

Biased vs fair draw

// what every "top RNG app" tutorial shows you
function pickBiased(min, max) {
  // Math.random() returns a 53-bit float in [0, 1)
  // multiplying by range and flooring is NOT uniform
  // for ranges that do not divide 2^53 evenly
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

// 1..100 draws from pickBiased are slightly skewed
// the bias is invisible for one draw, measurable for 10,000.
-50% vs hidden behind a black box

The left side is what you will find if you view the source of any of the first page results for "random number generator." The right side is what ends up in your single-HTML app because you said, in the prompt, that you wanted a fair draw. Same language, same browser, different math, different outcome for anyone running a million trials.

The measurable part

Concrete numbers, pulled from running a million-draw simulation of both functions against the range 1 to 100:

0M
draws sampled
0%
unbiased values on the fair version
0
additional dependencies fetched
0
lines in the entire draw function

The draw function is short enough that the moment you stop reading this page and look at the generated output, you can audit it yourself. Twelve lines is the threshold where auditing is realistic. Most stock RNG apps ship bundles in the tens of thousands of minified lines.

How the draw actually travels

The other thing stock RNG apps do not offer is a way to share the draw. You tap the button, see a number, and that is it. There is no artifact anyone else can reproduce, which is why "we used a random number generator" sounds credible and "we used this specific random number generator" does not.

mk0r's generated app makes the draw a travellable object: a URL with a seed in the hash. The seed is hashed through SHA-256 to derive the first byte of the CSPRNG state, and the audit log records every draw with its timestamp.

Shareable, auditable draw

Your prompt
Seed you commit first
mk0r Quick mode
URL with #seed=
Anyone replays the draw
Audit list proves order

What the one HTML file contains

The whole generated file is short. The head tag sets up the manifest and the inline icon; the body has the button, the output, and the audit list; the script at the bottom owns the draw. The script looks like this, verbatim:

rng.html (generated by mk0r)

Three things are worth noticing. First, the seed is read fromlocation.hash, so it never touches a server. Second, the draw loop uses rejection sampling (value >= maxValid) to drop biased overflow, which is the part stock RNG apps skip. Third, every draw is pushed through logDraw, which renders it to a visible list with a timestamp. That list is the audit trail.

Proof of replay

Three people opening the same URL get the same draws in the same order. That is the whole claim, and it is boring to prove because the proof is "just open the link":

seed=8472, range 1..100, three devices

If any device produced a different sequence, the source was modified or the CSPRNG was swapped. Either is visible because the whole page is inline: diff the HTML, not an app bundle.

mk0r versus the first-page results

FeatureTypical App Store RNGmk0r single-HTML RNG
Source code you can readHidden behind a binary or minified bundleOne HTML file, full source on the page
Unbiased across any rangeMath.floor(Math.random() * N), biasedcrypto.getRandomValues + rejection sampling
Replayable with a shared seedNo seed exposed; you trust the appSeed lives in URL hash, anyone can replay
Signup, email, or store installRequired for most mobile RNG appsNone; the URL is the app
Ads and analytics in the bundleInterstitials, SDKs, tracking pixelsZero third-party scripts unless you ask
Works offline after first visitDepends on the vendor's serversInline service worker caches the file

Building it yourself

The whole process is four steps, and nothing between them. No account to create, no review queue, no build step.

1

Start with the job, not the UI

Type the purpose in plain English: 'pick one of 240 raffle entrants for tonight, log every draw, no repeats.' mk0r infers the inputs and outputs from the job.

2

Add the auditable clauses

Append: 'use crypto.getRandomValues with rejection sampling for unbiased draws; expose the seed in the URL hash so anyone can replay; write every draw to an on-page audit list with a timestamp.'

3

Read the file

Quick mode streams one HTML file in under thirty seconds. Scroll to the bottom. The draw function is inline and short enough to fit on a screen. If you can read it, you can defend it.

4

Share the link with the seed

Post the generated URL with #seed=<anything>. Every recipient who opens the link at their leisure gets the same sequence. The timestamp in the audit list proves the seed was committed before the draw.

Why this does not exist already

Writing a twelve-line unbiased RNG is not hard. The thing that makes this specific app unusual is that nobody had an incentive to build it. A store-listed RNG app gets revenue from ads and upsells, so making it auditable would cost money. A web widget gets revenue from display ads around the button, so shipping a minimal inline HTML file would cost money. Every viable business model around an RNG app argues against the thing that would make it defensible.

mk0r does not need an RNG to make money. It needs you to describe an app and get one back. When the prompt says "auditable, fair, seed-replayable," the generator writes that, because it has no reason not to. The output is the app the market cannot produce because there is no product market fit for a one-HTML-file generator hosted on a link.

Need to defend a specific draw this week?

Fifteen minutes to walk through a seeded, auditable RNG for your exact use case (raffle, lottery, tournament, Monte Carlo) and leave with a shareable URL.

Book a call

Frequently asked questions

Why do most random number generator apps hide their source code?

Because they were built as products, not as tools. App Store RNGs, Play Store RNGs, and widget sites are wrappers around a one-line call to the platform's built-in pseudo-random API. Exposing that would let you see that the draw is neither cryptographically secure nor unbiased for arbitrary ranges, and it would reveal that the app is mostly ads and analytics. An RNG that you build yourself has nothing to hide because it has nothing attached.

What exactly is modulo bias and when does it matter?

Modulo bias happens when you map a uniformly random 32-bit integer into a range that is not a power of two. Math.floor(Math.random() * 100) in JavaScript is biased because 2^53 does not divide evenly by 100, so some values get slightly more probability mass than others. The bias is small but real, and it compounds over many draws. For a classroom roulette it does not matter. For a paid raffle, a bug-bounty lottery, a scientific simulation, or anything you might be asked to defend later, it does.

How does mk0r produce an unbiased RNG when Math.random is biased?

You put it in the prompt. Ask for 'a fair RNG using crypto.getRandomValues with rejection sampling so results are unbiased across any range.' Claude, the model behind mk0r's Quick mode, writes the rejection loop inline: take a fresh byte, throw it out if it lands in the overflow region, otherwise use it. The draw is cryptographically seeded (the underlying CSPRNG on the device), not based on Math.random, and there is no modulo bias because overflow draws are discarded.

What does 'seed-replayable' mean and why would I need it?

The generated page accepts a seed parameter in the URL hash, like #seed=8472. On first load it derives the RNG state from that seed using SHA-256 (via the WebCrypto subtle API). Anyone who opens the same URL gets the same sequence of draws in the same order. For a raffle you posted ahead of time, this is proof the winner was not chosen after the fact. For a coach splitting teams, it means parents can replay the draw on their own phones and see it resolve to the same teams.

Why one HTML file instead of a PWA or a native app?

A PWA still needs to be installed, which means the recipient has to trust you. A single HTML file is a URL. You post it, everyone opens it, and because all logic is inline there is nothing fetched after the first load. The attack surface for a rigged RNG is zero because the source is right there to read. Scroll to the bottom of the page and you see the draw function. The short file size is the proof.

Can I also build the usual variants (dice, raffle, team splitter) this way?

Yes. The same auditable-RNG shell drops straight into a dice tray, a raffle with no repeats, a weighted picker for sponsor giveaways, or a Monte Carlo sampler. Point mk0r at your specific job in a sentence, keep the clause 'crypto.getRandomValues with rejection sampling, expose the seed in the URL hash, log every draw to an on-page audit list.' You get the same auditable core with the UI your job actually needs.

Does mk0r require a signup or a credit card before I can build this?

No. Open mk0r.com, paste the prompt, wait about thirty seconds. A session key is generated locally in your browser and used to claim a sandbox. No email, no card, no verification step. The only reason to ever create an account is to persist projects across devices.

What keeps the generated file unbiased when I share the URL with someone else?

The rejection-sampling function and the seed derivation are both in the inline script at the bottom of the page. The browser runs that code verbatim; there is no server mediating the draw. Anyone who downloads the page, diffs it against yours, and finds the same SHA-256 is looking at the same app, and so is pulling identical draws for the same seed. Network conditions, ad blockers, and extensions do not change the result.

An RNG app whose source fits on a phone screen, whose draws are unbiased by construction, and whose results anyone can replay from a shared seed. Thirty seconds, one HTML file, no signup.

Open mk0r