Phaser AE

Bubble shooter

Pro packv3.0.0-42DGrid

The bubble shooter, from the mechanic up to a whole arcade session: aim, bank off the walls, snap into a hanging hex grid, pop three, and drop everything cut loose, with the ceiling pressing down. Presets follow the classic arcade rules, and every one of those rules is a setting.

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

Bubble shooter: 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

bubbleshooter

function bubbleshooter(): Pack<{ bubbleshooter: BubbleshooterApi }>

The bubbleshooter pack. Pure logic, so it needs no backend and runs headless.

Helpers

BUBBLE_DIFFICULTY

const BUBBLE_DIFFICULTY: Readonly<Record<BubbleDifficultyName, BubbleDifficulty>>

Easy and Normal show the guide line and slow the press; Arcade is the original (guide only after a continue).

bubbleDifficulty

function bubbleDifficulty(name: BubbleDifficultyName = 'normal'): BubbleDifficulty

The difficulty table entry for a name.

ceilingInterval

function ceilingInterval(c: CeilingConfig, live: number): number

Shots between ceiling drops for live colours on the board.

createBubbleField

function createBubbleField(cfg: ShooterConfig): BubbleField

Creates a BubbleField from the given configuration.

createBubbleGame

function createBubbleGame(config: BubbleGameConfig): BubbleGame

Creates a session.

DEFAULT_LEGEND

const DEFAULT_LEGEND: Readonly<Record<string, LegendEntry>>

The default layout legend. Colours follow Puzzle Bobble's eight, in the order the pack numbers them: B blue, Y yellow, R red, G green, P purple, O orange, K black, W white; digits 0-9 are colour indices too. # clear (uncoloured) bubble, * star, X stone; ., _ and - are empty.

dropScore

function dropScore(n: number, base = 10, cap = 17): number

Puzzle Bobble's dropped-bubble bonus: 10 x 2^n for n bubbles dropped by one shot, n capped at cap (17).

exportRounds

function exportRounds(rounds: readonly BubbleRound[]): string

Export rounds in the importRounds format.

importRounds

function importRounds(text: string): BubbleRound[]

Import rounds from text. Rounds are separated by blank lines; a line starting with = names the round and may carry cols=N for a wide board ("= Big one cols=17"). Other lines are layout rows (see parseLayout): colour letters BYRGPOKW or digits, # clear, * star, X stone, . empty; spaces are ignored.

parseLayout

function parseLayout(rows: readonly string[], legend: Readonly<Record<string, LegendEntry>> = DEFAULT_LEGEND): [number, number, LegendEntry][]

Parse a layout: one string per row from the ceiling; whitespace is ignored, so rows may be written with the half-bubble indent of the screen. Returns [col, row, entry] for every occupied cell. Throws on unknown characters, naming the row and the character.

PUZZLE_BOBBLE_2_BOARDS

const PUZZLE_BOBBLE_2_BOARDS: Readonly<Record<string, readonly string[]>>

Puzzle Bobble 2 (Taito, 1995): the 135 boards of the alphabet tree, keyed by stage and round ("A-01"). Shapes, stones (X), uncoloured bubbles (#), stars (*) and colour counts from the level-map FAQ; colours authored. Wide boards are 17 bubbles across.

PUZZLE_BOBBLE_2_TIME_BONUS

const PUZZLE_BOBBLE_2_TIME_BONUS: TimeBonusConfig

Puzzle Bobble 2's: 500,000 within 5 s, falling linearly (about 11,850 a second, timed finer than a second), none from 48 s. The slope is fitted to the FAQ's sample table.

PUZZLE_BOBBLE_2_TREE

const PUZZLE_BOBBLE_2_TREE: readonly (readonly string[])[]

Puzzle Bobble 2's alphabet tree: two choices after every five rounds, six stages, seven endings.

PUZZLE_BOBBLE_CEILING

const PUZZLE_BOBBLE_CEILING: CeilingConfig

The press: with all eight colours on the board it comes down every baseShots shots, one shot sooner per missing colour (FAQ). The base of 12 is an estimate that gives round 1 (four colours) a drop every eight shots.

PUZZLE_BOBBLE_COLOURS

const PUZZLE_BOBBLE_COLOURS: readonly { letter: string; name: string; monster: string }[]

Puzzle Bobble's eight bubble colours in pack order, with the Bubble Bobble monster inside each.

PUZZLE_BOBBLE_HURRY

const PUZZLE_BOBBLE_HURRY: HurryConfig

About ten seconds to fire, with a countdown for the last five (FAQ).

PUZZLE_BOBBLE_LAUNCHER

const PUZZLE_BOBBLE_LAUNCHER: LauncherConfig

The arcade launcher. Tilt range, turn speed, shot speed and reload are estimates from footage-era play.

PUZZLE_BOBBLE_ROUNDS

const PUZZLE_BOBBLE_ROUNDS: readonly (readonly string[])[]

Puzzle Bobble (Taito, 1994): the 30 rounds of the one-player game. Shapes and colour counts from the arcade FAQ's round diagrams; colours of rounds 1, 3 and 4 from arcade screenshots, the rest authored.

PUZZLE_BOBBLE_TIME_BONUS

const PUZZLE_BOBBLE_TIME_BONUS: TimeBonusConfig

Puzzle Bobble's round-clear bonus: 50,000 within 5 s, 840 less each further whole second, none from 65 s.

puzzleBobble2Preset

function puzzleBobble2Preset(opts: BubblePresetOptions = {}): BubbleGameConfig

Puzzle Bobble 2 (Taito, 1995): the alphabet-tree route (choose a stage after every five rounds), stone blocks, uncoloured bubbles that only drop, stars that clear a colour, wide 17-bubble boards, and the 500,000 time bonus. Same launcher, hurry and press as the first game (FAQ: "screen drop method is the same").

puzzleBobblePreset

function puzzleBobblePreset(opts: BubblePresetOptions = {}): BubbleGameConfig

Puzzle Bobble (Taito, 1994): 8 x 11 field above the line, 30 rounds, the arcade's scoring and timers.

pyramidRoute

function pyramidRoute(tiers: readonly (readonly string[])[], roundsPerStage: number, boards: Readonly<Record<string, readonly string[]>>): { rounds: BubbleRound[]; route: BubbleRoute; widths: Record<string, number> }

Build a route from a pyramid of stage ids: stage i of a tier leads to stages i and i+1 of the next tier. Each stage's rounds are looked up as ${id}-${nn} in boards, numbered on from the tier's first round.

timeBonus

function timeBonus(cfg: TimeBonusConfig | null, seconds: number): number

Puzzle Bobble's time bonus formula from a config.

Classes

BubbleField

class BubbleField

An offset-hex bubble field hanging from a ceiling. Create one with createBubbleField.

  • readonly cols: number — Bubbles in a full row.
  • readonly rows: number — Rows that fit above the dead line before any press.
  • readonly colors: number — Palette size for random draws.
  • readonly radius: number — The bubble radius, in world units.
  • readonly rowHeight: number — Distance between row centres.
  • readonly oddRows: 'short' | 'full' — Shifted-row policy.
  • readonly hitScale: number — Contact distance as a fraction of a bubble's diameter.
  • readonly popMin: number — Smallest group that pops.
  • score: number — Legacy: score gained by shoot so far.
  • shots: number — Legacy: shots fired by shoot that hit the field.
  • topOut: boolean — Legacy: true once shoot has left a bubble over the line.
  • constructor(cfg: ShooterConfig)
  • shifted(y: number): boolean — True when row y is drawn half a bubble to the right.
  • rowWidth(y: number): number — Cells in row y.
  • inBounds(x: number, y: number): boolean — True when (x, y) is a cell of the grid (it may be empty).
  • get press(): number — Ceiling presses so far.
  • get ceilingY(): number — The world y of the ceiling (moves down a row per press).
  • get lineRow(): number — The first row index that lies over the dead line.
  • get width(): number — Field width in world units.
  • get lineY(): number — World y of the dead line (fixed: the ceiling comes down to meet it).
  • get height(): number — Legacy alias: the playfield height from the unpressed ceiling to the dead line.
  • get launcher(): Vec — Where the launcher sits: centred, just below the line.
  • centre(x: number, y: number): Vec — World centre of a cell (includes the press).
  • at(x: number, y: number): Cell | null — The cell at (x, y), or null when empty or outside.
  • bubble(x: number, y: number): number | null — Legacy: the colour at a cell (-1 for uncoloured kinds), or null when the cell is empty or outside.
  • allocateId(): number — Reserve a fresh cell id (a session gives its flying shot the id the bubble will keep when it lands).
  • cells(): CellView[] — Every occupied cell with its position, row by row.
  • load(rows: readonly string[], legend: Readonly<Record<string, LegendEntry>> = DEFAULT_LEGEND): void — Replace the contents with a layout (see parseLayout); the press and parity reset, ids carry on (never reused).
  • set(x: number, y: number, kind: CellKind | null, color = 0): Cell | null — Set or clear one cell directly (editors, tests, garbage). Returns the new cell.
  • neighbours(x: number, y: number): XY[] — Hex neighbours of (x, y): six, offset-aware.
  • liveColors(): number[] — Colours of the coloured bubbles still in play. Sorted, so draws from it are deterministic.
  • remaining(): number — Cells still to clear (everything except stones).
  • get won(): boolean — True when nothing but stones is left.
  • crossed(): boolean — True when a non-stone cell lies over the dead line.
  • lowestRow(): number — The lowest occupied non-stone row, or -1 when empty: how close the field is to the line.
  • trace(tilt: number, from?: Vec, maxBounces = 64): TraceResult — Trace a shot from from (default the launcher) at tilt radians from straight up (positive to the right, i.e. clockwise), reflecting off the side walls, until it touches a bubble or the ceiling. The shot is a circle: contact is exact (ray against circle), not a stepped walk.
  • place(x: number, y: number, color: number, kind: CellKind = 'bubble', id?: number): Resolution — Put a shot into cell (x, y) and resolve it: a star it touches clears its colour; otherwise a same-colour group of popMin or more pops; then everything no longer hanging from the ceiling or a stone drops.
  • dropOrphans(): CellView[] — Remove everything not connected to row 0 or to a stone; returns what fell.
  • pressDown(): boolean — Lower the ceiling one row (Puzzle Bobble's press): every cell moves down with it. Returns crossed().
  • pushRow(colors: readonly (number | null)[]): boolean — Push a new row in from the top (rising-row modes): every row moves down one, parity flips, and row 0 is filled from colors (one entry per cell; null leaves a gap). Returns crossed().
  • snapshot(): FieldSnapshot — A plain-data snapshot.
  • restore(s: FieldSnapshot): void — Restore a snapshot taken from a field with the same geometry.
  • aim(tilt: number, launcher?: Vec): { path: Vec[]; hit: XY | null } — Legacy: trace from the launcher (or launcher), returning only the path and the snap cell.
  • shoot(tilt: number, color?: number): ShotResult — Legacy: fire a bubble of color (or a live colour) at tilt and resolve it instantly, scoring with the Puzzle Bobble table. A session (BubbleGame) is the timed, rule-complete alternative.
  • findShots(samples = 60, colors?: readonly number[], range = 1.3): { angle: number; color: number; pops: number; drops: number; score: number; hit: XY }[] — Candidate shots scored by pops and drops, best first: a hint, and the brain of the bundled bots. Tilts are sampled evenly across range (default ±1.3 rad). Coloured candidates use colors (default the live colours). Never mutates the field.
  • autoplay(maxShots = 300): ShotResult[] — Legacy: play best shots (scoring ones only) until cleared, crossed or stuck.
  • debugGrid(): string — The field as text, one line per row (shifted rows indented): colour digits, # clear, * star, X stone.

BubbleGame

class BubbleGame

A whole bubble-shooter session. Create one with createBubbleGame.

  • config: BubbleGameConfig — The configuration (rules may be edited between rounds through configure).
  • field: BubbleField — The field of the current round.
  • constructor(config: BubbleGameConfig)
  • turn(dir: number): void — Hold a turn direction: -1 left, 1 right, 0 none. Also moves the route highlight.
  • setTilt(tilt: number): void — Set the tilt directly (pointer aiming), clamped to the launcher's range.
  • aimAt(x: number, y: number): void — Aim at a world point (pointer aiming). Points below the launcher aim at the nearest limit.
  • centre(): void — Point straight up.
  • suggest(samples = 80): { tilt: number; pops: number; drops: number } | null — The best tilt for the loaded bubble (most drops, then most pops, then the best place to leave it), or null when nothing is loaded: an aim hint and the brain of an attract-mode or CPU player.
  • fire(): void — Fire the loaded bubble (ignored while nothing is loaded); confirms the route choice; continues.
  • chooseRoute(index: number): void — Choose a route stage by index of the offered choices.
  • continueGame(): void — Take a continue during the countdown.
  • goToRound(n: number): void — Jump to a 1-based round (debug, level select). Without a route only.
  • skipRound(): void — Leave the current round unscored and go on as if it had been cleared (route rounds follow the route; a finished stage offers the next choice). For level select, practice and tests.
  • configure(patch: Partial<Pick<BubbleGameConfig, 'launcher' | 'hurry' | 'ceiling' | 'scoring' | 'timeBonus' | 'guide' | 'continues' | 'rerollCleared'>>): void — Replace rule tables in a running session (launcher, hurry, ceiling, scoring, time bonus, guide).
  • tick(dt: number): BubbleState — Advance by dt seconds in fixed 1/120 s steps. Returns the state.
  • drain(): BubbleEvent[] — Events since the last drain.
  • get state(): BubbleState — The current state (rebuilt lazily after each tick).
  • snapshot(): BubbleSnapshot — A plain-data snapshot.
  • restore(snap: BubbleSnapshot): void — Restore a snapshot taken from a session with the same configuration.

Types

BubbleDifficulty

interface BubbleDifficulty

Difficulty adjustments over the arcade numbers.

  • ceilingShots: number — Shots added to the ceiling interval.
  • hurryScale: number — Multiplier on the hurry timer.
  • guide: BubbleGameConfig['guide'] — When the guide line shows.

BubbleDifficultyName

type BubbleDifficultyName = 'easy' | 'normal' | 'arcade'

Difficulty presets: arcade is the original's numbers; the others relax them.

BubbleEvent

type BubbleEvent = | { kind: 'round'; round: number; name: string; stage: string | null } | { kind: 'go' } | { kind: 'load'; color: number; next: number } | { kind: 'fire'; id: number; color: number; tilt: number; auto: boolean } | { kind: 'bounce'; x: number; y: number } | { kind: 'stick'; id: number; col: number; row: number; x: number; y: number } | { kind: 'pop'; cells: CellView[]; star: boolean } | { kind: 'drop'; cells: CellView[] } | { kind: 'score'; value: number; x: number; y: number; reason: 'pop' | 'drop' | 'time' } | { kind: 'warn'; shotsLeft: number } | { kind: 'press'; mode: 'press' | 'push' } | { kind: 'hurry'; secondsLeft: number } | { kind: 'clear'; time: number; bonus: number } | { kind: 'lost' } | { kind: 'continue'; left: number } | { kind: 'over' } | { kind: 'route'; choices: string[] } | { kind: 'complete' }

What the session reports through drain().

BubbleFieldConfig

interface BubbleFieldConfig

Field geometry for every round (see ShooterConfig for each option's meaning).

  • cols: number — Bubbles in a full row.
  • rows: number — Rows above the dead line.
  • radius: number — Bubble radius in world units.
  • rowHeight?: number — Distance between row centres.
  • hitScale?: number — Contact distance as a fraction of a diameter.
  • oddRows?: 'short' | 'full' — Shifted-row policy.
  • popMin?: number — Smallest same-colour group that pops.
  • lineGap?: number — Space between the lowest legal row and the dead line.
  • launcherDrop?: number — Launcher centre below the line.

BubbleGameConfig

interface BubbleGameConfig

Everything a session needs. Presets build one (puzzleBobblePreset, puzzleBobble2Preset).

  • name?: string — Display name of the ruleset.
  • field: BubbleFieldConfig — Field geometry.
  • palette: number — Colours in the palette (0 .. palette-1).
  • rounds: BubbleRound[] — The rounds, in order (or referenced by route).
  • route?: BubbleRoute — A branching route over rounds; without one the rounds are played in order.
  • startRound?: number — 1-based round to start from (ignored with a route). Default 1.
  • loop?: boolean — After the last round, start again from the first instead of finishing. Default false.
  • legend?: Readonly<Record<string, LegendEntry>> — Layout characters. Default DEFAULT_LEGEND.
  • launcher: LauncherConfig — The launcher.
  • hurry: HurryConfig | null — The idle timer, or null for none.
  • ceiling: CeilingConfig — The ceiling.
  • scoring: ScoringConfig — Points.
  • timeBonus: TimeBonusConfig | null — The time bonus, or null for none.
  • guide: 'always' | 'continue' | 'never' — When the aim guide (the traced path) is shown: always, only for the round after a continue, or never.
  • continues: number — Continues allowed (-1 for unlimited).
  • continueScore: 'reset' | 'keep' — A continue restarts the round with the score reset (Puzzle Bobble) or kept.
  • rerollCleared?: boolean — Re-deal a loaded or next bubble whose colour has just left the board. Default true.
  • timings: BubbleTimings — Phase timings.
  • seed?: number — Seed for the colour deal.
  • difficulty?: BubbleDifficultyName — The difficulty the config was built for (informational).

BubblePresetOptions

interface BubblePresetOptions

Options shared by the presets.

  • difficulty?: BubbleDifficultyName — Easy, Normal (default) or Arcade.
  • startRound?: number — 1-based start round (Puzzle Bobble only).
  • seed?: number — Seed for the colour deal.
  • rounds?: BubbleRound[] — Replace the rounds (e.g. from importRounds).
  • continues?: number — Continues (-1 unlimited, the default: a continue is a coin).

BubbleRound

interface BubbleRound

One authored round: a layout and, optionally, its own width.

  • name?: string — Display name (e.g. "ROUND 1", "A-3"). Default "ROUND n".
  • layout: readonly string[] — Layout rows from the ceiling (see parseLayout).
  • cols?: number — Bubbles in a full row for this round (Puzzle Bobble 2's wide boards use 17). Default field.cols.

BubbleRoute

interface BubbleRoute

A branching route: the player picks a stage at the start and after each stage.

  • start: string[] — The stage ids offered at the start.
  • stages: RouteStage[] — Every stage.

BubbleshooterApi

type BubbleshooterApi = typeof kit

game.bubbleshooter — every function and type this pack carries, as one namespace.

BubbleSnapshot

interface BubbleSnapshot

A plain-data snapshot of a session.

  • s: Record<string, unknown> — Session scalars.
  • field: FieldSnapshot — The field.
  • cols: number — Field columns (rounds may change width).
  • rng: RngState — Where the seeded stream stands (a kernel Rng snapshot).

BubbleState

interface BubbleState

The read-only session state, rebuilt after each tick.

  • status: BubbleStatus — Phase.
  • statusTime: number — Seconds in this phase.
  • round: number — Rounds played in this run, 1-based (the number on screen).
  • roundIndex: number — Index into rounds of the round on the field.
  • roundName: string — The round's name.
  • stage: string | null — Route stage id, or null without a route.
  • score: number — Score.
  • continuesUsed: number — Continues used.
  • width: number — Field width (world units) for this round.
  • cols: number — Columns for this round.
  • rows: number — Rows above the line.
  • radius: number — Bubble radius.
  • ceilingY: number — World y of the ceiling (animated during a press).
  • lineY: number — World y of the dead line.
  • bubbles: BubbleView[] — Every bubble on the field.
  • shot: { id: number; color: number; x: number; y: number } | null — The flying shot, or null.
  • launcher: { x: number; y: number; tilt: number; maxTilt: number } — Launcher centre and tilt (radians from straight up, positive to the right).
  • current: number | null — Colour in the launcher, or null while reloading.
  • next: number | null — Colour waiting in the bag.
  • loaded: number — 0 while the next bubble is being loaded, rising to 1 when it can fire.
  • shots: number — Shots fired this round.
  • shotsToDrop: number — Shots left before the ceiling comes down (Infinity when it never does).
  • shake: number — 0 still, 1 shaking, 2 shaking hard: the warning before a drop.
  • hurry: number | null — Seconds left on the HURRY UP countdown, or null when it is not showing.
  • roundTime: number — Seconds since the round started.
  • guide: Vec[] | null — The guide path when shown.
  • lastBonus: number — The bonus paid at the last clear.
  • lastClearTime: number — The time of the last clear.
  • route: { choices: string[]; selected: number } | null — Route choices while choosing, with the highlighted index.
  • continueLeft: number — Seconds left on the continue countdown.
  • danger: number — How full the field is: lowest occupied row / rows above the line (0..1); presenters speed music with it.

BubbleStatus

type BubbleStatus = 'route' | 'ready' | 'playing' | 'clear' | 'lost' | 'continue' | 'over' | 'complete'

Session phase.

BubbleTimings

interface BubbleTimings

Banner and phase timings, seconds.

  • ready: number — Round banner and READY before play starts.
  • clear: number — CLEAR banner and bonus before the next round.
  • lost: number — Lost animation before the continue countdown.
  • continueSeconds: number — The continue countdown.
  • route: number — Route choice before the highlighted stage is taken anyway.

BubbleView

interface BubbleView

A bubble as the presenter sees it: stable id, kind, colour and position (press animation applied).

  • id: number — Stable id: one sprite per id.
  • kind: CellKind — Cell kind.
  • color: number — Colour (-1 for uncoloured kinds).
  • col: number — Column.
  • row: number — Row.
  • x: number — World x.
  • y: number — World y.

CeilingConfig

interface CeilingConfig

The ceiling schedule.

  • mode: 'press' | 'push' | 'none' — press: the ceiling and everything on it come down a row (Puzzle Bobble). push: a new row of live colours is pushed in from the top (rising-row variants). none: never.
  • baseShots: number — Shots between drops when every palette colour is on the board.
  • palette: number — The palette size counted as "every colour".
  • perMissingColour: number — Shots taken off the interval per palette colour missing from the board.
  • minShots: number — The shortest interval.
  • warnShots: number — The board shakes when this many shots or fewer remain before a drop (0 disables).
  • dropSeconds: number — Seconds the press takes to come down (no firing meanwhile).

Cell

interface Cell

One occupied cell. id is stable for the cell's whole life, so a presenter can key one sprite to it.

  • id: number — Stable id, unique within the field.
  • kind: CellKind — What the cell holds.
  • color: number — The colour index for bubble; -1 for every other kind.

CellKind

type CellKind = 'bubble' | 'clear' | 'stone' | 'star'

What a cell holds.

  • bubble: a coloured bubble. Pops in a same-colour group of popMin or more; drops when cut loose.
  • clear: an uncoloured bubble (Puzzle Bobble 2's jama bubble). Never pops; only drops.
  • stone: a fixed block (Puzzle Bobble 2's jama block). Never pops, never drops, and anchors whatever hangs from it as the ceiling does. Ignored by the clear test and the dead line.
  • star: Puzzle Bobble 2's gem. A coloured shot that lands touching it pops every bubble of the shot's colour and the star. Otherwise it behaves as a clear bubble.

CellView

interface CellView extends Cell

A cell together with where it is: what queries, pops and drops report.

  • col: number — The column.
  • row: number — The row.
  • x: number — The world centre x.
  • y: number — The world centre y (includes the ceiling press).

FieldSnapshot

interface FieldSnapshot

A plain-data snapshot of a field.

  • cells: [number, number, number, CellKind, number][] — Occupied cells as [col, row, id, kind, color].
  • press: number — Ceiling presses so far.
  • parity: number — Row parity offset (toggled by pushRow).
  • nextId: number — Next cell id.
  • score: number — Legacy counters.
  • shots: number — Legacy counters.
  • rng: RngState — Where the seeded stream stands (a kernel Rng snapshot).

HurryConfig

interface HurryConfig

The idle timer: a warning countdown, then the launcher fires by itself.

  • warnAfter: number — Seconds after a bubble is loaded before the HURRY UP countdown shows.
  • fireAfter: number — Seconds after a bubble is loaded when it fires automatically at the current tilt.

LauncherConfig

interface LauncherConfig

The launcher ("pointer").

  • maxTilt: number — Largest tilt either side of straight up, in radians.
  • turnSpeed: number — Turn speed while a direction is held, radians per second.
  • shotSpeed: number — Shot speed, world units per second.
  • reloadSeconds: number — Seconds after a shot lands before the next bubble is loaded and can fire.

LegendEntry

type LegendEntry = { … }

How a layout character maps to a cell. Colour letters map to { kind: 'bubble', color }.

  • kind: CellKind
  • color?: number

Resolution

interface Resolution

What place did: the bubble that landed, what popped, what fell.

  • placed: CellView — The placed cell as it landed (it is also in pops when it popped).
  • pops: CellView[] — Cells cleared by the pop (the placed bubble included), or by a star. Empty when nothing popped.
  • drops: CellView[] — Cells that fell because they no longer hang from the ceiling or a stone.
  • star: boolean — True when a star did the popping.

RouteStage

interface RouteStage

A stage of a branching route (Puzzle Bobble 2's alphabet tree).

  • id: string — Stage id shown on the map ("A", "B", "?").
  • rounds: number[] — Indices into rounds, played in order.
  • next: string[] — Stage ids the player may choose after this one; empty for a final stage.

ScoringConfig

interface ScoringConfig

Points.

  • pop: number — Points per popped bubble.
  • dropBase: number — Dropped bubbles score dropBase * 2^n for n dropped by one shot.
  • dropCap: number — n is capped here (17 in Puzzle Bobble: 1,310,720).

ShooterConfig

interface ShooterConfig

Configures a BubbleField (and, through createBubbleField, the legacy instant-resolution board).

  • cols: number — Bubbles in a full row. Puzzle Bobble: 8 (17 on Puzzle Bobble 2's wide boards).
  • rows: number — Rows that fit above the dead line. A bubble that comes to rest in row rows or below (after presses) has crossed the line. Puzzle Bobble: 11.
  • seed?: number — Seed for colour draws made by the field itself (legacy shoot, fillRows, pushRow). Default 1.
  • colors?: number — Palette size used by random draws. Default 6.
  • radius?: number — Bubble radius in world units. Default 16 (the Puzzle Bobble presets use 8, the arcade's 16-pixel bubble).
  • rowHeight?: number — Distance between row centres. Default radius * 1.75 (14 for the arcade's 8).
  • oddRows?: 'short' | 'full' — short: shifted rows hold cols - 1 bubbles and the field is cols bubbles wide (Puzzle Bobble). full: every row holds cols and the field is half a bubble wider. Default short.
  • hitScale?: number — A shot stops when its centre comes within 2 * radius * hitScale of a bubble's centre. Below 1 lets a well-aimed shot slip into a one-bubble gap, as the arcade does. Default 0.8.
  • lineGap?: number — Extra space between the lowest legal row and the drawn dead line. Default radius / 4.
  • launcherDrop?: number — Launcher centre below the dead line. Default radius * 1.25.
  • layout?: readonly string[] — Initial layout, one string per row from the ceiling (see parseLayout).
  • legend?: Readonly<Record<string, LegendEntry>> — Characters for layout. Default DEFAULT_LEGEND.
  • fillRows?: number — Legacy: pre-fill this many top rows with random colours when no layout is given. Default 0 with a layout, otherwise 5.
  • ceilingEveryShots?: number — Legacy instant shoot: push a new random row in from the top after this many shots. 0 disables. Default 0.
  • popMin?: number — Smallest same-colour group that pops. Default 3.

ShotResult

interface ShotResult

The outcome of one legacy BubbleField.shoot call.

  • path: Vec[] — World-space flight path (launcher to snap), reflecting off walls.
  • snap: XY | null — The cell the shot bubble snapped to, or null when the shot missed.
  • pops: XY[] — The cells cleared by the same-colour pop. Empty when the group was smaller than popMin.
  • drops: XY[] — The cells that fell because the pop cut them off from the ceiling.
  • ceilingStepped: boolean — True when this shot pushed a new row in from the top (ceilingEveryShots).
  • topOut: boolean — True when a bubble has crossed the dead line: the game is lost.
  • won: boolean — True when the field is now empty.
  • gained: number — The score gained by this shot (Puzzle Bobble table: 10 a pop, 10 x 2^n for n dropped, n capped at 17).

TimeBonusConfig

interface TimeBonusConfig

The round-clear time bonus: full until fullUntil seconds, then falling by perSecond, none from cutoff.

  • max: number — The full bonus.
  • fullUntil: number — Seconds within which the full bonus is paid.
  • perSecond: number — Points lost per second after fullUntil.
  • cutoff: number — No bonus at or after this many seconds.
  • wholeSeconds: boolean — Count whole seconds (Puzzle Bobble) or exact time (Puzzle Bobble 2).
  • step?: number — Round the bonus down to a multiple of this. Default 10.

TraceResult

interface TraceResult

The outcome of BubbleField.trace: where a shot goes and what it touches.

  • path: Vec[] — World-space path: the start, each wall bounce, and the contact point.
  • hit: XY | null — The cell the shot would snap into, or null when it never touches anything.
  • contact: XY | null — The bubble it touched, or null for the ceiling (or a miss).
  • bounces: number — Number of wall bounces on the way.

Vec

interface Vec

A world-space point, in field units (y down, origin at the ceiling's left end).

  • x: number — The x position, in world units.
  • y: number — The y position, in world units.

XY

interface XY

A grid cell position on the field: column x, row y counted down from the ceiling.

  • x: number — The column of the cell.
  • y: number — The row of the cell (0 hangs from the ceiling).