Hood to Coast Athlete TrackeriPhone web app

When is our runner getting here?

Making a nearly 200-mile relay a little less chaotic.

Hood to Coast is a 12-person relay where runners rotate through dozens of legs while two vans leapfrog their way from Mt. Hood to the Oregon coast.

After racing it, one problem kept bothering me: we were surprisingly bad at knowing when the next handoff was actually going to happen.

Role
Designer, developer, team captain, runner
Platform
iPhone web app
Timeline
Jul 2026–present
Status
Raced once, iterating for 2027
Three iPhone screens on blue: the Race timeline list of legs, the dark Live map screen, and the More settings screen.
Three screens from the app: the Race timeline, the Live screen for the runner on the course, and the More screen with tracking status and the fallback pace.

Why I made it

Hood to Coast is the largest relay race in the world, run every year since 1982. It starts at Timberline Lodge on Mount Hood, runs through Portland and the Coast Range, and finishes on the beach in Seaside, through a full day and an overnight. Teams split into two vans that leapfrog down the course, and every handoff depends on the next runner being at the exchange at the right moment, often in the dark and often with no cell service.

Miles
197
Runners
12
Vans
2
Legs
36
Hours to the finish
28
Teammates using the app
12 of 12
A dense crowd of runners and spectators on dry grass under an overcast sky, with evergreens and tents behind.
From the mountain to the beach, in one day and one night.

I was the team captain, one of the twelve runners, and the only person building the app. That overlap shaped the product more than anything else: I couldn’t design something that needed me watching it. It had to work while I was running, sleeping, or out of signal.

The project came straight out of our first year, when we shared iPhone locations. It felt useful, but a dot on a map says where someone is, not when they’ll reach the exchange. Working that out meant guessing distance and pace and doing the math in a moving van, and a wrong answer meant a runner waiting in the cold or a van arriving late. The printed schedule was a good plan for about the first hour. By the overnight legs it was mostly guesswork.

The problem wasn’t location. It was timing: turning where the runner is into when they’ll arrive, and keeping that accurate as the race drifts away from the plan.

What I designed

Most running apps are built around one athlete. This one was built around a team.

The runner already knows where they are. Everyone else needed the information: the next runner deciding when to warm up, the driver deciding whether there’s time to stop, and the rest of the team deciding whether they can sleep. Find My shows where someone is, Strava and Garmin track one athlete well, and the printed schedule can’t adjust. None of them answered the timing question.

The product came down to one mental model: what’s happening now, and what happens next. The main screen answers it in one glance, from a passenger seat, often at night. It shows who’s running, which leg, and how far along they are, and it leads with the ETA and the next runner, because those change what people do. Instead of coordinates, the app says “Runner 8 · 72% through Leg 8 · Exchange in ~14 min.” The map is still there, but as supporting detail, not the headline.

iPhone Live screen: a map with the runner on Leg 4 above a card of live pace, distance covered and time remaining.
iPhone screen labeled Fallback Pace on Leg 1, with a card showing a set pace, distance, elapsed time and the next runner.

Built to be read in two seconds by someone who just woke up in a van.

I knew location would drop out, so I built a fallback. When GPS goes quiet, the app keeps estimating from the leg’s start time, its distance, and the runner’s planned pace, then snaps back to real data when a location returns. That works because the app keeps the plan and the live state separate.

Deciding what not to build mattered as much. Social features, chat, leaderboards, and deep analytics are already well covered elsewhere. If a feature didn’t help someone get to the right place at the right time, it didn’t ship.

It’s a relay operations app, not a fitness tracker.

How I built it

Tools
Claude, Claude Code, VS Code, GitHub Copilot, Notion, FigJam
Tech stack
Vanilla JavaScript, Supabase, Vercel, Leaflet, OpenStreetMap, Traccar

I built it as a progressive web app, so setup meant opening a link in Safari and choosing Add to Home Screen. There was no App Store review and no TestFlight. Under the hood it’s vanilla JavaScript, HTML, and CSS, with no framework and no build step. Supabase handles the database and live data, Vercel handles hosting, and Traccar reports each runner’s location in the background. The map runs on Leaflet and OpenStreetMap, so there were no licensing costs.

I was the only person on the project, but I didn’t work alone. Claude was my strategy and spec partner, Claude Code in VS Code did the implementation, and GitHub Copilot handled small interface tasks. The speed came from the tools. The quality came from the rules I set around them. Every task started with an audit before any change, the fragile parts (race state, ETA math, handoff logic, the map) were off-limits unless they were the target, and every change went through a branch, a pull request, and my review. That was more than 60 pull requests. Notion held every bug and feature as its own item, and FigJam became my bug-reporting tool: I’d mark up a screenshot from my phone and bring it back into Claude Code.

Four app windows: Claude, ChatGPT and Notion across the top, and VS Code with the project open below.
A FigJam board titled Buffalo Tracker with four groups, including a moodboard and a competitive analysis table.

Notion tracked what to build. FigJam showed what to fix.

A few days out, I removed the testing simulation entirely, because leftover test data had come close to interfering with the live race. The night before, I built a manual override that let me set the active runner and leg directly. I hoped not to need it.

The AI wrote most of the code. I owned every merge.

Using it for real

There was no test environment. The race itself was the test: all twelve of us used the app for 28 hours, overnight, while running, driving, and sleeping in shifts.

Five teammates in matching pink-and-white jerseys stand at the open rear doors of a van under a blue sky.
Part of the team at the back of one of the vans.

The core idea held up. Instead of asking where the runner was, the team could see who was running, how far along, and when they’d reach the exchange. Next runners timed their warm-ups off the ETA, and the other van could follow the race without a stream of texts. The pace fallback worked better than I expected: when runners lost signal, the app kept estimating instead of freezing.

Connectivity was the biggest constraint. Losing a runner’s GPS mid-leg was survivable. Losing service at an exchange wasn’t: automatic handoff detection couldn’t register, so the app kept the previous runner active after the race had moved on. The override earned its place. I corrected the active runner and leg from the van, and the fix reached every phone in seconds, because only the live state was wrong. It was a recovery tool, not the experience I ultimately want, but it’s why the app stayed useful all the way to Seaside.

In this environment, it isn’t an edge case. It’s the normal condition.

What I learned

Twelve teammates in jerseys and finisher medals stand in a row on the sand beneath the Relay Finish arch.
197 miles, 28 hours, and one very tired captain.

Going in, I thought I was building a prediction tool: how do I predict when the runner will reach the exchange? Coming out, I saw the real problem was different: how do I keep a distributed team in sync when the network can’t be trusted? I’d had the design constraint backwards. I designed for connectivity as the normal case, but through the Coast Range and overnight, no signal was the default, and the app worked because the fallbacks carried it.

Two more lessons. Any system that decides things on its own, like deciding a handoff happened, will eventually get something wrong, so the key question is how quickly and safely a person can correct it. And no amount of testing at home would have shown me what happens at an exchange with no signal at 3 a.m.

The next version treats poor connectivity as a core requirement from day one: race state kept on each phone, handoffs confirmed at the exchange itself, automatic recovery when a runner’s location reappears, and an ETA that shows how confident it is. The goal isn’t to eliminate uncertainty. It’s for the app to understand its own uncertainty and say so clearly.

This is why the project leads the Making page. There was no brief and no stakeholder. I hit a problem during something I love, built something, used it for real, and watched my assumptions break. That’s the work I want to keep doing.

Credits: Designed, built, and operated by Tyler Wain. Raced by The Buffalos, Hood to Coast 2026.