Candy Rush โ a project by Ahsan Mahmood
A match-3 puzzle game with 150 levels across 10 worlds, special candies, boosters, a daily challenge and offline play โ live on the web.
A daily challenge only works if everybody gets the same board.
That is a constraint on the engine long before it is a feature. Deal the board from an ordinary random number and two players comparing scores are comparing two different games, which makes the leaderboard beside it decorative.
So the match-3 engine is pure and deterministically seeded.
Same seed, same board, same cascades, on any machine. It is a set of functions with no reference to the screen at all, which is what makes it testable properly rather than testable by playing it.
That decision paid for itself twice.
Because the engine is decoupled from rendering, the same logic drives a React board animated with Framer Motion and an optional Phaser 3 renderer. Neither of them holds a rule. A bug in a rule cannot be a rendering bug. A rendering change cannot quietly alter a score.
The game on top is 150 hand-crafted levels across 10 themed worlds.
Striped, wrapped and colour-bomb specials, cascade scoring, boosters, achievements, and leaderboards kept in Firestore. Hand-crafted rather than generated, which is much slower to make and is the difference between a level with an idea in it and a level with a difficulty number attached.
Cascades are where scoring gets interesting.
A cleared match drops new pieces in. Those can match again, and again after that. A scoring model that treats the fifth cascade like the first is a scoring model that ignores the thing players are actually aiming at.
It installs as a progressive web app and it plays offline.
Progress stays on the device until there is somewhere to put it. Sign-in is Google or anonymous, and cloud save carries an account onto another machine, which is the part that has to be right: a lost level is a small betrayal a player remembers for much longer than a good one. Anonymous matters more than it sounds. A puzzle game that demands an account before the first move is asking for something before it has given anything.
The soundtrack is procedural.
Every note is synthesised at runtime through the Web Audio API rather than downloaded as a file, which keeps the install small and makes the audio code like everything else in the project.
What it cost is the second renderer.
Two rendering paths is one more than a game of this size needs, and keeping the engine ignorant of both is a discipline the codebase has to keep paying for rather than a decision made once. Every new special, every new booster, has to be expressed as a rule first and a picture second.
The reward is that the rules have one home.
There is a second cost and it is the levels. 150 of them, by hand, is a long stretch of work that no framework helps with and no test can tell you is good. The engine can replay a level identically from its seed. It cannot say it is good.
It is live on the web at candyrush.aoneahsan.com.
Play the daily challenge if you want a single measurement of any of this. Everyone playing that day is on the same board. That is the only fair comparison a puzzle game is able to offer, and it exists because the engine was built to make it possible rather than added afterwards.
What it does, and what that costs to build
- 150 levels ยท 10 worlds
- Special candies + cascades
- Pure functional engine
- Offline PWA + cloud save
- Daily challenge + boosters
Built with
- React 18
- TypeScript
- Vite
- Phaser 3
- Radix / shadcn
- Zustand
- Framer Motion
- Firebase
- Web Audio API
- Tailwind CSS
- Capacitor
- Vitest
Worth knowing
- match-3
- puzzle
- game
- pwa
- phaser
- react
- firebase
- daily-challenge
Who built Candy Rush?
Ahsan Mahmood built all of it, and for a game that means more parts than usual: the match-3 engine, the 150 levels, the two renderers, the cloud save and the soundtrack. It is live at candyrush.aoneahsan.com, which is the only claim on this page you have to take on trust for as long as it takes to open a tab. A game is an unforgiving portfolio piece, because a reader does not have to read anything to find out whether it works.
Why does the engine need to be deterministic?
Because the daily challenge is worldwide, and a shared challenge only means something if every player gets the same board. A deterministically seeded engine produces the same layout and the same cascades from the same seed on any machine, so a score is comparable rather than a coincidence. The same property makes the game testable: a level that broke for somebody can be reproduced exactly instead of hunted for. Without it, a leaderboard is a list of people who were dealt different games.
Does Candy Rush work without a connection?
Yes. It installs as a progressive web app and plays offline, because a puzzle game is the exact thing people reach for when the connection is bad. Progress made offline belongs to the device until sign-in gives it somewhere to go, at which point cloud save carries it to another machine. The parts that genuinely need the network are the ones that involve other people: the worldwide daily challenge and the Firestore leaderboards.
Does Candy Rush work on iPhone?
No installed version exists. It is a web game, so a browser on a phone will open and play it, and that is the only route onto an iPhone there is. There is no iOS release behind any of my work, because there is no Apple Developer account here and nothing I build has shipped to the App Store. The web build is what is live and playable today, and it is the only one this page describes.
Do I have to make an account to play?
No. Anonymous sign-in gets you into the first level without a form, and a Google sign-in exists for anyone who wants cloud save and a place on the leaderboards. A puzzle game that asks for an account before the first move is asking for something before it has given anything. The whole game is built the same way round: play first, decide later whether you want the progress to follow you somewhere else.
https://aoneahsan.com/projects/com.aoneahsan.candyrush