Skip to content
Build log

The parrot and the trophy room

7 min readby Manuel

I closed the build log ten days ago, then shipped v1.1 anyway: a mascot that was hiding in the app name all along, eighty trophies, and a new AI model in the co-author line.

The achievements trophy room on iPhone with unlocked cups and progress bars

Ten days ago I ended this build log with "see you on the trails." Version 1 was out, the story was told, and I meant it. Then I kept opening the project anyway. For the first time since February there was no list of things the app needed, and it turns out that is not the end of building, it is the start of a different kind of building. This week version 1.1.0 went live, and it is the first update I made not because something was missing, but because I wanted the app to be more fun. Not louder, not busier. More fun without getting in the way, and partly just for the sake of it.

There is a parrot now. Let me explain.

The bird was hiding in the name

"Runara" was never supposed to mean anything. I wanted a word that sounded like movement and started with "run", and that was the whole brief. It was months later, staring at the name for the hundredth time, that I actually read the second half of it: an ara. An ara is a macaw, the big, loud, slightly ridiculous kind of parrot. The name came first; the bird had been hiding inside it the entire time, waiting for me to notice.

Once I had seen it I could not unsee it, and the app that deliberately has no mascot energy anywhere, all hairline borders and instrument numerals, suddenly had a mascot anyway. So I leaned in, carefully:

feat(design): motion tiers, ParrotMark, Reduce-Motion gate feat(parrot): mascot moments — idle perch, summary celebration, empty states

A small coloured parrot now perches in a corner of the watch idle screen and does a little hop every eight seconds or so. Finish a workout and it flies across the summary header while your stats cascade in below, with a success tap on the wrist. That is nearly all it does. It does not talk, it does not nag you about closing rings, it does not have opinions. It perches, it hops, and it celebrates when you have actually done something. I find that to be the correct amount of parrot.

Fun without distraction

The whole update hangs on one design rule: boundary moments celebrate, live numerals stay still.

While you are mid-run reading your pace, the app stays an instrument. Nothing pulses, nothing bounces, no number does a little dance while you are trying to glance at it at kilometre nine. But the moments at the edges, where you are not reading data, got warmth: the countdown pops its numerals and flashes GO, pausing dims the screen and morphs the button, splits slide in, the Water-Lock droplet does a small bounce, and the summary numerals roll up like an odometer. It is the difference between a friend who claps at the finish line and one who claps through the entire run.

And every bit of it collapses under Reduce Motion. Switch that on in the accessibility settings and the parrot stands still, the celebrations become quiet fades, and the app goes back to being entirely sober. Joy should be something you can opt out of.

The trophy room

Then, because apparently I was not done, achievements:

feat(core): achievement model, engine, 68-entry catalog feat(ios): achievement detection, unlock celebrations, trophy room

Eighty of them by release day, across sixteen workout types. Distance ladders for running, cycling and swimming, long cumulative climbs like a thousand lifetime kilometres, streaks, counts, and a few I am disproportionately pleased with, like Early Bird and All-Weather Parrot. They live in a trophy room inside the History tab: unlocked cups with their dates, locked ones with honest progress bars, and every cup carries its own engraving, "10K", "42.2", "Σ100". Unlock one on the wrist and the workout summary grows a small NEW TROPHY strip; on the phone the parrot celebrates properly, with five different flight styles and a burst of feather confetti.

Two details I care about more than anyone will ever notice. First, the confetti is deterministic: each celebration is seeded by the achievement itself, so replaying a trophy's unlock shows the exact same flight every time, like a memory rather than a slot machine. Second, the bookkeeping is honest: only workouts Runara itself recorded count toward trophies, and if you delete a workout, any trophy it earned goes with it. A medal you keep after deleting the run it came from is not a medal.

The running ladder also had a gap problem. It originally jumped from one to ten to fifteen kilometres, which meant your second-ever 2 km run earned you nothing for a long while. That bothered me the way a missing stair bothers you, so the last feature commit before release filled every rung from one to fifteen:

feat(achievements): filter, per-km ladder, cup engravings, reconcile

A small thing. But ladders should not have missing rungs.

One small honest toggle

In between, a tiny feature that will never appear in a screenshot: a "Play sounds in Silent Mode" setting, plus a speaker toggle on the watch actions page that overrides it for just the current workout. I added it because my own watch lives permanently on silent, and the voice cues I built in May were being faithfully muted by my own settings. Sometimes the user you fix the app for is you.

The honest reckoning, part two

The last post ended with an accounting of what building this app with Claude was actually like, and I promised to stay straight about the AI part. So, an update, because the AI part changed.

This whole v1.1 sprint was built with Anthropic's new model, Fable 5, which came out right around the time version 1 shipped. The co-author line in my commits changed with it: Co-Authored-By: Claude Fable 5. Same arrangement, newer brain. And yes, the first draft of this post came out of the same model, and was then rewritten wherever it did not sound like me.

Is it better? Honestly, yes, noticeably. The celebration flight is a hand-rolled Canvas animation, Bézier flight paths, the parrot banking into turns, wing beats with squash-and-stretch, feathers shedding along the path, and the first draft of that code mostly just worked. During the v1.0 sprint I would have budgeted an evening of fixing for something like that. The achievement engine, an eighty-entry catalog with localized names in two languages and a pile of edge cases, came out structured roughly the way I would have structured it myself. Fewer wrong fixes, fewer plausible-but-hollow suggestions.

But the shape of the collaboration did not change, and I want to be precise about that, because it is the part people get wrong in both directions. The first version of the celebration flight worked and was boring, the parrot slid across the screen like a slide transition, and "this does not feel like flying" is not something a model can feel. I made it rebuild the entire scene as an actual flight. And two days before release, every achievement name in the trophy room quietly turned into a raw localization key, achievement.%@.name staring out of a gold cup, because of a subtle string-interpolation trap in Swift's localization API. Fable 5 wrote that bug. It also wrote the fix and the regression test within minutes, once I put the screenshot in front of it. The eyes on the actual screen, the taste that says rebuild it, the judgment about what deserves a trophy and what is noise, that part still does not come out of the machine.

Faster horse, same rider. That is the honest version.

Out now

Version 1.1.0 is on the App Store as a free update. Same deal as always: no account, no subscription, nothing collected, and the training history behind your trophies never leaves your devices. The parrot lives entirely on your wrist.

I said last time that I did not know whether there would be more. Apparently there is more. See you on the trails, and if you run fifteen kilometres, there is a cup waiting.