Recipes
Short solutions to common dice-rolling problems.
Seeded rolls
Section titled “Seeded rolls”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 42Combining multiple rolls into one total
Section titled “Combining multiple rolls into one total”Pass multiple arguments to roll() — they are combined into a single total.
import { roll } from '@randsum/roller'
// Attack roll + damage rollconst result = roll('1d20+5', '2d6+3')console.log(result.total) // d20+5 + 2d6+3, combined
// Mix numbers, strings, and options objectsconst combined = roll(20, '2d6', { sides: 8, quantity: 1 })Advantage with arbitrary dice
Section titled “Advantage with arbitrary dice”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 2d6roll({ sides: 6, quantity: 2, modifiers: { drop: { highest: 1 } } })
// Advantage shorthand via notationroll('2d12H') // Roll 2d12, drop highest (disadvantage)roll('2d12L') // Roll 2d12, drop lowest (advantage)Subtracting one roll from another
Section titled “Subtracting one roll from another”Use the arithmetic: 'subtract' option on a roll group.
import { roll } from '@randsum/roller'
// 2d12 minus 1d6const result = roll( { sides: 12, quantity: 2 }, { sides: 6, quantity: 1, arithmetic: 'subtract' })Custom faces (non-numeric dice)
Section titled “Custom faces (non-numeric dice)”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. ['+', '-', ' ', '+']Rolling and filtering results
Section titled “Rolling and filtering results”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).lengthOr 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 >= 4Generating a roll histogram
Section titled “Generating a roll histogram”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, ... }Using a crypto-quality random function
Section titled “Using a crypto-quality random function”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 })