Phaser AE

Box-pushing puzzles

Free packv3.0.0-32DGrid

The crate-pushing puzzle: walk the keeper round a warehouse and push crates, never pulling, until every one is on a goal. The pack plays authored levels with full undo, tells the player when a level can no longer be won, and solves levels for hints.

This is a Free pack. Every phaser.io account can use it in their games.

Released October 14, 2026 · updated October 20, 2026

Box-pushing puzzles: 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.

What it does

You load a level from its rows of text and call move with a direction. The keeper walks one cell, pushing the crate ahead if the cell beyond it is free, and each move reports whether a crate was pushed, whether it landed on a dead square, whether the level is now deadlocked and whether it is solved. A move into a wall or a blocked crate changes nothing. The whole game is a history, so undo goes all the way back, redo replays, and a new move clears the redo branch.

Pushes cannot be taken back in the puzzle itself, so the real kindness is telling the player when they have lost. At load the pack works out the dead squares, the floor cells from which no crate could ever reach a goal, by pulling a crate backwards from every goal. During play it spots frozen crates, stuck for good against walls, dead squares and each other. If any crate off its goal is on a dead square or frozen, the level is deadlocked, and the game can say so at once instead of leaving the player to push on.

For hints, solution runs a breadth-first search over crate positions, one push per step, treating the keeper's walking between pushes as free and skipping pushes into dead squares or frozen positions. It finds the solution with the fewest pushes, proves a level unsolvable when it is, and says plainly when it ran out of budget instead.

Features

  • The standard rules — push one crate at a time, never pull, every crate on a goal to win.
  • Standard level text — walls, floor, goals, crates and the keeper in the usual characters, with ragged rows allowed.
  • Your own legend — swap in any characters for walls, floor, goals, crates and the keeper.
  • Level collections — parseLevels reads whole collection files, with each level's title and comments skipped.
  • Full undo and redo — back to the start, with reset.
  • Moves and pushes — counted separately, for the two classic scores.
  • Dead squares — found once at load; isDead tells you which cells to shade.
  • Frozen crates — isFrozen and deadlocked catch the common lost positions the moment they happen.
  • A fewest-pushes solver — for hints, for checking levels, and as a proof when a level cannot be solved.

Good for

  • Classic crate-pushing puzzle games, in the style of Sokoban or Boxxle, played through a level collection.
  • Crate-pushing rooms inside a larger game, such as a dungeon's puzzle chamber.
  • Teaching versions that shade dead squares and warn the moment a push loses the level.
  • Level design tools, where the solver checks that a new level can be won and counts its pushes.
  • Any grid game with irreversible pushes that needs undo and a "you can no longer win" check.

Make it yours

A level is just rows of text, so a new level is data: hand-written, pasted from a collection or loaded from a file with parseLevels. The legend lets you use your own characters, for instance when levels come from a tile editor that writes letters for each tile. Moves and pushes are reported separately, so a game can score on either, and the solver's budget can be set per call.

Two quite different uses: a classic puzzle game that loads a collection file, shows each level's title, shades dead squares and offers a hint arrow from the solver; and a single crate room in an adventure game, written with a custom legend, that warns the player when a crate is stuck and offers to reset the room.

A quick look

A collection loaded, a move played, a deadlock caught, and a hint:

const levels = game.pusher.parseLevels(collectionText);
const room = game.pusher.createPusher({ level: levels[0]!.level });
const r = room.move('right');      // { moved, pushed, ontoDeadSquare, deadlocked, solved }
if (r.deadlocked) say('That crate can never reach a goal: undo.');
score(room.metrics);               // { moves, pushes }
const hint = room.solution();
if (hint.status === 'solved') showArrow(hint.moves[0]!);

Works with

  • sliding-blocks — for blocks that slide until they hit something, or that the player drags.
  • board — to place the level's cells in the world.
  • tween — to animate the keeper's steps and the crates' pushes.

Good to know

  • There is no level generator: levels are authored or read from a collection.
  • The solver handles small and medium levels, a handful of crates in a few dozen cells in well under a second; large competition levels will exhaust its budget, so run it away from the frame for anything big.
  • The deadlock check catches dead squares and frozen crates, not every lost position: crates corralled in a closed room are not detected.
  • No variants: no pulling, no multiple keepers and no coloured crates matched to coloured goals.
  • Levels are capped at 65,535 cells.

More Grid packs

Show all →