Inspiration

I checked my screen time and it said six hours.

Every app I had that was supposed to fix that was just one more thing to open. Another streak to keep. Another guilt notification at 9pm.

So I built the opposite. A little creature that gets fed by the time I am not on my phone, by my sleep, by my steps. When I have a bad day it does not yell at me and it does not die. It just gets sleepy and waits for me.

That turned out to be the whole app.

What it does

You answer three questions about your vibe and a creature hatches. It is yours, and there is only one of it.

After that it runs on your real life:

  • Your steps and sleep come from Apple Health and feed it
  • Checking in and doing a focus session earns Yolks, the in-game coins
  • Time spent off your phone feeds it too

Live well and it is bright and bouncy. Sleep four hours and it goes dim and sleepy with little z z Z floating over its head. It never gets sick. It never dies. If you miss a day, nothing bad happens.

Around that there is a cozy little game. 203 species to find, 88 outfits, 17 rooms, 34 pieces of furniture, 21 rare colours. Once a day your creature walks off to a friend's room by itself and comes back with a postcard from a room it actually visited. You can send friends coins, trade spare outfits, and go look at strangers' rooms.

Postcards are built by picking from a list we control, not by typing. So nobody can send you anything mean.

And every creature in the app is drawn by code. There is not a single image file in the whole thing.

How we built it

SwiftUI and SwiftData for the app. Supabase for the friends and social stuff. RevenueCat for the subscription and the coin ledger.

The creatures are not drawings. They are recipes. About 46 hats and heads, 26 body patterns, and a set of colour palettes, which multiply out to over 900 possible combinations. 203 of them have real names. Because it is all maths, the same creature can be drawn at any size, in a room, on a card, inside a postcard, without us making a second picture.

It also means it can actually feel alive. It breathes unevenly, so the breath in and the breath out are different lengths, like real breathing. It blinks at random instead of on a timer. When it moves, its hat swings a beat late and then settles.

The screen time part we had to build twice. The first version asked Apple for today's usage inside a piece of code that Apple runs in a locked box. It turns out that box quietly throws away anything you try to save from it, and it never tells you. So the app just said "counting" forever on every phone, with no error to find.

The second version works differently. We set 48 little alarms, one every 15 minutes up to 12 hours, and a different piece of code, one Apple does let save things, writes down the highest alarm that went off. It undercounts a bit, and the app says so instead of pretending.

Challenges we ran into

The locked box above. Two days gone to an API that fails silently on purpose.

Wallets that refunded themselves. When the phone and the server disagreed about your coins, both of them kept the bigger number. Which meant every time you spent coins, the old balance came back on the next sync. One player spent down to 200 coins and woke up with 565 again, and their purchases were gone. We fixed it by putting a version number on the wallet, so the newest change always wins even when it is the smaller number.

Trading that cloned things. When a trade moved an item away, the phone never noticed it was gone, so the next sync put it back. Both people ended up owning it. We found that ourselves in an audit, not from a bug report.

Accomplishments that we're proud of

We used RevenueCat's currency system specifically so we could not sell currency.

RevenueCat's ledger holds every coin that came from money. Our database holds every coin that came from living. They are kept completely separate, on purpose. A free player who actually uses the app earns about 3.4x more coins than a subscriber does. You cannot buy coins at any price, and money never touches anything random.

The second one is a file called CLAIMS.md. It is a list of every promise our website makes, next to what the app actually does, with dates.

It works because it corrects us in both directions. It caught us saying "no in-app purchases" after we had already shipped a subscription. It also caught us about to delete a true claim about trading from our own website, because we had forgotten we built it.

What we learned

A checklist only asks whether you built the thing. A claims file asks whether the sentence on your website is still true. The second question is harder and much more useful.

And the interesting money question is not how to charge more. It is what your income goes up with. Most free apps make more money the longer you stay in them. Ours does not, so we have no reason to keep you here.

What's next for Yolkling

Testing the screen time rewrite on a real phone. It is built, tested and shipped, but Apple does not report phone usage in the simulator, so it has genuinely never run for real yet.

After that: trading species cards, which needs database work we have not done, and making the holographic cards reachable. They are finished and they look great, and right now you can only see them through a developer shortcut.

Built With

  • deviceactivity
  • family-controls
  • healthkit
  • next.js
  • postgresql
  • revenuecat
  • storekit
  • supabase
  • swift
  • swift-testing
  • swiftdata
  • swiftui
  • typescript
  • vercel
  • xcodegen
Share this project:

Updates

Submission history