Specification

RANDSUM Dice Notation

A formal specification for dice notation syntax used in tabletop role-playing games.

RANDSUM Dice Notation Specification

Version: 0.9.0 Status: Draft Date: 2026-03-21


Abstract

This document defines the RANDSUM Dice Notation (RDN), a human-readable, machine-parseable format for expressing dice rolls in tabletop role-playing games. RDN specifies a three-stage execution pipeline with deterministic modifier ordering, a faceted classification system for modifiers, and four conformance levels for partial implementation. The notation supports standard dice, custom faces, geometric dice, draw dice, and 26 modifiers across three pipeline stages. This specification is intended to enable interoperable dice notation processing across virtual tabletop platforms, chat bots, and game automation tools.

Document Information:

Status of This Memo

This document is a community specification published by the RANDSUM project. It is not an Internet Standards Track specification; a submission to the IETF is forthcoming. Distribution of this memo is unlimited.

This is a draft release. The specification is believed to be stable for implementation but may undergo revisions before the 1.0 release. Feedback is welcome via the project repository.

1. Introduction

1.1 Purpose

This document is the formal specification for RANDSUM Dice Notation (RDN), a compact language for describing dice rolls, modifiers, and resolution mechanics used in tabletop role-playing games and related systems.

1.2 Scope

This specification covers:

  • Dice types and their generation models
  • Modifier taxonomy, classification, and execution semantics
  • The three-stage execution pipeline and two-channel architecture
  • Condition expression sub-grammar
  • Notation syntax overview
  • Safety limits and implementation guidance
  • Conformance levels for partial implementations

This specification is language-agnostic. It describes the required behavior of any conforming implementation without prescribing implementation language, data structures, or API shape.

1.3 Conventions

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in BCP 14 (RFC 2119, RFC 8174) when, and only when, they appear in all capitals, as shown here.

1.4 Versioning

This is version 0.9.0 of the RANDSUM Dice Notation Specification. Future versions will follow semantic versioning: breaking changes increment the major version, additive changes increment the minor version.

1.5 Document History

VersionDateChanges
0.9.02026-03-21Initial public draft. Three-stage pipeline, 26 modifiers, four conformance levels, faceted classification, ABNF grammar, 48 conformance test vectors, security considerations, IANA section.

2. Glossary

The following terms are used normatively throughout this specification.

TermDefinition
Die ExpressionA notation string that describes one or more dice and their modifiers. Example: 4d6L.
RollA single random outcome produced by a die. A numeric value selected from the die’s face set.
PoolThe ordered array of roll values produced by evaluating a die expression. Modified in-place by Stage 1 and Stage 2 modifiers.
TotalThe scalar numeric result derived from a pool, typically by summation, but optionally by counting (see Reinterpret).
ModifierA named transformation applied to a pool or total during the execution pipeline. Each modifier has a priority, stage, verb, and channel.
PrimitiveA modifier or die type that provides irreducible behavior not expressible as a composition of other features.
AliasA notation convenience that de-aliases to one or more primitives with identical observable behavior.
MacroA modifier that dispatches to different primitive behaviors based on runtime state.
StageOne of three ordered phases of the execution pipeline. Each stage has a contract governing what operations are permitted.
VerbThe operational classification of a modifier describing what it does to the pool or total. One of: Clamp, Map, Filter, Substitute, Generate, Accumulate, Scale, Reinterpret.
ChannelThe output target of a modifier: Pool (transforms the rolls array) or Total (transforms the scalar total).
PriorityA numeric value that determines execution order within the pipeline. Lower numbers execute first.
Condition ExpressionA sub-grammar for specifying numeric comparisons used by multiple modifiers. See Section 5.
Die TypeThe generation model and face configuration of a die. Standard, Custom Faces, Geometric, or Draw.
ConditionA single comparison operator and operand within a condition expression (e.g., >=7, <3).
Presentation DirectiveA notation feature that affects display ordering but does not alter the total. Sort is the sole presentation directive.
Parser DirectiveA notation feature resolved at parse time before the execution pipeline runs. Repeat (xN) is the sole parser directive.
Notation MetadataInformation embedded in notation that does not participate in the execution pipeline. Annotations ([text]) are the sole metadata feature.

3. Classification System

3.1 Faceted Classification Overview

Every modifier in RDN is classified along four independent facets:

  1. Derivation Status — whether the feature is primitive, alias, or macro
  2. Pipeline Stage — when the modifier executes (Stage 1, 2, or 3)
  3. Operational Verb — what the modifier does (Clamp, Map, Filter, etc.)
  4. Output Channel — where the modifier writes its result (Pool or Total)

These facets are orthogonal but not fully independent: certain combinations are constrained (see Section 3.6). Together they form a complete taxonomy of every modifier in the system.

3.2 Derivation Status

StatusDefinitionSet
PrimitiveIrreducible behavior. Cannot be expressed as a composition of other modifiers.Closed
AliasDe-aliases to one or more primitives. Observable behavior is identical to the de-aliased form.Closed
MacroDispatches to different primitives based on runtime state.Closed

The set of derivation statuses is closed. No other status exists or may be added without a new specification version.

3.3 Pipeline Stage

StageNamePriority RangeContractBoundary Signal
1Deterministic Value Shaping10—39No RNG. Pure value transformations over the dice array. No pool size changes. requiresRollFn = false.requiresRollFn = false
2Pool Dynamics40—69Both stochastic and deterministic pool operations. Stochastic modifiers require a roll function. requiresRollFn = true (stochastic). Drop/Keep run after explosions so the filter operates on the expanded pool.requiresRollFn = true (stochastic)
3Total Derivation80—100Pool is frozen. Operates on the scalar total only. mutatesRolls = false.mutatesRolls = false

Stage boundaries are structural: a modifier declaring requiresRollFn = true cannot run in Stage 1. A modifier declaring mutatesRolls = false cannot modify the dice array.

3.4 Operational Verb

VerbStageDescription
Clamp1Constrain individual die values to boundaries. Pool size unchanged.
Map1Deterministic value substitution. Pool size unchanged.
Filter2Remove dice from the pool. Pool shrinks.
Substitute2Re-randomize matching dice. Pool size unchanged.
Generate2Append new dice to the pool. Pool grows.
Accumulate2Fold additional rolls into an existing die. Pool size preserved.
Scale3Arithmetic transformation of the total.
Reinterpret3Replace the aggregation model (sum to cardinality).

There are exactly 8 operational verbs. Wild Die uses Dispatch (see Section 3.2 on Macros), which is not a verb but a macro classification.

3.5 Output Channel

ChannelDescriptionUsed By
PoolModifier transforms the rolls array. The resulting array is input to the next modifier.Stage 1, Stage 2
TotalModifier provides a transformTotal function. The pool passes through unchanged.Stage 3

A modifier MUST use exactly one channel. No modifier uses both channels simultaneously.

3.6 Facet Interaction Constraints

The following constraints govern valid facet combinations:

  1. Channel is determined by Stage. Stage 1 and Stage 2 modifiers use the Pool channel. Stage 3 modifiers use the Total channel. An implementation MUST NOT assign a Stage 1 modifier to the Total channel or vice versa.

  2. Macros do not have a Verb. A macro dispatches to multiple primitives at runtime; its verb varies by execution path. Wild Die dispatches to Accumulate, Filter, or no-op depending on the rolled value.

  3. Aliases inherit facets from their parent primitive. An alias’s Stage, Verb, and Channel are identical to the primitive it de-aliases to. Keep inherits Stage 2 / Filter / Pool from Drop. Minus inherits Stage 3 / Scale / Total from Plus.

3.7 Valid Facet Combinations

StageVerbChannelModifiers
1ClampPoolCap
1MapPoolReplace
2SubstitutePoolReroll, Reroll Once (alias), Unique
2GeneratePoolExplode, Explode Sequence, Inflation (alias), Reduction (alias)
2AccumulatePoolCompound, Penetrate
2FilterPoolDrop, Keep (alias), Keep Middle (alias)
2DispatchPoolWild Die (macro)
3ReinterpretTotalCount, Count Successes (alias), Count Failures (alias)
3ScaleTotalMultiply, Plus, Minus (alias), Margin of Success (alias), Integer Divide, Modulo, Multiply Total (alias)

Sort (Stage 3, priority 95) is a Presentation Directive, not an operational modifier. It reorders the pool array for display but does not alter the total. It is classified under the Pool channel as a special case: it mutates the array ordering but not the array contents or the total.


4. Dice Expressions

4.1 Standard Dice (NdS)

Classification: Primitive

PropertyValue
NotationNdS where N is quantity (default 1), S is number of sides
Generation ModelUniform random selection
Face TypeNumeric, sequential integers
Face Range[1..S]

A standard die produces values uniformly distributed over the integers 1 through S inclusive. When N is omitted, it defaults to 1. When S is a positive integer, the die has faces numbered 1 through S.

Implementations MUST support S values of at least 1 through 1000. The quantity N MUST be a positive integer.

4.2 Custom Faces (d{…})

Classification: Primitive

PropertyValue
NotationNd{f1,f2,...,fN}
Generation ModelUniform random selection
Face TypeNumeric or string, arbitrary values
Face RangeExactly the listed face values

Custom faces dice select uniformly from the explicitly listed face values. Duplicate values are permitted and create weighted distributions: d{1,1,2} has a 2/3 probability of producing 1.

When faces are non-numeric strings, the roll result contains string values. String-faced dice do not produce a numeric total; the total is undefined for string-faced pools.

4.3 Geometric Dice (gN)

Classification: Primitive

PropertyValue
NotationgN
Generation ModelOpen-ended (repeat until termination)
Face TypeNumeric, sequential integers
Face Range[1..N] per roll
TerminationStops when a roll is not equal to N (not max)
Safety Cap1000 iterations

A geometric die rolls a standard dN repeatedly as long as each roll equals N (the maximum). The total is the sum of all rolls in the sequence. The die terminates when a roll is less than N, or when the safety cap of 1000 iterations is reached.

4.4 Draw Dice (DDN)

Classification: Primitive

PropertyValue
NotationQddN or QDDN where Q is quantity, N is sides
Generation ModelSampling without replacement
Face TypeNumeric, sequential integers
Face Range[1..N]

Draw dice sample without replacement from the face set [1..N]. Each value appears at most once within each pass through the pool. If the quantity Q exceeds N, the pool is exhausted and then reshuffled, and drawing continues from the fresh pool until all Q values are produced. For example, 8DD6 produces 8 values: the first 6 are a permutation of [1..6], then the pool reshuffles and 2 more values are drawn from it. Implementations SHOULD use Fisher-Yates shuffle or an equivalent unbiased algorithm for each shuffle pass.

4.5 Dice Aliases

4.5.1 Percentile (d%)

Classification: Alias

De-aliases to: Standard die 1d100.

The notation d% is equivalent to 1d100. Implementations MUST treat d% identically to 1d100 in all contexts.

4.5.2 Fate/Fudge (dF, dF.2)

Classification: Alias

Fate Core (dF): De-aliases to d{-1,0,1} (a custom faces die). Produces values in {-1, 0, +1}.

Extended Fudge (dF.2): De-aliases to d{-2,-1,0,1,2} (a custom faces die). Produces values in {-2, -1, 0, +1, +2}.

dF.1 is an alias for dF (standard Fate die with faces [-1, 0, 1]). Implementations that accept dF.1 MUST treat it identically to dF.

The standard Fate roll is 4dF, producing a total in the range [-4, +4].

4.5.3 Zero-Bias (zN)

Classification: Alias

De-aliases to: Custom Faces die d{0,1,2,...,N-1}. Produces values in [0..N-1] instead of [1..N].

4.6 Dice Type Classification Table

Die TypeGeneration ModelFace TypePrimitive/AliasNotation
StandardUniform selectionNumeric sequentialPrimitiveNdS
Custom FacesUniform selectionNumeric or string, arbitraryPrimitiveNd{...}
GeometricOpen-ended repeatNumeric sequentialPrimitivegN
DrawWithout replacementNumeric sequentialPrimitiveDDN
PercentileUniform selectionNumeric sequentialAlias (Standard)d%
Fate/FudgeUniform selectionNumeric mappedAlias (Custom)dF, dF.2
Zero-BiasUniform selectionNumeric shiftedAlias (Custom Faces)zN

5. Condition Expressions

Condition expressions are a shared sub-grammar used by Cap, Drop, Reroll, and Count modifiers.

5.1 Operator Syntax

A condition consists of an optional comparison operator followed by an integer operand.

OperatorMeaningExample
>NGreater than N>5
<NLess than N<3
>=NGreater than or equal to N>=7
<=NLess than or equal to N<=2
=NExactly equal to N=4
N (bare integer)Modifier-specific (see Section 5.3)5

5.2 Condition Lists

Multiple conditions MAY be specified by separating them with commas within braces:

{>=7,<3}    -- matches values >= 7 OR values < 3
{1,6}       -- bare integers, interpretation depends on modifier
{>=5,<=2}   -- matches values >= 5 OR values <= 2

Conditions within a list are combined with logical OR unless the modifier specifies otherwise (see Count deduct mode in Section 6.6.2).

5.3 Modifier-Specific Semantics

The bare integer form (no operator prefix) has different semantics depending on the modifier:

ModifierBare Integer Meaning
CapMaximum cap: no result exceeds N. Equivalent to >N (clamp down to N).
DropExact match: drop dice showing exactly N. Equivalent to =N.
RerollExact match: reroll dice showing exactly N. Equivalent to =N.
CountExact match: count dice showing exactly N. Equivalent to =N.

Implementations MUST document this divergence. The Cap modifier’s bare integer interpretation is the only case where a bare integer does not mean exact match.


6. Execution Pipeline

This section is normative. Conforming implementations MUST execute modifiers according to the rules described here.

6.1 Three-Stage Model

The execution pipeline processes modifiers in three sequential stages:

  1. Stage 1 — Deterministic Value Shaping (priority 10—39): Pure value transformations of the pool array. No random number generation. No pool size changes.
  2. Stage 2 — Pool Dynamics (priority 40—69): Both stochastic and deterministic pool operations. Requires a roll function for stochastic modifiers. Drop and Keep run after explosions so the filter operates on the expanded pool.
  3. Stage 3 — Total Derivation (priority 80—100): Pool is frozen. Operates on the scalar total.

Modifiers execute in ascending priority order. Within a stage, priority ordering is strict: a modifier with priority 20 MUST execute before a modifier with priority 30.

6.2 Two-Channel Architecture

The pipeline maintains two output channels:

  • Pool channel (rolls): An ordered array of numeric values representing individual die results. Stage 1 and Stage 2 modifiers write to this channel.
  • Total channel (transformTotal): A function that transforms the computed scalar total. Stage 3 modifiers write to this channel.

Mutual exclusion invariant: A single modifier invocation MUST write to exactly one channel. No modifier writes to both channels simultaneously.

The total is computed by summing the final pool array, then applying all transformTotal functions in priority order.

6.3 Priority Ordering

The following priority assignments are normative. Implementations MUST respect these exact values:

PriorityModifierStage
10Cap1
30Replace1
40Reroll2
50Explode2
51Compound2
52Penetrate2
53Explode Sequence2
55Wild Die2
60Unique2
65Drop2
66Keep (alias for Drop)2
80Count3
85Multiply3
90Plus3
91Minus (alias for Plus)3
93Integer Divide3
94Modulo3
95Sort3
100Multiply Total (alias for Multiply)3

6.4 Stage 1 — Deterministic Value Shaping

6.4.1 Contract

Stage 1 modifiers:

  • MUST NOT invoke a random number generator.
  • MUST be pure functions: given the same pool and options, they produce the same output.
  • MUST NOT require a roll function (requiresRollFn = false).
  • MUST NOT change pool size (no dice are added or removed).

6.4.2 Cap

Primitive | Stage 1 | Clamp | Pool channel | Priority 10

Notation: C{condition-list}

Options: ComparisonOptions

Effect: Constrains individual die values to specified boundaries. Values exceeding an upper bound are clamped down to the bound. Values below a lower bound are clamped up to the bound. Pool size is unchanged.

Evaluation order: Upper bounds are applied first (greaterThan, greaterThanOrEqual, exact), then lower bounds (lessThan, lessThanOrEqual).

Bare integer semantics: A bare integer N in the condition expression means “maximum cap” — no result exceeds N. This differs from other modifiers where bare integers mean exact match (see Section 5.3).

Pool size: Unchanged.

Aliases: None.

6.4.3 Replace

Primitive | Stage 1 | Map | Pool channel | Priority 30

Notation: V{from=to,...}

Options: ReplaceOptions (from/to value pairs)

Effect: Deterministic substitution of die values. For each die in the pool, if its value matches a from value, it is replaced with the corresponding to value. Pool size is unchanged.

Multiple replacement rules are applied in the order specified. A die may be replaced multiple times if subsequent rules match the replaced value.

Pool size: Unchanged.

Aliases: None.

6.5 Stage 2 — Pool Dynamics

6.5.1 Contract

Stage 2 modifiers:

  • MAY have access to a roll function (requiresRollFn = true for stochastic modifiers).
  • MAY introduce new random values into the pool.
  • MAY grow, shrink, or preserve the pool size depending on the modifier.

6.5.2 Reroll

Primitive | Stage 2 | Substitute | Pool channel | Priority 40

Notation: R{condition-list}, R{condition-list}N

Options: RerollOptions (comparison conditions, optional max count)

Effect: Re-randomizes dice matching the condition expression. Each matching die is re-rolled. If the new value still matches, the die is re-rolled again, up to a safety maximum of 99 attempts per die. The optional trailing integer N limits the total number of dice that will be rerolled across the pool.

Pool size: Unchanged.

Aliases: Reroll Once (Section 6.7.3).

6.5.3 Unique

Primitive | Stage 2 | Substitute | Pool channel | Priority 60

Notation: U

Options: boolean or UniqueOptions

Effect: Enforces that no two dice in the pool share the same value. This is a pool-level constraint: any duplicate values are re-rolled until unique or until the safety limit is reached.

When specified as a boolean true, applies to all dice. UniqueOptions may specify a notUnique list of values exempt from the uniqueness constraint.

Pool size: Unchanged.

Aliases: None.

6.5.4 Drop

Primitive | Stage 2 | Filter | Pool channel | Priority 65

Notation: L, Ln, H, Hn, D{condition-list}

Options: DropOptions (highest, lowest, and/or comparison conditions)

Effect: Removes dice from the pool. L drops the lowest-valued die (or Ln drops the N lowest). H drops the highest-valued die (or Hn drops the N highest). D{...} drops dice matching comparison conditions.

When both positional (highest/lowest) and conditional drops are specified, conditional filtering is applied first, then positional drops operate on the remaining pool.

Drop runs after all explosion-family modifiers (priority 50—55), so the filter operates on the fully expanded pool.

Pool size: Shrinks.

Validation: The total number of dice dropped MUST be less than the pool size. Dropping all dice is an error.

Aliases: Keep (Section 6.7.1), Keep Middle (Section 6.7.2).

6.5.5 Keep

Alias | Stage 2 | Filter | Pool channel | Priority 66

Notation: K, Kn, kl, klN

De-aliases to: Drop (inverse). Keeping the highest N dice from a pool of Q dice is equivalent to dropping the lowest (Q - N) dice.

Pool size: Shrinks.

Aliases: None (is itself an alias).

6.5.6 Explode

Primitive | Stage 2 | Generate | Pool channel | Priority 50

Notation: !

Options: boolean | ComparisonOptions

Effect: Each die showing its maximum value triggers one additional die roll appended to the pool. This is a single-pass operation: newly added dice are not evaluated for further explosions. This is a known limitation of the current implementation.

Implementation note: The RANDSUM roller applies explode in a single pass. Newly added dice that also show the maximum value do not trigger further explosions in the current implementation.

Conditional Explode (!{condition}): When a condition expression is provided, the explosion triggers on values matching the condition instead of only on the maximum value. Bare ! with no condition defaults to triggering on the die’s maximum face value.

Pool size: Grows (one new die per triggered explosion per pass).

Aliases: None.

6.5.7 Explode Sequence

Primitive | Stage 2 | Generate | Pool channel | Priority 53

Notation: !s{N1,N2,...}

Options: number[] (sequence of die sizes)

Effect: On a maximum roll, instead of re-rolling the same die, the next die in the provided size sequence is rolled. If that die also shows its maximum, the sequence advances again. When the sequence is exhausted, the last die size repeats (capped by the explosion depth limit).

Pool size: Grows.

Aliases: Inflation (Section 6.7.9), Reduction (Section 6.7.10).

6.5.8 Compound

Primitive | Stage 2 | Accumulate | Pool channel | Priority 51

Notation: !!, !!N

Options: boolean | number | ComparisonOptions (explosion depth; true = default depth, 0 = unlimited up to safety cap, integer N = max N additional rolls)

Effect: Like Explode, but instead of adding new dice to the pool, each additional roll is added to the triggering die’s value. Pool size is preserved. The resulting die value may exceed the die’s maximum face value.

Conditional Compound (!!{condition}): When a condition expression is provided, the compound triggers on values matching the condition instead of only on the maximum value.

Pool size: Preserved.

Aliases: None.

6.5.9 Penetrate

Primitive | Stage 2 | Accumulate | Pool channel | Priority 52

Notation: !p, !pN

Options: boolean | number | ComparisonOptions (explosion depth)

Effect: Like Compound, but each subsequent roll has 1 subtracted from its value before accumulation. On a maximum roll, the die is re-rolled, 1 is subtracted from the new roll, and the result is added to the triggering die’s accumulated total. This continues while subsequent rolls also hit the maximum, up to the depth limit.

Conditional Penetrate (!p{condition}): When a condition expression is provided, the penetrate triggers on values matching the condition instead of only on the maximum value.

Pool size: Preserved.

Aliases: None.

6.5.10 Wild Die

Macro | Stage 2 | Dispatch | Pool channel | Priority 55

Notation: W

Options: boolean

Effect: The Wild Die macro implements the D6 System wild die mechanic. It examines the last die in the pool and dispatches:

  • Maximum value: Compound-explode the wild die (Accumulate behavior). The wild die’s value is replaced with the accumulated total.
  • Value of 1: Drop the wild die AND the highest remaining non-wild die (Filter behavior). Pool shrinks by 2.
  • Any other value: No operation. Pool unchanged.

Wild Die requires rollOne because the compound-explosion path introduces randomness.

Pool size: Varies (preserved on max, shrinks by 2 on 1, unchanged otherwise).

Aliases: None.

6.6 Stage 3 — Total Derivation

6.6.1 Contract

Stage 3 modifiers:

  • MUST NOT modify the pool array (mutatesRolls = false).
  • Operate exclusively on the scalar total via transformTotal.
  • The pool is frozen: its contents are final after Stage 2 completes.

Presentation directive carve-out: Presentation directives (Sort) MAY reorder the pool array but MUST NOT alter its values or the total. Sort does not violate the Stage 3 immutability contract because it changes only presentation order, not values.

6.6.2 Count

Primitive | Stage 3 | Reinterpret | Total channel | Priority 80

Notation: #{condition-list}

Options: CountOptions (comparison conditions, optional deduct flag)

Effect: Replaces the default sum aggregation with a cardinality count. Instead of summing all die values, the total becomes the number of dice matching the specified conditions.

Count is the only modifier that changes what the total means rather than what the total is. All subsequent Scale modifiers operate on the count result, not the original sum.

Dual-condition deduct mode: When both an upper condition (greaterThan/greaterThanOrEqual) and a lower condition (lessThan/lessThanOrEqual) are specified, the modifier automatically activates deduct mode. Dice matching the upper condition are counted as successes; dice matching the lower condition are counted as failures and subtracted from the success count.

Pool size: N/A (Total channel).

Aliases: Count Successes (Section 6.7.7), Count Failures (Section 6.7.8).

6.6.3 Multiply

Primitive | Stage 3 | Scale | Total channel | Priority 85

Notation: *N

Options: number

Effect: Multiplies the current total by N. This is a pre-arithmetic multiplication: it runs before Plus/Minus (priority 90/91) but after Count (priority 80).

Pool size: N/A (Total channel).

Aliases: Multiply Total (Section 6.7.6).

6.6.4 Plus

Primitive | Stage 3 | Scale | Total channel | Priority 90

Notation: +N

Options: number

Effect: Adds N to the current total.

Pool size: N/A (Total channel).

Aliases: Minus (Section 6.7.4), Margin of Success (Section 6.7.5).

6.6.5 Integer Divide

Primitive | Stage 3 | Scale | Total channel | Priority 93

Notation: //N

Options: number

Effect: Divides the current total by N using truncating integer division (round toward zero).

Pool size: N/A (Total channel).

Aliases: None.

6.6.6 Modulo

Primitive | Stage 3 | Scale | Total channel | Priority 94

Notation: %N

Options: number

Effect: Replaces the current total with the remainder of dividing by N (total mod N).

Pool size: N/A (Total channel).

Aliases: None.

6.7 Modifier Aliases

Each alias de-aliases to a normative primitive form. An alias MUST produce identical observable behavior to its de-aliased form.

6.7.1 Keep

Notation: K, Kn, kl, klN

De-aliases to: Drop (inverse).

Keeping the highest N dice from a pool of Q dice is equivalent to dropping the lowest (Q - N) dice. KN on a pool of Q dice de-aliases to L(Q-N). klN (keep lowest) de-aliases to H(Q-N).

When N is omitted, it defaults to 1.

Inherits: Stage 2 | Filter | Pool channel | Priority 66.

6.7.2 Keep Middle

Notation: KM

De-aliases to: Drop lowest 1 + Drop highest 1.

Removes both the lowest and highest die from the pool, keeping only the middle values.

Inherits: Stage 2 | Filter | Pool channel | Priority 66.

6.7.3 Reroll Once

Notation: ro{condition-list}

De-aliases to: Reroll with max: 1.

Rerolls matching dice at most once. The new result stands regardless of whether it still matches the condition.

Inherits: Stage 2 | Substitute | Pool channel | Priority 40.

6.7.4 Minus

Notation: -N

De-aliases to: Plus with negated operand. -N is equivalent to +(-N).

Inherits: Stage 3 | Scale | Total channel | Priority 91.

6.7.5 Margin of Success

Notation: ms{N}

De-aliases to: Minus N, which itself de-aliases to Plus (-N). This is a transitive de-aliasing chain: ms{N} -> -N -> +(-N).

Subtracts a target number from the total to compute how far above or below the target the roll landed.

Inherits: Stage 3 | Scale | Total channel | Priority 91.

6.7.6 Multiply Total

Notation: **N

De-aliases to: Multiply at priority 100 (post-arithmetic phase).

Unlike Multiply (*N, priority 85) which runs before Plus/Minus, Multiply Total runs after all arithmetic modifiers have been applied.

Inherits: Stage 3 | Scale | Total channel | Priority 100.

6.7.7 Count Successes

Notation: S{N}

De-aliases to: Count with greaterThanOrEqual: N. Optionally S{N,B} de-aliases to Count with greaterThanOrEqual: N, lessThanOrEqual: B, deduct: true.

Counts dice meeting or exceeding threshold N. Used in dice pool systems (e.g., World of Darkness).

Inherits: Stage 3 | Reinterpret | Total channel | Priority 80.

6.7.8 Count Failures

Notation: F{N}

De-aliases to: Count with lessThanOrEqual: N.

Counts dice at or below threshold N.

Inherits: Stage 3 | Reinterpret | Total channel | Priority 80.

6.7.9 Inflation

Notation: !i

De-aliases to: Explode Sequence with the ascending TTRPG standard die set: !s{4,6,8,10,12,20,100}.

On a maximum roll, the next die in the standard ascending sequence is rolled.

Inherits: Stage 2 | Generate | Pool channel | Priority 53.

6.7.10 Reduction

Notation: !r

De-aliases to: Explode Sequence with the descending TTRPG standard die set: !s{100,20,12,10,8,6,4}.

On a maximum roll, the next die in the standard descending sequence is rolled.

Inherits: Stage 2 | Generate | Pool channel | Priority 53.

6.8 Non-Modifier Notation Features

The following features appear in notation but are not modifiers in the pipeline sense.

6.8.1 Sort

Classification: Presentation Directive

Notation: sa (ascending), sd (descending)

Priority: 95

Effect: Reorders the pool array for display purposes. Sort does not alter the total. It runs in Stage 3 by execution ordering (the pool is frozen before sort runs), but produces no arithmetic change.

Sort is the only feature that modifies the pool array in Stage 3. This is a presentation-only reordering: the set of values is unchanged, only their order differs.

6.8.2 Annotations

Classification: Notation Metadata

Notation: [text]

Priority: None (no pipeline participation)

Effect: Attaches a label or descriptor to a die expression. Annotations have no effect on rolls, pools, or totals. They are preserved for display and logging purposes.

Examples: 2d6+3[fire], 1d8[healing].

6.8.3 Repeat

Classification: Parser Directive

Notation: xN

Priority: None (pre-pipeline expansion)

Effect: Expands a single die expression into N independent roll evaluations. 4d6Lx6 is equivalent to rolling 4d6L six separate times, producing six independent results.

Repeat is resolved at parse time before the execution pipeline runs. Each repeated expression is evaluated independently with its own pool, modifiers, and total.

6.9 Modifier Composition Rules

When multiple modifiers are applied to the same die expression, the following composition rules govern their interaction:

Count + Scale: Count (priority 80) replaces the sum with a cardinality count before any Scale modifiers run. Plus (+N, priority 90), Minus (-N, priority 91), Multiply (*N, priority 85), and other Scale modifiers operate on the count result, not the original sum. Example: 5d10S{7}+2 counts successes >= 7, then adds 2 to that count.

Explosion + Filter: Explosions (Stage 2, priority 50—55) run before drop/keep (priority 65—66), so the pool is fully expanded before filtering. 4d6L! explodes first, then drops the lowest from the expanded pool — matching Roll20 and Foundry VTT conventions.

Cap + Drop: Cap (priority 10) runs before Drop (priority 65). A value that would have been dropped may first be capped, potentially changing which dice are “lowest” or “highest”. Example: 4d6C{>5}L caps all values at 5, then drops the lowest of the capped results.

Multiply + Plus: Multiply (priority 85) runs before Plus (priority 90). 2d6*2+3 doubles the sum first, then adds 3. To multiply after arithmetic, use Multiply Total (**N, priority 100): 2d6+3**2 adds 3 first, then doubles the result.

Count + Count: Multiple Count modifiers on the same expression are not supported. The behavior is undefined. Implementations SHOULD reject notation containing more than one Count-family modifier.


7. Operational Groups (Informative)

See Appendix E for the operational group reference.


8. Notation Syntax

This section provides a brief overview of notation syntax. The full syntax is defined in this specification. For a practical guide with interactive examples, see https://randsum.dev/notation/randsum-dice-notation/.

8.0 Character Encoding

RDN notation strings are sequences of Unicode scalar values. Implementations SHOULD accept UTF-8 encoded input. All syntactic tokens (d, L, H, K, C, R, V, etc.) are drawn from the ASCII subset. Annotation text ([text]) and custom face labels (d{face1,face2}) MAY contain arbitrary Unicode text excluding their respective closing delimiters (] and }). Implementations that render annotation text in HTML MUST sanitize against injection attacks (see Section 9.6).

8.1 Case Insensitivity

All RDN notation is case-insensitive. 2d8, 2D8, 2d8l, and 2D8L are equivalent. Implementations MUST treat uppercase and lowercase notation identically.

8.2 Whitespace

RDN notation strings MUST NOT contain whitespace between tokens. 4d6L is valid; 4 d6 L is not. Implementations MAY strip whitespace from input as a preprocessing convenience, but MUST NOT rely on whitespace for semantic meaning. Leading and trailing whitespace MUST be ignored. Whitespace within annotation text ([fire damage]) and custom face values (d{fire, ice}) is preserved as part of the text content.

8.3 Lexical Segmentation

RDN notation is parsed left-to-right. After the core die expression (NdS or special die type) is consumed, the remaining suffix is matched against modifier patterns in a longest-match, priority-ordered fashion. When two modifier patterns could match at the same position, the more specific pattern takes precedence (e.g., !! is matched as Compound before ! is matched as Explode; ** is matched as Multiply Total before * is matched as Multiply).

Any characters in the notation string that do not match a recognized die expression, modifier, annotation, or repeat operator MUST cause the implementation to reject the notation as invalid. Implementations MUST NOT silently discard unrecognized characters.

Disambiguation rules:

  • S followed by { is Count Successes, not Sort
  • S followed by a or d (not followed by { or a digit) is Sort
  • d{...} or D{...} at the die-core position (start of expression or after +/- pool separator) is Custom Faces. D{...} at a modifier position (after a die-core has been consumed) is conditional Drop. Case-insensitive matching applies to token identity; positional context resolves the ambiguity.
  • !! is Compound; ! alone is Explode; !p is Penetrate; !s{...} is Explode Sequence; !i is Inflation; !r is Reduction
  • ** is Multiply Total; * is Multiply
  • // is Integer Divide
  • +NdS or -NdS after a core die is an additional pool, not arithmetic Plus/Minus

8.4 Base Syntax

The base die expression follows the form NdS where:

  • N is the quantity of dice (positive integer, default 1 if omitted)
  • d is the die separator (literal character)
  • S is the number of sides (positive integer)

Special die types replace the dS portion: d%, dF, dF.2, d{...}, zN, gN, DDN.

8.5 Modifier Suffix Chaining

Modifiers are appended as suffixes to the base die expression. Multiple modifiers chain left to right in notation, but execute in priority order regardless of notation position.

4d6L!+2    -- Drop lowest, explode, add 2
            -- Execution: Explode(50) -> Drop(65) -> Plus(90)

The notation order does not determine execution order. Priority ordering (Section 6.3) is the sole determinant.

8.6 Annotations

Annotations are enclosed in square brackets and may appear at the end of a die expression:

2d6+3[fire damage]
1d8[healing]

Annotations do not affect the roll result. They are metadata only.

8.7 Multi-Roll Expressions

Multiple die expressions within a single notation string are combined via arithmetic operators. + introduces an additive pool and - introduces a subtractive pool: 1d20+5+2d6 rolls 1d20, adds 5, and adds the result of 2d6.

Comma-separated notation (e.g., 1d20+5, 2d6) is NOT part of the RDN grammar. Implementations that accept multiple independent roll expressions SHOULD provide a separate API mechanism (e.g., variadic arguments, array input) rather than overloading the notation string.

8.8 Repeat Operator

The repeat operator xN expands a single expression into N independent evaluations:

4d6Lx6    -- Six independent rolls of 4d6-drop-lowest

Repeat is a parser directive resolved before the execution pipeline.


9. Safety and Limits

Implementations MUST enforce safety limits to prevent unbounded computation.

9.1 Explosion Depth

Explode, Compound, and Penetrate modifiers have a default explosion depth cap of 1000 iterations. When a depth of 0 is specified (unlimited), the implementation MUST still cap at 1000.

Implementations MAY allow configuration of this limit but MUST NOT allow it to be disabled entirely.

9.2 Geometric Die Cap

Geometric dice (gN) MUST terminate after at most 1000 iterations, even if every roll equals the maximum.

9.3 Reroll Attempts

The Reroll modifier MUST terminate after at most 99 re-roll attempts per die. If the condition is still matched after 99 attempts, the current value stands.

9.4 Pool Size Considerations

Implementations SHOULD impose a reasonable upper bound on pool size to prevent memory exhaustion. Explosion-family modifiers (Explode, Explode Sequence) can grow the pool unboundedly in theory. The explosion depth cap (Section 9.1) provides practical limits.

Implementations MAY reject die expressions where the initial pool size exceeds an implementation-defined maximum. Such limits SHOULD be documented and SHOULD be at least 1000 dice.

9.5 Error Semantics

Conforming implementations MUST reject invalid notation before execution and MUST signal an error. The error signaling mechanism is implementation-defined (exceptions, error objects, result types). Implementations MUST NOT silently ignore invalid notation or produce a result from partially-parsed input.

Examples of invalid notation that MUST be rejected:

  • Malformed expressions (e.g., 4d, d, 2d6LL)
  • Out-of-range values (e.g., d0, negative pool sizes)
  • Notation that violates explicit constraints defined in this specification

9.6 Security Considerations

RDN notation strings MAY originate from untrusted sources (user input, network messages, database records). Implementations MUST consider the following security implications:

Denial of Service: Crafted notation can cause excessive computation. The explosion depth cap (Section 9.1), geometric die iteration cap (Section 9.2), and reroll attempt cap (Section 9.3) provide baseline protection, but implementations SHOULD impose additional limits on:

  • Total pool size (number of dice across all pools)
  • Repeat operator count (xN — large N values generate many independent evaluations)
  • Input string length

Input Validation: Implementations MUST validate notation strings before execution. Notation strings MUST NOT be interpolated into shell commands, SQL queries, or other injection-susceptible contexts without proper escaping. The annotation feature ([text]) permits arbitrary text content — implementations that display annotations MUST sanitize them against cross-site scripting (XSS) if rendered in HTML contexts.

Resource Exhaustion: Implementations SHOULD set timeouts on notation evaluation to prevent unbounded computation from blocking other operations.

Randomness: RDN does not require cryptographically secure random number generation. Pseudorandom number generators (PRNGs) are acceptable for tabletop gaming use cases. Implementations used in contexts where roll integrity matters (e.g., gambling, competitive play) SHOULD use a CSPRNG and SHOULD document their randomness source.

Annotation Privacy: Annotation text ([text]) may contain personally identifiable information (PII) or sensitive context (e.g., character names, campaign details). Implementations that log, persist, or transmit roll results SHOULD treat annotation content as potentially sensitive and apply appropriate data handling policies.


10. Conformance Levels

Implementations MAY claim partial conformance to this specification at one of four levels. Each level is a strict superset of the previous level.

10.1 Level 1 — Core

Universal features supported by all major dice platforms (Roll20, Foundry VTT, Avrae, rpg-dice-roller, Sophie’s Dice, GNOLL, Dice Maiden).

FeatureNotationLevel
Standard diceNdS1
Plus+N1
Minus-N1
Multiply*N1
DropL, H, D{...}1
KeepK, kl1
RerollR{...}2
Reroll Oncero{...}2
Explode!2
Conditional Explode!{condition}2
Count#{...}2
Count SuccessesS{N}2
Count FailuresF{N}2
Condition ExpressionsSection 52
CapC{...}3
Compound!!3
Penetrate!p3
Sortsa, sd3
UniqueU3
Custom Facesd{...}3
Keep MiddleKM3
ReplaceV{...}3
Multiply Total**N3
Integer Divide//N3
Modulo%N3
Percentile diced%3
Fate/Fudge dicedF, dF.23
Annotations[text]3
Zero-Bias dicezN4
Geometric dicegN4
Draw diceDDN4
RepeatxN4
Explode Sequence!s{...}4
Inflation!i4
Reduction!r4
Wild DieW4
Conditional Compound!!{condition}4
Conditional Penetrate!p{condition}4
Margin of Successms{N}4

10.2 Level 2 — VTT Baseline

Features supported by 5+ of 7 major platforms. This level covers running games on any mainstream VTT — D&D 5e, World of Darkness, Fate Core, PbtA, and most published systems. Includes all Level 1 features plus the features marked Level 2 in the table above.

10.3 Level 3 — Extended

Features supported by 2—4 major platforms. Covers Savage Worlds (Compound), Hackmaster (Penetrate), Fate Core (dF), custom dice systems, and advanced pool mechanics. Includes all Level 2 features plus the features marked Level 3 in the table above.

10.4 Level 4 — Full

RANDSUM extensions and features with 0—1 platform precedent. Includes all Level 3 features plus the features marked Level 4 in the table above.

10.5 Partial Conformance Claims

An implementation claiming conformance MUST state the level and version:

"RDN v1.0 Level 2 Conformant"

An implementation MAY support individual features from a higher level without claiming that level, provided all features of the claimed level are fully supported.


11. IANA Considerations

This document has no IANA actions at this time. A future version of this specification MAY register a media type for RDN notation strings (e.g., text/x-dice-notation) if protocol-level identification becomes necessary.

12. References

12.1 Normative References

  • [BCP14] Bradner, S., “Key words for use in RFCs to Indicate Requirement Levels”, BCP 14, RFC 2119, March 1997; Leiba, B., “Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words”, BCP 14, RFC 8174, May 2017.
  • [RFC5234] Crocker, D., Ed. and P. Overell, “Augmented BNF for Syntax Specifications: ABNF”, STD 68, RFC 5234, January 2008.
  • [RFC7405] Kyzivat, P., “Case-Sensitive String Support in ABNF”, RFC 7405, December 2014.

12.2 Informative References


Appendix A: Priority Table

Complete modifier priority ordering. Modifiers execute in ascending priority order.

PriorityNameStageVerbChannelStatus
10Cap1ClampPoolPrimitive
30Replace1MapPoolPrimitive
40Reroll2SubstitutePoolPrimitive
50Explode2GeneratePoolPrimitive
51Compound2AccumulatePoolPrimitive
52Penetrate2AccumulatePoolPrimitive
53Explode Sequence2GeneratePoolPrimitive
55Wild Die2DispatchPoolMacro
60Unique2SubstitutePoolPrimitive
65Drop2FilterPoolPrimitive
66Keep2FilterPoolAlias
80Count3ReinterpretTotalPrimitive
85Multiply3ScaleTotalPrimitive
90Plus3ScaleTotalPrimitive
91Minus3ScaleTotalAlias
93Integer Divide3ScaleTotalPrimitive
94Modulo3ScaleTotalPrimitive
95Sort3PoolDirective
100Multiply Total3ScaleTotalAlias

Appendix B: Alias De-Aliasing Table

AliasNotationPrimitiveDe-Aliasing Rule
KeepKNDropKN on Q dice = Drop lowest (Q - N)
Keep (lowest)klNDropklN on Q dice = Drop highest (Q - N)
Keep MiddleKMDropDrop lowest 1 + Drop highest 1
Reroll Oncero{...}RerollReroll with max: 1
Minus-NPlusPlus with negated operand: +(-N)
Margin of Successms{N}PlusMinus N -> Plus (-N). Transitive chain.
Multiply Total**NMultiplyMultiply at priority 100 (post-arithmetic)
Count SuccessesS{N}CountCount with greaterThanOrEqual: N
Count FailuresF{N}CountCount with lessThanOrEqual: N
Inflation!iExplode Sequence!s{4,6,8,10,12,20,100} (ascending)
Reduction!rExplode Sequence!s{100,20,12,10,8,6,4} (descending)

Appendix C: Full Faceted Records

Complete faceted classification for every modifier, alias, macro, and directive in RDN.

ModifierNotationStatusStageVerbChannelPriorityPool SizeOptionsGroup
CapC{...}Primitive1ClampPool10UnchangedComparisonOptionsValue Transformers (E.1)
ReplaceV{...}Primitive1MapPool30UnchangedReplaceOptionsValue Transformers (E.1)
RerollR{...}Primitive2SubstitutePool40UnchangedRerollOptionsPool Shapers (E.2)
Reroll Oncero{...}Alias -> Reroll2SubstitutePool40UnchangedRerollOptions (max: 1)Pool Shapers (E.2)
Explode!Primitive2GeneratePool50Growsboolean | ComparisonOptionsExplosion Variants (E.3)
Compound!!Primitive2AccumulatePool51Preservedboolean | number | ComparisonOptionsExplosion Variants (E.3)
Penetrate!pPrimitive2AccumulatePool52Preservedboolean | number | ComparisonOptionsExplosion Variants (E.3)
Explode Sequence!s{...}Primitive2GeneratePool53Growsnumber[]Explosion Variants (E.3)
Inflation!iAlias -> Explode Sequence2GeneratePool53Growsnumber[] (fixed: [4,6,8,10,12,20,100])Explosion Variants (E.3)
Reduction!rAlias -> Explode Sequence2GeneratePool53Growsnumber[] (fixed: [100,20,12,10,8,6,4])Explosion Variants (E.3)
Wild DieWMacro2DispatchPool55VariesbooleanExplosion Variants (E.3)
UniqueUPrimitive2SubstitutePool60Unchangedboolean | UniqueOptionsPool Shapers (E.2)
DropL, H, D{...}Primitive2FilterPool65ShrinksDropOptionsPool Shapers (E.2)
KeepK, klAlias -> Drop2FilterPool66ShrinksKeepOptionsPool Shapers (E.2)
Keep MiddleKMAlias -> Drop2FilterPool66Shrinks(none)Pool Shapers (E.2)
Count#{...}Primitive3ReinterpretTotal80N/ACountOptionsCounting (E.5)
Count SuccessesS{N}Alias -> Count3ReinterpretTotal80N/ACountOptions (greaterThanOrEqual: N)Counting (E.5)
Count FailuresF{N}Alias -> Count3ReinterpretTotal80N/ACountOptions (lessThanOrEqual: N)Counting (E.5)
Multiply*NPrimitive3ScaleTotal85N/AnumberArithmetic (E.4)
Plus+NPrimitive3ScaleTotal90N/AnumberArithmetic (E.4)
Minus-NAlias -> Plus3ScaleTotal91N/AnumberArithmetic (E.4)
Margin of Successms{N}Alias -> Plus (via Minus)3ScaleTotal91N/AnumberArithmetic (E.4)
Integer Divide//NPrimitive3ScaleTotal93N/AnumberArithmetic (E.4)
Modulo%NPrimitive3ScaleTotal94N/AnumberArithmetic (E.4)
Sortsa/sdPresentation Directive3Pool (display only)95Unchanged’asc’ | ‘desc’Display (E.6)
Multiply Total**NAlias -> Multiply3ScaleTotal100N/AnumberArithmetic (E.4)

Appendix D: Four-Gate Test for Extensions

Any proposed addition to the RANDSUM Dice Notation MUST pass all four gates:

Gate 1: Mechanical

The feature MUST operate on dice values, the dice pool, or the total. Features that do not interact with the dice pipeline are out of scope for RDN. (They may belong in game-specific specifications.)

Gate 2: Game-Agnostic Describable

The feature MUST be explainable without naming a specific game system. “Reroll dice below 3” passes. “Roll Blades in the Dark resistance” fails. Game-specific mechanics belong in game packages, not in the notation.

Gate 3: Precedented

The feature MUST be supported by at least 2 other dice platforms (Roll20, FoundryVTT, Avrae, rpg-dice-roller, etc.) OR be used by at least 3 published tabletop game systems.

Gate 4: Composable

The feature MUST work with existing modifiers without introducing a new return type, channel, or pipeline stage. It MUST be assignable to an existing verb and stage, or the proposal MUST include a justification for extending the taxonomy.

All four gates MUST pass. A feature that fails any single gate is rejected. The proposer MAY revise the feature to address the failing gate and resubmit.


Appendix E: Operational Groups (Informative)

This appendix provides a player-facing view of modifiers organized by what they do, rather than by pipeline stage. This grouping is informative and does not override the normative definitions in Section 6.

E.1 Value Transformers

Modifiers that change individual die values without adding or removing dice.

ModifierNotationEffect
CapC{...}Clamp values to boundaries
ReplaceV{...}Substitute specific values

E.2 Pool Shapers

Modifiers that change which dice remain in the pool or re-randomize their values.

ModifierNotationTypeEffect
DropL, H, D{...}PrimitiveRemove dice from pool
KeepK, klAlias (Drop)Keep N dice, drop the rest
Keep MiddleKMAlias (Drop)Drop lowest and highest
RerollR{...}PrimitiveRe-roll matching dice
Reroll Oncero{...}Alias (Reroll)Re-roll matching dice at most once
UniqueUPrimitiveEnforce no duplicate values

E.3 Explosion Variants

Modifiers that generate additional dice or accumulate values on trigger conditions.

ModifierNotationTypeEffect
Explode!PrimitiveAdd new die on max
Compound!!PrimitiveFold extra rolls into existing die
Penetrate!pPrimitiveFold extra rolls minus 1
Explode Sequence!s{...}PrimitiveStep through die sizes
Inflation!iAlias (Explode Sequence)Ascending standard set
Reduction!rAlias (Explode Sequence)Descending standard set
Wild DieWMacroD6 System wild die dispatch

E.4 Arithmetic

Modifiers that perform arithmetic on the total.

ModifierNotationTypeEffect
Plus+NPrimitiveAdd N to total
Minus-NAlias (Plus)Subtract N from total
Margin of Successms{N}Alias (Plus)Subtract target N from total
Multiply*NPrimitiveMultiply total (pre-arithmetic)
Multiply Total**NAlias (Multiply)Multiply total (post-arithmetic)
Integer Divide//NPrimitiveTruncating division
Modulo%NPrimitiveRemainder

E.5 Counting

Modifiers that replace the summation model with a count.

ModifierNotationTypeEffect
Count#{...}PrimitiveCount dice matching conditions
Count SuccessesS{N}Alias (Count)Count dice >= N
Count FailuresF{N}Alias (Count)Count dice <= N

E.6 Display

Notation features that affect presentation without altering the total.

FeatureNotationEffect
Sortsa, sdReorder pool ascending/descending

Appendix F: Formal Grammar (ABNF)

This appendix provides a formal grammar for RDN notation per RFC 5234 (ABNF) with the case-sensitive string extension from RFC 7405. All alphabetic literals use %i (case-insensitive). This grammar assumes whitespace-stripped input (Section 8.2).

Six prose constraints supplement the grammar where ABNF cannot express negative lookahead or ordered alternation:

  • P1: mod-sort MUST NOT match when S/s is immediately followed by { or a digit. Implementations MUST attempt mod-count-successes before mod-sort.
  • P2: When input contains ** followed by digits, implementations MUST match mod-multiply-total, not mod-multiply followed by stray *.
  • P3: When input begins with !, implementations MUST attempt matches in order: !! (compound), !p (penetrate), !s{ (explode sequence), !i (inflation), !r (reduction), then bare ! (explode).
  • P4: When +/- is followed by digits then d then digits, implementations MUST parse as an additional dice pool, not arithmetic.
  • P5: A conforming parser MUST reject any die-expression containing more than one Count-family modifier (#{}, S{}, F{}).
  • P6: Implementations MUST strip all whitespace from the notation string before grammatical parsing, except within annotation delimiters ([...]) and custom face delimiters (d{...}), where whitespace is preserved as content.
;; ===================================================================
;; RANDSUM Dice Notation (RDN) v0.9.0
;; Augmented Backus-Naur Form (ABNF) per RFC 5234 / RFC 7405
;; ===================================================================

;; Top-Level
rdn-input         = die-expression
die-expression    = die-core *modifier [repeat] [annotation]

;; Core Die Types
die-core          = draw-die / geometric-die / fate-die / zero-bias-die
                  / custom-faces-die / percentile-die / standard-die
standard-die      = [quantity] %i"d" positive-integer
custom-faces-die  = [quantity] %i"d" "{" face-list "}"
face-list         = face-value *( "," face-value )
face-value        = ["-"] 1*DIGIT / 1*( ALPHA / DIGIT / "-" / "_" / SP )
geometric-die     = [quantity] %i"g" positive-integer
draw-die          = [quantity] %i"dd" positive-integer
percentile-die    = [quantity] %i"d" "%"
fate-die          = [quantity] %i"dF" ["." ("1" / "2")]
zero-bias-die     = [quantity] %i"z" positive-integer
quantity          = positive-integer

;; Condition Expressions
condition-block   = "{" condition-list "}"
condition-list    = condition *( "," condition )
condition         = comparison-op integer / integer
comparison-op     = ">=" / "<=" / ">" / "<" / "="

;; Modifiers (ordered by specificity for disambiguation)
modifier          = mod-cap / mod-replace / mod-reroll-once / mod-reroll
                  / mod-explode-seq / mod-inflation / mod-reduction
                  / mod-compound / mod-penetrate / mod-explode
                  / mod-wild-die / mod-unique
                  / mod-drop-conditional / mod-drop-highest / mod-drop-lowest
                  / mod-keep-middle / mod-keep-lowest / mod-keep
                  / mod-count-successes / mod-count-failures / mod-count
                  / mod-multiply-total / mod-multiply
                  / mod-integer-divide / mod-modulo
                  / mod-margin-of-success / mod-minus / mod-plus
                  / mod-sort / mod-add-pool

;; Stage 1: Deterministic Value Shaping
mod-cap           = %i"C" condition-block
mod-replace       = %i"V" "{" replace-list "}"
replace-list      = replace-pair *( "," replace-pair )
replace-pair      = [comparison-op] non-neg-integer "=" non-neg-integer

;; Stage 2: Pool Dynamics
mod-reroll        = %i"R" condition-block [non-neg-integer]
mod-reroll-once   = %i"ro" condition-block
mod-explode       = "!" [condition-block]
mod-compound      = "!!" [non-neg-integer] [condition-block]
mod-penetrate     = "!" %i"p" [non-neg-integer] [condition-block]
mod-explode-seq   = "!" %i"s" "{" integer-list "}"
mod-inflation     = "!" %i"i"
mod-reduction     = "!" %i"r"
mod-wild-die      = %i"W"
mod-unique        = %i"U" ["{" non-neg-integer *("," non-neg-integer) "}"]
mod-drop-lowest   = %i"L" [positive-integer]
mod-drop-highest  = %i"H" [positive-integer]
mod-drop-conditional = %i"D" condition-block
mod-keep          = %i"K" [positive-integer]
mod-keep-lowest   = %i"kl" [positive-integer]
mod-keep-middle   = %i"km"

;; Stage 3: Total Derivation
mod-count         = "#" condition-block
mod-count-successes = %i"S" "{" positive-integer ["," positive-integer] "}"
mod-count-failures = %i"F" "{" positive-integer "}"
mod-multiply      = "*" positive-integer
mod-plus          = "+" non-neg-integer
mod-minus         = "-" non-neg-integer
mod-integer-divide = "//" positive-integer
mod-modulo        = "%" positive-integer
mod-sort          = %i"sa" / %i"sd"
mod-multiply-total = "**" positive-integer
mod-margin-of-success = %i"ms" "{" positive-integer "}"

;; Additional Pool
mod-add-pool      = ("+" / "-") positive-integer %i"d" positive-integer

;; Non-Modifier Features
repeat            = %i"x" positive-integer
annotation        = "[" 1*( %x20-5C / %x5E-7E / UTF8-non-ascii ) "]"
;; Unicode scalar values above ASCII, excluding surrogates
UTF8-non-ascii    = %x80-D7FF / %xE000-10FFFF

;; Numeric Primitives
positive-integer  = %x31-39 *DIGIT
non-neg-integer   = "0" / positive-integer
integer           = ["-"] non-neg-integer
integer-list      = positive-integer *( "," positive-integer )
DIGIT             = %x30-39
ALPHA             = %x41-5A / %x61-7A
SP                = %x20
WSP               = SP / %x09

Appendix G: Conformance Test Vectors

The following test vectors enable independent implementors to verify conformance with RDN v0.9.0. Each vector specifies a notation input, fixed dice values (the raw values the RNG would produce, in order), the expected pool after all modifiers, and the expected total.

Conventions:

  • “Seed/Rolls” lists the raw die values produced by the RNG, in order consumed
  • “Expected Pool” is the pool array after all modifiers have executed
  • “Expected Total” is the scalar result after total derivation
  • “ERROR” means the implementation MUST reject the notation

G.1 Dice Expressions

#NotationSeed/RollsExpected PoolExpected TotalSection
11d20[14][14]144.1
2d20[14][14]144.1
33d6[3, 5, 2][3, 5, 2]104.1
4d%[73][73]734.5.1
54dF[-1, 0, 1, 1][-1, 0, 1, 1]14.5.2
61dF.2[-2][-2]-24.5.2

G.2 Stage 1 Modifiers

#NotationSeed/RollsExpected PoolExpected TotalSection
74d6C{5}[6, 3, 5, 6][5, 3, 5, 5]186.4.2
84d6V{1=6,3=5}[1, 3, 4, 1][6, 5, 4, 6]216.4.3

G.3 Stage 2 Modifiers

#NotationSeed/RollsExpected PoolExpected TotalSection
94d6R{1}[1, 3, 5, 2] reroll: [4][4, 3, 5, 2]146.5.2
104d6L[3, 5, 2, 6][3, 5, 6]146.5.4
114d6H[3, 5, 2, 6][3, 5, 2]106.5.4
124d6![6, 3, 5, 2] explode: [4][6, 3, 5, 2, 4]206.5.6
134d6![3, 4, 2, 5][3, 4, 2, 5]146.5.6

G.4 Stage 3 Modifiers

#NotationSeed/RollsExpected PoolExpected TotalSection
142d6+5[3, 4][3, 4]126.6.4
152d6-3[4, 5][4, 5]66.7.4
162d6*3[2, 4][2, 4]186.6.3
172d6//3[4, 5][4, 5]36.6.5
185d10#{>=7}[8, 3, 10, 7, 2][8, 3, 10, 7, 2]36.6.2

G.5 Aliases

#NotationSeed/RollsExpected PoolExpected TotalSection
194d6K3[2, 5, 3, 6][5, 3, 6]146.7.1
204d6kl[2, 5, 3, 6][2]26.7.1
215d10S{7}[8, 3, 10, 7, 2][8, 3, 10, 7, 2]36.7.7
225d10F{3}[8, 3, 10, 1, 2][8, 3, 10, 1, 2]36.7.8
231d20ms{15}[18][18]36.7.5

G.6 Non-Modifier Features

#NotationSeed/RollsExpected PoolExpected TotalSection
244d6sa[3, 1, 5, 2][1, 2, 3, 5]116.8.1
252d6+3[fire][4, 5][4, 5]126.8.2

G.7 Case Insensitivity

#NotationSeed/RollsExpected PoolExpected TotalSection
262D6[3, 4][3, 4]78.1
274D6l[3, 5, 2, 6][3, 5, 6]148.1

G.8 Error Cases

#NotationExpectedSection
284dERROR9.5
29dERROR9.5
30d0ERROR9.5

G.9 Extended Coverage

#NotationSeed/RollsExpected PoolExpected TotalSection
312d{fire,ice,lightning}[face2=ice, face1=fire][ice, fire]N/A (string faces)4.2
32g6[6, 6, 3][6, 6, 3]154.3
333DD6[4, 1, 6][4, 1, 6]114.4
34z6[0][0]04.5.3
353d6U[3, 3, 5] reroll: [4][3, 4, 5]126.5.3
362d6!![6, 3] compound: [4][10, 3]136.5.8
372d6!p[6, 3] penetrate: [3][8, 3]116.5.9
385d6W[6, 3, 4, 2, 5][6, 3, 4, 2, 5]206.5.10
393d6!s{4,6,8}[4, 2, 5] sequence: [6][4, 2, 5, 6]176.5.7
402d6%4[3, 5][3, 5]06.6.6
412d6**2[3, 4][3, 4]146.7.6
424d6C{5}L!+2[6, 1, 5, 6] cap: [5, 1, 5, 5] explode: [3] drop: [1, 5, 5, 5, 3] -> drop lowestdepends on priority6.9
434d6ro{1}[1, 3, 5, 4] reroll: [2][2, 3, 5, 4]146.7.3
446d6KM[1, 4, 3, 5, 2, 6][4, 3, 5, 2]146.7.2
455d10#{>=7,<=2}[8, 1, 10, 7, 2][8, 1, 10, 7, 2]16.6.2

G.10 Additional Error Cases

#NotationExpectedSection
460d6ERROR9.5
475d10S{7}F{3}ERROR (multiple Count modifiers)6.9
484d6 LERROR (whitespace between tokens)8.2

G.11 Conformance Level Cross-Index

Implementors can verify conformance at each level using the following vector subsets:

LevelRequired VectorsFeatures Covered
Level 1 (Core)1-3, 10-11, 14-16, 19-20, 26-27NdS, +, -, *, L, H, K, kl
Level 2 (VTT Baseline)All Level 1 + 7, 9, 12-13, 18, 21-22, 25, 35, 40, 43, 45R, ro, !, !{}, #, S{}, F{}, conditions
Level 3 (Extended)All Level 2 + 4-6, 8, 23, 31, 34, 36-37, 41, 44C, !!, !p, U, d{}, dF, KM, V{}, **, //, %, d%
Level 4 (Full)All Level 3 + 32-33, 38-39gN, DDN, W, !s{}, zN
Error Cases28-30, 46-48Invalid notation rejection

Authors’ Addresses

Alex Jarvis RANDSUM Email: alxjrvs@gmail.com URI: https://github.com/alxjrvs


End of RANDSUM Dice Notation Specification v0.9.0 rev.1