Dice Roller - Elegant TypeScript Dice Rolling Library
A sophisticated TypeScript dice rolling library for tabletop RPGs, games, and any application requiring elegant dice mechanics.
Features
- Simple dice rolling (d4, d6, d8, d10, d12, d20, d100)
- Complex dice expressions (e.g., "3d6+5", "2d8-1d4+3")
- Custom dice with user-defined values for each side (numeric and non-numeric)
- Non-numeric dice support for text, symbols, and mixed content
- Fibonacci dice for Scrum planning and estimation
- Weighted dice for non-uniform probability distributions
- Text-based dice (Yes/No, Magic 8-Ball, etc.)
- Advanced rolling mechanics:
- Advantage/Disadvantage
- Keep highest/lowest N dice
- Exploding dice
- Custom random functions
- Statistical analysis of dice expressions and custom dice
- Comprehensive test suite with 100% coverage
- TypeScript support with full type definitions
Try It Now with npx
No installation required! Try the dice roller immediately:
npx @risadams/dice-roller "3d6+5"
npx @risadams/dice-roller roll d20
npx @risadams/dice-roller "2d8+1d4-2"
npx @risadams/dice-roller advantage d20
npx @risadams/dice-roller disadvantage d20
npx @risadams/dice-roller exploding 3d6
npx @risadams/dice-roller demo
npx @risadams/dice-roller stats "3d6"
npx @risadams/dice-roller help
Installation
npm install @risadams/dice-roller
Quick Start
import { Roller, CustomDie, DicePresets } from '@risadams/dice-roller';
const roller = new Roller();
const d20Roll = roller.rollDie(20);
const damage = roller.rollSum(3, 6);
const attack = roller.rollExpression('1d20+5');
const fireball = roller.rollExpression('8d6');
const customDie = new CustomDie([2, 4, 6, 8, 10]);
const customRolls = roller.rollCustomDice(customDie, 3);
const fibDie = DicePresets.createFibonacciDie(8);
const storyPoints = fibDie.roll();
const scrumDie = DicePresets.createScrumPlanningDie();
const estimate = scrumDie.roll();
const coinDie = DicePresets.createCoinDie();
const coinFlip = coinDie.roll();
const magic8Ball = DicePresets.createMagic8BallDie();
const answer = magic8Ball.roll();
const lootDie = DicePresets.createWeightedDie([
{ value: 'Common', weight: 5 },
{ value: 'Rare', weight: 1 }
]);
const advantageRoll = roller.rollWithAdvantage(20);
const abilityScores = roller.rollKeepHighest(4, 6, 3);
API Reference
Roller Class
Basic Rolling
rollDie(sides: number): number - Roll a single die
rollDice(count: number, sides: number): number[] - Roll multiple dice
rollSum(count: number, sides: number): number - Roll and sum multiple dice
Expression Rolling
rollExpression(expression: string): number - Evaluate dice expression
rollExpressionDetailed(expression: string) - Get detailed results
Advanced Rolling
rollWithAdvantage(sides: number) - Roll twice, take higher
rollWithDisadvantage(sides: number) - Roll twice, take lower
rollKeepHighest(count: number, sides: number, keep: number) - Drop lowest dice
rollKeepLowest(count: number, sides: number, keep: number) - Drop highest dice
rollExploding(count: number, sides: number, maxExplosions?: number) - Reroll on max
Utilities
rollStandard() - Roll standard RPG dice set
getStatistics(expression: string, samples: number) - Generate statistics
rollCustomDice(customDie: CustomDie, count: number) - Roll custom dice
rollCustomDiceSum(customDie: CustomDie, count: number) - Sum custom dice rolls
getCustomDieStatistics(customDie: CustomDie, samples: number) - Analyze custom dice
compareCustomDice(die1: CustomDie, die2: CustomDie, samples: number) - Compare dice
CustomDie Class
import { CustomDie } from '@risadams/dice-roller';
const customDie = new CustomDie([1, 3, 5, 7, 9]);
console.log(customDie.roll());
console.log(customDie.getExpectedValue());
console.log(customDie.getProbability(5));
DicePresets Class
import { DicePresets } from '@risadams/dice-roller';
const fibDie = DicePresets.createFibonacciDie(8);
const scrumDie = DicePresets.createScrumPlanningDie();
const arithDie = DicePresets.createArithmeticDie(5, 3, 4);
const weightedDie = DicePresets.createWeightedDie([
{ value: 1, weight: 1 },
{ value: 2, weight: 2 },
{ value: 3, weight: 3 }
]);
DiceExpression Class
import { DiceExpression } from '@risadams/dice-roller';
const expr = new DiceExpression('3d6+5');
console.log(expr.evaluate());
console.log(expr.getMinValue());
console.log(expr.getMaxValue());
console.log(expr.toString());
Die Class
import { Die } from '@risadams/dice-roller';
const d6 = new Die(6);
console.log(d6.roll());
console.log(d6.rollMultiple(3));
Supported Dice Expressions
The library supports mathematical expressions with dice notation:
- Basic notation:
d6, 3d6, 1d20
- Arithmetic:
3d6+5, 2d8-2, 1d4*2, 10d6/2
- Complex expressions:
2d20+1d6+3, 4d6+2d8-1d4
Examples
Character Creation (D&D 5e)
const roller = new Roller();
const strength = roller.rollKeepHighest(4, 6, 3);
console.log(`Strength: ${strength.result} (${strength.kept.join('+')}, dropped: ${strength.dropped})`);
const attack = roller.rollWithAdvantage(20);
console.log(`Attack: ${attack.result} (rolled: ${attack.rolls})`);
Damage Calculation
const roller = new Roller();
const swordDamage = roller.rollExpression('1d8+3');
const criticalHit = roller.rollExpression('2d8+3');
const fireball = roller.rollExpression('8d6');
const healingPotion = roller.rollExpression('2d4+2');
Custom Dice for Scrum Planning
const roller = new Roller();
const fibDie = DicePresets.createFibonacciDie(8);
console.log(`Story points: ${fibDie.roll()}`);
const scrumDie = DicePresets.createScrumPlanningDie();
const estimate = scrumDie.roll();
console.log(`Estimate: ${estimate}`);
const stats = roller.getCustomDieStatistics(fibDie, 1000);
if (stats.expectedValue !== null) {
console.log(`Average story points: ${stats.expectedValue.toFixed(1)}`);
}
Text-Based Dice
const roller = new Roller();
const yesNoDie = DicePresets.createTextDie(['Yes', 'No', 'Maybe']);
console.log(`Decision: ${yesNoDie.roll()}`);
const magic8Ball = DicePresets.createMagic8BallDie();
console.log(`Magic 8-Ball says: "${magic8Ball.roll()}"`);
const coinDie = DicePresets.createCoinDie();
console.log(`Coin flip: ${coinDie.roll()}`);
const lootDie = DicePresets.createWeightedDie([
{ value: 'Common', weight: 5 },
{ value: 'Uncommon', weight: 3 },
{ value: 'Rare', weight: 2 },
{ value: 'Legendary', weight: 1 }
]);
console.log(`Loot rarity: ${lootDie.roll()}`);
Mixed Numeric and Non-Numeric Dice
const mixedDie = new CustomDie([1, 2, 'Skip', 4, 'Double']);
console.log(`Roll result: ${mixedDie.roll()}`);
const scrumDie = DicePresets.createScrumPlanningDie();
const estimate = scrumDie.roll();
console.log(`Story points: ${estimate}`);
const stats = roller.getCustomDieStatistics(scrumDie, 1000);
console.log(`Has numeric values: ${stats.hasNumericValues}`);
console.log(`Has non-numeric values: ${stats.hasNonNumericValues}`);
if (stats.expectedValue !== null) {
console.log(`Expected value of numeric faces: ${stats.expectedValue}`);
}
Statistics and Analysis
const roller = new Roller();
const stats = roller.getStatistics('1d8+3', 1000);
console.log(`Average damage: ${stats.mean.toFixed(1)}`);
console.log(`Range: ${stats.min}-${stats.max}`);
console.log(`Standard deviation: ${stats.standardDeviation.toFixed(2)}`);
const customDie = new CustomDie([2, 4, 6, 8, 10]);
const customStats = roller.getCustomDieStatistics(customDie, 1000);
if (customStats.expectedValue !== null && customStats.mean !== null) {
console.log(`Expected value: ${customStats.expectedValue}`);
console.log(`Theoretical vs actual mean: ${customStats.expectedValue} vs ${customStats.mean.toFixed(2)}`);
}
const mixedDie = new CustomDie([1, 'A', 2, 'B']);
const mixedStats = roller.getCustomDieStatistics(mixedDie, 1000);
console.log(`Has numeric values: ${mixedStats.hasNumericValues}`);
console.log(`Has non-numeric values: ${mixedStats.hasNonNumericValues}`);
Custom Random Function
import { Roller } from 'roller';
const seededRandom = () => 0.5;
const roller = new Roller(seededRandom);
console.log(roller.rollDie(6));
Development
Building
npm run build
Testing
npm test
npm run test:watch
npm run test:coverage
Demo
npm run demo
TypeScript Support
This library is written in TypeScript and includes full type definitions. All classes and methods are properly typed for excellent IDE support and compile-time error checking.
License
MIT - see the LICENSE file for details.
Contributing
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
Changelog
1.1.1
- NEW: CLI support for Scrum planning dice (
npx @risadams/dice-roller scrum)
- NEW: CLI support for Fibonacci dice (
npx @risadams/dice-roller fibonacci)
- PERFORMANCE: Optimized custom dice value processing with single-pass algorithms
- PERFORMANCE: Improved statistics calculation performance for large datasets
- Enhanced CLI help documentation with custom dice examples
1.1.0
- NEW: Custom dice with user-defined values for each side
- NEW: Non-numeric dice support - dice can now have text, symbols, or mixed content
- NEW:
CustomDie<T> class with TypeScript generics for type-safe custom dice
- NEW:
DicePresets with factory methods for common custom dice patterns:
- Fibonacci sequence dice (perfect for Scrum planning)
- Scrum planning poker dice with actual "?" character
- Text-based dice (Yes/No, Magic 8-Ball, coin flip, etc.)
- Arithmetic and geometric progression dice
- Weighted dice supporting both numeric and text values
- NEW: Enhanced statistics methods that gracefully handle mixed numeric/non-numeric dice
- NEW: Dice comparison functionality supporting different value types
- NEW: Type detection methods (
hasNumericValues(), hasNonNumericValues())
- ENHANCED:
Roller class now supports custom dice operations with full type safety
- ENHANCED: Fair rolling ensures all custom dice maintain proper probability distributions
- ENHANCED: Statistics analysis separates numeric and non-numeric data appropriately
1.0.0
- Initial release of TypeScript dice rolling library
- Complete API with Die, DiceExpression, DiceExpressionPart, and Roller classes
- Advanced rolling mechanics (advantage/disadvantage, exploding dice, keep highest/lowest)
- CLI interface with npx support
- Comprehensive test suite with Jest
- Statistical analysis capabilities
- Full TypeScript support with type definitions