Cascade Puzzle: a daily block-swapping puzzle for the web

I shipped a Panel de Pon-style puzzle game: a daily challenge with a move limit, a level editor, and an online versus mode. What it is, and the engineering that makes a puzzle provably fair.


I shipped a puzzle game: Cascade Puzzle. It's a block-swapping puzzle in the family of Panel de Pon and Tetris Attack, two SNES-era games that I think hold up better than almost anything from that generation. You swap two adjacent blocks, line up three or more of the same color, and they clear. Gravity pulls everything down, which can line up new matches, which clear again. Chains are the whole art of it.

The twist is the format. Instead of an endless arcade mode, the core of Cascade Puzzle is a daily challenge: one board per day, a fixed move limit, and the goal of clearing every block before you run out. Solve it and you earn a medal. It's the Wordle loop applied to a genre I love: small, self-contained, and done in a few minutes.

There's also a practice mode with a large pool of puzzles, personal stats, a level editor where you can build and share your own boards, and a versus mode where you play in real time against a bot or another person.

Making a move limit fair

The interesting engineering problem wasn't rendering or animation. It was trust. If a daily puzzle says "solve this in 5 moves", players need that number to be honest. Too generous and the puzzle is boring; impossible and the game is broken.

Cascade Puzzle generates its boards, then runs a BFS solver over the full move graph, including setup moves that don't match anything by themselves. The solver either finds the shortest solution or proves there isn't one. Boards without a solution get thrown away, and the move limit of every published puzzle is exactly the length of the shortest solution. Par isn't an estimate. It's a proof.

That solver only exists because the game logic lives in a pure TypeScript package with zero dependencies: board state, swaps, match detection, gravity, chain resolution. Pure functions all the way down, which makes them trivial to test and lets the solver simulate thousands of board states without touching a renderer.

The stack

Rendering is Phaser embedded in React, so the game scene handles blocks and animations while React handles everything around it: menus, dialogs, stats, routing with TanStack Router. The backend is tRPC with Drizzle and PostgreSQL, and the whole thing is a pnpm monorepo where the game, the level editor and the server share the same core packages.

Versus mode was its own adventure. The simulation is fully deterministic, so online matches run on lockstep netcode with rollback: both clients only exchange inputs, and each one simulates the match locally. The bot opponent uses the same deterministic engine, with difficulty tiers that are literally actions per minute.

If you enjoy this kind of puzzle, the daily is waiting. It runs in the browser, on desktop and mobile, and a round takes less time than reading this post.