Hammy is a pixel-art hamster who lives on your phone and grows as you run. Connect Strava and go for a run. By the time you've caught your breath, Hammy has the XP, maybe a level and a new pair of shoes, and an opinion about your training.
I'm an ultrarunner, and most running apps are spreadsheets with a map. They're good at telling you what you did and bad at making you want to go again tomorrow. Hammy is the opposite bet: a small creature you care about, whose health is your training. It's in beta on TestFlight now and goes on the App Store soon.
Impact
- Image files for the hamster. It, 95 pieces of gear and 24 scenes are drawn in code
- 0
- Coaching rules and triggers reading your last 16 weeks of training
- 33
- Lessons in Hammy's library, one behind every piece of advice
- 53
- Automated tests across the app, Cloud Functions and security rules
- 3,500+
The loop
You run, and Strava syncs. Strava's webhook calls a Cloud Function, which stores the run and awards it: 100 XP a kilometre, tokens for the shop and progress on your goals. Then the app plays the run back to you one step at a time: the XP, a level up, a good week, a new growth stage, what your coach noticed, a goal hit and any gear you just unlocked.
Levels get steadily harder and never stop. Level 2 costs 900 XP and each one after costs 40 more. Hammy grows from a baby to a standard to an experienced hamster along the way, and free gear unlocks every few levels, so there's always something close.
Hammy talks back, too. After a run he sends a line to match it: "PB! Hammy wants to know what you had for breakfast." Go quiet for longer than you usually do and he nudges you, and on a Saturday morning he'll tell you if the week's at risk. He sends at most one message a day.
A hamster that tells the truth
The interesting design problem wasn't the rewards. It was making Hammy honest.
Hammy has four traits: happiness, strength, energy and endurance. Five hearts sum them up, but not as an average. The hearts can never sit more than one above the weakest trait, because a chain is only as strong as its weakest link. Three great traits can't hide one that's failing, so the hearts always point at what's actually wrong.
The traits come from a coaching engine that reads your last 16 weeks of runs. It has 26 rules and 7 triggers, built on how marathon and ultra runners actually train. Jump your weekly distance too fast and Hammy gets tired. Run every run at the same pace and he wants variety. Ease off after a big week and he's pleased with you. Endurance and strength fade by at most one point a week, so one lazy week doesn't undo a good block.
Every piece of advice links to Hammy's library: 53 short lessons on seven shelves, from building up to race-day fuel. Hammy gives you the nudge, and the library tells you why.
Stopping has a cost. After two weeks without a run, Hammy starts to worry. At three weeks he collapses, and a run in the next fortnight brings him back. At five weeks he's gone and you start again with a new hamster, though your tokens and gear are kept. It sounds harsh, but it's the mechanic that gets people out the door.
What Hammy deliberately doesn't do is reward daily streaks. A hamster that punishes rest days teaches exactly the wrong habit, so consistency is counted by the week, against the number of runs you said you'd do.
Pixel art, drawn in code
There isn't a single image file for the hamster. Hammy, every piece of gear and every scene are drawn by a small pixel engine I wrote in TypeScript. The hamster is a grid of 80 by 92 cells, built from shapes and hand-drawn rows. Scenes are 104 by 226.
Drawn naively in React Native, that's thousands of views. Instead, the engine merges each horizontal run of same-coloured cells into one rectangle, and each colour into one SVG path, so a whole hamster is about a dozen paths. Every cell snaps to a whole number of device pixels and sprites are never scaled with a transform, so the edges stay crisp on every phone. Texture like grass and gravel comes from a deterministic hash, so a scene looks the same every time it's drawn.
Because it's all code, everything composes. Any shoe fits any body shape, in any mood, in any scene, with nothing to export. When I doubled the resolution of the whole art style just before the beta (Hammy used to be 40 by 46 cells), it was four rounds of redrawing on contact sheets, not thousands of new files.
The same engine bakes everything else: the app icon, Android's adaptive and monochrome icons, the splash screen and the widget's fallback images. The website at hammy.run vendors the engine too, so the hamster on the landing page is the same code as the one in the app.
Most of the gear gently parodies real running kit: the Nyke Vapourfli, the Hokka Speedgote, the Garmyn Forerunna and the Salamon S/Lab Genesys. The race scenes are real: Western States, UTMB, the Barkley Marathons, Tarawera and the Queenstown Marathon. The home track changes with the time of day.
Your own Hammy on your home screen
The iOS widget was the hardest small thing in the app. A widget can't run React Native, so it can't run the pixel engine. The first version showed a generic hamster, and it didn't feel like yours.
So the app draws your hamster, with its growth stage, body, fur, gear and mood, at one pixel per cell, and encodes it as a PNG on the phone. React Native has no zlib, so the encoder writes uncompressed deflate blocks by hand. A sprite is only a few kilobytes either way. The image goes into a shared App Group, and the SwiftUI widget scales it up by the largest whole number that fits, with smoothing turned off, so it stays pixel-perfect. If you haven't adopted a hamster yet, it asks you to.
Strava, done properly
Every reward hangs off one webhook, so it had to be dependable.
- Exactly once: XP is awarded in a Firestore transaction that refuses a run that's already been awarded, so Strava's retries never pay twice.
- Deletes: a run is only removed if it belongs to the athlete in the event and Strava confirms it's gone.
- Tokens: Strava tokens are encrypted at rest with a key from Secret Manager, and refreshed when they expire.
- Sign-in: the OAuth state is a single-use nonce from the server. It lasts ten minutes and can only send you back into the app.
- History: when you connect, your last 16 weeks of runs are imported as context, with no XP. The coach knows your training from day one, and nobody gets a level 40 hamster for running last year.
How it's built
- Mobile: Expo SDK 54 and React Native 0.81 on the New Architecture, with the React Compiler, expo-router, NativeWind and TanStack Query.
- Backend: Firebase Auth, Firestore on a named database, and about 30 Cloud Functions on Node 22 in Sydney, including three scheduled jobs on New Zealand time.
- Security: the app can write five fields on its own hamster and nothing else. XP, tokens and owned gear are written only by the server. Anything one runner sees about another, like the leaderboard or a profile, goes through a function that returns only the public fields.
- The rules engine: pure TypeScript with no React or Firebase in it, which a test enforces. Thirteen files are shared by the app and the backend, and a drift test fails the moment the copies differ.
- A simulator:
npm run simruns 120 generated runners (10 archetypes, 4 training histories, 3 seeds) through the engine into an HTML report, so a tuning change is checked against a season of fake training before a real runner feels it. - Widget: SwiftUI and WidgetKit, built alongside the Expo app with
@bacons/apple-targets. - Shipping: EAS builds, RevenueCat subscriptions, Expo push, Sentry, and PostHog for every event and screen view.
How it grew
- October 2025Strava and a hamster
The Expo app, Firebase auth, Strava sign-in, the webhook and token refresh.
- December 2025Moods, bodies and a shop
XP and achievements, body shapes and emotions, then tokens and the gear shop.
- January 2026Everything else
Goals, friends, the first training advisor, push notifications, subscriptions and scenes.
- February 2026Hearts and the widget
Strength and the hearts, the iOS widget, growth stages and account deletion.
- April 2026Getting to know you
A redesign, the leaderboard, and onboarding that reads your Strava history to work out your running.
- October 2026Pixel art, and the beta
The whole app redrawn as code-drawn pixel art, the rules engine and its simulator, the library, messages from Hammy, the 2x pass and the TestFlight beta.
What I'd take from it
The thing I'd keep is honesty as a design rule. It would have been easy to make Hammy a slot machine: XP for everything, a streak to protect, a guilt notification every morning. But the runners who get hurt are the ones who never rest. So Hammy rewards the week rather than the day, gets tired when you ramp up too fast, and tells you why. Making the hamster honest turned out to be the same work as making it good for you.
