Dice Core API

Entrypoints, functions, results, replay, limits, and errors.

Public entrypoints

The root @erpg/dicecore package reexports the entire API. To load only what you need:

Import Contents
@erpg/dicecore/core Engine, compilation, validation, generic rolls, limits, errors
@erpg/dicecore/systems All systems and mixed batches
@erpg/dicecore/systems/fate Fate
@erpg/dicecore/systems/vampire-v5 Vampire V5
@erpg/dicecore/systems/assimilation Assimilation
@erpg/dicecore/systems/daggerheart Daggerheart
@erpg/dicecore/systems/mixed Mixed batches

Deep imports outside these exports are not part of the public contract.

Compilation and inspection

Function Return Purpose
compileRpgDice(input, options?) RollPlan Normalize and compile a reusable formula
inspectRpgDiceNotation(input, options?) DiceNotationInspection Validate and estimate cost without rolling; invalid notation is returned
verifyRpgDiceNotation(input, options?) boolean Boolean validation
normalizeRpgDiceNotation(input) string Expand shorthand and remove comments

RollPlan has schemaVersion: 3, planFingerprint, normalizedNotation, rollCount, groups, and cost. A deserialized plan is revalidated before execution; its structure is not an editable AST.

import { compileRpgDice, inspectRpgDiceNotation, rollRpgDice } from '@erpg/dicecore/core'
const inspection = inspectRpgDiceNotation('4d6kh3')
if (inspection.isValid) {
  const plan = compileRpgDice('4d6kh3')
  console.log(inspection.cost.totalStaticDice)
  console.log(rollRpgDice(plan).total)
} else {
  console.error(inspection.error.code)
}

Execution and projections

Function Return
rollRpgDice(inputOrPlan, options?) Complete DiceRollResult
rollRpgDiceDetails(inputOrPlan, options?) DiceRollDetails with dice but without groups/events/output
rollRpgDiceSummary(inputOrPlan, options?) DiceRollSummary without dice/groups/events/output
rollMixedDice(notation, options?) MixedRollResult discriminated per segment

In the full result, total is numeric; output is convenience text; dice, groups, and events are root arrays; rolls references ranges in those arrays. pool is null without a target. stats counts rolls, initial/generated dice, RNG calls, modifier steps, events, groups, and result items. DTOs are readonly and JSON-safe.

ResolvedDie field Meaning
id, parentDieId Local identity and explosion link
sides, rawValue Die type and first face
value Value after transformations
included, contribution Participation and contribution to total
states Applied modifiers/classifications

For animation, consume the events journal: roll, reroll, explode, transform, include, exclude, and classify. An explosive child has a roll event before the explode event that links it to its parent. Build dependencies by IDs. See Dice View for visual integration.

Options, seeds, and replay

RollOptions accepts limits and either seed: string | number / randomAlgorithm: 'mt19937' | 'xoshiro128ss' or replay. Seed and replay are exclusive. MT19937 is the default. Without a seed, Core requires crypto.getRandomValues and never uses Math.random. ReplayDescriptor records the algorithm, versions, decimal12-v1 math profile, seed material, and plan fingerprint. Changing the formula raises REPLAY_PLAN_MISMATCH.

const first = rollRpgDice('2d20kh1')
const repeated = rollRpgDice(first.input, { replay: first.replay })

Engine and systems

createDiceEngine({ limits, cache, randomAlgorithm, freezeResults }) creates isolated configuration. An engine exposes compile, inspect, normalize, roll, rollDetails, rollSummary, verify, clearCache, and getCacheStats. cache: false disables caching; cache options are maxInputEntries, maxProgramEntries, and maxProgramNodes. freezeResults accepts never (default), development, or always.

createSystemRoller(engine) binds rollFateDice, rollVampireV5, rollAssimilation, rollDaggerheart, and rollMixedDice to that engine. Semantic APIs are documented under Fate, Vampire, Assimilation, and Daggerheart. Each semantic die has sourceDieId, profileId, dieKind, faceKey, and symbols. detail: 'compact' summarizes only the internal baseRoll.

Limits and errors

DICE_LIMIT_PRESETS provides browser, trustedServer, and untrustedServer. By default, Core caps input at 4,096 characters, AST depth at 64, nodes at 10,000, rolls at 100, initial dice at 10,000, generated dice at 20,000, and RNG calls at 100,000. Events, sides, seed length, steps, groups, items, and output have limits too. Per-call limits may only lower engine ceilings.

DiceRollError carries code, span, input, details, and toJSON(). Use isDiceRollError(); for JSON transport, check isDiceRollErrorData() and restore with DiceRollError.fromJSON(). Common codes include INVALID_NOTATION, UNSUPPORTED_NOTATION, NON_TERMINATING_MODIFIER, IMPOSSIBLE_UNIQUE, INVALID_SYSTEM_INPUT, RNG_UNAVAILABLE, and REPLAY_PLAN_MISMATCH.

import { DiceRollError, isDiceRollError, isDiceRollErrorData } from '@erpg/dicecore/core'
try {
  rollRpgDice('7d6u')
} catch (error: unknown) {
  if (isDiceRollError(error)) console.error(error.code, error.span)
}
const received: unknown = JSON.parse(payload)
if (isDiceRollErrorData(received)) throw DiceRollError.fromJSON(received)

Try the examples

Try 2d20kh1 · Try 5d10>=8f=1