Claude Code Skill
RANDSUM provides a dice rolling skill for LLM agents — a structured prompt and reference that enables AI assistants to roll dice using RANDSUM notation for any tabletop RPG system.
What is an LLM skill?
Section titled “What is an LLM skill?”An LLM skill is a markdown document that gives an AI assistant specialized knowledge. When an agent loads the RANDSUM dice rolling skill, it learns:
- RANDSUM dice notation — a compact syntax for any roll (
4d6L,2d20H+5,3d6!) - Game system mechanics — how to interpret rolls for D&D, Blades in the Dark, Daggerheart, PbtA, Root RPG, and Salvage Union
- Best practices — when to validate, how to explain results, matching the right system
The skill works with any LLM that supports tool use or structured prompts — Claude, ChatGPT, or custom agents.
The skill file lives at skills/dice-rolling/SKILL.md in the RANDSUM repository.
Place the skill file in your project’s .claude/skills/ directory:
# Download the skillcurl -o .claude/skills/dice-rolling/SKILL.md \https://raw.githubusercontent.com/RANDSUM/randsum/main/skills/dice-rolling/SKILL.mdLoad the skill content as part of your agent’s system prompt or tool definitions:
import { readFileSync } from 'fs'
const skillContent = readFileSync('skills/dice-rolling/SKILL.md', 'utf-8')// Include skillContent in your agent's system promptPaste the skill content directly into any LLM conversation. The skill is self-contained and includes notation reference, game system support, and usage examples.
Programmatic usage
Section titled “Programmatic usage”If you’re building a custom agent, you can also use @randsum/roller directly:
bun add @randsum/rollerimport { roll } from '@randsum/roller'
const result = roll('4d6L')console.log(result.total) // Sum after dropping lowestconsole.log(result.rolls) // Individual die resultsSee the Roller documentation for the full API.
Skill definition
Section titled “Skill definition”The full skill file that agents receive:
Dice Rolling Skill
Executing Rolls
When a user asks you to roll dice, produce an actual result — don’t just show notation or code. If you have shell access, use the CLI:
bunx @randsum/cli <notation> # in bun projects (preferred)npx @randsum/cli <notation> # anywhere elseExamples:
bunx @randsum/cli 4d6L # D&D ability scorebunx @randsum/cli 2d20L+7 # advantage attackbunx @randsum/cli 3d6 # Blades in the Dark poolbunx @randsum/cli 5d10S{7} # World of Darkness successesIf you don’t have shell access, simulate the roll yourself — mentally generate random numbers as you would genuinely roll dice, and present them clearly. Don’t just describe how the roll would work without giving a result.
Response Format
After rolling, always show:
- What you rolled — the notation and what it represents
- The dice — raw values (and which were dropped/kept if relevant)
- The total — the final number
- The meaning — what it means in the game context (hit/miss, success tier, stat value, etc.)
Rolling 4d6L (4 six-sided dice, drop lowest) for Strength:Dice: [5, 3, 4, 2] → dropped 2 → kept [5, 3, 4]Total: 12→ Strength score: 12 (modifier: +1)Keep it compact — one block, no lengthy preamble. For game-system rolls, add one sentence of flavor or consequence after the result (e.g. “You pull it off cleanly.” or “Brace for a complication.”).
Notation Quick Reference
All notation is case-insensitive. Basic syntax: NdS (N dice, S sides).
Core Modifiers
| Notation | Description |
|---|---|
4d6L | Drop lowest die |
4d6H | Drop highest die |
4d6L2 | Drop 2 lowest |
4d6K3 | Keep highest 3 |
4d6kl2 | Keep lowest 2 |
1d20+5 | Add 5 to total |
4d6-1 | Subtract 1 |
2d6*2 | Multiply dice sum (before +/-) |
2d6+3**2 | Multiply final total (after +/-) |
Conditional Modifiers
Conditions use comparison operators: >N (greater than), <N (less than), >=N (at or over), <=N (at or under), =N or bare N (exact match).
| Notation | Description |
|---|---|
4d6R{1} | Reroll 1s (bare number = exact match) |
4d6R{=1} | Same — explicit = form |
4d20R{<5} | Reroll under 5 |
4d20R{<=5} | Reroll 5 or under |
4d20R{>=17} | Reroll 17 or over |
4d20R{<5}3 | Reroll under 5, max 3 attempts |
4d20V{8=12} | Replace 8s with 12s |
4d20V{>17=20} | Replace results over 17 with 20 |
4d20V{>=17=20} | Replace results at or over 17 with 20 |
4d20V{<=3=1} | Replace results at or under 3 with 1 |
4d20C{>18} | Cap rolls over 18 down to 18 |
4d20C{5} | Cap rolls above 5 to 5 (bare number = max cap) |
4d20C{=5} | Same — explicit = form |
4d20C{>=5} | Cap rolls at or over 5 to 5 |
4d20C{<2,>19} | Floor 2, ceiling 19 |
4d20U | All results must be unique |
4d20D{>17} | Drop dice over 17 |
4d20D{>=17} | Drop dice at or over 17 |
4d20D{1,2} | Drop 1s and 2s |
4d20D{=1,=2} | Same — explicit = form |
Ultra-complex example — roll 8d10, cap to [3,8] range, keep top 5, reroll floor values, add 4:
8d10C{>8,<3}K5R{=3}+4Exploding Dice
| Notation | Description |
|---|---|
3d6! | Explode: new die on max result |
3d6!! | Compound: add to same die on max |
3d6!p | Penetrate: explode minus 1 each time |
3d6!5 | Explode up to 5 times per die |
Dice Pools
| Notation | Description |
|---|---|
5d10S{7} | Count dice ≥ 7 (successes) |
5d10S{7,1} | Successes ≥ 7, subtract botches ≤ 1 |
Multiple Groups
1d20+2d6+5 # attack (d20) + damage (2d6) + mod2d12-1d6 # roll 2d12, subtract 1d6Modifier order (lower = earlier): Cap (10) → Drop/Keep (20/21) → Replace (30) → Reroll (40) → Explode (50-52) → Unique (60) → Multiply (85) → Plus/Minus (90/91) → Count Successes (95) → Total Multiply (100)
Full notation reference: references/NOTATION.md
Game Systems
See references/GAME_SYSTEMS.md for full mechanics.
| Game | Roll | Interpretation |
|---|---|---|
| D&D 5E advantage | 2d20L+mod | Keep highest + modifier |
| D&D 5E disadvantage | 2d20H+mod | Keep lowest + modifier |
| D&D 5E ability score | 4d6L | Drop lowest of 4d6 |
| D&D 5E crit | 2×damage dice + mod | Double the dice |
| Blades in the Dark | Nd6, keep highest | 6 = success, 4–5 = partial, 1–3 = failure; two 6s = critical |
| Daggerheart | 2d12 (Hope/Fear) | Higher die = narrative control; sum = mechanical success |
| PbtA / Root RPG | 2d6+stat | 10+ = strong hit, 7–9 = weak hit, 6– = miss |
| Salvage Union | d20 vs target | Roll under; 1 = critical success, 20 = critical failure |
Programmatic API
import { roll } from "@randsum/roller"
roll(20) // 1d20roll("4d6L") // notation stringroll({ sides: 6, quantity: 4, modifiers: { drop: { lowest: 1 } } })roll("1d20+5", "2d6") // multiple args, combined total
const result = roll("2d6+3")result.total // final sumresult.rolls // RollRecord[] — full roll data per dice groupresult.values // string[] — rolled values as stringsNotation reference
Section titled “Notation reference”Randsum Dice Notation
Table of Contents
Overview
Dice notation is a compact way to represent dice rolls and their modifications. For example, 4d20+2 means “roll four twenty-sided dice, then add two”.
Randsum extends standard dice notation with powerful modifiers like dropping lowest rolls, rerolling specific values, and ensuring unique results.
The core roll() function accepts several argument types: a number (sides for a single die, e.g. roll(20) for 1d20), a notation string (e.g. roll("4d6L")), an options object (e.g. roll({ sides: 6, quantity: 4, modifiers: { drop: { lowest: 1 } } })), or multiple arguments combined into one total (e.g. roll("1d20+5", "2d6")).
Basic Syntax
All notation in randsum is case-insensitive (2d8 = 2D8).
Standard Rolls
// Roll one d20roll(20) // number argumentroll("1d20") // notation stringroll({ sides: 20, quantity: 1})
// Roll four d6roll("4d6")roll({ sides: 6, quantity: 4})Modifiers
Basic Arithmetic
roll("4d6+2") // Add 2 to totalroll({ sides: 6, quantity: 4, modifiers: { plus: 2 }})
roll("4d6-1") // Subtract 1 from totalroll({ sides: 6, quantity: 4, modifiers: { minus: 1 }})Cap Modifiers
Limit roll values to specific ranges:
roll("4d20C{>18}") // Cap rolls over 18 to 18roll({ sides: 20, quantity: 4, modifiers: { cap: { greaterThan: 18 } }})
roll("4d20C{<3}") // Cap rolls under 3 to 3roll({ sides: 20, quantity: 4, modifiers: { cap: { lessThan: 3 } }})
roll("4d20C{<2,>19}") // Cap rolls under 2 to 2 and over 19 to 19roll({ sides: 20, quantity: 4, modifiers: { cap: { greaterThan: 19, lessThan: 2 } }})Drop Modifiers
Drop specific dice from the results:
roll("4d6L") // Drop lowestroll({ sides: 6, quantity: 4, modifiers: { drop: { lowest: 1 } }})
roll("4d6L2") // Drop 2 lowestroll({ sides: 6, quantity: 4, modifiers: { drop: { lowest: 2 } }})
roll("4d6H") // Drop highestroll({ sides: 6, quantity: 4, modifiers: { drop: { highest: 1 } }})
roll("4d6H2") // Drop 2 highestroll({ sides: 6, quantity: 4, modifiers: { drop: { highest: 2 } }})
roll("4d6LH") // Drop both lowest and highestroll({ sides: 6, quantity: 4, modifiers: { drop: { lowest: 1, highest: 1 } }})
// Drop by valueroll("4d20D{>17}") // Drop rolls over 17roll({ sides: 20, quantity: 4, modifiers: { drop: { greaterThan: 17 } }})
roll("4d20D{<5}") // Drop rolls under 5roll({ sides: 20, quantity: 4, modifiers: { drop: { lessThan: 5 } }})
roll("4d20D{8,12}") // Drop 8s and 12sroll({ sides: 20, quantity: 4, modifiers: { drop: { exact: [8, 12] } }})Reroll Modifiers
Reroll dice matching certain conditions:
roll("4d20R{>17}") // Reroll results over 17roll({ sides: 20, quantity: 4, modifiers: { reroll: { greaterThan: 17 } }})
roll("4d20R{<5}") // Reroll results under 5roll({ sides: 20, quantity: 4, modifiers: { reroll: { lessThan: 5 } }})
roll("4d20R{8,12}") // Reroll 8s and 12sroll({ sides: 20, quantity: 4, modifiers: { reroll: { exact: [8, 12] } }})
roll("4d20R{<5}3") // Reroll under 5, max 3 attemptsroll({ sides: 20, quantity: 4, modifiers: { reroll: { lessThan: 5, max: 3 } }})Replace Modifiers
Replace specific results with new values:
roll("4d20V{8=12}") // Replace 8s with 12sroll({ sides: 20, quantity: 4, modifiers: { replace: { from: 8, to: 12 } }})
roll("4d20V{>17=20}") // Replace results over 17 with 20roll({ sides: 20, quantity: 4, modifiers: { replace: { from: { greaterThan: 17 }, to: 20 } }})
roll("4d20V{<5=1}") // Replace results under 5 with 1roll({ sides: 20, quantity: 4, modifiers: { replace: { from: { lessThan: 5 }, to: 1 } }})Unique Results
Force unique rolls within a pool:
roll("4d20U") // All results must be uniqueroll({ sides: 20, quantity: 4, modifiers: { unique: true }})
roll("4d20U{5,10}") // Unique except 5s and 10s can repeatroll({ sides: 20, quantity: 4, modifiers: { unique: { notUnique: [5, 10] } }})Keep Modifiers
Keep specific dice from the result (complement to drop):
roll("4d6K3") // Keep highest 3roll({ sides: 6, quantity: 4, modifiers: { keep: { highest: 3 } }})
roll("4d6K") // Keep highest 1roll({ sides: 6, quantity: 4, modifiers: { keep: { highest: 1 } }})
roll("4d6kl2") // Keep lowest 2roll({ sides: 6, quantity: 4, modifiers: { keep: { lowest: 2 } }})
roll("4d6kl") // Keep lowest 1roll({ sides: 6, quantity: 4, modifiers: { keep: { lowest: 1 } }})Note: Keeping N highest is equivalent to dropping (quantity - N) lowest. For example, 4d6K3 is the same as 4d6L1.
Exploding Dice
Roll additional dice on maximum results:
roll("4d20!") // Roll an extra d20 for each 20 rolledroll({ sides: 20, quantity: 4, modifiers: { explode: true }})
roll("3d6!5") // Explode with max depth of 5roll({ sides: 6, quantity: 3, modifiers: { explode: 5 }})
roll("3d6!0") // Explode unlimited (capped at 1000 for safety)roll({ sides: 6, quantity: 3, modifiers: { explode: 0 }})How it works: When a die shows its maximum value, it “explodes” - a new die is rolled and added to the result. This continues for each new maximum value rolled, creating additional dice in the result.
Example: 3d6! rolls [6, 4, 6]. The two 6s explode, adding [5, 3]. Final result: [6, 4, 6, 5, 3] = 24.
Compounding Exploding (!!)
Exploding dice that add to the triggering die instead of creating new dice:
roll("3d6!!") // Compound explode: add to die instead of new diceroll({ sides: 6, quantity: 3, modifiers: { compound: true }})
roll("3d6!!5") // Compound explode with max depth of 5roll({ sides: 6, quantity: 3, modifiers: { compound: 5 }})
roll("3d6!!0") // Compound explode unlimited (capped at 1000)roll({ sides: 6, quantity: 3, modifiers: { compound: 0 }})How it works: When a die shows its maximum value, it compounds - a new roll is added directly to that die’s value. Unlike regular exploding, this doesn’t create new dice; it modifies the existing die.
Example: 1d6!! rolls 6. This compounds, rolling 4. The die value becomes 6 + 4 = 10. If that 4 had been a 6, it would compound again: 6 + 6 + 3 = 15.
Use cases: Compounding is useful in systems where you want explosive growth on a single die value rather than multiple dice. Common in damage systems where a critical hit adds to the base damage value.
Differences from Explode:
- Explode (
!): Creates new dice →[6, 4, 6]becomes[6, 4, 6, 5, 3](5 dice) - Compound (
!!): Modifies existing die →[6, 4, 6]becomes[15, 4, 12](still 3 dice)
Penetrating Exploding (!p)
Exploding dice where each subsequent explosion subtracts 1 (Hackmaster-style):
roll("3d6!p") // Penetrate explode: subtract 1 from subsequent rollsroll({ sides: 6, quantity: 3, modifiers: { penetrate: true }})
roll("3d6!p5") // Penetrate with max depth of 5roll({ sides: 6, quantity: 3, modifiers: { penetrate: 5 }})
roll("3d6!p0") // Penetrate unlimited (capped at 1000)roll({ sides: 6, quantity: 3, modifiers: { penetrate: 0 }})How it works: When a die shows its maximum value, it penetrates - a new roll is made, but 1 is subtracted from the result before adding. Each subsequent penetration also subtracts 1. This creates a diminishing return effect.
Example: 1d6!p rolls 6. This penetrates, rolling 5. The value added is 5 - 1 = 4, so the die becomes 6 + 4 = 10. If that roll had been a 6, it would penetrate again: roll 3, subtract 1 = 2, so the die becomes 6 + 4 + 2 = 12.
Use cases: Penetrating dice are used in Hackmaster and similar systems where you want explosive results but with diminishing returns to prevent unlimited growth.
Comparison:
- Explode (
!):[6]→[6, 6, 4]= 16 (new dice added) - Compound (
!!):[6]→[16]= 16 (die value modified) - Penetrate (
!p):[6]→[12]= 12 (6 + (6-1) + (3-1) if it keeps penetrating, die value modified with -1 on each subsequent roll)
Pre-Arithmetic Multiplier (*)
Multiply the dice sum before adding/subtracting arithmetic modifiers:
roll("2d6*2+3") // (dice sum * 2) + 3roll({ sides: 6, quantity: 2, modifiers: { multiply: 2, plus: 3 }})
roll("4d6*3") // Multiply dice sum by 3roll({ sides: 6, quantity: 4, modifiers: { multiply: 3 }})How it works: The multiplier is applied to the sum of all dice after other modifiers (drop, keep, explode, etc.) but before plus/minus arithmetic modifiers are applied.
Order of operations: (dice sum × multiply) ± plus/minus
Example: 2d6*2+3 rolls [4, 5] = 9. Multiplied by 2 = 18. Plus 3 = 21.
Use cases: Critical hits that double or triple base damage before modifiers. Or systems where dice are multiplied before bonuses are added.
Total Multiplier (**)
Multiply the entire final total after all other modifiers:
roll("2d6+3**2") // (dice + 3) * 2roll({ sides: 6, quantity: 2, modifiers: { plus: 3, multiplyTotal: 2 }})
roll("4d6L+2**3") // ((drop lowest) + 2) * 3roll({ sides: 6, quantity: 4, modifiers: { drop: { lowest: 1 }, plus: 2, multiplyTotal: 3 }})How it works: The total multiplier is applied last, after all other modifiers including plus/minus. It multiplies the complete final result.
Order of operations: ((dice sum × multiply) ± plus/minus) × multiplyTotal
Example: 2d6+3**2 rolls [4, 5] = 9. Plus 3 = 12. Multiplied by 2 = 24.
Use cases: Final multipliers like area effect multipliers, critical hit total multipliers, or system-wide bonuses that apply to the entire result.
Difference from Pre-Arithmetic Multiplier:
- Pre-Arithmetic (
*):2d6*2+3= (9 × 2) + 3 = 21 - Total (
**):2d6+3\*\*2= (9 + 3) × 2 = 24
Count Successes (S{…})
Count dice meeting a threshold instead of summing values. Used in dice pool systems like World of Darkness and Shadowrun:
roll("5d10S{7}") // Count how many dice rolled >= 7roll({ sides: 10, quantity: 5, modifiers: { countSuccesses: { threshold: 7 } }})
// With botch threshold (successes - botches)roll("5d10S{7,1}") // Count successes >= 7, subtract botches <= 1roll({ sides: 10, quantity: 5, modifiers: { countSuccesses: { threshold: 7, botchThreshold: 1 } }})How it works: Instead of summing dice values, the total becomes a count of dice that meet or exceed the threshold. If a botch threshold is specified, dice at or below that value are subtracted from the success count.
Example: 5d10S{7} rolls [8, 3, 10, 6, 9]. Successes >= 7: [8, 10, 9] = 3.
Example with botch: 5d10S{7,1} rolls [8, 1, 10, 1, 9]. Successes: 3, Botches: 2. Result = 1.
Combining Modifiers
Modifiers can be chained together. They are applied in a specific order to ensure consistent results:
Modifier Application Order:
- Cap
- Drop / Keep
- Replace
- Reroll
- Explode / Compound / Penetrate
- Unique
- Count Successes
- Pre-Arithmetic Multiply (
*) - Plus / Minus
- Total Multiply (
**)
roll("4d6L+2") // Drop lowest, add 2roll("2d20H!+1") // Drop highest, explode, add 1roll("4d6R{<3}L") // Reroll under 3, then drop lowestroll("3d6!!*2+3") // Compound explode, multiply by 2, add 3roll("2d6*2+3**2") // Multiply dice by 2, add 3, multiply total by 2roll("4d6K3!+2") // Keep highest 3, explode, add 2roll("3d6!pL+1") // Penetrate explode, drop lowest, add 1Important Notes:
- Pre-arithmetic multiply (
*) applies beforeplus/minus:2d6*2+3= (sum × 2) + 3 - Total multiply (
**) applies after everything:2d6+3**2= (sum + 3) × 2 - You can use both multipliers together:
2d6*2+3**2= ((sum × 2) + 3) × 2 - Keep is processed before explode/compound/penetrate, so explosions only happen on kept dice
- Drop/Keep happen after reroll but before explode, so you reroll first, then keep/drop
Multiple Dice Sides in a Single Roll
You can roll multiple dice sides in a single by passing multiple arguments:
roll("1d20", "-2d6", "10d8+2") // Roll 1d20, 2d6, and 10d8 + 2.roll("1d20-2d6+10d8+2") // Same as above, but in a single stringAdding or Subtracting Rolls from the Total
You can add or subtract rolls from the total by using the arithmetic option, or by adding a + or - to the notation:
roll("2d12-1d6") // Roll 2d12, add them, then subtract 1d6Common Use Cases
D&D 5e Critical Hits
- Double base damage:
2d6+3*2→ (9 × 2) + 3 = 21 - Double total damage:
2d6+3**2→ (9 + 3) × 2 = 24
D&D 5e Ability Score Generation
roll("4d6K3") // Roll 4d6, keep highest 3roll("4d6L") // Equivalent: Roll 4d6, drop lowest 1D&D 5e Advantage/Disadvantage
roll("2d20K") // Advantage: keep highestroll("2d20kl") // Disadvantage: keep lowestHackmaster Penetrating Dice
roll("1d6!p") // Standard penetrateroll("2d6!p+3") // Penetrate with modifierArea Effect Spells
roll("8d6*2") // 8d6 damage, doubled for area effectroll("8d6+5**2") // 8d6+5 damage, doubled for area effectPerformance Considerations
Depth Limits
All explosive modifiers (explode, compound, penetrate) have built-in depth limits:
- Explicit depth:
!N,!!N,!pN- Limited to N depth - Unlimited (0):
!0,!!0,!p0- Capped at 1000 for safety - Default:
!,!!,!p- Limited to 1 explosion per die
Best Practices
- Use depth limits for explosive modifiers in production code
- Keep dice quantities reasonable (< 100 dice for best performance)
- Prefer compound over explode if you don’t need separate dice tracking
- Use multipliers sparingly - they’re cheap but unnecessary if not needed
Attribution
The extended notation syntax was inspired by Sophie’s Dice.
Game systems reference
Section titled “Game systems reference”RANDSUM Game Systems
Supported Game Packages
@randsum/games/blades - Blades in the Dark
- Mechanics: d6 dice pools, keep highest result
- Outcomes: 6 = success, 4-5 = partial, 1-3 = failure; multiple 6s = critical
- 0 dice pool: rolls 2d6, drops highest (desperate position)
- Result type:
'critical' | 'success' | 'partial' | 'failure' - Usage:
roll(rating?: number)— 0 = desperate (2d6, keep lowest), 1-4 = roll that many d6, keep highest
const result = roll(3)result.result // 'critical' | 'success' | 'partial' | 'failure'result.total // highest die value@randsum/games/daggerheart - Daggerheart RPG
- Mechanics: Hope/Fear d12 system
- Roll: 2d12 (one Hope die, one Fear die) + optional advantage/disadvantage d6
- Outcome: Higher die determines narrative (Hope/Fear/Critical Hope); sum determines mechanical success
- Result type:
'hope' | 'fear' | 'critical hope' - Usage:
roll(arg?: DaggerheartRollArgument)
interface DaggerheartRollArgument { modifier?: number // added to total rollingWith?: 'Advantage' | 'Disadvantage' // adds/subtracts a d6 amplifyHope?: boolean // use d20 instead of d12 for Hope amplifyFear?: boolean // use d20 instead of d12 for Fear}
const result = roll({ modifier: 3, rollingWith: 'Advantage' })result.result // 'hope' | 'fear' | 'critical hope'result.details // { hope, fear, advantage, modifier }@randsum/games/fifth - D&D 5th Edition
- Mechanics: d20 with advantage/disadvantage
- Advantage: Roll 2d20, keep highest (
2d20L— drop lowest) - Disadvantage: Roll 2d20, keep lowest (
2d20H— drop highest) - Ability Scores: use
roll("4d6L")from@randsum/rollerdirectly - Result type:
number(d20 + modifier) - Usage:
roll(arg?: FifthRollArgument)
interface FifthRollArgument { modifier?: number // range -30 to +30 rollingWith?: 'Advantage' | 'Disadvantage'}
roll({ modifier: 5 })roll({ modifier: 3, rollingWith: 'Advantage' })roll({ modifier: -2, rollingWith: 'Disadvantage' })@randsum/games/root-rpg - Root RPG
- Mechanics: 2d6 + stat modifier
- Outcomes: 10+ = strong hit, 7-9 = weak hit, 6- = miss
- Result type:
'Strong Hit' | 'Weak Hit' | 'Miss' - Usage:
roll(bonus: number)— range -20 to +20
const result = roll(2)result.result // 'Strong Hit' | 'Weak Hit' | 'Miss'result.total // 2d6 + bonus@randsum/games/pbta - Powered by the Apocalypse
- Mechanics: 2d6 + stat modifier (generic PbtA)
- Outcomes: 10+ = strong hit, 7-9 = weak hit, 6- = miss
- Advantage: roll 3d6, keep 2 highest; Disadvantage: roll 3d6, keep 2 lowest
- Result type:
'strong_hit' | 'weak_hit' | 'miss' - Usage:
roll(arg: PbtARollArgument)—statis required
interface PbtARollArgument { stat: number // required; range -3 to +5 forward?: number // one-time bonus; range -5 to +5 ongoing?: number // persistent bonus; range -5 to +5 rollingWith?: 'Advantage' | 'Disadvantage' // 3d6 keep highest/lowest 2}
const result = roll({ stat: 2, forward: 1 })result.result // 'strong_hit' | 'weak_hit' | 'miss'Games: Dungeon World, Monster of the Week, Apocalypse World, Masks, and more.
@randsum/games/salvageunion - Salvage Union
- Mechanics: d20 roll-under system; lower is better
- Outcome: 1 = critical success, 20 = critical failure; results looked up in reference tables
- Result type:
SalvageUnionRollRecord(label, description, table metadata) - Usage:
roll(tableName?: SalvageUnionTableName)— defaults to'Core Mechanic'
const result = roll() // defaults to Core Mechanic tableconst result = roll('Morale') // specific table
result.result.label // human-readable result nameresult.result.description // result descriptionresult.result.roll // d20 value (1-20)result.result.tableName // table usedCommon Patterns
All game packages:
- Depend on
@randsum/rollercore package - Return a result object with
result,total, androllsfields - Export roll function and result types
Quick Reference by System
| Game | Notation / Pattern | Outcome |
|---|---|---|
| D&D 5E | roll({ modifier: 5 }) | d20 + modifier |
| D&D 5E adv | 2d20L+5 (roller) | Higher of 2d20 + modifier |
| D&D 5E dis | 2d20H+5 (roller) | Lower of 2d20 + modifier |
| D&D 5E scores | 4d6L (roller) | Ability score (drop lowest) |
| Blades | roll(N) | Highest die: 6 success, 4-5 partial, 1-3 fail |
| Daggerheart | roll({ modifier: N }) | Hope/Fear interpretation |
| PbtA / Root | roll({ stat: N }) | 10+ strong, 7-9 weak, 6- miss |
| Salvage Union | roll('Core Mechanic') | Roll under; lower is better |