The notation this parser actually accepts
The grammar is small and strict, which is a feature. An expression is a sequence of terms joined by plus or minus signs, where a term is either a dice group or a plain number. A dice group is NdM, and the count is optional, so d20 means 1d20. Whitespace is stripped and case is ignored, so 3D6 + 2 and 3d6+2 parse identically.
You can chain as many terms as you like. 2d6+1d8+3 rolls two six-sided dice, one eight-sided die, and adds three. A group can be subtracted too: 2d6-1d4 rolls both groups and takes the d4 total away, which is why that expression can legitimately land on a negative number. Its real range is -2 to 11.
What the grammar deliberately does not do is guess. Two dice groups written next to each other with no operator, as in d20d20, is an error rather than two rolls, because silently inferring an operator is how a roller ends up producing a number the player never asked for. The same goes for 3d, d0, 0d6 and a dangling 3d6+.
Where the numbers come from
Every die face is drawn by the same randomInt helper the Random Number Generator uses, imported directly rather than reimplemented. It pulls a 32-bit unsigned word from crypto.getRandomValues and then rejects any value at or above the largest exact multiple of the die size that fits in 32 bits, redrawing until it gets one below the cut.
That rejection step is the whole point. Taking a raw 32-bit value modulo 20 would make the low faces very slightly more likely than the high ones, because 2^32 is not divisible by 20. Discarding the overhang removes that skew entirely, so a natural 20 really is a one in twenty event. The same primitive is shared by the Coin Flip and the Wheel of Names, which is why all three can make the same fairness claim.
Rolling an expression and reading what comes back
- Type into the Dice notation box, or tap one of the preset chips from d4 through d100. Tapping a chip replaces whatever was in the box rather than appending to it.
- Glance at the line underneath, which reports the range and average for what you have typed. For
3d6+2it reads a range of 5 to 20 and an average of 12.5. - Click Roll dice, or just press Enter in the box.
- Read the large total, then the breakdown below it, which lists each group’s individual faces and the modifier as a separate row. Faces at the maximum and at 1 are styled differently so criticals stand out.
The total is always the signed sum of the faces shown plus the modifier, with nothing hidden: a group written with a minus is labelled with one and subtracted, which is the point of printing every die rather than just the sum.
Advantage and disadvantage, scoped to the d20
The second panel implements the D&D 5e rule literally. Advantage rolls two twenty-sided dice and keeps the higher, disadvantage rolls two and keeps the lower, and Normal rolls a single d20. Whatever you put in the Modifier field is added to the kept die, not to both.
Both dice are always displayed, with the kept one marked and the discarded one visibly dropped, so you can see the roll that was thrown away. This is a separate control from the expression box on purpose: the 5e rule is defined for the d20 and nothing else, and dressing it up as generic notation would imply support the parser does not have.
Range and average, before you commit to a roll
The stats line is computed exactly, not sampled. For a positive group NdM the minimum is N, the maximum is N*M, and the mean is N*(M+1)/2, all shifted by the flat modifier. Subtracted groups contribute their extremes flipped and everything adds up linearly.
It is genuinely useful for sanity-checking a homebrew expression before you roll it. 2d6+1d8+3 runs from 6 to 23 with a mean of 14.5. 4d6 runs 4 to 24 with a mean of 14. 100d6 runs 100 to 600 with a mean of 350. If a number in that line surprises you, the expression is probably not the one you meant to type.
Errors, caps and the history list
Bad input produces a specific message, never a fabricated result. Typing 0d6 says each dice group must roll at least one die. Typing d0 says a die must have between 1 and 1000 sides. Typing d20d20 tells you to separate dice with a plus or minus. Exceeding one hundred dice is refused outright. An empty box shows nothing at all and simply leaves the roll button disabled, which is deliberate: an empty box is not a mistake, it is just not a roll yet.
Every completed roll is appended to a history list capped at twenty entries, formatted as the expression, the faces and the total, for example 3d6+2: 3d6 [4, 1, 6] + 2 = 13. It is held in memory for the current tab only, and a Clear button wipes it early. For picking who goes first rather than what they rolled, the Tournament Bracket Generator and the rest of the generators cover the surrounding table logistics.

