Phaser AE

Place and merge

Pro packv3.0.0-12DGrid

The placement-merge puzzle: place the dealt item, and three or more connected equals merge into the next tier on the cell you chose, which can set off the next merge. Walkers, tombstones, wildcards, bombs and generators complete the set, and chains, scores and the deal are all yours to define.

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

Place and merge: 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

placeMerge

function placeMerge(): Pack<{ placeMerge: PlaceMergeApi }>

The place-merge pack. Pure logic, so it needs no backend and runs headless.

Helpers

createPlaceMerge

function createPlaceMerge(cfg: PlaceMergeConfig): PlaceMerge

Creates a placement-merge board.

TRIPLE_TOWN_CHAINS

const TRIPLE_TOWN_CHAINS: readonly MergeChain[]

Triple Town's three chains: grass to the triple castle, tombstone to the treasure chest, rock to the mountain, with their points per tier.

TRIPLE_TOWN_DEAL

const TRIPLE_TOWN_DEAL: readonly DealEntry[]

A deal like Triple Town's: mostly grass, some bushes and trees, a bear now and then, rare crystals and bombs.

Classes

PlaceMerge

class PlaceMerge

A Triple Town board.

  • readonly cols: number — Columns.
  • readonly rows: number — Rows.
  • readonly chains: readonly MergeChain[] — The chains in force.
  • gameOver: boolean — True once the board is full.
  • score: number — Score.
  • turns: number — Turns played.
  • constructor(cfg: PlaceMergeConfig)
  • item(x: number, y: number): Item | null — The item at (x, y), or null.
  • get deal(): Item — The item to place next.
  • get storage(): Item | null — The item in the storage slot, or null.
  • get topTier(): number — The highest block tier on the board.
  • place(at: XY): PlaceResult — Place the deal. Blocks, walkers, wildcards and generators need an empty cell; a bomb needs an occupied one.
  • store(): void — Swap the deal with the storage slot (an empty slot takes the deal, and a new one is dealt).
  • findPlaces(): { at: XY; merges: number; tier: number }[] — Every legal placement for the deal, best first: the biggest tier made, then the most merges.
  • autoplay(maxTurns = 500): PlaceResult[] — Play the best placement each turn until the board fills or maxTurns pass.
  • snapshot(): PlaceMergeSnapshot — The whole state as plain data.
  • restore(snap: PlaceMergeSnapshot): void — Return to a snapshot() of a board with the same size and rules.
  • debugGrid(): string — The board as text, for tests: . empty, B walker, G generator, otherwise the chain letter (a, b, c…) and tier.

Types

DealEntry

type DealEntry = | { kind: 'block'; type: number; tier: number; weight: number } | { kind: 'walker' | 'wildcard' | 'bomb'; weight: number } | { kind: 'generator'; type: number; tier: number; every: number; charges: number; weight: number }

One entry of the deal table.

Item

interface Item

A placed or dealt item.

  • id: number — Unique id for the item's life.
  • kind: ItemKind — What it is.
  • type: number — A block's chain (an index into the config's chains); a generator's output chain; -1 otherwise.
  • tier: number — A block's tier in its chain; a generator's output tier; 0 otherwise.
  • charges?: number — A generator: drops left.
  • every?: number — A generator: turns between drops.
  • wait?: number — A generator: turns until the next drop.

ItemKind

type ItemKind = 'block' | 'walker' | 'wildcard' | 'bomb' | 'generator'

What an item is. Only blocks merge.

MergeChain

interface MergeChain

One merge chain: how many tiers it has and what each scores when made.

  • name?: string — Name, for presenters ('grass').
  • tiers: number — Tiers in the chain: a merge into the last tier makes it, and it never merges again.
  • score?: readonly number[] — Points for making each tier, by tier. Missing entries use the last one.

PlaceMergeApi

type PlaceMergeApi = typeof kit

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

PlaceMergeConfig

interface PlaceMergeConfig

Configures createPlaceMerge.

  • cols: number — Columns.
  • rows: number — Rows.
  • seed?: number — Seed for the deal and the walkers. Default 1.
  • chains?: readonly MergeChain[] — The merge chains, by type. Default: TRIPLE_TOWN_CHAINS.
  • deal?: readonly DealEntry[] — The deal table. Default: TRIPLE_TOWN_DEAL.
  • tombstone?: { type: number; tier: number } — What a trapped walker becomes. Default: tier 0 of chain 1 (the tombstone chain).
  • rock?: { type: number; tier: number } — What a wildcard becomes when nothing would merge. Default: tier 0 of chain 2 (a rock).
  • overMerge?: number — Score multiplier for a merge of four or more. Default 2.
  • start?: readonly [number, number, Omit<Item, 'id'>][] — Items on the board at the start, as [x, y, item].

PlaceMergeSnapshot

interface PlaceMergeSnapshot

The plain-data state of a board.

  • grid: (Item | null)[] — Cells, row by row.
  • s: { score: number; turns: number; gameOver: boolean; deal: Item; stored: Item | null; nextId: number; rng: RngState } — The other state.

PlaceResult

interface PlaceResult

The result of one place().

  • valid: boolean — False when the placement was refused: nothing changed.
  • steps: PlaceStep[] — The turn's steps, in order.
  • merges: number — Merges the turn caused, cascades and trapped walkers included.
  • points: number — Points the turn scored.
  • topTier: number — The highest tier on the board after the turn.
  • gameOver: boolean — True once the board is full.

PlaceStep

type PlaceStep = | { type: 'place'; at: XY; item: Item } | { type: 'wildcard'; at: XY; becomes: Item } | { type: 'bomb'; at: XY; removed: Item } | { type: 'merge'; at: XY; from: XY[]; result: Item; points: number } | { type: 'walk'; moves: { id: number; from: XY; to: XY }[] } | { type: 'trapped'; cells: XY[] } | { type: 'generatorSpawn'; from: XY; at: XY; item: Item } | { type: 'generatorSpent'; at: XY } | { type: 'gameOver' }

One journal step of a turn, in play order.

XY

interface XY

A cell: column x, row y, both from 0 at the top left.

  • x: number — Column.
  • y: number — Row.