Phaser AE

Versus garbage

Pro packv3.0.0-32DGrid

The competitive layer between puzzle boards: who attacks whom, how much, when it lands and who wins the round. It seats any boards that expose its versus hooks, adds offsetting, margin time, rounds, handicaps and CPU opponents, and never takes over a board's own rules.

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

Released October 14, 2026 · updated October 20, 2026

Versus garbage: 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

versusGarbage

function versusGarbage(): Pack<{ versusGarbage: typeof api }>

Install the versus garbage API.

Helpers

chainPotential

function chainPotential(f: Field, colors: readonly number[], pop: number, minY = 0): number

Longest chain that dropping one or two puyos of one colour onto one column would set off (the board's chain potential), by simulating pops and gravity on a copy.

CPU_LEVELS

const CPU_LEVELS: Readonly<Record<CpuLevel, CpuProfile>>

CPU levels for faller boards (Puyo: fire is the chain length it builds to).

cpuProfile

function cpuProfile(level: CpuLevel | (Partial<CpuProfile> & { level?: CpuLevel }), table: Readonly<Record<CpuLevel, CpuProfile>> = CPU_LEVELS): CpuProfile

A profile from a level name or overrides on one.

CRASH_CPU_LEVELS

const CRASH_CPU_LEVELS: Readonly<Record<CpuLevel, CpuProfile>>

CPU levels for crash-gem boards (fire is the gems a break must take unless it is under attack).

crashGemBoard

function crashGemBoard(game: CrashGemGame): CrashGemVersusBoard

Wraps a crash-gem board for a versus match.

crashGemCpu

function crashGemCpu(level: CpuLevel | (Partial<CpuProfile> & { level?: CpuLevel }) = 'normal'): CpuFactory<CrashGemVersusBoard, FallerInput>

A CPU for crash-gem boards: it builds same-coloured clusters and power gems, keeps the spawn column low, holds its crash gems until a break would take fire gems, and breaks at once to counter incoming gems or when in danger.

createVersusMatch

function createVersusMatch<B extends VersusBoard<I>, I>(options: VersusOptions<B, I>): VersusMatch<B, I>

Creates a match. Throws a RangeError for an unsupported configuration.

DROP_CPU_LEVELS

const DROP_CPU_LEVELS: Readonly<Record<CpuLevel, CpuProfile>>

CPU levels for grab-and-throw boards: think frames between moves, moveEvery frames per column step.

dropBoard

function dropBoard(game: DropGame, opts: DropBoardOptions = {}): DropVersusBoard

Wraps a grab-and-throw game for a versus match.

dropCpu

function dropCpu(level: CpuLevel | (Partial<CpuProfile> & { level?: CpuLevel }) = 'normal'): CpuFactory<DropVersusBoard, DropInput>

A CPU for grab-and-throw boards (Magical Drop): for every grab column and throw column it tries the move on a snapshot, settles it, and scores lines sent, pieces cleared and the tallest column; then it walks the clown there and back at its level's speed. A failed grab re-plans.

fallerBoard

function fallerBoard(game: FallerGame, opts: FallerBoardOptions = {}): FallerVersusBoard

Wraps a faller game for a versus match.

fallerCpu

function fallerCpu(level: CpuLevel | (Partial<CpuProfile> & { level?: CpuLevel }) = 'normal'): CpuFactory<FallerVersusBoard, FallerInput>

A CPU for faller boards. Puyo rulesets: it values chain potential (the longest chain one or two more puyos would set off), connected colours, low stacks and a clear third column, and fires when its chain reaches fire or when garbage is on its way or the stack is high (so it counters). Rows rulesets: the classic height / lines / holes / bumpiness weights plus attack. Others: points and attack against height.

magicalDropVersus

function magicalDropVersus(o: MagicalDropVersusOptions = {}): VersusOptions<DropVersusBoard, DropInput>

Magical Drop versus on grab-throw-columns (Data East): each board's chain sends its attack lines at chain end, offsetting cancels waiting lines, and lines enter only while the receiving board is idle (the pack's rule). Proves the versus layer is not tied to falling pieces.

marginAt

function marginAt(rule: MarginRule, seconds: number): { targetPoints: number | null; scale: number; step: number }

The margin state at seconds into a round: Tsu target points (or null) and the attack multiplier for boards that cannot take target points.

puyoTsuVersus

function puyoTsuVersus(o: PuyoVersusOptions = {}): VersusOptions<FallerVersusBoard, FallerInput>

Puyo Puyo Tsu versus (Compile, 1994): two 6 x 12 wells dealt the same pairs from one seed, nuisance at 70 target points with the fraction carried, offsetting, nuisance held until the attacker's chain ends and then dropped after the receiver's next move (at most 30 a move), +30 after an all clear, margin time from 96 s, first to two wins. The fall speed stays at the first level (Tsu's versus has no speed levels; an assumption, see the docs).

PUZZLE_FIGHTER_MARGIN

const PUZZLE_FIGHTER_MARGIN: MarginRule

Super Puzzle Fighter II Turbo's attack multiplier by time, as set in the X' rebalance patch's data table (github.com/KScl/puzzle-fighter-x-prime): x1.1 from 75 s, then +0.1 every 30 s up to x1.7. The patch notes say it shortened the original's thresholds, which are not published, so this is the nearest documented table.

puzzleFighterVersus

function puzzleFighterVersus(o: PuzzleFighterVersusOptions = {}): VersusOptions<CrashGemVersusBoard, FallerInput>

Super Puzzle Fighter II Turbo versus (Capcom, 1996): two crash-gem boards on one drop order, counter gems sent at the end of each break in the attacker's drop pattern, offsetting (counter-attacks cancel waiting gems, survivors start at 3), counter gems falling after the receiver's next pair, the margin multiplier, first to two wins.

STANDARD_TRAY

const STANDARD_TRAY: TrayRule

The standard tray from Puyo Puyo! 15th Anniversary on: small 1, large 6, rock 30, star 180, moon 360, crown 720, comet 1440, at most six symbols (Puyo Nexus, "Nuisance queue").

targetPointsSequence

function targetPointsSequence(rule: Extract<MarginRule, { kind: 'targetPoints' }>): number[]

The target-points sequence of a 'targetPoints' rule, from the base value to the last reduction.

tetrisVersus

function tetrisVersus(o: TetrisVersusOptions = {}): VersusOptions<FallerVersusBoard, FallerInput>

Two-player Guideline Tetris: endless Marathon wells, line clears attack by the Guideline attack table (T-spins, back-to-back and combos included), waiting garbage cancelled by your own clears, garbage rising after a piece that clears nothing.

trayIcons

function trayIcons(amount: number, rule: TrayRule = TSU_TRAY): TrayIcon[]

The symbols for amount garbage, largest first, at most rule.max (greedy, as the games draw them).

TSU_MARGIN

const TSU_MARGIN: MarginRule

Puyo Puyo Tsu: 70 target points, margin time 96 s, a reduction every 16 s, at most 14 (70, 52, 35, 26, 17, 13, 8, 6, 4, 3, 2, 1).

TSU_TRAY

const TSU_TRAY: TrayRule

Puyo Puyo Tsu's tray: small 1, large 6 (a row), rock 30 (one drop), mushroom 200, star 300, crown 420 (Puyo Nexus, "Nuisance queue"; the Mega Drive version is presumed to show up to nine symbols).

warningLevel

function warningLevel(amount: number, thresholds: readonly [number, number, number] = [1, 11, 31]): '' | 'CAUTION' | 'WARNING' | 'DANGER'

Super Puzzle Fighter II Turbo's incoming warnings (PlayStation manual): CAUTION 1-10, WARNING 11-30, DANGER 31+.

Classes

CrashGemVersusBoard

class CrashGemVersusBoard implements VersusBoard<FallerInput>

A crash-gem board (faller's CrashGemGame, Puzzle Fighter rules) in a versus match. Each break attacks with its counter gems (the running total for the move, after the board's own send rate); receive queues counter gems in the ATTACKER's drop pattern; offset cancels them (the survivors then start at the shorter countdown).

  • readonly kind: "crash-gems" — Board family.
  • readonly game: CrashGemGame — The game.
  • constructor(game: CrashGemGame) — Wraps a board.
  • get pattern(): readonly string[] — This board's drop pattern (what its attacks look like on the other side).
  • step(input: FallerInput): void — One 60 Hz frame.
  • take(): VersusBoardEvent[] — Normalised events since the last call.
  • events(): CrashGemEvent[] — The board's own events since the last call.
  • receive(amount: number, from: VersusBoard<never> | null): void — Queues counter gems in the attacker's pattern.
  • offset(amount: number): number — Cancels waiting counter gems.
  • get pending(): number — Counter gems waiting.
  • get lost(): boolean — Topped out.
  • get score(): number — Score.
  • snapshot(): CrashGemSnapshot — Snapshot.
  • restore(s: unknown): void — Restore.

DropVersusBoard

class DropVersusBoard implements VersusBoard<DropInput>

A grab-throw-columns game (Magical Drop) in a versus match. Its attack event (lines for the chain, at chain end) attacks; receive queues lines that enter from the ceiling only while this board is idle (the pack's rule); offset cancels waiting lines. Lines are coloured by the attacker's pattern when it has one.

  • readonly kind: "drop" — Board family.
  • readonly game: DropGame — The game.
  • readonly pattern?: readonly string[] — Attack colour pattern, if any.
  • constructor(game: DropGame, opts: DropBoardOptions = {}) — Wraps a game.
  • step(input: DropInput): void — Applies the input's actions, then advances 1/60 s.
  • take(): VersusBoardEvent[] — Normalised events since the last call.
  • events(): DropEvent[] — The game's own events since the last call.
  • receive(amount: number, from: VersusBoard<never> | null): void — Queues lines, coloured by the attacker's pattern when it has one.
  • offset(amount: number): number — Cancels waiting lines.
  • get pending(): number — Lines waiting (kept as lines accepted by receive, less those offset or landed, so no state copy is made each tick and the count is right the moment receive returns).
  • get lost(): boolean — Lost.
  • get score(): number — Score.
  • snapshot(): { game: string; sentLines: number; waiting: number; total: number; dead: boolean } — Snapshot.
  • restore(s: unknown): void — Restore.

FallerVersusBoard

class FallerVersusBoard implements VersusBoard<FallerInput>

A faller game in a versus match. Puyo-style rulesets (with rules.nuisance): chain steps attack with their nuisance, receive queues nuisance (it falls after this player's next move, Tsu's rules), offset cancels it, and margin time sets the target points. Rows rulesets (Tetris): line clears attack with rules.attack, receive queues garbage rows that rise after the next piece that clears nothing, and offset cancels waiting rows. Other rulesets (Columns, Dr. Mario) have no incoming-garbage hook in faller and are refused.

  • readonly kind: "faller" — Board family.
  • readonly game: FallerGame — The game.
  • readonly pattern?: readonly string[] — Attack colour pattern, if any.
  • constructor(game: FallerGame, opts: FallerBoardOptions = {}) — Wraps a game. Throws a RangeError for a ruleset with no incoming-garbage hook.
  • step(input: FallerInput): void — One 60 Hz frame.
  • take(): VersusBoardEvent[] — Normalised events since the last call.
  • events(): FallerEvent[] — The game's own events since the last call (for sounds, toasts and animation).
  • receive(amount: number, _from: VersusBoard<never> | null): void — Queues nuisance or garbage rows.
  • offset(amount: number): number — Cancels waiting nuisance or garbage rows (newest rows first).
  • get pending(): number — Nuisance or rows waiting.
  • get lost(): boolean — Topped out.
  • get score(): number — Score.
  • setTargetPoints(points: number): void — Margin time (nuisance rulesets only).
  • snapshot(): { game: FallerSnapshot; rowsWaiting: number } — Snapshot.
  • restore(s: unknown): void — Restore.

VersusMatch

class VersusMatch<B extends VersusBoard<I>, I>

A versus match between puzzle boards. Call step(inputs) once per 60 Hz tick.

  • readonly options: VersusOptions<B, I> — The options in force.
  • constructor(options: VersusOptions<B, I>) — Creates a match and its first round.
  • get seats(): VersusSeat<B>[] — Seats, in order.
  • board(i: number): B — Seat i's board.
  • incoming(i: number): number — Garbage on its way to seat i (committed plus in transit).
  • get round(): number — Round number (1-based).
  • get phase(): VersusPhase — Phase.
  • get winner(): number | null — The last round's winner (null for a draw), or the match winner once it is over.
  • get ticks(): number — Ticks since the round started.
  • get seconds(): number — Seconds since the round started.
  • get margin(): { targetPoints: number | null; scale: number; step: number } — The margin state in force: target points (Tsu) and the attack multiplier for other boards.
  • get alive(): number[] — Live seats this round.
  • drain(): VersusEvent[] — Removes and returns the pending events.
  • nextRound(): void — Starts the next round now (after a round is over and the match is not).
  • restart(): void — Starts the whole match again (wins cleared, same options).
  • step(inputs: readonly (I | undefined)[] = []): void — One 60 Hz tick: every board steps (CPU seats take their own input), attacks are routed, margin time advances, and the round is decided. inputs[i] is seat i's input (ignored for CPU seats).
  • snapshot(): VersusSnapshot — A deep copy of the whole match (boards, transit, wins, CPU state).
  • restore(snap: VersusSnapshot): void — Restores a snapshot() of a match with the same options.

Types

CpuFactory

type CpuFactory<B, I> = (board: B, seat: number, seed: number) => VersusCpu<I>

Builds a CPU for a board (called at the start of every round).

CpuLevel

type CpuLevel = 'easy' | 'normal' | 'hard'

CPU difficulty names.

CpuProfile

interface CpuProfile

How a CPU plays.

  • think: number — Frames it waits on a new piece before moving (its reaction time).
  • moveEvery: number — Frames between its taps (shift, rotate).
  • drop: 'none' | 'soft' | 'hard' — How it finishes a placement: let gravity drop it, hold soft drop, or hard drop where the rules allow.
  • depth: 1 | 2 — Look-ahead: 1 = the current piece; 2 = also the next piece for the best beam placements.
  • beam: number — Placements carried into the second ply, and the pool a mistake is picked from.
  • mistakes: number — Chance of playing a random placement from the best beam instead of the best.
  • fire: number — Patience: the smallest attack it sets off unprompted (Puyo: chain length; crash gems: gems broken).
  • budget: number — Previews it runs per tick while thinking.

CpuView

interface CpuView

What a CPU controller may know about the match beyond its own board.

  • incoming: number — Garbage on its way to this seat (committed plus held in transit).
  • seconds: number — Seconds since the round started.
  • outgoing: number — The highest attack waiting for any opponent (to judge whether to counter).

DropBoardOptions

interface DropBoardOptions

Options for dropBoard.

  • pattern?: readonly string[] — Colour pattern of this board's attacks: incoming lines take these colours (a character's attack pattern); without one, lines are random.

DropInput

interface DropInput

One tick of input for a grab-and-throw board: actions applied before the tick.

  • move?: -1 | 1 — Step the clown one column.
  • moveTo?: number — Jump straight to a column.
  • grab?: boolean — Grab.
  • throw?: boolean — Throw.
  • push?: boolean — Push a row in (when the rules allow).

FallerBoardOptions

interface FallerBoardOptions

Options for fallerBoard.

  • pattern?: readonly string[] — Colour pattern of this board's attacks (for boards that colour incoming garbage).

MagicalDropVersusOptions

interface MagicalDropVersusOptions extends VersusPresetOptions

Options for magicalDropVersus.

  • patterns?: readonly (readonly string[] | null)[] — Attack colour pattern per seat (rows of R G B Y). Default: random lines.

MarginRule

type MarginRule = | { kind: 'none' } | { kind: 'targetPoints'; base: number; start: number; every: number; first: number; steps: number } | { kind: 'scale'; steps: readonly { at: number; scale: number }[] }

How attack power grows with time.

  • 'none': never.
  • 'targetPoints': Puyo Puyo Tsu. After start seconds the target points (score per nuisance) fall, then again every every seconds: the first reduction multiplies by first (0.75), each later one halves the value from two reductions before, rounded down; at most steps reductions, never below 1 (Puyo Nexus, "Margin time"). Boards with setTargetPoints get the value; others have their attacks scaled by base / current.
  • 'scale': attacks multiplied by scale from at seconds (Super Puzzle Fighter's margin table).

PuyoVersusOptions

interface PuyoVersusOptions extends VersusPresetOptions

Options for puyoTsuVersus.

  • colors?: number — Colours (Tsu: 3 Easy, 4 Normal, 5 Hard).
  • popSize?: number — Pop size. Default 4.
  • cols?: number — Well width. Default 6.
  • rows?: number — Well height. Default 12.

PuzzleFighterVersusOptions

interface PuzzleFighterVersusOptions extends VersusPresetOptions

Options for puzzleFighterVersus.

  • patterns?: readonly (string | DropPattern)[] — Drop pattern per seat (keys of faller's DROP_PATTERNS, or your own). Default 'bands' and 'halves'.
  • speeds?: readonly number[] — Drop speed per seat, 1..5 (the original's VS handicap). Default 3.
  • diamond?: number — Diamond damage: 0.5 original, 0.8 HD Remix.
  • colors?: number — Gem colours (2..4). Default 4.
  • cols?: number — Board width. Default 6.
  • rows?: number — Board height. Default 12.

TetrisVersusOptions

interface TetrisVersusOptions extends VersusPresetOptions

Options for tetrisVersus.

  • samePieces?: boolean — Both players get the same piece order. Default false (a bag each).

Transit

interface Transit

Garbage on its way to a seat, held while the attacker's move resolves.

  • from: number — Attacking seat.
  • amount: number — Amount.

TrayIcon

interface TrayIcon

One tray symbol and how much garbage it stands for.

  • name: string — Symbol name ('small', 'large', 'rock', ...).
  • value: number — Garbage it stands for.

TrayRule

interface TrayRule

A tray: its symbols (any order) and how many fit.

  • icons: readonly TrayIcon[] — Symbols.
  • max: number — Most symbols shown at once.

VersusBoard

interface VersusBoard<I>

A puzzle board taking part in a versus match. One step is one 60 Hz tick. Adapters for the engine's board packs: fallerBoard, crashGemBoard, dropBoard. Implement it for any other board that can attack and take garbage.

  • readonly kind: string — Board family, for reports ('faller', 'crash-gems', 'drop', ...).
  • step(input: I): void — Advances the board one 60 Hz tick with this input.
  • take(): VersusBoardEvent[] — Removes and returns the normalised events produced since the last call.
  • receive(amount: number, from: VersusBoard<never> | null): void — Commits incoming garbage: it lands by the board's own rules (Puyo: after this player's next move). from is the attacking board, whose pattern some boards use to colour what lands.
  • offset(amount: number): number — Cancels up to amount committed garbage that has not landed yet. Returns how much was cancelled.
  • readonly pending: number — Committed garbage that has not landed yet.
  • readonly lost: boolean — True once the board has topped out.
  • readonly score: number — Score (used by the 'leader' routing).
  • readonly pattern?: readonly string[] — The colours this board's attacks arrive in (rows of colour letters, top to bottom), if it has a pattern.
  • setTargetPoints?(points: number): void — Sets Tsu-style target points (margin time). Boards without it get their attacks scaled instead.
  • snapshot(): unknown — A deep copy of the board (plain data).
  • restore(snapshot: unknown): void — Restores a snapshot() of a board with the same rules.

VersusBoardEvent

type VersusBoardEvent = /** One step of a move produced attack (a chain step, a line clear). Raw: before offsetting, handicaps, margin. */ | { type: 'attack'; amount: number; chain: number } /** The move that attacked has finished resolving: attacks held while it ran are released. */ | { type: 'moveEnd' } /** Garbage this board had received has landed on it. */ | { type: 'landed'; amount: number } /** The board emptied itself (Puyo all clear). */ | { type: 'allClear' } /** The board topped out. */ | { type: 'lost'; reason: string }

What a board reports to the versus layer, normalised from its own events.

VersusCpu

interface VersusCpu<I>

A CPU player: produces one input per tick for its own board.

  • input(view: CpuView): I — The input for this tick (called once per tick, before the board steps).
  • snapshot(): unknown — Plain-data state for match snapshots.
  • restore(snapshot: unknown): void — Restores snapshot().

VersusEvent

type VersusEvent = | { type: 'round'; round: number } | { type: 'attack'; from: number; raw: number; amount: number; offset: number; to: number[] } | { type: 'commit'; from: number; to: number; amount: number } | { type: 'landed'; seat: number; amount: number } | { type: 'allClear'; seat: number } | { type: 'margin'; step: number; targetPoints: number | null; scale: number } | { type: 'lost'; seat: number; reason: string } | { type: 'roundOver'; round: number; winner: number | null } | { type: 'matchOver'; winner: number }

Events from drain().

VersusHandicap

interface VersusHandicap

Per-seat handicap.

  • send?: number — Multiplier on attacks this seat sends. Default 1.
  • receive?: number — Multiplier on attacks this seat receives. Default 1.
  • start?: number — Garbage committed to this seat when each round starts (Tsu CPU "Very Hard" starts with two rows). Default 0.

VersusOptions

interface VersusOptions<B extends VersusBoard<I>, I>

How a match is set up. Presets: puyoTsuVersus, puzzleFighterVersus, magicalDropVersus, tetrisVersus.

  • players: number — Seats, 2..8.
  • board: (seat: number, round: number, seed: number) => B — Builds seat seat's board for a round. seed is the round's seed (the same for every seat when sharedSeed).
  • seed?: number — Match seed. Default 1.
  • sharedSeed?: boolean — Every board in a round gets the same seed, so the same pieces (Puyo Tsu, Puzzle Fighter). Default true.
  • firstTo?: number — Round wins needed to take the match (best of 2n - 1). Default 2.
  • routing?: VersusRouting — Attack routing. Default 'opponent'.
  • offset?: boolean — A seat's attack first cancels garbage waiting for it (Tsu's offsetting, Puzzle Fighter's counter-attack). Default true.
  • hold?: boolean — Attacks wait in transit until the attacker's move has finished (Tsu: nuisance cannot fall while the opponent's chain runs). Default true.
  • margin?: MarginRule — Margin time. Default none.
  • handicaps?: readonly VersusHandicap[] — Per-seat handicaps.
  • cpu?: readonly (CpuFactory<B, I> | null)[] — Per-seat CPU players (null = human).
  • draw?: 'replay' | 'share' — Both (all) remaining boards topping out on one tick: 'replay' the round with no point, or 'share' a point each. Default 'replay'.
  • roundPause?: number — Ticks between a round ending and the next starting (when autoNextRound). Default 150.
  • autoNextRound?: boolean — Start the next round by itself after roundPause. Default true; otherwise call nextRound().

VersusPhase

type VersusPhase = 'playing' | 'roundOver' | 'matchOver'

Match phase.

VersusPresetOptions

interface VersusPresetOptions

Options shared by the presets.

  • difficulty?: FallerDifficulty — Board difficulty (the board pack's Easy / Normal / Arcade). Default 'normal'.
  • seed?: number — Match seed.
  • players?: number — Seats. Default 2.
  • firstTo?: number — Round wins to take the match. Default 2.
  • cpu?: readonly (CpuLevel | null)[] — CPU level per seat (null = human). Default: seat 0 human, the others 'normal'.
  • margin?: boolean — Margin time on. Default true.
  • offset?: boolean — Offsetting on. Default true.
  • handicaps?: readonly VersusHandicap[] — Per-seat handicaps.

VersusRouting

type VersusRouting = 'opponent' | 'all' | 'split' | 'leader' | 'random' | ((attacker: number, alive: readonly number[]) => number[])

Where a seat's attacks go. 'opponent': the other seat (two players) or the next live seat. 'all': every live opponent gets the full attack (Puyo four-player). 'split': shared out between them. 'leader': the live opponent with the highest score. 'random': a live opponent chosen by the match's seeded generator. Or a function.

VersusSeat

interface VersusSeat<B>

A seat in the match.

  • readonly index: number — Seat index.
  • readonly board: B — This round's board.
  • readonly wins: number — Rounds won.
  • readonly incoming: number — Garbage on its way: committed to the board but not landed, plus held in transit.
  • readonly transit: readonly Transit[] — The part of incoming still held while attackers' moves run.
  • readonly lost: boolean — Lost this round.
  • readonly cpu: boolean — True when a CPU plays this seat.
  • readonly sent: number — Total attack sent this round (after offsetting).

VersusSnapshot

interface VersusSnapshot

A match snapshot (plain data plus each board's own snapshot).

  • round: number — Round number.
  • phase: VersusPhase — Phase.
  • tick: number — Ticks this round.
  • pause: number — Pause ticks left after a round.
  • winner: number | null — Winner of the last round or the match.
  • marginStep: number — Margin step in force.
  • rng: RngState — Where the match's seeded stream stands (a kernel Rng snapshot).
  • seats: SeatState[] — Seats.
  • boards: unknown[] — Each board's snapshot.