Inspiration

Every virtual pet I grew up around ran on guilt. Forget it for a day and it got sick. Forget it for a week and it died. Fitness apps do the same thing in a nicer outfit: a streak that drops to zero, a ring that stays empty, a number in red.

I wanted to make something for the person having a bad month. Someone injured, ill, busy, or just tired. So Ambly started from two rules. The creature can never die, never get sick, and never lose what it grew. A quiet stretch only makes it sleepy. And it has to be yours. Not one of a dozen mascots everyone gets, but something that exists nowhere else.

What it does

Ambly is a little creature that grows on the exercise you actually do. You pick an egg, finish one workout, and it hatches into a creature generated from a seed. Its colours, body, eyes, ears, tail, crest, pattern and name all come from one number, so no two people get the same one.

After that it grows on Apple Health. Walks and runs count through their steps. Rides, swims and gym sessions count through workout time, because a swimmer takes no steps and still worked hard. It lives where you already look: widgets, the Lock Screen, the Dynamic Island and the Apple Watch.

Every creature you raise stays in your collection as a record of the time you spent together. There is a field of your year with a streak that forgives rest days and never forgets your best run, and an album of 99 stamps. The app is free, and there are only two purchases. Rehatch gives your creature a new look and keeps its name, level and history, and you see the new look before you pay. New egg starts another creature while your current one keeps everything it grew.

How we built it

I built Ambly in SwiftUI for iPhone and Apple Watch, overall direction and idea of the app, Cliff Cheon shaped how it should look and feel, and Ryan Lee has worked on setting up the overall levelling logic. The creature engine is its own Swift package, so the app, the widgets, the Live Activity and the Watch all rebuild the exact same creature from about twenty bytes.

A creature is a seed. The generator turns it into small palette sprites, 32 by 32 pixels, draws an outline around them, and renders every frame with smoothing switched off so the pixels stay sharp. Every pose reads only the body shape, so every creature can walk, run, ride, swim, lift and sleep. That gives 115,200 combinations across four families, plus any hue on the colour wheel, and a 1.5% chance of a shiny. Nothing is drawn by hand. Even the app icon came out of the generator.

Growth is calculated, never stored. A creature's level is worked out from your Health history each time, so it cannot drift, count something twice, or go backwards.

Your steps and workouts stay on your phone. Only your collection syncs, through your own iCloud, and the analytics code is tested so it can never carry a health number.

RevenueCat runs both purchases. I had planned a free trial and then a subscription, but a paywall on day 14 made no sense for a pet that can never die, so I dropped it for two simple purchases.

About 570 unit tests and 48 UI tests keep it honest, including one that renders every pose for 108,000 creatures and checks nothing falls outside the frame. Even the App Store screenshots and preview videos are recorded by tests from the real app, and the music in them is a chiptune I generated in code.

Challenges we ran into

Health data is not allowed in iCloud, even in your own private space. I had built sync on top of it, so I split the app into two stores: one that stays on the phone and one that syncs. Getting there nearly cost me my own data. An upgrade tripped over the old sync records and the app opened empty. I reproduced it from a copy of my phone's data before fixing it, and got every creature back.

The phone's motion sensor told me I was standing still for an entire walk, measured on my own iPhone. I moved the live walking animation to step cadence, which is an actual measurement, and it has been right ever since.

App Review turned me down the first time. My Health screen had a Not now button, and the reviewer could not get in because the first egg needs a real workout. I rebuilt the reviewer path as a proper demo mode that opens the egg and loads twelve weeks of sample activity, and made sure it can never touch the real data of anyone who used it on an earlier build.

The purchases needed care too. Rarity sells, but rarity you can buy is a loot box. Shiny creatures can only be earned, never bought, and Rehatch charges only after you have seen the result, so nobody pays for a roll of the dice.

Accomplishments that we're proud of

A creature that is truly yours, with no drawn artwork, and exactly the same on your phone, your widgets, your Dynamic Island and your Watch.

An app that never punishes you. No step goals, no calorie counts, no streak that resets to zero, and not one guilt trip in a notification.

Health data that stays on your phone, backed by tests rather than good intentions.

Full English and Korean from day one.

A way of making money I would be happy to explain to the person paying.

What we learned

Calculating things beats storing them. Every bug I was afraid of, counting twice, drifting between devices, progress slipping backwards, went away once growth became a calculation instead of a counter.

RevenueCat works just as well for simple purchases as for subscriptions, and dropping the subscription made Ambly more honest.

And App Store Connect has its own vocabulary. "Ready for Review" does not mean submitted. I learned that one the slow way.

What's next for Ambly

Letting the Watch count its own steps, a tuned level curve with an earlier first evolution, better accessibility with larger text next, and Game Center battles where two creatures meet using nothing but their seeds.

Built With

  • cloudkit
  • core-graphics
  • core-motion
  • firebase
  • firebase-analytics
  • healthkit
  • ios
  • live-activities
  • revenuecat
  • storekit
  • swift
  • swift-testing
  • swiftdata
  • swiftui
  • watchconnectivity
  • watchos
  • widgetkit
  • xcode
  • xctest
Share this project:

Updates

Submission history