Numbers come from crypto.getRandomValues() โ the browser's cryptographically secure random generator โ rather than Math.random(), which isn't designed to be unpredictable. Each draw generates a random 32-bit integer and reduces it into your range with modulo; "no duplicates" works by drawing into a Set and retrying on any collision until it's full.
FAQ
Does reducing the random value with modulo introduce bias?
In theory, a tiny amount when the range doesn't evenly divide 2^32, but for any range you'd realistically enter here that bias is far too small to matter for a raffle, dice roll, or lottery pick.
What happens if I ask for more unique numbers than the range allows?
It stops and tells you the range is too small โ you can't draw 50 unique numbers from a range of 1 to 20, so the generator won't return duplicates or silently hand back fewer numbers than requested.
Free, unlimited, no account. If this saved you a paid tool, a small thanks is appreciated.