Skip to content

Dice Notation

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

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

import { roll } from '@randsum/roller'
// Roll one d20
roll('1d20')
// Roll four d6
roll('4d6')
// Roll two d12
roll('2d12')

You can also pass a number directly to roll a single die:

roll(20) // same as roll('1d20')

Add or subtract a fixed value from the total.

NotationDescription
+NAdd N to total
-NSubtract N from total
roll('4d6+2') // Add 2 to total
roll('4d6-1') // Subtract 1 from total

Remove dice from the result pool.

NotationDescription
LDrop lowest 1
L2Drop lowest 2
HDrop highest 1
H2Drop highest 2
D{>N}Drop rolls over N
D{<N}Drop rolls under N
D{X,Y}Drop exact values X and Y
// D&D ability score: 4d6 drop lowest
roll('4d6L')
// Drop 2 highest
roll('4d6H2')
// Drop by value
roll('4d20D{>17}') // Drop rolls over 17
roll('4d20D{<5}') // Drop rolls under 5
roll('4d20D{8,12}') // Drop 8s and 12s

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

NotationDescription
KKeep highest 1
K3Keep highest 3
klKeep lowest 1
kl2Keep lowest 2
// Keep highest 3 of 4d6 (equivalent to 4d6L)
roll('4d6K3')
// Keep lowest 2
roll('4d6kl2')
// Advantage: keep highest d20
roll('2d20K')
// Disadvantage: keep lowest d20
roll('2d20kl')

Limit roll values to a specific range.

NotationDescription
C{>N}Cap rolls over N to N
C{<N}Cap rolls under N to N
C{<N,>M}Cap both ends
roll('4d20C{>18}') // Cap rolls over 18 to 18
roll('4d20C{<3}') // Cap rolls under 3 to 3
roll('4d20C{<2,>19}') // Cap both ends

Reroll dice matching certain conditions.

NotationDescription
R{>N}Reroll results over N
R{<N}Reroll results under N
R{X,Y}Reroll exact values X, Y
R{<N}MReroll under N, max M attempts
roll('4d20R{>17}') // Reroll results over 17
roll('4d20R{<5}') // Reroll results under 5
roll('4d20R{8,12}') // Reroll 8s and 12s
roll('4d20R{<5}3') // Reroll under 5, max 3 attempts

Replace specific results with new values.

NotationDescription
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
roll('4d20V{8=12}') // Replace 8s with 12s
roll('4d20V{>17=20}') // Replace results over 17 with 20
roll('4d20V{<5=1}') // Replace results under 5 with 1

Force all dice in a pool to show different values.

NotationDescription
UAll results must be unique
U{X,Y}Unique except X and Y can repeat
roll('4d20U') // All results must be unique
roll('4d20U{5,10}') // Unique except 5s and 10s can repeat

Roll additional dice when a die shows its maximum value.

NotationDescription
!Explode once per die
!NExplode with max depth N
!0Explode unlimited (capped at 100)
roll('4d20!') // Roll extra d20 for each 20
roll('3d6!5') // Explode with max depth of 5
roll('3d6!0') // Explode unlimited (capped at 100)

When a die shows its maximum value, it “explodes” — a new die is rolled and added to the result. This continues for each new maximum value rolled.

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

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

NotationDescription
!!Compound once per die
!!NCompound with max depth N
!!0Compound unlimited (capped at 100)
roll('3d6!!') // Compound explode
roll('3d6!!5') // Compound with max depth of 5

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)

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

NotationDescription
!pPenetrate once per die
!pNPenetrate with max depth N
!p0Penetrate unlimited (capped at 100)
roll('3d6!p') // Penetrate explode
roll('3d6!p5') // Penetrate with max depth of 5

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

Multiply the dice sum before adding/subtracting arithmetic modifiers.

NotationDescription
*NMultiply dice sum by N
roll('2d6*2+3') // (dice sum * 2) + 3
roll('4d6*3') // Multiply dice sum by 3

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

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

NotationDescription
S{N}Count dice >= N
S{N,B}Count successes >= N, subtract botches <= B
roll('5d10S{7}') // Count how many dice rolled >= 7
roll('5d10S{7,1}') // Count successes >= 7, subtract botches <= 1

Example: 5d10S&#123;7&#125; rolls [8, 3, 10, 6, 9]. Successes >= 7: [8, 10, 9] = 3 successes.

Multiply the entire final total after all other modifiers.

NotationDescription
**NMultiply final total by N
roll('2d6+3**2') // (dice + 3) * 2
roll('4d6L+2**3') // ((drop lowest) + 2) * 3

Difference from pre-arithmetic multiplier:

  • Pre-arithmetic (*): 2d6*2+3 = (sum x 2) + 3
  • Total (**): 2d6+3**2 = (sum + 3) x 2

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

PriorityModifierNotationDescription
10CapC{…}Limit roll values to a range
20DropH, LRemove dice from pool
21KeepK, klKeep dice in pool
30ReplaceV{…}Replace specific values
40RerollR{…}Reroll dice matching conditions
50Explode!Roll additional dice on max
51Compound!!Add explosion to existing die
52Penetrate!pAdd explosion minus 1 to die
60UniqueUEnsure no duplicate values
85Multiply*NMultiply dice sum (pre-arithmetic)
90Plus+NAdd to total
91Minus-NSubtract from total
95Count SuccessesS{…}Count dice meeting threshold
100Total Multiply**NMultiply entire final total
// Reroll under 3, then drop lowest
roll('4d6R{<3}L')
// Drop lowest, add 2
roll('4d6L+2')
// Compound explode, multiply by 2, add 3
roll('3d6!!*2+3')
// Keep highest 3, explode, add 2
roll('4d6K3!+2')

Roll different dice types in a single expression:

// Attack roll + damage
roll('1d20+5', '2d6+3')
// Subtract a die group
roll('2d12-1d6') // Roll 2d12, subtract 1d6
roll('4d6K3') // Roll 4d6, keep highest 3
roll('4d6L') // Equivalent: drop lowest 1
roll('2d20K') // Advantage: keep highest
roll('2d20kl') // Disadvantage: keep lowest
roll('2d6+3*2') // Double base dice, then add modifier
roll('2d6+3**2') // Double entire damage including modifier
roll('1d6!p') // Standard penetrate
roll('2d6!p+3') // Penetrate with modifier
roll('5d10S{7}') // Count successes >= 7
roll('5d10S{7,1}') // With botch counting