MC.
Field noteBack to résumé
Field note · 19 August 2026

Two hours to a departure board.

I wanted one thing: to glance at my wrist and know when the next train comes. No app to open, no tapping. Two hours later the thing worked. Getting it onto the watch took the rest of the afternoon.

A watchOS complication built against the live OneBusAway Puget Sound feed

What I actually wanted was the platform sign, on my wrist.

That is what a watch complication is: a small live number sitting on the watch face, updating itself without being asked. So I built one.

2commutes covered
76tests
~40refreshes allotted per day
2hstart to wrist

Here it is, on an actual watch.

Three views: the app, the complication doing its job, and the complication deliberately doing nothing. Everything after this is how it got there.

The Lightrail watch app listing three Lynnwood City Center trains at 4:02, 15:46 and 26:20, two marked live and one scheduled.
The app · list viewWhere minutes and seconds earn their place — there is width for them here. Note the two glyphs on the right: a live signal for trains actually reporting, a timetable icon for the one that is only a schedule guess. Same distinction the feed tries to blur.
An Infograph watch face with the complication in the top-left corner reading 2, MI, THEN 9M.
Corner slot · the targetTwo minutes to the next train, nine to the one after. This is the whole point of the project, and it works: readable without stopping, without tapping. Four glyphs is the entire budget, so the stop becomes MI and the following train gets THEN 9M.
A watch face with the inline complication at the top reading MERCER ISLAN, showing no countdown because it is outside the tracked commute window.
Inline slot · off dutyNo countdown, because there is nothing to count. This is 6:15 PM — outside both commute windows — so the complication is asleep and spending no network at all. It shows the stop it will wake up for and nothing more. Off-duty is a state worth rendering, not a blank.

A number, in a circle, roughly 40 points across.

The whole app reduces to one question: how many minutes until the next train? Everything else is in service of showing that number honestly in a space smaller than a dime.

There are two of them, because I have two commutes, and they are awake at different times:

Morning, into Seattle

  • Platform: Mercer Island, westbound
  • Awake: 7:00–9:00 AM

Evening, toward Redmond

  • Platform: Westlake, eastbound
  • Awake: 4:00–5:30 PM

Data comes from OneBusAway Puget Sound, the same live feed behind the official Sound Transit apps. Real vehicle positions, real predictions.

You get about forty updates a day.

Here is the constraint that shapes everything. A watch complication cannot poll. The system hands out something on the order of a few dozen refreshes per day, total, and it decides when. You do not get to ask for more.

A naive version burns through that budget by three in the morning, refreshing all night for nobody, and is stale exactly when you are standing on a platform.

Sleep when it doesn't matter

Outside my two commute windows the complication makes zero network calls and tells the system to wake it at the next opening. Nearly the whole daily allowance lands in the three and a half hours I actually care about.

One fetch covers an hour

Refreshes are rationed, but pre-computed display frames are free. A single fetch generates a frame for every upcoming minute, plus one at each train's exact arrival — one request, a full hour of accurate counting down.

Admit when it's guessing

Between refreshes you are counting against a snapshot up to fifteen minutes old. Frames older than twenty minutes render dimmed — the display says it might be wrong rather than lying confidently.

Transit feeds lie in specific ways.

Most of the real work was not the interface. It was discovering how a live public feed misbehaves, and refusing to pass that through to the number on my wrist.

The countdown to 1970

When no train is actually reporting its position, the feed does not send a null prediction. It sends 0. Trust that field and your watch face confidently counts down to January 1st, 1970. The fix is to treat zero as absence and fall back to the timetable — and to say which one you are showing.

Predictions that were never predictions

The other endpoint is subtler and worse. It always sends an expected arrival time — quietly copying the scheduled time when nothing is live. Infer "this is a real prediction" from the field being present and every timetable guess gets a live indicator. There is a separate flag that carries the truth, and it is the only thing worth believing.

"At stop," thirty minutes away

A train with an uncomputed position reports negative one stops away, bundled with a friendly human-readable label reading "at stop." Pass that through and a train half an hour out appears to be arriving now. That is the failure that makes you miss a train while looking at the thing that was supposed to help.

Every one of these is a case where the honest display is worse-looking than the dishonest one. A dimmed number admitting it is stale is less satisfying than a crisp confident countdown — and it is the only version worth wearing.

And one that only shows up downtown

Westlake is an underground station where two lines share a platform. Query it without filtering and you get four trains to Federal Way interleaved with four to Redmond, in equal numbers, all looking identical. Mercer Island never surfaces this — it is a single-line stop. Filtering by route there is defensive; downtown it is the difference between working and useless.

The clock that didn't fit.

The first version used the system's built-in countdown text — the kind that animates itself for free, no work required. Obviously correct, and it was wrong.

A timer renders as minutes and seconds: 12:50. That is five characters. In a sub-dial roughly forty points across, those digits overflow the circle and get clipped into unreadability at exactly the worst moment.

Whole minutes fit with room to spare. And the seconds were false precision anyway — nobody sprints for a train because it says forty-seven seconds. The free animated version went in the app's list view, where there is width for it, and the complication counts in plain minutes.

Running, with edges.

It builds, it signs, it installs, and it renders live arrivals on an Apple Watch Series 8 — on the face, in the corner slot, counting down correctly. The core logic — time windows, filtering, the display planner, both feed decoders — is covered by seventy-six tests, several built from real captured responses containing the exact traps above.

Still unproven: What the screenshots cannot show is whether the number is right. Between refreshes it counts against a snapshot up to fifteen minutes old, and the only way to find out how often that misleads me is to wear it through a few weeks of actual delays — including the held trains and short-turns that a sunny Wednesday never produces.

Two hours is not enough time to build something finished. It was enough to build something real: a thing that reads a live public feed, works within a genuinely tight budget, and refuses to tell me a confident lie about when the train is coming.

The rest is wearing it and finding out what it gets wrong.