Live Exact odds Seedable SVG & PNG

Dice, exactly

Full dice notation for bots, chat servers and game nights: 4d6kh3, 2d20kh1+5, exploding dice, rerolls, Fudge dice. Every roll shows its work, and every expression has its odds worked out to the last fraction.

Rolled just now! A live roll of 4d6kh3+2: four six-sided dice, the lowest crossed out, and the total.
How a roll works

Fair dice, shown working

Every die goes through its modifiers in one order: reroll, then explode, then keep or drop, then count successes. An exploding die adds a new die to the pool, which can be rerolled, dropped or explode again like any other. The answer lists every die as it landed, which ones were kept, and what each term adds up to.

Without a seed, dice come from PHP's random_int, the system's secure generator, so nobody can steer a roll. With seed, the same seed and expression give the same roll every time, which makes a roll shareable as a link. Seeded rolls are reproducible on purpose, so do not use them where fairness matters.

Cheat sheet

The notation

Terms are dice or whole numbers, joined by + and -. Modifiers stick to their dice, in any order. Upper or lower case, it does not matter.

WriteExampleMeans
NdM3d6N dice with M sides. N is 1 to 100 and can be left out (d20 is 1d20); M is 2 to 1000.
d%2d%Percentile dice, the same as d100.
NdF4dFFudge dice, as in Fate: two minus faces, two blank, two plus, so each one is -1, 0 or +1.
+ -1d20+5Add or take away dice and constants. Up to 10 terms.
khN, kN4d6kh3Keep the highest N. k3 is kh3.
klN2d20kl1Keep the lowest N.
dlN, dN4d6dl1Drop the lowest N. d1 is dl1.
dhN5d6dh2Drop the highest N.
!3d6!Explode: a die on its highest face adds another die, which can explode too.
rN, r<N2d6r1Reroll once when the die matches: r1, r<3, r>=5. ro means the same.
rrN4d6rr1Reroll until it stops matching.
>=N, >N, <=N, <N, =N10d6>=5Count successes instead of adding up: every kept die that matches counts 1.
A space is a plus

In a URL query a literal + arrives as a space, so a space between terms reads as + and ?expr=4d6kh3+2 just works. To be exact, send %2B. And d% is d%25 in a URL, or simply write d100.

Crits

crit is natural_20 or natural_1 when the roll is a single d20 that keeps one die: 1d20+5, or 2d20kh1 for advantage (roll a second d20 and use the higher) and 2d20kl1 for disadvantage. Otherwise it is null.

Limits

200 characters, 10 terms, 100 dice in all. Explosions may add up to 100 more dice per die and 1,000 per term; even the likeliest explosion chains 100 times about once in three trillion. rr gives up after 20 tries and picks one of the other faces directly, which is the same thing, only faster.

Some classics

4d6kh3 rolls a D&D ability score (four dice, the best three). 2d20kh1 is advantage. 4dF is a Fate roll. 10d10>=8 counts hits in a dice pool.

Base URL: https://api.tasta.space/v1/dice

Endpoints

MethodPathWhat you get
GET/v1/dice/rollA roll: every die, what was kept and dropped, each term's subtotal, the total, and the crit. Takes seed, times and format=text.
GET/v1/dice/oddsEvery total the expression can roll, with its probability, percent, exact fraction and the chance of rolling at least or at most it. Mean, standard deviation, min, max, the most likely total. Takes format=text.
GET/v1/dice/roll/imageThe roll as a picture: d6s with pips, other dice as their shapes, dropped dice crossed out, the total big. SVG or PNG. Takes seed.
GET/v1/dice/odds/imageThe odds as a bar chart, SVG or PNG.

Parameters

NameExampleDoes
expr4d6kh3%2B2The dice, in the notation above. Default 1d20.
seedgamenightRolls only. 1 to 64 letters, digits, - or _. The same seed rolls the same dice, and the answer carries a permalink.
times6/roll only, 1 to 20. Rolls that many times; data becomes a list and meta.totals lists the totals.
formattexttext for one plain line per roll, on /roll and /odds. On the image endpoints, svg (default) or png.

Calls

$ curl "https://api.tasta.space/v1/dice/roll?expr=4d6kh3%2B2"
$ curl "https://api.tasta.space/v1/dice/roll?expr=1d20+5&format=text"
$ curl "https://api.tasta.space/v1/dice/roll?expr=4d6kh3&times=6"
$ curl "https://api.tasta.space/v1/dice/odds?expr=2d20kh1&format=text"

A roll looks like this

With seed=gamenight, so it is the same on every call. As text: 4d6kh3+2 = 16 (5, 6, [2], 3). Dropped dice are in brackets, a die that exploded has a !, a counted success a *. Terms with those modifiers also carry exploded (extra dice), rerolled (the faces rerolled away) and successes.

{
  "data": {
    "expr": "4d6kh3+2",
    "total": 16,
    "terms": [
      {
        "dice": "4d6kh3",
        "rolls": [5, 6, 2, 3],
        "kept": [5, 6, 3],
        "dropped": [2],
        "subtotal": 14
      },
      {
        "constant": 2
      }
    ],
    "crit": null,
    "seed": "gamenight"
  },
  "meta": {
    "permalink": "https://api.tasta.space/v1/dice/roll?expr=4d6kh3%2B2&seed=gamenight",
    "image": "https://api.tasta.space/v1/dice/roll/image?expr=4d6kh3%2B2&seed=gamenight",
    "odds": "https://api.tasta.space/v1/dice/odds?expr=4d6kh3%2B2"
  }
}

The odds look like this

at_least is the chance of rolling that total or more (handy against a target number), at_most that total or less. mode is the likeliest total; when several tie, the lowest, and mode_ties says how many share it.

{
  "data": {
    "expr": "2d4",
    "method": "exact",
    "samples": null,
    "floor": 2,
    "ceiling": 8,
    "open_ended": false,
    "unlisted": 0,
    "min": 2,
    "max": 8,
    "mean": 5,
    "sd": 1.581139,
    "mode": 5,
    "mode_percent": 25,
    "mode_ties": 1,
    "distribution": [
      {"total": 2, "probability": 0.0625, "percent": 6.25, "fraction": "1/16", "at_least": 1, "at_most": 0.0625},
      {"total": 3, "probability": 0.125, "percent": 12.5, "fraction": "1/8", "at_least": 0.9375, "at_most": 0.1875},
      {"total": 4, "probability": 0.1875, "percent": 18.75, "fraction": "3/16", "at_least": 0.8125, "at_most": 0.375},
      {"total": 5, "probability": 0.25, "percent": 25, "fraction": "1/4", "at_least": 0.625, "at_most": 0.625},
      {"total": 6, "probability": 0.1875, "percent": 18.75, "fraction": "3/16", "at_least": 0.375, "at_most": 0.8125},
      {"total": 7, "probability": 0.125, "percent": 12.5, "fraction": "1/8", "at_least": 0.1875, "at_most": 0.9375},
      {"total": 8, "probability": 0.0625, "percent": 6.25, "fraction": "1/16", "at_least": 0.0625, "at_most": 1}
    ]
  }
}
Exact, then simulated

How the odds are worked out

Sums are exact. Each term's distribution is built die by die and the terms are combined, so 2d6 gives 7 exactly 1/6. Fractions are given while the count of outcomes fits in 253; past that, probabilities are decimals to ten significant digits.

Keep and drop are exact too, by going through every sorted hand of dice once, weighted by the number of ways it can land: 4d6kh3 averages 15869/1296, about 12.24, and 10d10kh3 takes 92,378 hands instead of ten billion rolls.

Exploding dice are followed until a longer chain is less likely than one in a trillion; unlisted says how much probability that leaves out.

Floor and ceiling are the lowest and highest totals possible at all, rerolls, keeps and signs included. Explosions that can keep adding to the total leave one of them null and make open_ended true; 1d6!kh1 still tops out at 6. min and max are the lowest and highest totals in the list.

Anything bigger, and exploding dice that are also kept or dropped, is rolled a few thousand times instead: method says simulated and samples how many rolls. The seed comes from the expression, so the same question always gets the same answer. Past 1000 different totals, the list comes as buckets of bucket_size totals.

Bar chart of the odds of 4d6kh3: totals from 3 to 18, most likely 13.
https://api.tasta.space/v1/dice/odds/image?expr=4d6kh3

Errors of its own

On top of the hub's errors. Notation mistakes say what to fix, and sometimes have opinions.

StatusCodeWhen
422invalid_parameterNotation that does not parse or breaks a limit (d1: "A d1 is a marble."), a times out of range, a bad seed or format
Live, counts against your limit

Try it

https://api.tasta.space/v1/dice/roll?expr=4d6kh3%2B2
Press send. The response shows up here, headers included.

            
Sources

Where the facts come from

No dataset here: every roll and every probability is computed on the spot. The few game facts on this page are checked against: the Fate Core SRD for Fudge dice, the D&D 5e Basic Rules on advantage and disadvantage, and Aarhus University's physics colloquium on D&D dice for rolling four d6 and keeping three.

Dice notation has no single standard. This one follows what most dice bots and virtual tabletops share; where they differ, r rerolls once here and rr keeps going.