Getting Started with Games
Install @randsum/games and make your first game-specific roll in under a minute.
Install
Section titled “Install”bun add @randsum/gamesnpm install @randsum/gamesThis installs @randsum/roller automatically as a dependency.
Simplest example: Salvage Union
Section titled “Simplest example: Salvage Union”Import from the game’s subpath and call roll(). That’s it.
import { roll } from '@randsum/games/salvageunion'
const { result, total } = roll('Core Mechanic')console.log(result.label) // 'Success' | 'Tough Choice' | 'Failure' | ...console.log(result.description) // Full outcome textconsole.log(total) // d20 rollPass a table name to roll against any of Salvage Union’s many tables — combat, salvage, critical injuries, and more.
import { roll, VALID_TABLE_NAMES } from '@randsum/games/salvageunion'
roll('Core Mechanic') // Standard action rollroll('Group Initiative') // Who acts first in combatroll('Critical Injury') // What happens at 0 HP
console.log(VALID_TABLE_NAMES) // All available tablesModerately complex: D&D 5e
Section titled “Moderately complex: D&D 5e”The fifth edition package accepts an options object with modifier, advantage/disadvantage, and critical hit tracking.
import { roll } from '@randsum/games/fifth'
// Simple d20 rollconst { result, total } = roll()console.log(result) // number (d20 roll + any modifier)
// Roll with advantage and a +5 modifierconst attack = roll({modifier: 5,rollingWith: 'Advantage'})console.log(attack.result) // number
// Track natural 1s and 20sconst crit = roll({modifier: 3,crit: true})console.log(crit.details.criticals)// { isNatural1: false, isNatural20: true }Every game follows the same pattern
Section titled “Every game follows the same pattern”Each game subpath exports a roll() function that:
- Accepts game-specific input (a number, an options object, or nothing)
- Validates the input — throws
ValidationError(from roller) for out-of-range numbers, orSchemaErrorfor game-specific issues - Calls
@randsum/rollerinternally with the right dice configuration - Returns a typed
GameRollResultwithresult,total,rolls, and optionallydetails
The result field is game-specific — a rich outcome object in Salvage Union (with label, description, and tableName), a numeric total in D&D 5e, a hope/fear determination in Daggerheart.
Every game subpath re-exports SchemaError, GameRollResult, and RollRecord. Import ValidationError from @randsum/roller if you need to catch range errors.
Error handling
Section titled “Error handling”Game roll() functions can throw two types of errors:
ValidationError(from@randsum/roller) — for numeric validation like out-of-range valuesSchemaError(from@randsum/games) — for game-specific issues like unmatched outcome tables
import { roll, SchemaError } from '@randsum/games/salvageunion'import { ValidationError } from '@randsum/roller'
try {roll('Not A Real Table')} catch (e) {if (e instanceof ValidationError) { // Numeric input out of range console.error(e.message)} else if (e instanceof SchemaError) { // Game-specific error (e.g., invalid table name) console.error(e.code, e.message)}}| Error | Code | When |
|---|---|---|
ValidationError | VALIDATION_ERROR | Numeric input out of range or not finite |
SchemaError | INVALID_INPUT_TYPE | Input value is wrong type |
SchemaError | NO_TABLE_MATCH | Roll total doesn’t match any outcome tier |
SchemaError | INPUT_NOT_FOUND | Required input field is missing |
What’s next
Section titled “What’s next”- Games Introduction — overview of all supported game systems
- Salvage Union — table-based rolls for mech salvage RPG
- D&D 5e — ability checks, attacks, and saving throws
- Schema Overview — how game packages are generated from JSON specs