Skip to content

Recipes

Short solutions to common dice-rolling problems.

Produce the same result every time — useful for replays, testing, or deterministic outcomes.

import { roll } from '@randsum/roller'
// Simple seeded random (linear congruential generator)
function seededRandom(seed: number) {
let s = seed
return () => {
s = (s * 1664525 + 1013904223) >>> 0
return s / 0x100000000
}
}
const result = roll('4d6L', { randomFn: seededRandom(42) })
// Same result every time with seed 42

Pass multiple arguments to roll() — they are combined into a single total.

import { roll } from '@randsum/roller'
// Attack roll + damage roll
const result = roll('1d20+5', '2d6+3')
console.log(result.total) // d20+5 + 2d6+3, combined
// Mix numbers, strings, and options objects
const combined = roll(20, '2d6', { sides: 8, quantity: 1 })

The drop modifier works on any die type — not just d20.

import { roll } from '@randsum/roller'
// Advantage on a d12 (Daggerheart-style)
roll({ sides: 12, quantity: 2, modifiers: { drop: { lowest: 1 } } })
// Disadvantage on 2d6
roll({ sides: 6, quantity: 2, modifiers: { drop: { highest: 1 } } })
// Advantage shorthand via notation
roll('2d12H') // Roll 2d12, drop highest (disadvantage)
roll('2d12L') // Roll 2d12, drop lowest (advantage)

Use the arithmetic: 'subtract' option on a roll group.

import { roll } from '@randsum/roller'
// 2d12 minus 1d6
const result = roll(
{ sides: 12, quantity: 2 },
{ sides: 6, quantity: 1, arithmetic: 'subtract' }
)

Pass an array of strings or values as sides for dice with custom faces (Fate/Fudge dice, custom results).

import { roll } from '@randsum/roller'
// Fate dice: 4dF (−, ·, +)
const fate = roll({
sides: ['+', '+', ' ', ' ', '-', '-'],
quantity: 4
})
console.log(fate.result) // e.g. ['+', '-', ' ', '+']

Roll several times and collect only the results you want.

import { roll } from '@randsum/roller'
// Roll 10d6, keep only 6s (counting successes manually)
const results = Array.from({ length: 10 }, () => roll(6).total)
const successes = results.filter(r => r === 6).length

Or use the countSuccesses modifier to do it in one call:

import { roll } from '@randsum/roller'
const result = roll({
sides: 6,
quantity: 10,
modifiers: { countSuccesses: { threshold: 4 } }
})
console.log(result.total) // Count of dice >= 4

Roll many times and count how often each total appears.

import { roll } from '@randsum/roller'
const histogram: Record<number, number> = {}
for (let i = 0; i < 10000; i++) {
const { total } = roll('2d6')
histogram[total] = (histogram[total] ?? 0) + 1
}
console.log(histogram)
// { '2': ~278, '7': ~1667, '12': ~278, ... }

Replace Math.random with crypto.getRandomValues for better entropy.

import { roll } from '@randsum/roller'
const cryptoRandom = (): number =>
crypto.getRandomValues(new Uint32Array(1))[0] / 2 ** 32
const result = roll('2d6', { randomFn: cryptoRandom })