Swap How to Make a Match 3 Game (Browser Swap Grid 2026)

By Arron R.11 min read
How to make a match 3 game in 2026: model swap validation and cascade gravity on an 8×8 grid, wire pointer swaps in WizardGenie, then add Quick Sprites gem tile

Most beginners who search “how to make a match 3 game” want a swap grid: tap or drag two adjacent gems, clear three-in-a-row runs, watch gravity pull tiles down, refill empty cells, and chain cascades until the board settles. A full live-ops economy with hundreds of levels, boosters, and daily quests is a studio product. A browser swap grid is different. A coding agent scaffolds findMatches, applyGravity, and illegal-swap rejection from one prompt, and AI generation covers gem tiles and match pops. On desktop or web, that means WizardGenie for the swap-and-cascade loop, Quick Sprites for gem sprites and pop VFX, SFX Gen for swap and clear cues, and optional Music Gen for a puzzle bed. This guide is the honest end-to-end for how to make a match 3 game in 2026, as a weekend build you can finish once.

How to make a match 3 game browser pipeline: model grid swap validation and cascades, wire pointer swaps in WizardGenie, and ship a browser swap grid
The 2026 how to make a match 3 game recipe: model grid swap validation and cascade gravity, wire pointer swaps in WizardGenie, then add Quick Sprites gem tiles and SFX Gen match audio.

What how to make a match 3 game actually means in 2026 (swap, cascade, score)

The query “how to make a match 3 game” hides three intents. Some searchers want a paper prototype with colored stickers on a grid — that is craft, not a playable digital game. A second intent is a full candy crush clone with saga maps, lives timers, and IAP boosters — months of economy tuning before the first honest swap feels fair. The third intent, and the one this guide targets, is a browser swap grid: an 8×8 board, five or six gem types, adjacent swaps only, three-in-a-row clears, gravity, refill, cascade chains, a move counter or score HUD, and a Game Over or level-complete card. That is a weekend build, it demos the Sorceress toolset, and it is the format most match 3 tutorial and javascript match 3 searchers actually want.

The presentation contract is small and strict. A title screen shows the game name, Start, and optionally a moves-left preset. The play screen shows the gem grid, a score or combo multiplier, moves remaining, and Pause. On each valid swap, animate the exchange, run clears and cascades with input locked until stable, then re-enable swaps. On game over or target score reached, freeze input, play a short fanfare, show the final score, and offer Replay. The Bejeweled overview on Wikipedia (verified 2026-08-22) still separates the classic swap-and-match loop from tile-matching fallers like Tetris cleanly — cite it when you write your itch.io blurb so players know which promise you kept. If you already shipped a merge or roll loop, the sibling guides on how to make 2048 and how to make a dice game cover shared grid UI patterns; this post owns swap validation, cascade gravity, and combo scoring instead.

The match 3 loop in one minute (swap, detect, clear, gravity, refill)

Five moving parts, repeated until the player runs out of moves or hits a target score. First, swap — player picks two orthogonally adjacent cells; exchange their gem types in a scratch copy. Second, detect — run findMatches on the copy; if no run of three or more exists, revert the swap and unlock input. Third, clear — null out every matched cell and add base score plus combo multiplier. Fourth, gravity — for each column, compact gems downward and leave null holes at the top. Fifth, refill and cascade — spawn random gem types into null cells, re-run detection, and repeat clear-gravity-refill until the board is stable. That is the entire match 3 loop. Blockers, color bombs, and saga maps are polish layered after one honest browser match three session chains three clears in a row without illegal swaps slipping through.

Match 3 game loop state machine diagram showing swap, detect matches, clear cells, gravity refill, and cascade until stable
The match 3 loop: swap adjacent gems, detect three-in-a-row runs, clear and score, apply gravity and refill, then cascade until the board stabilizes.

Pick your engine for how to make a match 3 game: canvas grid, Phaser, or WizardGenie

Three good targets in 2026, each with a different trade-off. Vanilla JavaScript on a 2D canvas is the honest default and the pick this guide recommends for a first build. Store the board as a 2D array of gem type ids, blit sprite tiles at fixed cell size, and animate swap motion with requestAnimationFrame lerp between cell centers. Total code footprint for a working gem swap game is under 500 lines including match detection, gravity, and pointer hit-testing. No engine to install, ships as a static HTML file, deploys anywhere. The MDN Canvas API docs cover the drawing surface, and Pointer events cover drag-and-swap on the same canvas for mouse and touch.

DOM grid with CSS cells becomes the right pick if you want accessible focus rings on every gem for a classroom demo. You trade animation smoothness for semantics — fine for a 6×6 teaching board, heavier once cascades animate eight columns simultaneously with reflow cost.

Phaser 4.1.0 (verified 2026-08-22 on the official Phaser API documentation page) becomes the right pick if you want Scene lifecycle for title-play-score, tweens when gems swap and fall, or particle bursts on a four-in-a-row. Phaser does not invent your cascade resolver — you still need the same findMatches and applyGravity helpers. Use Phaser when motion polish is the product; use vanilla canvas when the product is a javascript match 3 loop people can play on a phone browser tab.

WizardGenie is not a separate rendering engine — it scaffolds whichever of the three you pick from a single natural-language prompt. WizardGenie ships as both a desktop app (Windows installer with auto-update, available to Early Access supporters and above) and a no-install web build. Its coding-model lineup covers Claude Opus 4.7, GPT-5.5, Gemini 3.1 Pro, DeepSeek V4 Pro, Kimi K2.5, Grok 4.2, and MiniMax M2.7 (verified 2026-08-22 in src/app/_home-v2/_data/tools.ts). For match-3 games, any frontier model scaffolds grid state, swap validation, and cascade resolution in one prompt. Pair a frontier planner with a budget executor like DeepSeek V4 Pro or Kimi K2.5 for the typing pass — the Dual-agent pattern lands most projects at roughly one-fifth the single-frontier cost.

Step 1 — model grid, swap validity, and cascade resolver

Nothing else in the pipeline matters if illegal swaps award points or if gravity leaves floating gems mid-air. Start with a small, testable model for an 8×8 gem swap game:

const COLS = 8;
const ROWS = 8;
const GEM_TYPES = 5;

function makeGrid() {
  const grid = Array.from({ length: ROWS }, () =>
    Array.from({ length: COLS }, () => randomGem())
  );
  while (findMatches(grid).size > 0) {
    resolveCascades(grid, { scoreRef: { value: 0 }, combo: 0 });
  }
  return grid;
}

function randomGem() {
  return Math.floor(Math.random() * GEM_TYPES);
}

function findMatches(grid) {
  const matched = new Set();

  for (let y = 0; y < ROWS; y++) {
    let runStart = 0;
    for (let x = 1; x <= COLS; x++) {
      const prev = grid[y][x - 1];
      const cur = x < COLS ? grid[y][x] : null;
      if (cur !== prev) {
        const runLen = x - runStart;
        if (runLen >= 3 && prev != null) {
          for (let i = runStart; i < x; i++) matched.add(`${i},${y}`);
        }
        runStart = x;
      }
    }
  }

  for (let x = 0; x < COLS; x++) {
    let runStart = 0;
    for (let y = 1; y <= ROWS; y++) {
      const prev = grid[runStart][x];
      const cur = y < ROWS ? grid[y][x] : null;
      if (cur !== prev) {
        const runLen = y - runStart;
        if (runLen >= 3 && prev != null) {
          for (let i = runStart; i < y; i++) matched.add(`${x},${i}`);
        }
        runStart = y;
      }
    }
  }

  return matched;
}

function applyGravity(grid) {
  for (let x = 0; x < COLS; x++) {
    let write = ROWS - 1;
    for (let y = ROWS - 1; y >= 0; y--) {
      if (grid[y][x] != null) {
        grid[write][x] = grid[y][x];
        if (write !== y) grid[y][x] = null;
        write -= 1;
      }
    }
    for (let y = write; y >= 0; y--) grid[y][x] = null;
  }
}

function resolveCascades(grid, ctx) {
  let chain = 0;
  while (true) {
    const matched = findMatches(grid);
    if (matched.size === 0) break;
    chain += 1;
    const mult = 1 + (chain - 1) * 0.5;
    ctx.scoreRef.value += Math.round(matched.size * 10 * mult);
    for (const key of matched) {
      const [x, y] = key.split(',').map(Number);
      grid[y][x] = null;
    }
    applyGravity(grid);
    for (let y = 0; y < ROWS; y++) {
      for (let x = 0; x < COLS; x++) {
        if (grid[y][x] == null) grid[y][x] = randomGem();
      }
    }
  }
  return chain;
}

Game state is { grid, score, movesLeft, inputLocked }. Unit-test four asserts before you paint UI: a horizontal run of exactly three marks only those three cells; a vertical four-clear removes four cells in one column; applyGravity leaves no null below a gem in any column; resolveCascades on a board with a preset L-shape produces chain depth 2 or higher. Those asserts are the difference between a cascade match game people trust and one that silently awards combo points on illegal board states.

Keep blockers, striped gems, and level objectives out of v1 — they are rule variants on top of the same swap-and-cascade idea. Related grid pacing also shows up in the snake grid-loop guide if you want another weekend board pattern after this one ships.

Step 2 — wire pointer swap and combos in WizardGenie

With the model solid, open WizardGenie. Drop in a bare index.html with a canvas element and a score HUD. Give the agent one paragraph: Build an 8×8 match-3 swap grid with five gem types. Only allow adjacent swaps. Revert swaps that create zero matches. Clear three-in-a-row runs, apply gravity, refill from the top, and cascade until stable. Lock input during cascades. Track score with combo multiplier on chain depth. Use canvas and pointer events for drag-to-swap. Feed that to any coding model and the scaffold lands in under five minutes.

The remaining afternoon is polish via follow-ups. Keep swap handling thin and testable:

function isAdjacent(a, b) {
  const dx = Math.abs(a.x - b.x);
  const dy = Math.abs(a.y - b.y);
  return (dx === 1 && dy === 0) || (dx === 0 && dy === 1);
}

function trySwap(game, a, b) {
  if (game.inputLocked || game.movesLeft <= 0) return false;
  if (!isAdjacent(a, b)) return false;

  const grid = game.grid;
  const tmp = grid[a.y][a.x];
  grid[a.y][a.x] = grid[b.y][b.x];
  grid[b.y][b.x] = tmp;

  const matched = findMatches(grid);
  if (matched.size === 0) {
    grid[b.y][b.x] = grid[a.y][a.x];
    grid[a.y][a.x] = tmp;
    playSfx('invalid');
    return false;
  }

  game.inputLocked = true;
  game.movesLeft -= 1;
  playSfx('swap');
  animateSwap(a, b, () => {
    const chains = resolveCascades(grid, game);
    if (chains > 1) playSfx('combo');
    renderGrid(game);
    game.inputLocked = false;
    if (game.movesLeft <= 0) endGame(game);
  });
  return true;
}

function onPointerUp(game, start, end) {
  if (!start || !end) return;
  const a = cellFromPixel(start.x, start.y);
  const b = cellFromPixel(end.x, end.y);
  if (a.x === b.x && a.y === b.y) {
    const neighbor = dragNeighbor(start, end);
    if (neighbor) trySwap(game, a, neighbor);
  } else {
    trySwap(game, a, b);
  }
}

Add a 150ms lerp tween between cell centers during swap — motion sells legality before the cascade runs. Highlight the combo multiplier in the HUD when chain depth exceeds one so players feel the cascade match game payoff. Persist best score with localStorage keyed by game id so Refresh does not wipe a personal record. For move-limited levels later, expose movesLeft in the title screen preset — the same loop already supports it once solo free-play feels fair.

Step 3 — Quick Sprites gems, SFX Gen match pops, Music Gen puzzle bed

Colored rectangles prove the loop. Art and audio make the board feel intentional. Open Quick Sprites (9 credits per generation, verified 2026-08-22 in src/app/quick-sprites/page.tsx) and run three passes: a sprite sheet of five distinct gem types at 64×64 with strong hue separation, a match pop VFX strip for clear frames, and an optional combo sparkle for chain depth 3 or higher. Keep gem silhouettes readable at cell size — rounded squares or faceted crystals with consistent outline weight. Drop the sheet onto your canvas draw path with drawImage and source rectangles per gem type id.

Open SFX Gen (1 credit per second of audio, verified 2026-08-22 in src/app/sfx-gen/page.tsx) and generate four short clips: a soft swap click (~0.5s), a bright match pop (~1s), a cascade whoosh when chain depth exceeds one (~1.5s), and a short level-complete fanfare (~2s). Trigger swap on valid exchange, pop on each clear pass, whoosh on combo chains, and fanfare when the target score or final move lands. Keep volumes low so a twenty-minute session does not fatigue.

Optional but nice: open Music Gen (10 credits per generation, verified 2026-08-22 in src/app/music-gen/page.tsx) and prompt a quiet puzzle bed — “gentle marimba puzzle loop, no vocals, low dynamics for a gem grid.” One or two tries is enough. Mute music by default so players who want silence stay in flow. Browse the rest of the stack from the tools guide if you later add Speech Gen for combo callouts. The asset stack for a weekend how to make a match 3 game project stays well under a dollar of credits; see the cost section below for the line-item math.

Match 3 game asset stack diagram showing Quick Sprites gem tiles, SFX Gen match pops, optional Music Gen puzzle bed, and total credit cost under one dollar
The match 3 asset stack: Quick Sprites for gem tiles and pop VFX, SFX Gen for swap and cascade cues, optional Music Gen puzzle bed — roughly 53 credits on the 2026 Sorceress rate card.

What a how to make a match 3 game project costs on Sorceress in 2026

Here is an honest first-project budget against the live Sorceress rate card (verified 2026-08-22 against local source). Three Quick Sprites generations at 9 credits each ($0.09) — gem sheet, pop VFX, combo sparkle — = 27 credits ($0.27). Four SFX clips totaling about 6 billable seconds at 1 credit/sec = 6 credits ($0.06). Optional Music Gen puzzle bed with a retry at 10 credits each = 20 credits ($0.20). Coding-model API time for the WizardGenie scaffold and polish pass is typically under $0.40 when you pair a frontier planner with DeepSeek V4 Pro or Kimi K2.5 as executor. Grand total: roughly 53 credits ($0.53) plus sub-dollar agent time. The free 100-credit signup grant covers the entire art and audio stack on day one. Credit packs and supporter tiers live on Plans if you outgrow the grant.

That is the whole pipeline for how to make a match 3 game in 2026: an 8×8 swap grid, five gem types, adjacent swap validation, cascade gravity with combo scoring, canvas rendering with pointer events, and a thin Sorceress asset layer so the board looks finished. Ship the static build, play one full session until moves run out without illegal swaps awarding points, then decide whether move-limited levels or striped power-ups are worth another afternoon — only after the first honest cascade chain already feels fair.

Frequently Asked Questions

Which grid size should a beginner use for how to make a match 3 game?

Start with 8×8 and five gem types. That is large enough for accidental three-in-a-row spawns to feel common during testing, small enough to trace swap detection on paper. Most match 3 tutorial and browser match three searchers expect a Bejeweled-scale board, not a 12×12 marathon. Skip special tiles, blockers, and level objectives until one honest swap-and-cascade loop clears and refills without deadlocking.

How does swap validation work in a javascript match 3 build?

Only allow swaps between orthogonally adjacent cells. Copy the grid, exchange the two cells, run findMatches on the copy, and revert if zero matches appear — illegal swaps should snap back with no score change. If matches exist, commit the swap, clear matched cells, run applyGravity column by column, refill empty tops with random gem types, then loop resolveCascades until the board is stable. That scratch-copy pattern is the core of every gem swap game and candy crush clone scaffold.

Canvas or DOM for a browser match three grid?

Canvas is the honest default for a first phaser match 3 or vanilla build — you blit dozens of gem sprites at 60fps and tween swap motion without fighting CSS grid reflow. DOM div cells work for a classroom demo but hurt once cascades animate five columns at once. Phaser 4.1.0 (verified 2026-08-22 on the official Phaser API documentation page) wraps the same canvas with Scene lifecycle and swap tweens if you want polish without rewriting hit-testing.

How do cascades and gravity work after a clear?

For each column, scan bottom to top and compact non-null gems downward, leaving null holes at the top. Refill each null with a random type from your palette (usually five to six colors). Re-run findMatches; if new runs appear, clear again and repeat until stable. Chain depth drives combo score multipliers in most cascade match game designs. Unit-test that a vertical four-clear leaves exactly four nulls in one column before refill — that assert catches off-by-one gravity bugs early.

How much does it cost to build a match 3 game on Sorceress?

A first-project browser swap grid with gem art and audio budgets like this against the 2026 Sorceress rate card (verified 2026-08-22 against local source). Three Quick Sprites passes at 9 credits each (src/app/quick-sprites/page.tsx line 21) — one gem sheet, one match pop VFX, one combo sparkle — = 27 credits or 0.27 USD. Four SFX clips at 1 credit per second (src/app/sfx-gen/page.tsx line 23) — swap click, match pop, cascade whoosh, level fanfare — roughly 6 credits or 0.06 USD. Optional Music Gen puzzle bed: two tries at 10 credits each (src/app/music-gen/page.tsx line 28) = 20 credits or 0.20 USD. Total roughly 53 credits or 0.53 USD plus under 0.40 USD in coding-model API time. The free 100-credit signup grant (src/app/api/admin/credits/route.ts line 12) covers the full art and audio stack outright.

Sources

  1. Bejeweled - Wikipedia
  2. MDN - Pointer events
  3. MDN - Canvas API
  4. Phaser 4.1.0 API Documentation
Written by Arron R.·2,481 words·11 min read

Related posts