PiriGram
Puzzle game by PiriGramLive in the browser

PopSkip

A puzzle played on sheets of bubble wrap. You pop one bubble, then jump to the next, and try to clear the whole sheet without trapping yourself.

Free in any modern browser, on a phone or a computer, in nine languages. No ads in the browser. The iPhone and Android apps are in testing.

PopSkip's home screen: a painted forest trail with a cat in a hat and scarf on the path, signposts for finished rolls behind it and a button for the next roll.
Home is a trail through painted places.
A roll in play: an irregular sheet of bubble wrap on a forest floor, seven bubbles popped and numbered in order, with Undo, Hint and Restart below.
Seven pops in. The numbers show the order.
Piri the cat teaching the rule: from one bubble, arrows show the jump to the third bubble left or right.
Piri teaches the rule in the first roll.
The Today page: a three-day streak, today's roll, Today's Climb with one try a day, and two daily goals.
Today: the streak, the daily roll and the Climb.
The end of a roll: five stars, Finished with no help, the treats earned, the time and the finished board.
A clean finish, and what it earned.

How to play

  • Pop every bubble. Start on any bubble that glints.
  • Straight: skip two bubbles and land on the third, up, down, left or right.
  • Diagonal: skip one and land on the second.
  • You can never land on a bubble you have already popped. The glowing bubbles are the ones you can reach next, but not every one of them leads to a finish.

Undo takes back your last move. Hint shows a safe next move, and when you are already stuck it offers to take you back to a point from which the roll can still be finished.

What is in the game today

  • A painted trail that grows chapter by chapter, from a meadow and a forest to lakes and snowy passes. Every roll on it is proven solvable before it ships.
  • A daily roll, the same for everyone on a given day; Today’s Climb, one try a day; and a 60-second Sprint.
  • Treats earned by playing, spent on undos and hints. In the apps, an optional video earns more.
  • A streak, two small goals a day, fourteen badges, and a share card that shows your result without giving away the route.
  • Nine languages. Progress stays on your device, and once the game has loaded it plays without a connection.

Having trouble? See PopSkip help.

Behind the build

One rule, a solver that checks every board, and no server

My role
Game design, product, architecture
Built with
Claude Code and Codex agents I direct
Stack
TypeScript, React, canvas, Capacitor
Runs on
Browser; iPhone and Android in testing
Server
None yet: it all runs on the device
Hosting
Azure Static Web Apps, GitHub Actions
Tests
328 unit tests, browser tests in CI
Languages
Nine

The problem

PopSkip is meant for a few quiet minutes on a phone, often without a signal. That puts two demands on the software. Every roll has to be finishable, because a player who gets stuck needs to trust that a full solution exists. And help has to be honest: a hint should point to a move that really can still finish the roll, and it has to work offline.

Where each part runs

BUILD TIME CLOUD ON THE DEVICE Roll generators scripts in TypeScript Proof and rating the solver proves a full route; 4,000 random games rate it Level packs boards only; the build fails if a solution is left in GitHub Actions typecheck, unit and browser tests, build, deploy every board only proven ones bundled Azure Static Web Apps popskip.pirigram.com App Store and Google Play Capacitor builds, in testing Aptabase anonymous counts, no device ID AdMob rewarded video, apps only Score server (planned) replays move lists with game-core deploys React client screens and a canvas board game-core the rules, pure TypeScript Solver in a Web Worker hints and rewind, node budget Local storage progress, treats, settings Service worker or app shell offline web; Capacitor in apps loads once, then offline installs one event a day asks for a video move lists, later
Boards are proven and rated before they ship, and solutions never leave the build. On the device the rules and the solver run without a network. The dashed box is planned, not built.

My part

I designed the game and its rule, and I make the product and architecture calls. The code is written by AI coding agents, Claude Code and OpenAI Codex, working under my direction; I keep responsibility for the architecture, the validation, the tests and what goes to production. Every decision goes into a numbered log with its reasons, more than two hundred of them so far. Changes go through CI, and I play each build on my phone before it ships.

Decisions, and what each one cost

A few of the decisions from that log, with the alternative each one turned down. The first is easier to see than to read:

Tap Hint on the board as it is Search in a Web Worker depth-first, up to 200,000 nodes the same answer on every phone cancelled if the board changes A proven next move shown on the board; it costs treats The budget runs out a best guess, labelled as one, free No finish is left an offer to rewind to a proven point
What happens when you tap Hint. Only a proven move costs anything; when the search runs out of budget, the game says so instead of guessing quietly.
  1. Decision log · D-0044 · D-0095

    Hints are proven on the phone, within a fixed budget

    Problem
    Hints have to work offline and at once, but a full search can take too long on a phone in the middle of a game. About one position in nine runs out of budget.
    Decision
    A depth-first search with Warnsdorff ordering, in a Web Worker, capped by a node count rather than a time limit, so every device gives the same answer. Only a proven hint costs anything.
    Turned down
    Hints from a server; charging for a hint that was only a guess.
    Cost
    The game is sometimes openly unsure. I chose that over a hint that is sometimes quietly wrong.
  2. Decision log · D-0062 · D-0090 · D-0137 · D-0171

    Every board is proven before it ships, and its difficulty is measured

    Problem
    A stuck player must be able to trust that a finish exists, and difficulty has to rise in a way players can feel.
    Decision
    The generators keep a board only if the solver proves a full route. Each roll is rated by how many of 4,000 random games finish it, and the trail is laid out in waves by that measure. The current pack builds rolls as chains, so a route exists by construction.
    Turned down
    Generating boards on the device; rating difficulty by the number of bubbles, which turned out to matter less than the shape.
    Cost
    The rating comes from a bot, not from people, until there is enough play data to check it against.
  3. Decision log · D-0058 · D-0034 · D-0214

    One rule engine, in plain TypeScript

    Problem
    The rule lives in the game today and will also live on a server that checks scores. Two implementations would drift apart.
    Decision
    game-core is pure TypeScript with no screen, storage or network code, pinned down by shared test fixtures. The server, when it comes, imports the same package.
    Turned down
    A second engine in C# on .NET, which the original plan called for.
    Cost
    It sets aside my usual .NET choice for the server side.
  4. Decision log · D-0094 · D-0168 · D-0204

    The client is not trusted, and the one exception is written down

    Problem
    Without accounts, everything a player owns lives on the device, and anything on a device can be changed.
    Decision
    A game that used help is flagged and will never rank. The build refuses to ship solution routes: there were 491 in the bundle, now there are none. Rewards for a video are credited on the device as a named exception until there is a server wallet, which brings AdMob’s server-side check with it.
    Cost
    A forged reward is possible today. It harms no one else, and the decision says when it has to end: before anything is sold.
  5. Decision log · D-0134

    Capacitor, not a native rewrite

    Problem
    The game had to reach iPhone and Android without a second codebase.
    Decision
    The same web build inside a Capacitor shell, with native plugins for video ads, notifications, haptics, sharing and review prompts.
    Turned down
    React Native or Unity, both a rewrite of the board and the screens; a thin web wrapper, which fails Apple’s guideline 4.2 and does not work offline.
    Cost
    WebView speed on mid-range Android, a Mac for every iPhone build, and WebView quirks: sound on iPhone failed until media requests sent a Range header.
  6. Decision log · D-0199 · D-0202

    Retention measured without identifiers

    Problem
    Launch decisions depend on how many players come back after a day and after a week, but the game has no accounts and I did not want device IDs.
    Decision
    Aptabase, which keeps no device ID or cookie and drops the IP address, plus one event a day that carries the number of days since first play, queued while offline.
    Turned down
    Firebase Analytics.
    Cost
    Counts are per device, and a reinstall looks like a new player.

In numbers

  • On the full 10 × 10 sheet, a finishing route is proven from every one of the 100 starting bubbles.
  • 4,000 random games are played against every roll to rate its difficulty.
  • A year of daily rolls ships inside the game, so the daily works offline.
  • 328 unit tests across the rules and the client, and browser tests on every change.
  • The sound a new player downloads first went from 10.8 MB to 1.7 MB.

What comes next

  • The App Store and Google Play releases. The iPhone app is in TestFlight and the Android app in closed testing.
  • A server that replays each move list before any ranking or leaderboard exists, and keeps progress in the cloud.
  • New chapters for the trail.

Updated 20 October 2026.