# Notation Syntax Guide

:::note[Looking for the formal spec?]
This page is a practical syntax guide. For the formal specification including conformance levels, execution pipeline, and modifier taxonomy, see the [RANDSUM Dice Notation Specification](https://notation.randsum.dev).
:::

RANDSUM uses an extended version of standard dice notation. All notation is **case-insensitive** (`2d8` = `2D8`).

## Basic syntax

The core format is `NdS` where **N** is the number of dice and **S** is the number of sides.

<NotationRoller defaultNotation="1d20" client:only="react" />
<NotationRoller defaultNotation="4d6" client:only="react" />
<NotationRoller defaultNotation="2d12" client:only="react" />

## Special dice

### Geometric die

A geometric die rolls dN repeatedly as long as the maximum face value is rolled, and the result is the sum of all rolls. All notation is **case-insensitive**.

| Notation | Description |
|---|---|
| `gN` | Roll dN until a non-maximum is rolled, result = sum |
| `3gN` | Three independent geometric rolls |

<NotationRoller defaultNotation="g6" client:only="react" />
<NotationRoller defaultNotation="3g6" client:only="react" />

A safety cap of 1000 iterations prevents infinite loops. Use cases include resource depletion tracking, chase mechanics, and survival countdowns.

### Draw die

A draw die samples without replacement from a pool of faces -- like drawing cards from a deck. Each face value can only appear once until the pool is exhausted, at which point it reshuffles. All notation is **case-insensitive** (`DD`, `dd`, `Dd`, `dD` all work).

| Notation | Description |
|---|---|
| `DDN` | Draw one unique value from [1..N] |
| `3DDN` | Draw 3 unique values from [1..N] |
| `6DD6` | Always a permutation of [1,2,3,4,5,6] |
| `8DD6` | Full permutation of [1..6] + 2 more (reshuffles) |

<NotationRoller defaultNotation="DD6" client:only="react" />
<NotationRoller defaultNotation="3DD6" client:only="react" />
<NotationRoller defaultNotation="6DD6" client:only="react" />

Use cases include card-deck mechanics, random encounter tables without repeats, draft picks, and Catan-style resource distribution.

### Percentile die

A percentile die rolls 1-100. Used in Call of Cthulhu, Warhammer Fantasy, and any system with percentage-based resolution. All notation is **case-insensitive**.

| Argument | Equivalent | Description |
|---|---|---|
| `d%` | `roll(100)` | Roll one d100 |

<NotationRoller defaultNotation="d%" client:only="react" />

`d%` maps internally to `{ quantity: 1, sides: 100 }`. It does not support a quantity prefix. To roll multiple percentile dice, pass multiple arguments: `roll('d%', 'd%')`.

`d%` does not support inline notation modifiers -- use the options object form for modified percentile rolls.

### Fate/Fudge dice

Fate dice (also called Fudge dice) produce results of -1, 0, or +1 per die. The standard Fate Core roll is `4dF`, giving a range of -4 to +4. An extended variant (`dF.2`) uses five faces: -2, -1, 0, +1, +2. All notation is **case-insensitive**.

| Argument | Faces | Range per die | Description |
|---|---|---|---|
| `dF` | -1, 0, +1 | -1 to +1 | Standard Fate/Fudge die |
| `dF.1` | -1, 0, +1 | -1 to +1 | Explicit standard variant |
| `dF.2` | -2, -1, 0, +1, +2 | -2 to +2 | Extended Fudge die |
| `4dF` | -1, 0, +1 | -4 to +4 | Standard Fate Core roll |
| `4dF.2` | -2, -1, 0, +1, +2 | -8 to +8 | Four extended dice |

<NotationRoller defaultNotation="4dF" client:only="react" />
<NotationRoller defaultNotation="dF.2" client:only="react" />

Internally, `dF` uses the replace modifier to map die faces to negative and zero values. `dF` does not support inline notation modifiers -- use the options object form for modified Fate rolls.

### Zero-bias dice

Zero-indexed dice that roll 0 to N-1 instead of 1 to N. All notation is **case-insensitive**.

| Notation | Description |
|---|---|
| `zN` | Zero-indexed die (0 to N-1) |
| `z6` | Roll 0-5 instead of 1-6 |
| `3z10` | Three zero-bias d10s (0-9) |

<NotationRoller defaultNotation="z6" client:only="react" />
<NotationRoller defaultNotation="3z10" client:only="react" />

Zero-bias dice are notation-only -- there is no options object equivalent. Use the notation string form `roll('z6')` or construct faces manually: `roll({ sides: [0, 1, 2, 3, 4, 5] })`.

**Use cases:** Zero-indexed random table lookups, percentile systems that use 0-99, programming-friendly dice for array index selection.

### Custom dice faces

Define dice with arbitrary face values. All notation is **case-insensitive**.

| Notation | Description |
|---|---|
| `d{2,3,5,7}` | Die with faces 2, 3, 5, 7 |
| `d{-1,0,1}` | Die with negative/zero faces |
| `d{fire,ice,lightning}` | Die with string faces |
| `3d{1,1,2}` | 3 dice with weighted faces |

<NotationRoller defaultNotation="d{2,3,5,7}" client:only="react" />
<NotationRoller defaultNotation="d{fire,ice,lightning}" client:only="react" />

Duplicate values create weighted distributions -- `d{1,1,2}` has a 2/3 chance of rolling 1 and a 1/3 chance of rolling 2. When faces are non-numeric strings, the roll result contains string values rather than numbers.

Custom faces dice do not support inline notation modifiers -- use the options object form for modified custom dice rolls.

**Use cases:** Custom damage type dice (fire/ice/lightning), narrative dice (success/failure/complication), weighted probability dice, or any die with non-standard faces.

## Arithmetic

Add or subtract a fixed value from the total.

| Notation | Description |
|---|---|
| `+N` | Add N to total |
| `-N` | Subtract N from total |

<NotationRoller defaultNotation="4d6+2" client:only="react" />
<NotationRoller defaultNotation="4d6-1" client:only="react" />

## Drop

Remove dice from the result pool.

| Notation | Description |
|---|---|
| `L` | Drop lowest 1 |
| `L2` | Drop lowest 2 |
| `H` | Drop highest 1 |
| `H2` | Drop highest 2 |
| `D{>N}` | Drop rolls over N |
| `D{>=N}` | Drop rolls at or over N |
| `D{<N}` | Drop rolls under N |
| `D{<=N}` | Drop rolls at or under N |
| `D{X,Y}` | Drop exact values X and Y |

<NotationRoller defaultNotation="4d6L" client:only="react" />
<NotationRoller defaultNotation="4d6H2" client:only="react" />
<NotationRoller defaultNotation="4d20D{>17}" client:only="react" />
<NotationRoller defaultNotation="4d20D{<5}" client:only="react" />
<NotationRoller defaultNotation="4d20D{8,12}" client:only="react" />

## Keep

Keep specific dice from the result (complement of drop).

| Notation | Description |
|---|---|
| `K` | Keep highest 1 |
| `K3` | Keep highest 3 |
| `kl` | Keep lowest 1 |
| `kl2` | Keep lowest 2 |

<NotationRoller defaultNotation="4d6K3" client:only="react" />
<NotationRoller defaultNotation="4d6kl2" client:only="react" />
<NotationRoller defaultNotation="2d20K" client:only="react" />
<NotationRoller defaultNotation="2d20kl" client:only="react" />

:::note
Keeping N highest is equivalent to dropping (quantity - N) lowest. For example, `4d6K3` is the same as `4d6L`.
:::

## Cap

Limit roll values to a specific range.

| Notation | Description |
|---|---|
| `C{>N}` | Cap rolls over N to N |
| `C{<N}` | Cap rolls under N to N |
| `C{<N,>M}` | Cap both ends |

<NotationRoller defaultNotation="4d20C{>18}" client:only="react" />
<NotationRoller defaultNotation="4d20C{<3}" client:only="react" />
<NotationRoller defaultNotation="4d20C{<2,>19}" client:only="react" />

## Reroll

Reroll dice matching certain conditions.

| Notation | Description |
|---|---|
| `R{>N}` | Reroll results over N |
| `R{>=N}` | Reroll results at or over N |
| `R{<N}` | Reroll results under N |
| `R{<=N}` | Reroll results at or under N |
| `R{X,Y}` | Reroll exact values X, Y |
| `R{<N}M` | Reroll under N, max M attempts |

<NotationRoller defaultNotation="4d20R{>17}" client:only="react" />
<NotationRoller defaultNotation="4d20R{<5}" client:only="react" />
<NotationRoller defaultNotation="4d20R{8,12}" client:only="react" />
<NotationRoller defaultNotation="4d20R{<5}3" client:only="react" />

## Replace

Replace specific results with new values.

| Notation | Description |
|---|---|
| `V{X=Y}` | Replace Xs with Y |
| `V{>N=Y}` | Replace results over N with Y |
| `V{<N=Y}` | Replace results under N with Y |

<NotationRoller defaultNotation="4d20V{8=12}" client:only="react" />
<NotationRoller defaultNotation="4d20V{>17=20}" client:only="react" />
<NotationRoller defaultNotation="4d20V{<5=1}" client:only="react" />

## Unique

Force all dice in a pool to show different values.

| Notation | Description |
|---|---|
| `U` | All results must be unique |
| `U{X,Y}` | Unique except X and Y can repeat |

<NotationRoller defaultNotation="4d20U" client:only="react" />
<NotationRoller defaultNotation="4d20U{5,10}" client:only="react" />

## Explode

Roll additional dice when a die shows its maximum value.

| Notation | Description |
|---|---|
| `!` | Explode: one additional die per max result (single pass) |

<NotationRoller defaultNotation="4d20!" client:only="react" />

When a die shows its maximum value, it "explodes" — one new die is rolled and added to the result. This is a single pass: the newly added dice are not checked for further explosions. For recursive explosions, use compound (`!!`) or penetrate (`!p`).

**Example:** `3d6!` rolls `[6, 4, 6]`. The two 6s explode, adding `[5, 3]`. Final result: `[6, 4, 6, 5, 3]` = 24.

## Compound

Exploding dice that add to the triggering die instead of creating new dice.

| Notation | Description |
|---|---|
| `!!` | Compound once per die |
| `!!N` | Compound with max depth N |
| `!!0` | Compound unlimited (capped at 1000) |

<NotationRoller defaultNotation="3d6!!" client:only="react" />
<NotationRoller defaultNotation="3d6!!5" client:only="react" />

**Example:** `1d6!!` rolls 6. This compounds, rolling 4. The die value becomes 6 + 4 = 10. Unlike regular exploding, this does not create new dice -- it modifies the existing die.

**Difference from explode:**
- **Explode (`!`)**: Creates new dice -- `[6, 4, 6]` becomes `[6, 4, 6, 5, 3]` (5 dice)
- **Compound (`!!`)**: Modifies existing die -- `[6, 4, 6]` becomes `[15, 4, 12]` (still 3 dice)

## Penetrate

Exploding dice where each subsequent explosion subtracts 1 (Hackmaster-style).

| Notation | Description |
|---|---|
| `!p` | Penetrate once per die |
| `!pN` | Penetrate with max depth N |
| `!p0` | Penetrate unlimited (capped at 1000) |

<NotationRoller defaultNotation="3d6!p" client:only="react" />
<NotationRoller defaultNotation="3d6!p5" client:only="react" />

**Example:** `1d6!p` rolls 6. This penetrates, rolling 5. The value added is 5 - 1 = 4, so the die becomes 6 + 4 = 10.

## Wild Die

The D6 System wild die modifier (West End Games). The last die in the pool is designated as the "wild die" with special behavior. All notation is **case-insensitive**.

| Notation | Description |
|---|---|
| `W` | Last die is the "wild die" |

<NotationRoller defaultNotation="5d6W" client:only="react" />

**Wild die behavior:**

- **Wild die = max value (6):** The wild die compound-explodes -- keep rolling and adding while the maximum is rolled.
- **Wild die = 1:** Remove the wild die AND the highest non-wild die from the pool.
- **Otherwise:** No special effect, the wild die acts as a normal die.

**Example:** `5d6W` rolls [4, 3, 5, 2, 6]. The wild die (6) compound-explodes: rolls 4, so wild die becomes 10. Result: [4, 3, 5, 2, 10] = 24.

**Example (wild 1):** `5d6W` rolls [4, 3, 5, 2, 1]. The wild die (1) triggers removal: remove the 1 (wild) and the 5 (highest non-wild). Result: [4, 3, 2] = 9.

## Pre-Arithmetic Multiply

Multiply the dice sum before adding/subtracting arithmetic modifiers.

| Notation | Description |
|---|---|
| `*N` | Multiply dice sum by N |

<NotationRoller defaultNotation="2d6*2+3" client:only="react" />
<NotationRoller defaultNotation="4d6*3" client:only="react" />

**Example:** `2d6*2+3` rolls `[4, 5]` = 9. Multiplied by 2 = 18. Plus 3 = 21.

## Count successes

Count dice meeting a threshold instead of summing values. Used in dice pool systems.

| Notation | Description |
|---|---|
| `S{N}` | Count dice >= N |
| `S{N,B}` | Count successes >= N, subtract botches &lt;= B |

<NotationRoller defaultNotation="5d10S{7}" client:only="react" />
<NotationRoller defaultNotation="5d10S{7,1}" client:only="react" />

**Example:** `5d10S{7}` rolls `[8, 3, 10, 6, 9]`. Successes >= 7: `[8, 10, 9]` = 3 successes.

## Count failures

Count how many dice rolled at or below a threshold. The total becomes the failure count. All notation is **case-insensitive**.

| Notation | Description |
|---|---|
| `F{N}` | Count dice that rolled &lt;= N |

<NotationRoller defaultNotation="5d10F{3}" client:only="react" />

:::note
`F` requires curly braces (`F{N}`) to avoid conflict with Fate dice notation (`dF`).
:::

**Example:** `5d10F{3}` rolls [8, 2, 10, 1, 9]. Failures &lt;= 3: [2, 1] = 2 failures.

## Sort

Sort dice results for display purposes without changing the total. All notation is **case-insensitive**.

| Notation | Description |
|---|---|
| `sa` | Sort ascending |
| `sd` | Sort descending |

<NotationRoller defaultNotation="4d6sa" client:only="react" />
<NotationRoller defaultNotation="4d6sd" client:only="react" />

Sort reorders the dice results for display without changing the total. Useful for readability when reviewing large pools.

## Integer divide

Integer divide the total, truncating toward zero. All notation is **case-insensitive**.

| Notation | Description |
|---|---|
| `//N` | Integer divide total by N (truncates via `Math.trunc`) |

<NotationRoller defaultNotation="4d6//2" client:only="react" />

**Example:** `4d6//2` rolls [3, 5, 4, 2] = 14. Integer divided by 2 = 7.

**Use cases:** Halving damage (e.g., resistance in D&D), averaging mechanics, systems that use integer math for resource calculation.

## Modulo

Apply modulo to the total. All notation is **case-insensitive**.

| Notation | Description |
|---|---|
| `%N` | Total modulo N |

<NotationRoller defaultNotation="4d6%3" client:only="react" />

**Example:** `4d6%3` rolls [3, 5, 4, 2] = 14. 14 % 3 = 2.

**Use cases:** Wrapping values into ranges, clock mechanics, cyclic resource systems.

## Total Multiply

Multiply the entire final total after all other modifiers.

| Notation | Description |
|---|---|
| `**N` | Multiply final total by N |

<NotationRoller defaultNotation="2d6+3**2" client:only="react" />
<NotationRoller defaultNotation="4d6L+2**3" client:only="react" />

**Difference from pre-arithmetic multiplier:**
- **Pre-arithmetic (`*`)**: `2d6*2+3` = (sum x 2) + 3
- **Total (`**`)**: `2d6+3**2` = (sum + 3) x 2

## Repeat operator

Notation sugar that repeats a roll expression N times. All notation is **case-insensitive**.

| Notation | Description |
|---|---|
| `xN` | Repeat the preceding notation N times |

<NotationRoller defaultNotation="4d6Lx6" client:only="react" />

The `xN` suffix is detected during notation parsing. It strips the suffix, then repeats the base notation N times as separate roll groups. N must be >= 1.

**Example:** `4d6Lx6` expands to six separate `4d6L` rolls -- perfect for generating all six D&D ability scores in a single call.

**Use cases:** D&D ability score generation (`4d6Lx6`), rolling multiple identical damage dice groups, batch stat generation.

## Annotations

Attach metadata labels to dice terms. Labels are flavor text with no mechanical effect. All notation is **case-insensitive**.

| Notation | Description |
|---|---|
| `[text]` | Label attached to a roll group |
| `2d6+3[fire]+1d4[cold]` | Labels on specific dice groups |

<NotationRoller defaultNotation="2d6+3[fire]" client:only="react" />

Labels are enclosed in square brackets and attached to the preceding dice term. They are stripped before modifier parsing and stored in the roll result. Labels are valid notation -- `isDiceNotation` accepts notation with labels.

**Use cases:** Tracking damage types in D&D, labeling ability score rolls, annotating complex multi-group rolls for display purposes.

## Combining modifiers

Modifiers can be chained together. They are applied in a fixed priority order:

| Priority | Modifier | Notation | Description |
|---|---|---|---|
| 10 | Cap | `C{...}` | Limit roll values to a range |
| 30 | Replace | `V{...}` | Replace specific values |
| 40 | Reroll | `R{...}` | Reroll dice matching conditions |
| 50 | Explode | `!` | Roll additional dice on max |
| 51 | Compound | `!!` | Add explosion to existing die |
| 52 | Penetrate | `!p` | Add explosion minus 1 to die |
| 60 | Unique | `U` | Ensure no duplicate values |
| 65 | Drop | `H`, `L` | Remove dice from pool |
| 66 | Keep | `K`, `kl` | Keep dice in pool |
| 70 | Explode Sequence | `!s{...}`, `!i`, `!r` | Explode through die size sequence |
| 75 | Wild Die | `W` | D6 System wild die behavior |
| 80 | Count Successes | `S{...}` | Count dice meeting threshold |
| 80 | Count Failures | `F{...}` | Count dice at or below threshold |
| 95 | Sort | `sa`/`sd` | Sort results for display |
| 100 | Multiply | `*N` | Multiply dice sum (pre-arithmetic) |
| 110 | Plus | `+N` | Add to total |
| 111 | Minus | `-N` | Subtract from total |
| 120 | Integer Divide | `//N` | Integer divide total |
| 130 | Modulo | `%N` | Total modulo N |
| 150 | Total Multiply | `**N` | Multiply entire final total |

<NotationRoller defaultNotation="4d6R{<3}L" client:only="react" />
<NotationRoller defaultNotation="4d6L+2" client:only="react" />
<NotationRoller defaultNotation="3d6!!*2+3" client:only="react" />
<NotationRoller defaultNotation="4d6K3!+2" client:only="react" />

## Multiple groups

Roll different dice types in a single expression:

<CodeExample code={`// Attack roll + damage
roll('1d20+5', '2d6+3')

// Subtract a die group
roll('2d12-1d6') // Roll 2d12, subtract 1d6`} />

## Common use cases

### D&D 5e ability scores
<NotationRoller defaultNotation="4d6K3" client:only="react" />
<NotationRoller defaultNotation="4d6L" client:only="react" />

### D&D 5e advantage/disadvantage
<NotationRoller defaultNotation="2d20K" client:only="react" />
<NotationRoller defaultNotation="2d20kl" client:only="react" />

### Critical hits (double base damage)
<NotationRoller defaultNotation="2d6+3*2" client:only="react" />
<NotationRoller defaultNotation="2d6+3**2" client:only="react" />

### Hackmaster penetrating dice
<NotationRoller defaultNotation="1d6!p" client:only="react" />
<NotationRoller defaultNotation="2d6!p+3" client:only="react" />

### World of Darkness / Shadowrun dice pools
<NotationRoller defaultNotation="5d10S{7}" client:only="react" />
<NotationRoller defaultNotation="5d10S{7,1}" client:only="react" />