Phaser AE

Run Progression

Pro packv3.0.0-2Arcade

The layer of a roguelike that sits between the fights: a seeded branching map to a boss, a draft of upgrades after each encounter, shops, evolutions and a profile that outlives every run. Your game supplies the combat; this pack keeps the run honest.

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

Run Progression: 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

runProgression

function runProgression():Pack<{runProgression:typeof rules}>

Install renderer-independent run progression policies.

Helpers

availableUpgrades

function availableUpgrades(defs: readonly Upgrade[], levels: Readonly<Record<string, number>>): Upgrade[]

The upgrades that can be taken at these levels: below their max level, with prerequisites met and not replaced by one already held.

createRun

function createRun(seed = 0, difficulty: Difficulty = 'medium', definitions: readonly Upgrade[] = actionUpgrades, profile?: Profile)

Start a run with a seed (default 0), difficulty (default medium), upgrade definitions (default actionUpgrades) and an optional profile. Throws on invalid definitions or seed.

draftUpgrades

function draftUpgrades(defs: readonly Upgrade[], levels: Readonly<Record<string, number>>, seed: number, count = 3): string[]

Stable without replacement draft. Evolution definitions use requirements and replaced weapon IDs.

generateRunMap

function generateRunMap(seed: number, difficulty: Difficulty = 'medium'): RunMap

Generate varied, reachable DAGs; every offered route reaches a boss and every node is reachable.

Classes

RunProgression

class RunProgression

A branching run: a seeded map of encounters, reward drafts, shops, upgrades and a persistent profile.

  • readonly definitions: Upgrade[] — The upgrade definitions, a copy of those passed in.
  • state: RunState — The run's plain-data state; snapshot() copies it.
  • constructor(seed = 0, difficulty: Difficulty = 'medium', definitions: readonly Upgrade[] = actionUpgrades, profile: Profile = { unlocks: [], completedRuns: 0 })
  • node() — The node the run is at.
  • finish(reward = 10) — Finish the current encounter: pay reward credits (default 10) and offer a draft, or win the run at the boss. Returns false when it was already finished or the run is over. Throws unless reward is a whole number, 0 or more.
  • offer() — The draft on offer: up to 3 upgrade ids. One is made if none is pending, then the same ids are returned until one is chosen.
  • choose(id: string) — Take an offered upgrade and clear the draft. Returns false when id is not on offer.
  • buy(id: string) — Buy an upgrade at a shop for its price. Returns false unless the run is at a shop with credits enough, the upgrade is available and not already bought there, and the run is not over.
  • travel(id: string) — Move to the connected node id. Returns false unless this encounter is finished, no draft is pending, id is one of the node's next and the run is not over.
  • fail() — End the run as lost, and drop any draft on offer. Does nothing once the run is won.
  • restart() — Start a new run on the same seed and difficulty, keeping the profile.
  • newRun(seed: number, difficulty = this.state.map.difficulty) — Start a new run on seed (difficulty defaults to the current one), keeping the profile and the definitions. Throws unless the seed is an unsigned 32-bit whole number.
  • snapshot() — A plain copy of the run state.
  • restore(s: RunState) — Load a snapshot. Throws when its version is not 1, its map does not match its seed and difficulty, it names an unknown node or upgrade, a level is out of range, a number is not a whole number or a draft entry is not available.

Constants

actionUpgrades

const actionUpgrades: Upgrade[]

The built-in upgrade set: bolt, haste, multishot, vitality and magnet, and Star nova, which evolves from bolt 3 with haste 1 and replaces bolt.

Types

Profile

interface Profile

What outlives a run: carried into the next by restart and newRun.

  • unlocks: string[] — Ids of unlocks earned; veteran is added on the first boss win.
  • completedRuns: number — Runs won so far.

RunMap

interface RunMap

A generated run map: a graph of encounters, column by column, from a start to a boss.

  • seed: number — The seed the map was generated from; the same seed and difficulty give the same map.
  • difficulty: Difficulty — The difficulty the map was generated for; harder maps are deeper.
  • nodes: RunNode[] — Every node, in column order.
  • start: string — Id of the first node.

RunNode

interface RunNode

One encounter on the run map.

  • id: string — Unique id of the form depth:lane.
  • depth: number — Column of the node along the run, 0 at the start; the last column is the boss.
  • lane: number — Row of the node within its column, 0 at the top.
  • kind: 'fight' | 'elite' | 'rest' | 'shop' | 'boss' — What the node is: a fight, an elite fight, a rest, a shop or the boss.
  • next: string[] — Ids of the nodes the run can travel to from here, in the next column.
  • seed: number — Unsigned 32-bit seed for the game to build this node's encounter from.

RunState

interface RunState

The whole run as plain data, for saving.

  • version: 1 — The snapshot format; always 1.
  • map: RunMap — The map the run is on.
  • current: string — Id of the node the run is at.
  • cleared: string[] — Ids of the nodes whose encounters have been finished.
  • credits: number — Credits held, from finished encounters; shops spend them.
  • upgrades: Record<string, number> — Level held of each upgrade, by id; upgrades not held are absent.
  • draft: string[] — Ids of the upgrades on offer now; empty when none is pending.
  • draftIndex: number — How many drafts have been offered; it varies the seed of the next one.
  • shopBought: string[] — Purchases made, as nodeId/upgradeId, so a shop sells each upgrade once.
  • won: boolean — Whether the boss has been cleared.
  • lost: boolean — Whether the run has been lost.
  • profile: Profile — The persistent profile carried between runs.

Upgrade

interface Upgrade

An upgrade a run can offer or sell.

  • id: string — Unique, non-empty id.
  • name: string — The name shown to the player.
  • maxLevel: number — Highest level it can reach; a whole number, 1 or more.
  • price: number — Price in credits at a shop; a whole number, 0 or more.
  • requires: Record<string, number> — Prerequisites as upgrade id to the minimum level that must be held first.
  • replaces: string[] — Ids of upgrades removed when this one is taken (an evolution replaces its base weapon), which can then not be offered again.