← All projects

Hammy

A running app where a pixel-art hamster grows as you run. It links to Strava, turns every run into XP and gear, and coaches your training through a hamster who gets fitter, tired or heartbroken depending on how you train.

Mobile apps, Integrations

Visit the live site ↗
Type
My product
Status
Live
Year
2026
Built with
Expo, React Native, TypeScript, expo-router, NativeWind, TanStack Query, Firebase Auth, Firestore, Cloud Functions, Strava API, SwiftUI, WidgetKit, RevenueCat, PostHog, Sentry, EAS, Next.js

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 run from Strava, with its stats, segment PRs and the XP it earned.
Hammy run detail: a tempo run from Strava and the XP it earned
Part of the post-run celebration. A good week is measured against your own number of runs, not anyone else's.
Hammy post-run celebration: a good week, three runs against the runner's own number

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.

What your coach noticed, straight after a run.
Hammy after a run: what your coach noticed
The lesson behind the advice: why a lighter week every month builds fitness.
Hammy library: why deload weeks build fitness

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.

Five hearts, and every trait explained. Tap one to learn why it's where it is.
Hammy home: a fit hamster at sunset, with five hearts and each trait explained
Seven days from collapse. Skip too long and you'll hear about it. You really don't want to.
Hammy home: a neglected hamster in tears, seven days from collapse

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.

Eight states across three body shapes, from content to collapsed. Body shape follows how consistently you run.
Hammy's eight states across three body shapes, drawn on an 80 by 92 pixel grid

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.

Every scene in the app, drawn in code: the home track at morning, day, sunset and night, then cities, mountains, races and the library.
Twenty-four scenes drawn in code: the home track at four times of day, cities, mountains, races and the library
The gear shop. Some pieces cost tokens, some unlock free at a level, and some come from milestones.
Hammy gear shop: shoes, some owned and some locked to a level
A level up. Every few levels, a free piece of gear unlocks with it.
Hammy post-run celebration: level 7

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.

Four runners' hamsters, as the widget draws them: each one's own stage, fur, gear and mood.
Four runners' own hamsters as the home-screen widget draws them: stage, fur, gear and mood

Strava, done properly

Every reward hangs off one webhook, so it had to be dependable.

How it's built

Strava and the runner feed Cloud Functions, which own every reward. Firestore's rules keep each runner's data their own, and the app, widget and website all draw the same hamster.

How it grew

  1. October 2025Strava and a hamster

    The Expo app, Firebase auth, Strava sign-in, the webhook and token refresh.

  2. December 2025Moods, bodies and a shop

    XP and achievements, body shapes and emotions, then tokens and the gear shop.

  3. January 2026Everything else

    Goals, friends, the first training advisor, push notifications, subscriptions and scenes.

  4. February 2026Hearts and the widget

    Strength and the hearts, the iOS widget, growth stages and account deletion.

  5. April 2026Getting to know you

    A redesign, the leaderboard, and onboarding that reads your Strava history to work out your running.

  6. 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.