JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 40
  • Score
    100M100P100Q72530F
  • License MIT

A high-performance dice probability engine for D&D 5e DPR calculations. Powers dprcalc.com.

Package Exports

  • @yipe/dice
  • @yipe/dice/builder
  • @yipe/dice/package.json

Readme

npm version License: MIT TypeScript Size Dice

Last Commit Dependencies GitHub issues Build Status Tests

๐ŸŽฒ @yipe/dice

A TypeScript library for D&D 5e damage-per-round (DPR) calculations, designed for players, Dungeon Masters, and developers who want to analyze combat mathematically.

This library powers dprcalc.com and provides a precise, composable way to model dice rolls, attacks, and outcomes with probability mass functions (PMFs) โ€” not just averages. This allows for rich charting and statistics with full outcome attribution. It provides two main entry points: a fluent typescript interface or a dice expression string.

import { parse } from "@yipe/dice";

const attack = parse("(d20 + 8 AC 16) * (1d8 + 4) crit (2d8 + 4)");
console.log("DPR:", attack.mean());

// or

const attack = d20.plus(8).ac(16).onHit(d8.plus(4));
console.log("DPR:", attack.mean());

โœจ Features

  • D&D 5e Focused: Designed around 5e rules (2014 and 2024).
  • Probability Mass Functions (PMF): Precise modeling of dice rolls and outcomes, not just averages.
  • Complex Attack Expressions: Supports crit ranges, advantage/disadvantage, conditional damage, rerolls, minimum damage, and more.
  • Composable API: Build dice expressions, run queries, and analyze results in just a few lines.
  • TypeScript First: Full type safety and developer experience.

๐Ÿš€ Quick Start

Installation

# Install with npm or yarn
npm install @yipe/dice
# or
yarn add @yipe/dice

Basic Usage

import { parse, DiceQuery } from "@yipe/dice";

const query = d20.plus(8).ac(16).onHit(d4.plus(4)).toQuery();

console.log("Hit chance:", query.probAtLeastOne(["hit", "crit"]));
console.log("Crit chance:", query.probAtLeastOne(["crit"]));
console.log("DPR:", query.mean());

Output:

Hit chance: 0.65
Crit chance: 0.05
DPR: 4.35

๐Ÿ›  Development Setup

Prerequisites

  • Node.js: >= 18.17
  • Yarn: 4.9.4 (specified in packageManager)

Initial Setup

# Clone the repository
git clone https://github.com/yipe/dice.git
cd dice

# Install dependencies
yarn install

# Build the project
yarn build

# Run tests
yarn test

# Run examples
yarn example

Available Scripts

Command Purpose
yarn build Compile TypeScript to JavaScript (outputs to dist/)
yarn test Run test suite once
yarn test:watch Run tests in watch mode
yarn typecheck Type-check without emitting files
yarn lint Run ESLint
yarn example Run example scripts

Project Structure

src/
โ”œโ”€โ”€ builder/          # Fluent API for building dice expressions
โ”‚   โ”œโ”€โ”€ factory.ts    # Factory functions (d20, d6, roll, etc.)
โ”‚   โ”œโ”€โ”€ roll.ts       # RollBuilder - core builder class
โ”‚   โ”œโ”€โ”€ ac.ts         # ACBuilder - attack roll builder
โ”‚   โ”œโ”€โ”€ attack.ts     # AttackBuilder - attack with damage
โ”‚   โ”œโ”€โ”€ save.ts       # SaveBuilder - saving throw builder
โ”‚   โ”œโ”€โ”€ dc.ts         # DCBuilder - difficulty check builder
โ”‚   โ”œโ”€โ”€ ast.ts        # AST generation and PMF conversion
โ”‚   โ””โ”€โ”€ nodes.ts      # AST node type definitions
โ”œโ”€โ”€ parser/           # String-based dice expression parser
โ”‚   โ”œโ”€โ”€ parser.ts     # Main parser implementation
โ”‚   โ””โ”€โ”€ dice.ts       # Dice class (legacy parser representation)
โ”œโ”€โ”€ pmf/              # Probability Mass Function core
โ”‚   โ”œโ”€โ”€ pmf.ts        # PMF class - core data structure
โ”‚   โ”œโ”€โ”€ query.ts      # DiceQuery - analysis interface
โ”‚   โ””โ”€โ”€ mixture.ts   # Mixture operations
โ””โ”€โ”€ common/           # Shared utilities
    โ”œโ”€โ”€ types.ts      # Type definitions
    โ””โ”€โ”€ lru-cache.ts  # LRU cache implementation

๐Ÿ— Architecture Overview

The library provides two parallel entry points for creating dice expressions:

Entry Point 1: String Parser

Parses text expressions like "(d20 + 8 AC 16) * (1d8 + 4) crit (2d8 + 4)":

String Expression
    โ”‚
    โ”œโ”€ parse() โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚                        โ”‚
    โ”‚                        โ–ผ
    โ”‚             parseExpression()
    โ”‚                        โ”‚
    โ”‚                        โ”œโ”€ parseArgument() โ”€โ”€โ–บ Dice objects
    โ”‚                        โ”‚
    โ”‚                        โ””โ”€ parseOperation() โ”€โ”€โ–บ Dice operations
    โ”‚                        โ”‚
    โ”‚                        โ–ผ
    โ”‚             Dice.toPMF() โ”€โ”€โ–บ PMF
    โ”‚                        โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Entry Point 2: Fluent Builder API

Type-safe builder pattern:

RollBuilder (d20, d6, roll(), etc.)
    โ”‚
    โ”œโ”€ .plus() โ”€โ”€โ–บ RollBuilder
    โ”œโ”€ .ac() โ”€โ”€โ”€โ”€โ–บ ACBuilder
    โ”‚                 โ”‚
    โ”‚                 โ””โ”€ .onHit() โ”€โ”€โ–บ AttackBuilder
    โ”‚                                    โ”‚
    โ”‚                                    โ”œโ”€ .toQuery() โ”€โ”€โ–บ DiceQuery
    โ”‚                                    โ””โ”€ .pmf โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ PMF
    โ”‚
    โ””โ”€ .toPMF() โ”€โ”€โ–บ PMF

Core Class Flow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    User Input Layer                         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  String Parser          โ”‚  Fluent Builder                   โ”‚
โ”‚  parse("...")           โ”‚  d20.plus(8).ac(16)               โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
             โ”‚                         โ”‚
             โ–ผ                         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    Builder Layer                            โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  RollBuilder โ”€โ”€โ–บ ACBuilder โ”€โ”€โ–บ AttackBuilder                โ”‚
โ”‚       โ”‚              โ”‚              โ”‚                       โ”‚
โ”‚       โ”‚              โ”‚              โ”‚                       โ”‚
โ”‚       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                       โ”‚
โ”‚                      โ”‚                                      โ”‚
โ”‚                      โ–ผ                                      โ”‚
โ”‚              astFromRollConfigs()                           โ”‚
โ”‚                      โ”‚                                      โ”‚
โ”‚                      โ–ผ                                      โ”‚
โ”‚              ExpressionNode (AST)                           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                       โ”‚
                       โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    PMF Generation                           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  pmfFromRollBuilder()                                       โ”‚
โ”‚       โ”‚                                                     โ”‚
โ”‚       โ”œโ”€ d20RollPMF() โ”€โ”€โ–บ PMF (for d20 rolls)               โ”‚
โ”‚       โ”œโ”€ diePMF() โ”€โ”€โ”€โ”€โ”€โ”€โ–บ PMF (for regular dice)            โ”‚
โ”‚       โ””โ”€ combinePMFs() โ”€โ–บ PMF (convolve multiple PMFs)      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                       โ”‚
                       โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    Query & Analysis                         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  DiceQuery                                                  โ”‚
โ”‚       โ”‚                                                     โ”‚
โ”‚       โ”œโ”€ .mean() โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ Expected damage              โ”‚
โ”‚       โ”œโ”€ .variance() โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ Damage variance              โ”‚
โ”‚       โ”œโ”€ .probAtLeastOne() โ”€โ”€โ–บ Hit/crit probabilities       โ”‚
โ”‚       โ”œโ”€ .toChartSeries() โ”€โ”€โ”€โ”€โ–บ Chart data                  โ”‚
โ”‚       โ””โ”€ .combined โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ Final PMF                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

PMF Data Structure

The PMF class is the core mathematical representation:

PMF
โ”œโ”€โ”€ map: Map<number, Bin>
โ”‚   โ””โ”€โ”€ Bin
โ”‚       โ”œโ”€โ”€ p: number          (probability)
โ”‚       โ”œโ”€โ”€ count: {...}       (outcome counts: hit, crit, miss)
โ”‚       โ””โ”€โ”€ attr: {...}        (damage attribution)
โ”œโ”€โ”€ epsilon: number            (probability threshold)
โ”œโ”€โ”€ normalized: boolean        (whether PMF sums to 1.0)
โ””โ”€โ”€ identifier: string         (cache key / debug name)

Main Flow Example

Here's how a simple attack flows through the system:

1. User creates: d20.plus(5).ac(15).onHit(d6.plus(2))

2. Builder chain:
   RollBuilder(d20) 
     โ†’ plus(5) โ†’ RollBuilder(d20 + 5)
     โ†’ ac(15) โ†’ ACBuilder(d20 + 5 AC 15)
     โ†’ onHit(...) โ†’ AttackBuilder

3. AST generation:
   RollConfig[] โ†’ ExpressionNode
     - DieNode (d20)
     - ConstantNode (+5)
     - D20RollNode (AC check)
     - ConditionalNode (on hit)

4. PMF generation:
   AST โ†’ PMF operations
     - d20RollPMF(rollType, rerollOne) โ†’ PMF
     - Conditional application โ†’ PMF.branch()
     - Damage PMF โ†’ PMF
     - Combine โ†’ PMF (final result)

5. Query creation:
   AttackBuilder.toQuery() โ†’ DiceQuery
     - singles: [PMF]
     - combined: PMF (convolved)

6. Analysis:
   DiceQuery.mean() โ†’ 3.20 DPR

๐Ÿ“ฆ Core Concepts

Concept Description
PMF Probability Mass Function. The core mathematical representation of outcomes.
Query Runs calculations and scenarios over one or more PMFs.
Parser Parses text-based dice expressions like (d20 + 8 AC 16) * (1d4 + 4).
Builder Fluent TypeScript API for building dice expressions.
AST Abstract Syntax Tree representing dice operations.

๐Ÿง™ Usage Examples

Basic Attack

import { parse, DiceQuery } from "@yipe/dice";

const query = d20.plus(8).ac(16).onHit(d4.plus(4)).toQuery();

console.log("Hit chance:", query.probAtLeastOne(["hit", "crit"]));
console.log("Crit chance:", query.probAtLeastOne(["crit"]));
console.log("DPR:", query.mean());

String Parser

import { parse } from "@yipe/dice";

const pmf = parse("(d20 + 8 AC 16) * (1d8 + 4) crit (2d8 + 4)");
const query = new DiceQuery(pmf);

console.log("DPR:", query.mean());

Sneak Attack (Conditional Damage)

Conditional damage ("once-per-turn damage riders") like Sneak Attack can be modeled easily:

import { DiceQuery, PMF, roll } from "@yipe/dice";

function sneakAttack() {
  const attackPMF = d20.plus(8).ac(16).onHit(d4.plus(4)).pmf;
  const sneakAttack = roll(3, d6);
  const attacks = new DiceQuery([attackPMF, attackPMF]);
  const [pHit, pCrit] = attacks.firstSuccessSplit(onAnyHit, onCritOnly);
  const sneakPMF = PMF.exclusive([
    [sneakAttack.pmf, pHit],
    [sneakAttack.doubleDice().pmf, pCrit],
  ]);

  return new DiceQuery([attackPMF, attackPMF, sneakPMF]);
}

console.log("DPR with once-per-turn sneak attack: ", sneakAttack().mean());

Statistics and Charts

import { parse, DiceQuery } from "@yipe/dice";

const query = parse("(d20 + 8 AC 16) * (1d4 + 4) crit (2d4 + 4)").toQuery();
console.table(query.toChartSeries());

Output:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ (index) โ”‚ x  โ”‚ y        โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0       โ”‚ 0  โ”‚ 0.35     โ”‚
โ”‚ 1       โ”‚ 5  โ”‚ 0.15     โ”‚
โ”‚ 2       โ”‚ 6  โ”‚ 0.153125 โ”‚
โ”‚ 3       โ”‚ 7  โ”‚ 0.15625  โ”‚
โ”‚ 4       โ”‚ 8  โ”‚ 0.159375 โ”‚
โ”‚ 5       โ”‚ 9  โ”‚ 0.0125   โ”‚
โ”‚ 6       โ”‚ 10 โ”‚ 0.009375 โ”‚
โ”‚ 7       โ”‚ 11 โ”‚ 0.00625  โ”‚
โ”‚ 8       โ”‚ 12 โ”‚ 0.003125 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿงช Running Examples

This repository includes example scripts:

yarn example basic
yarn example stats
yarn example sneakattack
yarn example misc

Here is the basic example output:

% yarn example basic

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Summary    โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Expression:     (d20 + 5 AC 15) * (1d6+2) crit (2d6 + 2) โ”‚
โ”‚ Success Chance: 0.55                                     โ”‚
โ”‚ Expected DPR:   3.20                                     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ PMF ()     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   0: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 45.00%  โ”‚
โ”‚   3: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–Œ                                                             8.33%  โ”‚
โ”‚   4: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‹                                                             8.47%  โ”‚
โ”‚   5: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‰                                                             8.61%  โ”‚
โ”‚   6: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–                                                            8.75%  โ”‚
โ”‚   7: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–                                                            8.89%  โ”‚
โ”‚   8: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‹                                                            9.03%  โ”‚
โ”‚   9: โ–ˆโ–Ž                                                                         0.83%  โ”‚
โ”‚  10: โ–ˆโ–                                                                         0.69%  โ”‚
โ”‚  11: โ–‰                                                                          0.56%  โ”‚
โ”‚  12: โ–‹                                                                          0.42%  โ”‚
โ”‚  13: โ–                                                                          0.28%  โ”‚
โ”‚  14: โ–                                                                          0.14%  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ CDF (): P(X โ‰ค x) โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   0: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–                                         45.00%  โ”‚
โ”‚   1: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–                                         45.00%  โ”‚
โ”‚   2: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–                                         45.00%  โ”‚
โ”‚   3: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–                                   53.33%  โ”‚
โ”‚   4: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–Œ                             61.81%  โ”‚
โ”‚   5: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‹                       70.42%  โ”‚
โ”‚   6: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–                79.17%  โ”‚
โ”‚   7: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–          88.06%  โ”‚
โ”‚   8: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‰    97.08%  โ”‚
โ”‚   9: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–Œ   97.92%  โ”‚
โ”‚  10: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ   98.61%  โ”‚
โ”‚  11: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–  99.17%  โ”‚
โ”‚  12: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‹  99.58%  โ”‚
โ”‚  13: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‰  99.86%  โ”‚
โ”‚  14: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 100.00%  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Outcome Table () โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ DAMAGE โ”‚ PERCENT โ”‚ Crit % โ”‚  Hit % โ”‚  Miss % โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0      โ”‚ 45.000% โ”‚ 0.000% โ”‚ 0.000% โ”‚ 45.000% โ”‚
โ”‚ 3      โ”‚  8.333% โ”‚ 0.000% โ”‚ 8.333% โ”‚  0.000% โ”‚
โ”‚ 4      โ”‚  8.472% โ”‚ 0.139% โ”‚ 8.333% โ”‚  0.000% โ”‚
โ”‚ 5      โ”‚  8.611% โ”‚ 0.278% โ”‚ 8.333% โ”‚  0.000% โ”‚
โ”‚ 6      โ”‚  8.750% โ”‚ 0.417% โ”‚ 8.333% โ”‚  0.000% โ”‚
โ”‚ 7      โ”‚  8.889% โ”‚ 0.556% โ”‚ 8.333% โ”‚  0.000% โ”‚
โ”‚ 8      โ”‚  9.028% โ”‚ 0.694% โ”‚ 8.333% โ”‚  0.000% โ”‚
โ”‚ 9      โ”‚  0.833% โ”‚ 0.833% โ”‚ 0.000% โ”‚  0.000% โ”‚
โ”‚ 10     โ”‚  0.694% โ”‚ 0.694% โ”‚ 0.000% โ”‚  0.000% โ”‚
โ”‚ 11     โ”‚  0.556% โ”‚ 0.556% โ”‚ 0.000% โ”‚  0.000% โ”‚
โ”‚ 12     โ”‚  0.417% โ”‚ 0.417% โ”‚ 0.000% โ”‚  0.000% โ”‚
โ”‚ 13     โ”‚  0.278% โ”‚ 0.278% โ”‚ 0.000% โ”‚  0.000% โ”‚
โ”‚ 14     โ”‚  0.139% โ”‚ 0.139% โ”‚ 0.000% โ”‚  0.000% โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

This enables rich statistics like "how much damage comes from crits vs hits".

๐Ÿงฑ Roadmap

  • Create a web playground with live examples
  • Consider creating higher-level APIs: Turn, Attack, DamageRider
  • Add more comprehensive 5e rule examples
  • Performance improvements for DPR-only calculations
  • Multi-round and sustained vs nova simulations
  • Deeper integration with dprcalc.com
  • Blog posts and documentation
  • Grammar refinements and new YACC parsing

๐Ÿ’ฌ Discuss

Join our Discord to discuss this library and more!

๐Ÿค Contributing

Clone the repo and install dependencies:

git clone https://github.com/yipe/dice.git
cd dice
yarn install

Run tests:

yarn test

Run examples:

yarn example

๐Ÿ“œ License

2025 MIT ยฉ Michael Margolis

Wizards of the Coast, Dungeons & Dragons, and their logos are trademarks of Wizards of the Coast LLC in the United States and other countries.

ยฉ 2025 Wizards. All Rights Reserved.

โค๏ธ Credits

Portions of this code are inspired by dice.clockworkmod.com by Koushik Dutta (2013), licensed under the Apache License 2.0.

Initial TypeScript port expertly created by loginName1.