Phaser AE

Rising-stack swap puzzles

Pro packv3.0.0-12DGrid

The rising-stack panel puzzle, frame by frame: the stack climbs from below, a cursor swaps panels side by side, and matches flash, pop and let what stood on them fall into chains. Garbage blocks and an adapter for versus matches make it ready for head-to-head play.

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

Released October 19, 2026 · updated October 20, 2026

Rising-stack swap puzzles: 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

riseStack

function riseStack(): Pack<{ riseStack: RiseStackApi }>

The rise-stack pack. Pure logic, so it needs no backend and runs headless.

Helpers

createRiseStack

function createRiseStack(cfg: RiseConfig = {}): RiseStack

Creates a rising stack.

riseVersusBoard

function riseVersusBoard(stack: RiseStack): RiseVersusBoard

Wrap a stack for versus-garbage's createVersusMatch.

TETRIS_ATTACK_TABLES

const TETRIS_ATTACK_TABLES: RiseTables

Tetris Attack's score and garbage tables as fans have documented them (combo bonus 20 at 4 panels up to 410 at 13; chain bonus 50 at ×2 up to 1800 at ×13; a 4-combo sends a 3-wide block, a 7-combo a 6-wide one, larger combos two or three blocks). The stop times are estimates.

Classes

RiseStack

class RiseStack

A Panel de Pon stack. Call step(input) once per 60 Hz frame.

  • readonly cols: number — Columns.
  • readonly rows: number — Rows.
  • readonly colors: number — Panel colours.
  • readonly timings: RiseTimings — Phase timings in force.
  • readonly tables: RiseTables — Tables in force.
  • riseSpeed: number — Rows a second the stack rises on its own; change it to speed the game up.
  • raiseSpeed: number — Rows a second while raising.
  • readonly grace: number — Frames of grace against the top.
  • score: number — Score.
  • chain: number — The chain the board is on: 1 when no chain is running.
  • stop: number — Frames of stop time left: the stack does not rise.
  • progress: number — How far (0 to 1) the next row has risen into view.
  • danger: number — Frames of grace used against the top.
  • topOut: boolean — True once the stack has topped out.
  • cursor: XY — The cursor: its left cell.
  • preview: number[] — Colours of the row rising into view beneath the stack.
  • frame: number — Frames stepped.
  • constructor(cfg: RiseConfig = {})
  • panel(x: number, y: number): PanelView | null — The panel or garbage cell at (x, y), or null.
  • garbage(): GarbageView[] — Every garbage block on the board.
  • get pendingGarbage(): number — Garbage cells waiting to drop.
  • get busy(): boolean — Whether anything is clearing, hovering or falling.
  • swap(x: number, y: number): boolean — Swap the cells at (x, y) and (x + 1, y) now, as a pointer or a script would. False if the swap is not allowed.
  • dropGarbage(w: number, h = 1): void — Queue a garbage block to drop at the top: w columns (from the left edge, alternating sides) by h rows.
  • cancelGarbage(cells: number): number — Cancel up to cells of queued garbage, newest first. Returns how many cells were cancelled.
  • findSwaps(): XY[] — Swaps that would make a match at once, for hints and simple AI: the left cell of each.
  • step(input: RiseInput = {}): RiseEvent[] — Advance one 60 Hz frame with this input. Returns what happened since the last step, in order (a swap made between steps included).
  • snapshot(): RiseSnapshot — The whole state as plain data.
  • restore(snap: RiseSnapshot): void — Return to a snapshot() of a stack with the same size and rules.
  • debugGrid(): string — The board as text, for tests: . empty, G garbage, * clearing, a colour digit otherwise.

RiseVersusBoard

class RiseVersusBoard implements VersusBoard<RiseInput>

A RiseStack as a VersusBoard.

  • readonly kind: "rise-stack" — Board family.
  • constructor(readonly stack: RiseStack)
  • step(input: RiseInput): void — One 60 Hz frame.
  • take(): VersusBoardEvent[] — Events since the last call.
  • receive(amount: number): void — Garbage arrives as full-width rows, then one block of what is left (at least 3 wide).
  • offset(amount: number): number — Cancel queued garbage.
  • get pending(): number — Garbage cells queued and not yet dropped.
  • get lost(): boolean — Topped out.
  • get score(): number — Score.
  • snapshot(): { stack: RiseSnapshot; resolving: boolean } — Plain data.
  • restore(snap: unknown): void — Restore a snapshot().

Types

GarbageView

interface GarbageView

A garbage block, as a renderer reads it.

  • id: number — Block id.
  • x: number — Left column.
  • y: number — Top row.
  • w: number — Width in columns.
  • h: number — Height in rows.
  • state: 'idle' | 'fall' | 'clear' — idle, fall, or clear while it flashes before its bottom row turns into panels.

PanelState

type PanelState = 'idle' | 'swap' | 'hover' | 'fall' | 'clear' | 'popped'

A panel's phase.

PanelView

interface PanelView

A panel, as a renderer reads it.

  • id: number — Stable id for the panel's life (a garbage cell's id is its block's).
  • color: number — Colour index, or -1 for garbage.
  • state: PanelState — Its phase. A clear panel is flashing or waiting to pop; a popped one is an empty-looking gap still holding up what stands on it.
  • timer: number — Frames left in the phase.
  • chain: boolean — Carries the chain flag: it fell because of a clear.
  • flashing?: boolean — A clear panel still in its flash (before it shows its face).
  • garbage?: number — The garbage block this cell belongs to, if any.

RiseConfig

interface RiseConfig

Configures createRiseStack.

  • cols?: number — Columns. Default 6.
  • rows?: number — Rows. Default 12.
  • colors?: number — Panel colours, 3 to 8. Default 5.
  • seed?: number — Seed for the panels. Default 1.
  • fillRows?: number — Rows filled at the start (a clean deal: no matches). Default 6. Ignored with layout.
  • layout?: readonly string[] — A starting board instead of a deal, for puzzles and tests: rows of text, top to bottom, . for empty and a digit for a colour. Fewer rows than the stack sit at its bottom. Panels left floating fall on the first frames.
  • riseSpeed?: number — Rows a second the stack rises on its own. Default 0.25.
  • raiseSpeed?: number — Rows a second while the raise button is held. Default 8.
  • grace?: number — Frames the stack may press against the top before the game is lost. Default 60.
  • timings?: Partial<RiseTimings> — Phase timings.
  • tables?: Partial<RiseTables> — Score, stop-time and garbage tables. Default TETRIS_ATTACK_TABLES.

RiseEvent

type RiseEvent = | { type: 'rise' } | { type: 'swap'; at: XY } | { type: 'match'; cells: XY[]; combo: number; chain: number; points: number } | { type: 'pop'; at: XY; id: number } | { type: 'land'; ids: number[] } | { type: 'chainEnd'; chain: number } | { type: 'attack'; garbage: { w: number; h: number }[]; combo: number; chain: number } | { type: 'garbageDrop'; id: number; at: XY; w: number; h: number } | { type: 'garbageBreak'; id: number; panels: XY[] } | { type: 'danger'; frames: number } | { type: 'topOut' }

One thing that happened in a frame, in order.

RiseInput

interface RiseInput

What a frame's input does. Movement and swap are presses (one action each); raise is held.

  • up?: boolean — Move the cursor up a row.
  • down?: boolean — Move the cursor down a row.
  • left?: boolean — Move the cursor left a column.
  • right?: boolean — Move the cursor right a column.
  • swap?: boolean — Swap the two cells under the cursor.
  • raise?: boolean — Raise the stack quickly while held.

RiseSnapshot

interface RiseSnapshot

The plain-data state of a stack, from snapshot().

  • grid: (Cell | null)[] — Grid cells, row by row (null for empty).
  • blocks: Block[] — Garbage blocks on the board.
  • queue: { w: number; h: number }[] — Garbage waiting to drop.
  • groups: { cells: number[]; timer: number; pops: number; total: number }[] — Clearing groups, as indices into grid.
  • s: { score: number; chain: number; stop: number; progress: number; danger: number; topOut: boolean; cursor: XY; preview: number[]; nextId: number; drops: number; frame: number; rng: RngState } — The other scalar state.

RiseStackApi

type RiseStackApi = typeof api

game.riseStack — every function and class this pack carries, as one namespace.

RiseTables

interface RiseTables

The scoring and attack tables. Index n of a table is the value for n; past the end, the last entry holds.

  • panel: number — Points per panel cleared. Default 10.
  • comboBonus: readonly number[] — Bonus for a combo of n panels (n ≥ 4), from index 4.
  • chainBonus: readonly number[] — Bonus for a chain link of length n (n ≥ 2), from index 2.
  • comboGarbage: readonly (readonly number[])[] — Garbage widths a combo of n panels sends, from index 4.
  • comboStop: readonly number[] — Frames of stop time for a combo of n panels, from index 4.
  • chainStop: readonly number[] — Frames of stop time for a chain link of length n, from index 2.

RiseTimings

interface RiseTimings

Frame counts (60 Hz) for each phase of a panel's life.

  • swap: number — A swap's slide. Default 4.
  • flash: number — A match flashes for this long. Default 44.
  • face: number — Then shows its face for this long before the first panel pops. Default 15.
  • pop: number — Then one panel pops every this many frames. Default 9.
  • hover: number — A panel that has lost its support hangs this long before it falls. Default 12.
  • fall: number — A falling panel or block drops one row every this many frames. Default 1.

XY

interface XY

A cell position: column x from the left, row y from the top.

  • x: number — Column, from 0 at the left.
  • y: number — Row, from 0 at the top.