A powerful dice notation parser that supports:
- 🎲 Standard dice notation parsing (
4d6
,2d20H
, etc.) - 🎯 Complex modifier validation
- 🔒 Full TypeScript support
- 📝 Human-readable descriptions
- 🪶 Tree-shakeable implementation
npm install @randsum/notation
# or
yarn add @randsum/notation
# or
bun add @randsum/notation
import {
validateNotation,
isDiceNotation,
notationToOptions,
type DiceNotation
} from '@randsum/notation'
const result = validateNotation('4d6L')
if (result.valid) {
console.log(result.description) // ["Roll 4 six-sided dice", "Drop lowest roll"]
}
isDiceNotation('2d20') // true
isDiceNotation('invalid') // false
const options = notationToOptions('4d6R{<3}')
console.log(options)
// {
// sides: 6,
// quantity: 4,
// modifiers: {
// reroll: { lessThan: 3 }
// }
// }
// Type inference examples
const validNotation: DiceNotation = '4d6L' // ✅ Valid
const invalidNotation: DiceNotation = 'invalid' // ❌ Type error
// TypeScript will infer these as valid DiceNotation
const examples = {
basic: '2d20',
withModifier: '4d6L',
withArithmetic: '2d8+3',
withReroll: '4d6R{<3}',
withCustomFaces: '2d{HT}',
complex: '4d6L!R{<3}+2'
} satisfies Record<string, DiceNotation>
// Function parameters are type-checked
function rollDice(notation: DiceNotation) {
const result = validateNotation(notation)
return result
}
rollDice('2d20') // ✅ Valid
rollDice('invalid') // ❌ Type error
// Type inference in arrays
const notations: DiceNotation[] = [
'2d20', // ✅ Valid
'4d6L', // ✅ Valid
'3d8!', // ✅ Valid
'2d{HT}' // ✅ Valid
// 'invalid' // ❌ Would cause type error
]
// Usage with template literals
function createAttackRoll(bonus: number): DiceNotation {
return `1d20+${bonus}` // ✅ Valid DiceNotation
}
// Regular usage examples
const result = validateNotation('4d6L')
if (result.valid) {
console.log(result.description) // ["Roll 4 six-sided dice", "Drop lowest roll"]
}
isDiceNotation('2d20') // true
isDiceNotation('invalid') // false
const options = notationToOptions('4d6R{<3}')
console.log(options)
// {
// sides: 6,
// quantity: 4,
// modifiers: {
// reroll: { lessThan: 3 }
// }
// } satisfies Record<string, DiceNotation>
// Function parameters are type-checked
function rollDice(notation: DiceNotation) {
const result = validateNotation(notation)
return result
}
rollDice('2d20') // ✅ Valid
rollDice('invalid') // ❌ Type error
// Type inference in arrays
const notations: DiceNotation[] = [
'2d20', // ✅ Valid
'4d6L', // ✅ Valid
'3d8!', // ✅ Valid
'2d{HT}' // ✅ Valid
// 'invalid' // ❌ Would cause type error
]
// Usage with template literals
function createAttackRoll(bonus: number): DiceNotation {
return `1d20+${bonus}` // ✅ Valid DiceNotation
}
-
NdS
: Roll N S-sided dice (e.g.,4d6
) -
NdS+X
: Add X to total (e.g.,2d8+3
) -
NdS-X
: Subtract X from total (e.g.,2d8-1
)
-
L
: Drop lowest (e.g.,4d6L
) -
H
: Keep highest (e.g.,2d20H
) -
R{<N}
: Reroll below N (e.g.,4d6R{<3}
) -
!
: Exploding dice (e.g.,3d8!
) -
U
: Unique results (e.g.,3d6U
)
See Dice Notation Reference for complete documentation.
const result = validateNotation('4d6L')
// Returns:
// {
// valid: true,
// type: 'numeric',
// description: ['Roll 4 six-sided dice', 'Drop lowest roll'],
// notation: { quantity: 4, sides: 6, modifiers: { drop: { lowest: 1 } } }
// }
isDiceNotation('2d20') // true
isDiceNotation('2d{HT}') // true (custom faces)
isDiceNotation('invalid') // false
notationToOptions('4d6L')
// Returns options object compatible with @randsum/dice
- @randsum/dice: Dice rolling implementation
- @randsum/5e: 5th Edition compatible dice rolling
Made with 👹 by RANDSUM