Skip to content

How We Built Prism Potions: A Puzzle Game Shipped to Google Play and the App Store

The decisions behind Prism Potions, a colour-sort puzzle game we built for a client: web technology instead of Unity, provably solvable levels, fair monetization and an App Store rejection.

Tom Boban · October 4, 2026 · 10 min read

On this page

Prism Potions is a colour-sort puzzle game we designed and built for a client. It's live on Google Play and the App Store. Players pour layers of coloured potion between bottles until every bottle holds a single colour. It has a 300-level campaign, a daily challenge, a Game Center leaderboard, and coins, boosters and bottle designs to unlock.

Colour-sort is one of the most crowded genres on either store. The rules aren't what separates the games; anyone can copy those. What separates them is whether the levels are fair, whether the game feels good on a mid-range phone and whether it makes money without driving players away. This post covers the decisions behind those three things, plus the App Store rejection we hit on the way. If you're planning a game of your own, these are the decisions you'll face too.

Three screens from Prism Potions: a level in progress, the chapter map and a three-star "Perfect" win. These are launch-version screenshots, taken while the campaign was still 500 levels long.
Three screens from Prism Potions: a level in progress, the chapter map and a three-star "Perfect" win. These are launch-version screenshots, taken while the campaign was still 500 levels long.

Built with web technology, not Unity

Most studios would build a mobile game like this in Unity. We didn't. Prism Potions is written in TypeScript. The bottles and the pouring are drawn with PixiJS, a 2D rendering engine for the browser, and animated with GSAP. The menus, buttons and text are ordinary web interface, so text stays sharp at any size and works with screen readers. For the stores, the whole thing is wrapped in Capacitor, which turns a web app into a real Android and iOS app with access to the phone's native features.

That decision paid off in three ways:

  • One codebase, three places to play. The same game runs in a browser from a link, on Android and on iPhone and iPad. A browser version is the fastest way to put a build in front of testers, and it's useful for a campaign: nobody has to install anything to try it.
  • Small and quick to load. The iOS app is 33 MB. Every sound effect and the background music are generated in code at runtime, so there are no audio files to download.
  • A familiar, well-tested toolchain. Type checking, linting and automated tests run on every change, using the same tools as our web development work.

The trade-off is that everything native has to come through a plugin: store billing, ads, vibration and cloud saves. Most of those plugins already exist. Cloud save didn't fit our needs, so we wrote our own, which backs up progress to the player's Google Play Games or iCloud account without any server of ours in between.

Every level is proven solvable before anyone plays it

The fastest way to collect one-star reviews on a puzzle game is a level that players believe is impossible. Many sort games generate random boards and hope. Prism Potions doesn't hope.

Each level is dealt from a fixed seed, so every player gets the same board. A solver then searches for the shortest possible solution. If it can't find one, the board is thrown away and dealt again. The solver's answer becomes the level's ideal: the number of moves you need for three stars. In the game we call it "ideal", not "par", because players understood the word straight away.

Because the solver searches exhaustively, the ideal is proven to be the shortest possible solution, not an estimate. A separate brute-force check confirms those results in the test suite, so a three-star target is a promise the game can keep.

Solving takes time. The hardest boards took over a second on a desktop and several seconds on a phone, so solving at the start of each level would have frozen the game. Instead, the whole campaign is solved once when the game is built and shipped as an 80 KB data file. Pressing "Next level" costs nothing.

The same solver works for the player during play:

  • Hints show the next move on a shortest route to a win.
  • Dead ends are detected. On smaller boards, the game checks after each move whether a win is still possible. When it isn't, it says so ("No way to win from here") instead of letting the player keep trying a board that can't be won.
  • The tutorial points at real moves. On level 1, the pointing hand follows the solver's actual next move, not a scripted path.

Fewer, harder levels after testing

The game launched with 500 levels. Feedback from testers was that the difficulty climbed too slowly, so we steepened the curve and cut the campaign to a tougher 300. A longer game wasn't a better game.

The current campaign runs in 15 named chapters of 20 levels, from "First Pour" to "The Grand Elixir". Difficulty rises in a sawtooth rather than a straight line. Every tenth level is a breather with an extra empty bottle, and every tenth is a squeeze with only one. As the minimum number of moves climbs, the campaign now ends at its hardest point instead of tailing off.

New mechanics arrive one at a time, each introduced with a short explanation:

TwistHow it works
The CauldronAccepts any colour, but must be empty before you can win
Murky potionsLower layers are hidden until they reach the top of the bottle
The Locked BottleCan't be used until you've sealed another bottle first
The One-Way FlaskTakes potion in but never lets it out, and must be full to win

The solver knows every one of these rules, so twist levels carry the same proof of solvability as plain ones.

Monetization that doesn't squeeze the player

Prism Potions is free, with in-app purchases from US$1.99 to US$14.99 and ads. The goal was a game that earns without making a free player feel punished. In practice, that meant some firm rules:

  • Hearts are only lost for real failure. A heart goes when you restart or leave a board that is stuck or proven unwinnable. Quitting a board you could still win is free. Hearts refill on their own, one every 30 minutes, up to five.
  • Everything paid can also be earned. Coins come from winning, and every booster can be bought with coins.
  • Replays can't be farmed. Replaying a level pays only for stars you hadn't already earned.
  • The extra bottle is never free. A free extra bottle on every level would erase the difficulty curve, so it's the booster players have to earn or buy.
  • Ads follow a written policy. Rewarded videos only play when the player chooses one, for example to earn a heart. Interstitial ads never appear before level 8. They show at most once every three wins, at least three minutes apart, never during the daily challenge, and never for anyone who has made a purchase.
  • No fake discounts. The shop uses "Popular" and "Best value" labels, not invented "90% OFF" prices.

Payments go through the stores themselves. Google's payments policy and Apple's App Review Guidelines both require their own billing for digital goods like virtual coins. The web version simply hides paid items. Purchases are also built to survive a crash: if the app closes between payment and delivery, it restores the purchase on the next launch, exactly once.

Retention comes from reasons to come back, not pressure. There's a daily challenge with streaks, a seven-day login reward, 17 achievements, and a share button that posts your daily result as a few lines of text, the way word games do.

The App Store rejection

Our first iOS submission was rejected. The reason was App Tracking Transparency, Apple's rule that an app must ask permission before tracking a user across other companies' apps and websites. Because Prism Potions shows ads through Google AdMob, it has to ask. Apple's guidelines say you need explicit permission through the ATT system prompt, and you can't make that permission a condition of using the app.

The fix had three parts:

  1. The prompt appears at launch, before the ad network or the consent form makes any request. If the player hasn't answered, ads stay switched off for that session.
  2. Declining blocks nothing. Every level, booster and feature works the same either way.
  3. The explanation text was rewritten to describe accurately what the advertising identifier is used for. The old wording claimed progress never left the device, which stopped being true once cloud save and analytics were added.

Then we tested on a physical iPad, recorded the flow from a fresh install and resubmitted. Version 1.0 went live on September 18.

The work players never notice

Much of a game's quality is invisible when it's done right:

  • Performance on ordinary phones. We profiled real levels rather than guessing. The biggest per-frame cost was redrawing the background stars and particles on every frame, so we replaced them with lightweight sprites. If a phone still struggles, the game lowers its rendering resolution on its own, based on measured frame times rather than a list of device models. It also stops drawing the board while a menu covers it.
  • Progress that survives anything. The current level is saved after every move, so closing the app mid-level costs nothing.
  • Accessibility. A colourblind setting adds a distinct shape to each colour. The game respects a phone's reduced-motion setting, and every touch target is at least 44 pixels however small the bottles get.
  • Thirteen languages. The game follows the phone's language, and each translation downloads only when it's needed.
  • Automated play-testing. Every change runs around 3,700 automated checks on the levels and rules. A browser test then plays a real level through to a win, including on the engine that powers Safari, before the change can ship.

If you're planning a game

The questions that shaped Prism Potions apply to almost any game you might commission:

DecisionWhat to ask your developer
Engine and platformsDoes this game need Unity, or can it run in a browser and on phones?
FairnessHow do you know every level can be finished?
DifficultyWhat will play-testing measure, and what happens if it isn't fun?
MonetizationWhich purchases and ads, and what limits stop them annoying players?
Store complianceWho handles privacy labels, tracking consent and billing rules?
PerformanceWhich real, mid-range devices will it be tested on?
OwnershipWho owns the source code, the store accounts and the art?

A developer who has shipped to both stores should have a direct answer to each one. If the answer is "we'll deal with that later," expect later to be the week you planned to launch.


Prism Potions is free on Google Play and the App Store. If you have a game in mind, whether it's a branded campaign game, gamification inside an existing app or an original title, see our game development service or book a call to talk it through. For apps that aren't games, see app development.

Frequently asked

Can a mobile game be built with web technology instead of Unity?

Yes, for the right kind of game. Prism Potions is written in TypeScript, drawn with PixiJS and wrapped for Android and iOS with Capacitor, so one codebase runs in a browser and ships to both app stores. That suits 2D puzzle, casual and branded games. A 3D game, or one that needs console-grade performance, is still better built in an engine like Unity.

Do in-game purchases have to go through Apple and Google?

For coins, boosters, extra lives and other digital items sold inside a game, yes in almost every case. Google Play's payments policy and Apple's App Review Guidelines both require their own billing systems for in-app digital goods. Prism Potions only sells through Google Play Billing and Apple's In-App Purchase, and its web version hides paid items entirely rather than offering a card checkout.

Why do mobile games get rejected by Apple?

Privacy and payments are the common reasons. Prism Potions' first iOS build was rejected over App Tracking Transparency: the game shows ads, and Apple wanted the tracking permission prompt to appear reliably before any ad code ran. We moved the prompt to launch, ahead of the ad SDK, kept the game fully playable if the player declines, and resubmitted. Plan for at least one review round when you budget a launch.

How do you make sure every puzzle level can be solved?

By solving each one with a computer before a player sees it. Prism Potions deals every level from a fixed seed, then a solver finds the shortest possible solution. A level that can't be solved is never accepted. The whole campaign is solved once when the game is built, so players never wait, and the 'ideal' move count shown for three stars is a proven minimum rather than a guess.

Sources

  1. Prism Potions on Google Play, Google Play
  2. Prism Potions on the App Store, Apple App Store
  3. App Review Guidelines, Apple Developer
  4. App Tracking Transparency, Apple Developer
  5. Payments policy, Play Console Help
  6. Capacitor documentation, Capacitor
  7. PixiJS, PixiJS

Want this done properly on your site?