Tabletop role-playing is 80% imagination and 20% arithmetic, and dice handle the arithmetic. Whether you are rolling 4d6kh3 for a wizard's Intelligence or 8d6 for a Fireball, this page speaks the same notation your DM does. It also runs every draw against the Web Crypto API rather than Math.random, persists your roll history locally, and refuses to send a single number to a server. That last part matters more for privacy than fairness — Gary Gygax never had to worry about a roller phoning home — but it is the policy.
Anatomy of XdY+Z notation
The grammar that emerged with Dungeons & Dragons in 1974 has held up shockingly well. XdY+Z reads: roll X dice with Y sides each, sum them, add the flat modifier Z. 3d6 is a basic damage roll. 1d20+5 is an attack with a +5 bonus. The notation composes: 1d20+1d4+5 means roll one d20, roll one d4, add 5, sum everything. The implementation here is a recursive descent parser that lexes the string, builds an AST, and evaluates each die expression with a CSPRNG. The AST is exposed for advanced callers (an early-preview UI could show the parse tree before committing the roll) but most users never see it.
One quiet decision worth flagging: when you write 3d6+2, that +2 attaches to the d6 component for display purposes, not as a separate floating term. With one die expression that distinction is invisible. With 1d20+1d4+5, the +5 attaches to the nearest die — the d4 — so the breakdown reads (d20=14) + (d4=3+5=8) = 22 rather than detaching the modifier into its own chip. That keeps multi-die reads aligned with how players narrate them aloud.
Modifiers beyond plain arithmetic
Six modifier operators cover almost every tabletop convention. kh3 means "keep highest 3" — the canonical 4d6kh3 rolls four dice and drops the lowest, which is the 5e stat-generation method. kl1 means "keep lowest 1" — used in reverse for disadvantage. The shorthand for advantage is 2d20kh1; for disadvantage, 2d20kl1. dh and dl drop highest / lowest instead of keeping, which is the same operation written from the other side.
! is the exploding die: when a die rolls its maximum face, it explodes — you roll another of the same kind and add it. 10d10! can therefore exceed 100 if a 10 explodes into another 10. The implementation here caps explosions at 100 per die to prevent a malicious or accidental formula from looping forever. r1 rerolls 1s once. t4 switches to target mode: instead of summing, you count dice that landed at 4 or higher — the World of Darkness mechanic. And 4dF uses Fudge dice, whose six faces are −1, −1, 0, 0, +1, +1; the math is the same, but the output is a small signed total rather than a sum.
The seven dice and their usual jobs
D&D 5e standardised on seven polyhedrons. The d4 handles dagger and magic-missile damage; small but consistent. The d6 is everywhere — the shortsword, the fireball, the most-common board-game die. The d8 covers the longsword and healing word. The d10 shows up for the rapier and certain spells, and pairs with another d10 to form a percentile. The d12 belongs to the raging barbarian's greataxe. The d20 is the king: attack rolls, saving throws, ability checks — anything where success is a binary question. The d100, rolled as paired d10s for tens and ones, fills random tables, loot drops, and percentile checks in BRP-family systems.
Statistical properties worth knowing
A flat 1d20 has a mean of 10.5 and a variance of 33.25. Stack two via advantage (2d20kh1) and the mean jumps to roughly 13.83 — the same expected value as a flat d20 with a +3.3 bonus, which is why DMs treat advantage as worth somewhere between +4 and +5 when balancing encounters. Disadvantage drops the mean to about 7.18, symmetrically. For 4d6kh3 the mean is 12.24 with a slight right skew; the chance of rolling an 18 is about 1.62%, which is why a perfect array of all 18s for a new character is a story-worthy event rather than a Tuesday.
Streaks feel weirder than they are. Three natural 20s in a row on a d20 is one chance in 8,000 — uncommon but not astonishing across a long campaign. Three natural 1s in a row is the same probability. Five natural 20s in a row is one in 3.2 million; at that point your GM is entitled to inspect the dice (or the RNG). The Web Crypto API used here passes standard uniformity tests, so the explanation when it happens at this table is coincidence, not bias.
Cryptographic randomness vs perceptual fairness
Two separate properties get conflated as "fairness." The first is distributional: do face values appear in their expected proportions over time? A quality CSPRNG nails this. The second is perceptual: does the sequence feel random to humans? It often does not, because humans expect alternation and dislike clusters. A coin flipper who never sees three heads in a row is using a coin that fails the first test; a player who sees three heads in a row and accuses the coin is failing the second test on themselves. The Spec #99 coin-flip page covers this asymmetry in depth, and the same logic applies here.
The honest framing for critical hits is similar. Natural 20s and natural 1s only have RAW (rules as written) consequences on attack rolls in 5e, where a 20 doubles the damage dice and a 1 misses regardless of bonus. On ability checks and saving throws the natural face is mechanically meaningless by default, though most tables houserule something. This generator highlights the natural value when a single d20 component lands on a 20 or 1, and stays out of the way otherwise.

