Phaser AE

Role-playing game

Pro packv3.0.0-42DLogic

A whole small role-playing game, played from a world document with no game code. Write the regions, towns, dungeons, heroes, monsters, items and quests as data, and it generates the maps, runs the battles and the quest log, and saves the run.

This is a Pro pack. Upgrade to Phaser Pro to use it in your games.See Phaser Pro →

Released October 14, 2026 · updated October 19, 2026

Role-playing game: a screenshot of its demo
A note about these graphics

Expansion packs don't come with graphics. This screenshot is one way of drawing what the pack does, made for its demo: none of the sprites, tiles or backgrounds in it are in the pack.

That's by design. A pack is a game's logic, mechanics and effects, and it works with whatever art you give it. Some packs draw effects, backdrops or 3D scenes of their own, but none carries a game's sprites.

So the look is yours. Make the art on phaser.io, bring your own, or let your agent draw it in code: the same pack can look like anything.

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 from save() 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, before load. 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; load does 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. onEnd hears 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: its party and quests are 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 to host.

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 over turn-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's effect uses.
  • 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 a title or gameover of 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's ui theme (game.ui.theme, a ui-skins skin): 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: a ui style for panels and the selected row, a bars style for meters.
  • speech?: { preset?: string; theme?: Readonly<Record<string, unknown>> } — The speech box: a dialogue preset (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: a transition cover (kind, duration in 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.