The pack
rpg
function rpg(options: RpgPackOptions = {}): Pack<{ rpg: RpgApi }>
The rpg pack: game.rpg, and the scenes title, overworld, town, dungeon, crawl, battle, dialogue,
shop, inn, menu, ending, gameover (each renamed by options.scenes). Requires the packs it drives to be
composed before it; see the docs page for the list. Headless it runs in full: the art registers blank and the pad
reads nothing.
Helpers
BIOME_BACKDROP
const BIOME_BACKDROP: Readonly<Record<string, string>>
Battle backdrop colour per built-in biome.
CLASS_COLOR
const CLASS_COLOR: Readonly<Record<string, string>>
Colour of each built-in hero class, for plates and figures.
DEFAULT_FONTS
const DEFAULT_FONTS: Readonly<Record<FontKey, string>>
The default faces, as CSS fonts.
DEFAULT_KEYS
const DEFAULT_KEYS: Readonly<Record<Btn, readonly string[]>>
The default key codes per button; the touch pack presses the Touch: ones.
DEFAULT_PAD
const DEFAULT_PAD: Readonly<Record<Btn, readonly string[]>>
The default gamepad buttons per button (the sticks also steer).
deliverItemFor
function deliverItemFor(world: World, quest: Quest, step: number, held: (id: string) => number): string | null
The item a deliver step hands over when it names none: the nearest earlier fetch step's item, else the nearest earlier kill step's monster drop, else the first quest item held. Null means the step is a plain talk.
ELEMENT_COLOR
const ELEMENT_COLOR: Readonly<Record<string, string>>
Colour of each built-in element, for tints, bars and monster bodies.
palette
function palette(c: RpgColours = {}): Palette
The palette for a game's colours over the built-in ones.
resolveOptions
function resolveOptions(o: RpgOptions = {}): Resolved
Fill in the defaults. Throws on two scenes given one name.
ROLE_COLOR
const ROLE_COLOR: Readonly<Record<string, string>>
Colour of each built-in npc role, for their figures.
RPG_SCENES
const RPG_SCENES: readonly RpgSceneKey[]
Every scene the player registers.
THEME
const THEME: Readonly<Record<string, ThemeColours>>
What the dungeon tiles of each built-in theme look like.
Types
BattleRequest
interface BattleRequest
A battle asked for by a map scene.
monsterIds: string[]— Monster ids, in the order they stand.backdrop: string— Backdrop colour.onEnd(result: 'win' | 'lose' | 'flee'): void— Called once the battle scene pops.
Btn
type Btn = 'up' | 'down' | 'left' | 'right' | 'confirm' | 'cancel'
The player's buttons.
EncounterOptions
interface EncounterOptions
Random encounters in the wilds.
groups?: readonly (readonly [number, number])[]— How many foes come, as [count, weight] pairs. Default 1 (45), 2 (40), 3 (15).cooldown?: number— Steps after a battle before the next can happen. Default 4.safeRadius?: number— No encounters within this many cells of a town or dungeon. Default 3.
FontKey
type FontKey = 'body' | 'big' | 'small' | 'title'
The faces the player draws its text in.
LoadOptions
interface LoadOptions
What load takes beside the world.
assets?: Record<string, string>— Portrait id → image URL (blob:, data:, https:). Ids the world does not name are ignored.save?: unknown | null— A save fromsave()to resume; null or absent starts fresh. A save for another world is ignored.
Palette
interface Palette
The colours of a world's vocabularies: the game's, then the built-in ones, then one made from the name.
element(e: string): string— An element's colour.cls(c: string): string— A hero class's colour.role(r: string): string— An npc role's colour.biome(b: string): string— A biome's battle backdrop.theme(t: string): ThemeColours— A dungeon theme's colours.
Resolved
interface Resolved
Options with every default filled in.
raw: RpgOptions— As given.vocab: WorldVocabulary— The world vocabulary.scenes: Record<RpgSceneKey, string>— Scene names.keys: Record<Btn, readonly string[]>— Key codes per button.pad: Record<Btn, readonly string[]>— Pad buttons per button.fonts: Record<FontKey, string>— CSS fonts.encounters: Required<EncounterOptions>— Encounters.maxFoes: number— Most foes a battle.hint: string— The title's controls line.look: { panel: string; row: string; bar: string }— The furniture's styles.transition: { kind: string; duration: number; color: string } | null— The map-to-map cover, or null to cut.
RpgApi
interface RpgApi
What game.rpg presents.
host(game: RpgHost, options?: RpgOptions): void— Hand the pack the composed game it drives, and the rules that are code (map generators, battle rules, skill effects, the party's curve). Call once, beforeload. The pack reaches every other pack only through this.load(world: unknown, opts?: LoadOptions): void— Clean a world document, build its maps, restore a save if given, and (re)start at the title.start(): void— Go to the title;loaddoes this itself once the game is running.newGame(): void— Start a new game at once, skipping the title (for a game with a title screen of its own).resume(): boolean— Continue the saved game, skipping the title; false when there is none.fight(monsterIds: readonly string[], onEnd?: (result: 'win' | 'lose' | 'flee') => void, backdrop?: string): boolean— Start a battle now against these monsters (ids from the world), over the current map scene: a scripted ambush, a boss a game's own event calls.onEndhears the result once the battle scene has gone. False when no game is being played or no id names a monster.save(): unknown | null— The run as JSON, or null before a world is loaded.onEvent(fn: (e: RpgEvent) => void): () => void— Hear what happens; returns the unsubscribe.readonly state: RpgState— A snapshot for the page.readonly world: World | null— The clean world in play, or null.readonly maps: WorldMaps | null— Its maps, or null.readonly run: Run | null— The run in play, or null: itspartyandquestsare the live Party and QuestLog.scene(key: RpgSceneKey): string— The scene name the player uses for a scene.mapsOf(world: unknown): WorldMaps— Every map of any world document, without loading it, cleaned and built with the options given tohost.
RpgColours
interface RpgColours
Colours for the world's vocabularies; a name with none gets a colour from its name.
elements?: Readonly<Record<string, string>>— Per element (tints, monster bodies).classes?: Readonly<Record<string, string>>— Per hero class (plates and figures).roles?: Readonly<Record<string, string>>— Per npc role (figures).biomes?: Readonly<Record<string, string>>— Per biome (the battle backdrop).themes?: Readonly<Record<string, ThemeColours>>— Per dungeon theme.
RpgEvent
type RpgEvent = | { type: 'scene'; scene: string; regionId?: string } | { type: 'talk'; npcId: string } | { type: 'quest'; id: string; status: 'started' | 'done' } | { type: 'battle'; monsterIds: string[]; result?: 'win' | 'lose' | 'flee' } | { type: 'level'; heroId: string; level: number } | { type: 'item'; id: string; how: 'found' | 'bought' | 'drop' | 'reward' } | { type: 'ending' } | { type: 'log'; text: string }
What the bundle and the page hear.
RpgHost
interface RpgHost extends GameBase
The composed game the pack drives: the kernel's face plus every pack it composes with.
spawn(spec: SpawnSpec & { anims?: Record<string, AnimDef>; brain?: Brain }): Handle— The full spawn, with anims and a brain.world: World2dApi— The top-down world.screen: ScreenApi— The screen-space world.typography: TypographyApi— Bitmap text.tiles: Tiles2dApi— Tilemaps.fsm: FsmApi— State machines for npcs and monsters.fog: FogApi— Fog of war grids.save: SaveApi— The save store.sound: SoundApi— The synth.feel: FeelApi— Shake, flash, hit-stop.rig: RigApi— The follow camera.art2d: Art2dApi— Procedural art.ui: UiApi— Panels and the menu cursor.bars: BarsApi— The meters.dialogue: DialogueApi— The speech box.transition: TransitionApi— Covers between map scenes.lights?: Lighting2dApi— 2D lights, when composed (WebGPU only).vector?: Vector2dApi— Line art and faces, when composed (WebGPU only): the first-person lens needs it.
RpgOptions
interface RpgOptions extends RpgPackOptions, RunOptions
What game.rpg.host(game, options) takes: the pack's options and the rules that are code.
maps?: MapOptions— The map generators: biome rules, town templates, terrain, the overworld's and floors' sizes.battle?: Partial<BattleRules>— The battle's rules overturn-battle's; the element wheel defaults to the world's.skillEffects?: Readonly<Record<string, SkillEffect>>— Skill effects of a game's own, by the name a skill'seffectuses.foeChoice?: (battle: Battle, actor: Fighter) => BattleAction— How foes choose their action. Default: attack a random standing hero.
RpgPackOptions
interface RpgPackOptions
What the pack factory takes (rpg(options), or the manifest): plain data.
scenes?: Partial<Record<RpgSceneKey, string>>— Scene names, for a game that has atitleorgameoverof its own. Only here: scenes are registered at compose time.keys?: Partial<Record<Btn, readonly string[]>>— Key codes per button, replacing the defaults for the buttons given.padButtons?: Partial<Record<Btn, readonly string[]>>— Gamepad buttons per button, replacing the defaults for the buttons given.fonts?: Partial<Record<FontKey, string>>— CSS fonts, replacing the defaults for the faces given.colours?: RpgColours— Colours for the vocabularies.encounters?: EncounterOptions— Random encounters.maxFoes?: number— The most foes in one battle; the battle screen lays them out across its left side. Default 4.hint?: string— The controls line on the title screen.look?: 'rpg' | 'theme'— What the furniture wears:'rpg'(default) is the player's own dark-and-gold panels, cursor, meters and speech box;'theme'follows the game'suitheme (game.ui.theme, aui-skinsskin): its panel and selected-row roles, glossy meters, and the theme's own speech box.styles?: { panel?: string; row?: string; bar?: string }— Individual styles over the look: auistyle for panels and the selected row, abarsstyle for meters.speech?: { preset?: string; theme?: Readonly<Record<string, unknown>> }— The speech box: adialoguepreset (a procedural one, or an illustrated one listed in the dialogue pack's options) and theme tokens over it.transition?: { kind?: string; duration?: number; color?: string } | false— Scene changes between maps: atransitioncover (kind,durationin seconds,color), or false to cut. Default a 0.3 s fade.startGold?: number— Gold at the start of a new game. Default 50.world?: WorldOptions— The world document's caps and vocabularies (biomes, classes, elements, item kinds, step kinds…).
RpgSceneKey
type RpgSceneKey = 'title' | 'overworld' | 'town' | 'dungeon' | 'crawl' | 'battle' | 'dialogue' | 'shop' | 'inn' | 'menu' | 'ending' | 'gameover'
The scenes the player registers.
RpgState
interface RpgState
A snapshot of the run for a page to read.
scene: string— The current scene name, '' before the title.regionId: string | null— The region the party is in, or null.level: number— The party leader's level.gold: number— Gold held.questsDone: string[]— Finished quest ids.playing: boolean— True from the title until the ending has played.
Run
interface Run
The whole run.
title: string— The world's title, so a save is matched to its world.party: Party— Heroes, levels, gear, the bag and gold.quests: QuestLog— The quests.flags: RunFlags— Bookkeeping.where: Where— The party's position.
RunFlags
interface RunFlags
Bookkeeping that is neither the party's nor the quests'.
talked: Record<string, number>— Times each npc was spoken to.cleared: Record<string, boolean>— Dungeons whose boss is beaten, by region id.chests: Record<string, boolean>— Chests opened, keyed${regionId}:${floor}.doors: Record<string, boolean>— Dungeon doors opened, keyed${regionId}:${floor}:${col},${row}.slain: Record<string, boolean>— Monsters beaten in dungeons, keyed${regionId}:${floor}:${index}.knownWeak: Record<string, boolean>— Monsters whose weakness has been found, by monster id.seen: Record<string, boolean>— Regions the party has stood in.ended: boolean— The ending has played.steps: number— Steps taken, for the encounter clock.
RunOptions
interface RunOptions
How a run's rules are set beyond the world document.
party?: Pick<PartyDef, 'slots' | 'slotOf' | 'elementSlot' | 'xpForLevel' | 'growth' | 'effects' | 'sellRatio' | 'unsellable' | 'stack' | 'bag'>— The party's rules: equipment slots, the level curve, growth, consumables, the shop, the bag.questRules?: Readonly<Record<string, StepRule>>— Quest step rules for step kinds of a game's own.startGold?: number— Gold at the start of a new game. Default 50.
RunSave
interface RunSave
A run as it is saved.
v: 2— Save format version.title: string— The world's title.party: PartySnapshot— The party's snapshot.quests: QuestState— The quest log's state.flags: RunFlags— Bookkeeping.where: Where— The party's position.
ThemeColours
interface ThemeColours
How a dungeon theme is drawn.
wall: string— Wall tiles.floor: string— Floor tiles.ambient: string— The 2D lights' ambient.torch: string— The torch.backdrop: string— The battle backdrop.
Where
interface Where
Where the party is.
scene: 'overworld' | 'town' | 'dungeon'— Which kind of map.regionId: string | null— The region, for town and dungeon; the region under the party on the overworld.col: number— Tile column; -1 is the scene's own start (the town's start, beside the town's door), -2 beside the dungeon's.row: number— Tile row.facing: number— Facing: 0 right, 1 down, 2 left, 3 up.floor: number— Dungeon floor index.


