Inspiration
Most idle games are designed never to end. The numbers just keep getting bigger, and you quit when you're bored, not when you're done. I wanted the opposite: an idle game with a real, reachable last box.
The idea is the simplest urge there is. You see an empty checkbox, and you tick it. Now do it a million times. The board is a real 1,000 × 1,000 grid:
$$1{,}000 \times 1{,}000 = 10^6 \text{ checkboxes}$$
At four taps a second, a million boxes by thumb alone takes
$$\frac{10^6}{4 \times 3600} \approx 69 \text{ hours}$$
That's where the game comes from. At some point you realise a million is a lot, and you start hiring help.
What it does
- Tick a box, earn a coin. Coins hire agents that keep checking boxes while the app is closed. Contracts run on real wall-clock time, so you come back to finished work.
- Six agent tiers with different behaviour. Some wander blindly, some hunt for empty cells, some sweep the board in order, and a couple will even un-check boxes behind you. Choosing who to hire is the real strategy.
- Four minigames (Chase, Scout, Sprint, Sweep), played on an actual square of your million rather than in a separate menu.
- A live global leaderboard that tracks split times at 10k, 100k, 250k, 500k and the million. Thumb runs and agent-assisted runs are ranked separately. The timer only counts time you actually spend playing.
- Pixel-art stamps, badges, share cards, daily rewards and a prize wheel.
- Plays fully offline, with no account needed.
How I built it
React Native 0.86 with the New Architecture. The whole million-cell board is drawn on a single Skia canvas, with no per-cell views at any zoom level.
- The board is a bitset. One bit per cell means the entire board is \(10^6\) bits, about 125 KB. It's stored encrypted in MMKV.
- Level-of-detail rendering. Zoomed out, the board is a single 1000×1000 texture with one pixel per cell. As you zoom in, a vector checkbox layer fades in, and taps only register once cells are big enough to hit reliably. The board is split into 1,000 sectors for caching and redrawing only what changed.
- Everything per-frame runs on the UI thread in Reanimated worklets (pan, pinch, camera, fading between zoom levels). The JS thread only updates the bitset.
- Monetization runs on RevenueCat (
react-native-purchases+react-native-purchases-ui), with two offerings: a default one for ad removal and bundles, and one for coin packs. Entitlements are reconciled fromCustomerInfoon launch, so purchases restore cleanly across reinstalls. - Save integrity: the board and the coin wallet are HMAC-signed, AES-encrypted and bound to the device, with rollback protection, so coins have to be earned or bought.
- Supabase for the leaderboard and feedback, Notifee for local "your agent finished" notifications (no server needed), and Firebase Crashlytics + PostHog for stability and funnel data.
Challenges
- Performance on budget phones. The hard rule was that it had to run smoothly on sub-$150 Android Go devices. That ruled out the obvious approach, a virtualised list of checkbox views, and led to the single-canvas, bitset and level-of-detail design.
- Designing an economy that ends. A finite board means a finite coin supply, roughly 54k net coins across a full run. Standard idle-game cost curves assume infinity and break here, so every price had to be sized against that ceiling. A coin pack that's too big becomes a "win" button.
- Selling time, not victory. I wanted it free and finishable without paying. Purchases buy convenience (ad removal, agent time, coin packs); they never lock off the ending.
- Notifications that silently didn't fire. iOS suspends the app before async calls made during backgrounding finish, so scheduling "agent done" pings on suspend registered nothing. The fix was to schedule them when the agent is hired, using the contract's fixed finish time.
- Keeping the leaderboard honest. The timer uses a monotonic clock and only counts foreground time, so changing the device clock doesn't help.
What I learned
- A single well-designed canvas beats thousands of views, and "it has to run on a cheap Android" is a great constraint for making design decisions.
- A finite game changes everything about monetization: you can't sell infinity, so you sell time.
- Real store data is humbling. After launch, the funnel showed the icon and screenshot thumbnails were the bottleneck, not the description text I'd been polishing.
What's next
Prestige boards (a fresh million with new rules), more minigames, and a finished-runs hall of fame for everyone who reaches the last box.
Built With
- admob
- firebase
- notifee
- onesignal
- posthog
- react-native
- react-native-reanimated
- revenuecat
- skia
- supabase
- typescript
Log in or sign up for Devpost to join the conversation.