Phaser AE

Falling letter tiles

Pro packv3.0.0-0WordNew

A board of letter tiles that never stands still: spell a word through tiles that touch and they vanish, the columns close up and new tiles fall in. Play weak words and burning tiles start eating down through the board; reach the bottom and the game is over. The pack runs every rule and tells you exactly what moved.

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

Released October 21, 2026

Falling letter tiles: 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

letterCascade

function letterCascade(): Pack<{ letterCascade: LetterCascadeApi }>

The letter-cascade pack: falling letter tile rules over the english-words lists. Pure logic, so it runs headless.

Helpers

CASCADE_LENGTH_MULTIPLIERS

const CASCADE_LENGTH_MULTIPLIERS: ReadonlyArray<number>

A word's multiplier by its length in letters: 3 letters ×1, 4 ×1.5, 5 ×2, rising to ×6 at 10 letters and beyond.

CASCADE_LEVELS

const CASCADE_LEVELS: ReadonlyArray<number>

The scores that reach levels 2, 3, 4 and on.

CASCADE_VALUES

const CASCADE_VALUES: Readonly<Record<string, number>>

Points for each letter, by rarity: common letters 1, the rarest 7. A QU tile counts as q.

cascadeNeighbours

function cascadeNeighbours(cols: number, rows: number, adjacency: CascadeAdjacency, pos: number): number[]

Every position next to pos (col * rows + row, row 0 at the top) on a board of cols × rows.

cascadeScore

function cascadeScore(tiles: ReadonlyArray<{ readonly letter: string; readonly kind?: CascadeKind }>, options: { values?: Readonly<Record<string, number>>; lengthMultipliers?: ReadonlyArray<number> } = {}): number

A word's points from its tiles, in order: the tiles' letter values added up, times the multiplier for the word's length in letters, times 2 for each gold tile and 3 for each gem in it, rounded. Burning tiles score as letters.

createLetterCascade

function createLetterCascade(options: LetterCascadeOptions): LetterCascade

Start a game. Throws a RangeError for options out of range: a board of no tiles, an adjacency other than 'hex', 8 or 4, a set board with uneven rows or characters other than letters, a special outside the board.

Types

CascadeAdjacency

type CascadeAdjacency = 'hex' | 8 | 4

Which tiles touch: 'hex' (columns offset by half a tile, six neighbours), 8 (sides and corners) or 4 (sides).

CascadeEvent

type CascadeEvent = /** The tiles of the word (or burnt) taken away. */ | { readonly kind: 'remove'; readonly ids: ReadonlyArray<number> } /** A tile falling down its column to close a gap. */ | { readonly kind: 'fall'; readonly id: number; readonly col: number; readonly fromRow: number; readonly toRow: number } /** A new tile at the top of a column, already at the row it lands in. */ | { readonly kind: 'spawn'; readonly id: number; readonly col: number; readonly row: number; readonly letter: string; readonly tileKind: CascadeKind } /** A burning tile burning the tile below it. */ | { readonly kind: 'burn'; readonly fireId: number; readonly burnedId: number } /** A scramble giving a tile a new letter. */ | { readonly kind: 'reletter'; readonly id: number; readonly letter: string } /** A scramble's cost: a tile set alight. */ | { readonly kind: 'ignite'; readonly id: number } /** A new level reached. */ | { readonly kind: 'level'; readonly level: number } /** A burning tile reached the bottom row: the game is over. */ | { readonly kind: 'over' }

What happened in a move, in the order it happened, for a game to animate.

CascadeFireOptions

interface CascadeFireOptions

How burning tiles come and go.

  • chance?: number — Chance that a word brings a burning tile, 0..1, before level and weak words add to it. Default 0.06.
  • perLevel?: number — Added to the chance for each level after the first. Default 0.03.
  • perWeak?: number — Added for each weak word in a row (a strong word starts the count again). Default 0.18.
  • weakBelow?: number — A word scoring fewer points than this is weak. Default 8.
  • max?: number — Most burning tiles on the board at once. Default the number of columns.

CascadeKind

type CascadeKind = 'normal' | 'fire' | 'gold' | 'gem'

What a tile is: an ordinary letter, a burning tile, or a bonus tile that multiplies a word's points.

CascadeMove

type CascadeMove = { readonly kind: 'word'; readonly path: ReadonlyArray<number> } | { readonly kind: 'scramble' }

A move: a word traced through tiles (positions col * rows + row), or a scramble.

CascadeResult

interface CascadeResult

What a move did.

  • readonly kind: 'word' | 'scramble' — 'word' or 'scramble'.
  • readonly word: string | null — The word played, lower case; null for a scramble.
  • readonly points: number — Points the word scored; 0 for a scramble.
  • readonly events: ReadonlyArray<CascadeEvent> — Everything that happened, in order.
  • readonly level: number — The level after the move.
  • readonly over: boolean — Did the move end the game?

CascadeTile

interface CascadeTile

One tile. Its id stays with it as it falls, so a game can animate it.

  • readonly id: number — Stable for the tile's life; never reused.
  • readonly letter: string — Its letters, lower case (qu for a QU tile).
  • readonly kind: CascadeKind — What kind of tile it is.

CascadeView

interface CascadeView

The game as it stands.

  • readonly phase: 'playing' | 'over' — 'playing', or 'over' once a burning tile has reached the bottom row.
  • readonly cols: number — Columns.
  • readonly rows: number — Rows.
  • readonly adjacency: CascadeAdjacency — Which tiles touch.
  • readonly tiles: ReadonlyArray<CascadeTile> — Every tile, at position col * rows + row, row 0 at the top.
  • readonly score: number — Points scored.
  • readonly level: number — The level, from 1.
  • readonly nextLevel: number | null — The score that reaches the next level, or null past the last.
  • readonly words: ReadonlyArray<{ readonly word: string; readonly points: number }> — Every word played, oldest first.
  • readonly best: { readonly word: string; readonly points: number } | null — The best-scoring word so far, or null.
  • readonly fires: number — Burning tiles on the board.
  • readonly fireChance: number — The chance the next word brings a burning tile, 0..1.
  • readonly turns: number — Moves made.
  • readonly minLength: number — Shortest word, in letters.

LetterCascade

interface LetterCascade

A game of falling letter tiles. Make one with createLetterCascade.

  • observation(): CascadeView — The game as it stands.
  • at(col: number, row: number): CascadeTile | null — The tile at a column and row (row 0 at the top), or null outside the board.
  • positionOf(id: number): number — Where the tile with this id is now (col * rows + row), or -1 when it is gone.
  • neighbours(pos: number): number[] — The positions that touch pos.
  • canExtend(path: ReadonlyArray<number>, pos: number): boolean — Can a trace at path go on to pos: touching its last tile and not used yet? True for any tile when the path is empty.
  • spell(path: ReadonlyArray<number>): string | null — What a path spells, lower case, or null when it is not a chain of touching tiles used once each.
  • check(path: ReadonlyArray<number>): { readonly ok: true; readonly word: string; readonly points: number } | Refusal — Would this word score now? { ok: true, word, points }, or the refusal with a reason a player can be shown.
  • play(path: ReadonlyArray<number>): { readonly ok: true; readonly result: CascadeResult } | Refusal — Play a word. Refused, changing nothing, when check would refuse it.
  • scramble(): { readonly ok: true; readonly result: CascadeResult } | Refusal — Give every ordinary tile a new letter, at the cost of scrambleFire burning tiles; a turn passes. Refused when the game is over.
  • undo(): boolean — Take back the last move.
  • hint(budget?: number): { readonly word: string; readonly points: number; readonly path: ReadonlyArray<number> } | null — The best-scoring word on the board and its path, searching at most budget steps (default 60000); null when there is none.
  • snapshot(): HistorySave<CascadeMove> — The game as a save: the seed and the moves. Restore it into a game made with the same options.
  • restore(save: HistorySave<CascadeMove> | string): void — Replace this game with a save. Throws, changing nothing, when it does not replay under these options.

LetterCascadeApi

type LetterCascadeApi = typeof rules

game.letterCascade: every function and type this pack carries, as one namespace.

LetterCascadeOptions

interface LetterCascadeOptions

How a game is set up. Only seed is required.

  • seed: number — Deals the letters and decides every chance, as an unsigned 32-bit integer.
  • cols?: number — Columns. Default 7, or the board's width.
  • rows?: number — Rows. Default 8, or the board's height.
  • adjacency?: CascadeAdjacency — Which tiles touch. Default 'hex'.
  • minLength?: number — Shortest word, in letters. Default 3.
  • words?: WordList — The words that count. Default the English lexicon.
  • qu?: boolean — Show Q as a QU tile. Default true.
  • values?: Readonly<Record<string, number>> — Points for each letter (a QU tile counts as q). Default CASCADE_VALUES, by rarity.
  • lengthMultipliers?: ReadonlyArray<number> — The multiplier for a word of each length in letters, by index; the last entry is used for anything longer. Default CASCADE_LENGTH_MULTIPLIERS.
  • fire?: CascadeFireOptions | false — Burning tiles, or false for none.
  • lengthForBonus?: number — A word this long or longer brings a gold tile (×2); two letters longer, a gem (×3). Default 6.
  • levels?: ReadonlyArray<number> — The score that reaches each next level: level 2 at the first, level 3 at the second, and so on. Default CASCADE_LEVELS.
  • scrambleFire?: number — Burning tiles a scramble costs, set on the top row. Default 1 (none when fire is off).
  • board?: ReadonlyArray<string> — A set board instead of a dealt one: one string a row, top first, one letter a tile (q is a QU tile when qu is on).
  • specials?: ReadonlyArray<{ readonly col: number; readonly row: number; readonly kind: Exclude<CascadeKind, 'normal'> }> — Special tiles on a set board.