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)