Reference → Syntax
Dice expression syntax
Everything the engine accepts. Every example below links to its
live distribution at /strike/ — click any to see the
exact rationals.
Quick reference
| Form | Meaning | Example |
|---|---|---|
K |
integer constant | 5 |
NdM |
roll N M-sided dice, sum the faces | 2d6 |
NdM+K / NdM-K |
add or subtract a constant to the sum | 2d6+5 |
A + B + … |
mix any number of dice + constant terms | 1d8 + 1d6 + 3 |
NdM! |
exploding dice — max face rolls again, sums in | 1d6! |
NdMrK |
reroll once if the first roll is ≤ K (GWF rule when K=1) | 2d6r1+5 |
NdMkh1 |
roll N, keep the highest 1 (advantage when N=2) | 2d20kh1 |
NdMkl1 |
roll N, keep the lowest 1 (disadvantage when N=2) | 2d20kl1 |
Constants and dice
An expression is a sum of terms. Each term is either an integer
constant (K) or a dice term (NdM, possibly
with a modifier). Whitespace between tokens is optional and ignored;
the d can be uppercase (D) too.
5— a constant 5 (degenerate "distribution" with one outcome).1d6— one six-sided die. Six equally-likely faces, mean 3.5.2d6— two d6 summed. The classic triangular distribution: 36 outcomes, mean 7, mode 7.4d6— four d6, used in 5e ability score generation (the "drop the lowest" variant isn't yet supported as a single expression).
Additive modifiers
The most common 5e weapon-damage form: NdM plus your
ability modifier. + and - are
left-associative; you can chain any number of terms.
1d8+3— longsword with +3 STR. Range 4–11, mean 7.5.2d6+5— greatsword with +5 STR. Range 7–17, mean 12.1d12+5— greataxe with +5 STR. Same modifier; very different shape.
For mixing different dice (e.g., weapon + sneak attack die, base damage + elemental rider), see the next section.
2d6+5
- 7 2.78%
- 8 5.56%
- 9 8.33%
- 10 11.11%
- 11 13.89%
- 12 16.67%
- 13 13.89%
- 14 11.11%
- 15 8.33%
- 16 5.56%
- 17 2.78%
Mixing dice and constants — the main reason to use the engine
Anyone can compute 2d6 alone. The interesting cases
combine different dice — weapon + sneak attack, base damage +
elemental rider, primary swing + bonus-action attack — and the resulting
distribution isn't an obvious shape. Convolving exact rationals is what
this engine does well.
Add as many dice and constant terms as you want, in any order, with
+ or - between them. Whitespace is optional.
-
2d6 + 1d4— pure dice mix, no constant. Range 3–16, mean 19/2 = 9.5. -
1d8 + 1d6 + 3— 5e rogue with a shortbow + sneak attack die + DEX modifier. Three independent terms. Range 5–17, mean 11. -
2d6 + 1d4 - 2— dice plus dice plus a negative constant. Useful for "deal 2d6 + 1d4 damage, target gains 2 temp HP" kind of net-damage scenarios. Range 1–14. -
1d8 + 3↔3 + 1d8— order doesn't matter for+terms; both produce the same distribution and the same slug encoding when you flip them through the parser.
The convolved shape is what you'd expect from the central limit theorem — adding more independent dice pulls the distribution toward a bell curve. Side by side: pure 1d8+1d6 (no modifier) vs the rogue pattern with +3 (same shape, shifted right by 3):
1d8+1d6
- 2 2.08%
- 3 4.17%
- 4 6.25%
- 5 8.33%
- 6 10.42%
- 7 12.50%
- 8 12.50%
- 9 12.50%
- 10 10.42%
- 11 8.33%
- 12 6.25%
- 13 4.17%
- 14 2.08%
1d8+1d6+3
- 5 2.08%
- 6 4.17%
- 7 6.25%
- 8 8.33%
- 9 10.42%
- 10 12.50%
- 11 12.50%
- 12 12.50%
- 13 10.42%
- 14 8.33%
- 15 6.25%
- 16 4.17%
- 17 2.08%
Exploding dice (!)
On a maximum-face roll, roll the die again and add. Recurses up to
depth 20 (truncation error ~M⁻²⁰, well below
floating-point noise for any practical M). Notation: append
! to the dice term.
1d6!— the canonical exploding die. Mean 21/5 = 4.2.1d8!— slightly tighter explosion rate.- Why this matters →
Constraint: a 1-sided die can't explode (it would loop forever).
Combining ! with r on the same die is
rejected — pick one modifier per die term.
1d6
- 1 16.67%
- 2 16.67%
- 3 16.67%
- 4 16.67%
- 5 16.67%
- 6 16.67%
1d6!
- 1 16.67%
- 2 16.67%
- 3 16.67%
- 4 16.67%
- 5 16.67%
- 6 0.00%
- 7 2.78%
- 8 2.78%
- 9 2.78%
- 10 2.78%
- 11 2.78%
- 12 0.00%
- 13 0.46%
- 14 0.46%
- 15 0.46%
- 16 0.46%
- 17 0.46%
- 18 0.00%
- 19 0.08%
- 20 0.08%
- 21 0.08%
- 22 0.08%
- 23 0.08%
- 24 0.00%
- 25 0.01%
- 26 0.01%
- 27 0.01%
- 28 0.01%
- 29 0.01%
- 30 0.00%
- 31 0.00%
- 32 0.00%
- 33 0.00%
- 34 0.00%
- 35 0.00%
- 36 0.00%
- 37 0.00%
- 38 0.00%
- 39 0.00%
- 40 0.00%
- 41 0.00%
- 42 0.00%
- 43 0.00%
- 44 0.00%
- 45 0.00%
- 46 0.00%
- 47 0.00%
- 48 0.00%
- 49 0.00%
- 50 0.00%
- 51 0.00%
- 52 0.00%
- 53 0.00%
- 54 0.00%
- 55 0.00%
- 56 0.00%
- 57 0.00%
- 58 0.00%
- 59 0.00%
- 60 0.00%
- 61 0.00%
- 62 0.00%
- 63 0.00%
- 64 0.00%
- 65 0.00%
- 66 0.00%
- 67 0.00%
- 68 0.00%
- 69 0.00%
- 70 0.00%
- 71 0.00%
- 72 0.00%
Reroll once (r<K>)
If the first roll is ≤ K, roll a second time and keep the second
result (whether it's higher or lower). The 5e Great Weapon Fighting
style is exactly NdMr1 — reroll any 1s and 2s once.
(Strict 5e GWF rerolls 1s AND 2s; the engine currently supports
only an inclusive ≤ K threshold, so r2 covers both.)
Keep-highest / keep-lowest (kh1 / kl1)
Roll N dice, keep only the single highest (kh1) or
single lowest (kl1). When N=2 this is exactly 5e
advantage and disadvantage.
2d20kh1— d20 with advantage. Mean 553/40 = 13.825.2d20kl1— d20 with disadvantage. Mean 287/40 = 7.175.- Why this matters →
Constraint: only kh1 / kl1 are evaluated
today. Larger keep counts (e.g. 4d6kh3 for 5e ability
score generation) parse but error with a clear message — that
requires the order-statistic engine extension, on the roadmap.
2d20kh1
- 1 0.25%
- 2 0.75%
- 3 1.25%
- 4 1.75%
- 5 2.25%
- 6 2.75%
- 7 3.25%
- 8 3.75%
- 9 4.25%
- 10 4.75%
- 11 5.25%
- 12 5.75%
- 13 6.25%
- 14 6.75%
- 15 7.25%
- 16 7.75%
- 17 8.25%
- 18 8.75%
- 19 9.25%
- 20 9.75%
2d20kl1
- 1 9.75%
- 2 9.25%
- 3 8.75%
- 4 8.25%
- 5 7.75%
- 6 7.25%
- 7 6.75%
- 8 6.25%
- 9 5.75%
- 10 5.25%
- 11 4.75%
- 12 4.25%
- 13 3.75%
- 14 3.25%
- 15 2.75%
- 16 2.25%
- 17 1.75%
- 18 1.25%
- 19 0.75%
- 20 0.25%
Combination rules
-
One modifier per die term.
1d6!r1is rejected — pick exploding or reroll. -
Modifiers attach to the dice term, not to the sum.
2d6!+5means "exploding 2d6, then add 5", not "explode the whole sum". -
No multiplication, no parentheses. The grammar
is intentionally additive-only.
3 × 1d6is just3d6(which has the same distribution as one die's worth tripled in count, by linearity). -
Case-insensitive operators.
2D20KH1works the same as2d20kh1. -
Whitespace is ignored between tokens.
2d6 + 1d4 - 2and2d6+1d4-2are equivalent.
What's not yet supported
-
Generic keep-K (
kh3,kl2, …). Parses but rejects withKeepNotImplemented. Needs the order-statistic engine extension — straightforward but not done yet. -
Multiplication (
3 × 1d6). Use3d6instead — the engine has no multiplication operator. -
Comparison / threshold operators (
≥,=, …). The kill-probability question is asked via the URL (/kill/<expr>/<hp>) or the per-page HP slider, not via expression syntax. -
Conditional / Boolean logic. No "roll X, on success roll Y"
expressions. Use the attack-resolution API
(
Diceplots.Engine.resolve_attack/1) for hit/miss/crit compositions; that's a different layer from raw damage expressions.
URL slug encoding
Pages under /strike/<slug> and
/vs/<a>/<b> use a tiny URL-safe substitution
so links don't need percent-encoding:
+↔p-↔m- whitespace stripped on encode
So 2d6+5 becomes /strike/2d6p5. Modifiers
that don't contain + or - (like
!, r1, kh1) pass through
unchanged.
Error messages
The parser surfaces specific errors rather than a generic "syntax error". Common ones:
unexpected end of input— truncated expression.unexpected character: 'x'— couldn't parse pastx.dice count must be at least 1—0d6.dice must have at least 1 side—1d0.a 1-sided die cannot explode—1d1!.a die can carry at most one modifier (! or r<N>)—1d6!r1.keep N not yet supported — only keep-1 (advantage / disadvantage) works today—4d6kh3.
Try it yourself
↦ Comparison tool — type any expression and see the distribution ↦ Concepts — counterintuitive damage math