npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@risadams/dice-roller

v1.1.2

Published

Elegant TypeScript dice rolling library for tabletop RPGs, games, and applications requiring dice mechanics

Readme

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:

# Quick dice rolls
npx @risadams/dice-roller "3d6+5"
npx @risadams/dice-roller roll d20
npx @risadams/dice-roller "2d8+1d4-2"

# Custom dice
npx @risadams/dice-roller scrum        # Scrum planning
npx @risadams/dice-roller fibonacci    # Fibonacci sequence
npx @risadams/dice-roller coin         # Coin flip
npx @risadams/dice-roller magic8       # Magic 8-Ball
npx @risadams/dice-roller yesno        # Yes/No decision

# Verbose output (with details)
npx @risadams/dice-roller "3d6+5" --verbose
npx @risadams/dice-roller coin -v

# Advanced mechanics
npx @risadams/dice-roller advantage d20
npx @risadams/dice-roller disadvantage d20
npx @risadams/dice-roller exploding 3d6

# Interactive demo
npx @risadams/dice-roller demo

# Statistical analysis
npx @risadams/dice-roller stats "3d6"

# Get help
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();

// Basic rolling
const d20Roll = roller.rollDie(20);
const damage = roller.rollSum(3, 6); // 3d6 damage

// Expression rolling
const attack = roller.rollExpression('1d20+5');
const fireball = roller.rollExpression('8d6');

// Custom dice
const customDie = new CustomDie([2, 4, 6, 8, 10]);
const customRolls = roller.rollCustomDice(customDie, 3);

// Fibonacci die for Scrum planning
const fibDie = DicePresets.createFibonacciDie(8);
const storyPoints = fibDie.roll(); // Returns: 0, 1, 1, 2, 3, 5, 8, or 13

// Scrum planning with actual "?" character
const scrumDie = DicePresets.createScrumPlanningDie();
const estimate = scrumDie.roll(); // Returns: 1, 2, 3, 5, 8, 13, 20, or "?"

// Text-based dice
const coinDie = DicePresets.createCoinDie();
const coinFlip = coinDie.roll(); // Returns: "Heads" or "Tails"

const magic8Ball = DicePresets.createMagic8BallDie();
const answer = magic8Ball.roll(); // Returns various text responses

// Weighted dice
const lootDie = DicePresets.createWeightedDie([
  { value: 'Common', weight: 5 },
  { value: 'Rare', weight: 1 }
]); // Use lootDie.getProbability('Common') to get actual percentages

// Advanced mechanics
const advantageRoll = roller.rollWithAdvantage(20);
const abilityScores = roller.rollKeepHighest(4, 6, 3); // 4d6 drop lowest

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';

// Create a custom die with specific values
const customDie = new CustomDie([1, 3, 5, 7, 9]);
console.log(customDie.roll()); // Returns one of: 1, 3, 5, 7, 9
console.log(customDie.getExpectedValue()); // 5
console.log(customDie.getProbability(5)); // 0.2 (20%)

DicePresets Class

import { DicePresets } from '@risadams/dice-roller';

// Fibonacci sequence die (perfect for Scrum planning)
const fibDie = DicePresets.createFibonacciDie(8);
// Values: [0, 1, 1, 2, 3, 5, 8, 13]

// Standard Scrum planning poker die
const scrumDie = DicePresets.createScrumPlanningDie();
// Values: [1, 2, 3, 5, 8, 13, 20, '?']

// Arithmetic progression die
const arithDie = DicePresets.createArithmeticDie(5, 3, 4);
// Values: [5, 8, 11, 14]

// Weighted die (some values more likely than others)
const weightedDie = DicePresets.createWeightedDie([
  { value: 1, weight: 1 },
  { value: 2, weight: 2 },
  { value: 3, weight: 3 }
]);
// Probability: 1=16.7%, 2=33.3%, 3=50.0% (calculated dynamically via getProbability())

DiceExpression Class

import { DiceExpression } from '@risadams/dice-roller';

const expr = new DiceExpression('3d6+5');
console.log(expr.evaluate()); // Roll the expression
console.log(expr.getMinValue()); // 8
console.log(expr.getMaxValue()); // 23
console.log(expr.toString()); // "3d6+5"

Die Class

import { Die } from '@risadams/dice-roller';

const d6 = new Die(6);
console.log(d6.roll()); // 1-6
console.log(d6.rollMultiple(3)); // [1-6, 1-6, 1-6]

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();

// Ability scores (4d6 drop lowest)
const strength = roller.rollKeepHighest(4, 6, 3);
console.log(`Strength: ${strength.result} (${strength.kept.join('+')}, dropped: ${strength.dropped})`);

// Attack roll with advantage
const attack = roller.rollWithAdvantage(20);
console.log(`Attack: ${attack.result} (rolled: ${attack.rolls})`);

Damage Calculation

const roller = new Roller();

// Weapon damage
const swordDamage = roller.rollExpression('1d8+3');
const criticalHit = roller.rollExpression('2d8+3'); // Double dice on crit

// Spell damage
const fireball = roller.rollExpression('8d6');
const healingPotion = roller.rollExpression('2d4+2');

Custom Dice for Scrum Planning

const roller = new Roller();

// Create a Fibonacci die for story point estimation
const fibDie = DicePresets.createFibonacciDie(8);
console.log(`Story points: ${fibDie.roll()}`); // 0, 1, 1, 2, 3, 5, 8, or 13

// Standard Scrum planning poker with actual "?" character
const scrumDie = DicePresets.createScrumPlanningDie();
const estimate = scrumDie.roll();
console.log(`Estimate: ${estimate}`); // Could be 1, 2, 3, 5, 8, 13, 20, or "?"

// Analyze the distribution
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();

// Simple Yes/No decision
const yesNoDie = DicePresets.createTextDie(['Yes', 'No', 'Maybe']);
console.log(`Decision: ${yesNoDie.roll()}`);

// Magic 8-Ball style responses
const magic8Ball = DicePresets.createMagic8BallDie();
console.log(`Magic 8-Ball says: "${magic8Ball.roll()}"`);

// Coin flip
const coinDie = DicePresets.createCoinDie();
console.log(`Coin flip: ${coinDie.roll()}`);

// Game loot with weighted text values
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

// Custom die with mixed values
const mixedDie = new CustomDie([1, 2, 'Skip', 4, 'Double']);
console.log(`Roll result: ${mixedDie.roll()}`);

// Scrum planning with actual "?" for unknown complexity
const scrumDie = DicePresets.createScrumPlanningDie();
const estimate = scrumDie.roll();
console.log(`Story points: ${estimate}`); // Could be number or "?"

// Statistics handle mixed types gracefully
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();

// Analyze weapon damage over 1000 rolls
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)}`);

// Analyze custom dice (works with both numeric and non-numeric)
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)}`);
}

// Mixed dice statistics
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';

// Use a seeded random function for reproducible results
const seededRandom = () => 0.5; // Always returns middle value
const roller = new Roller(seededRandom);

console.log(roller.rollDie(6)); // Always returns 4

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

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

Changelog

1.1.2

  • ENHANCED: CLI now shows clean output by default (just the result)
  • NEW: --verbose/-v flag for detailed output with emojis and breakdowns
  • NEW: Additional custom dice CLI commands:
    • coin (alias: flip) - Coin flip (Heads/Tails)
    • magic8 (aliases: 8ball, magic8ball) - Magic 8-Ball responses
    • yesno (aliases: yn, decision) - Simple Yes/No decision maker
  • ENHANCED: All CLI commands support both clean and verbose output modes
  • ENHANCED: Flexible flag positioning (--verbose can go before or after commands)
  • ENHANCED: Better user experience with intuitive command aliases

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