case file 04 · RB.RUN

RB.RUN: What if Strava and Mass Effect had a baby, but Star Trek was the stepdad?

I know the title sounds like a weird instance of fan fiction, but stay with me now…

TL;DRThe marathon coach I built because Strava only records the past. GPX in, plain-arithmetic coaching out: injury-aware, no LLM anywhere near my joints, and rendered as a 3D solar system you fly through.

What's under the hood No-LLM coaching

Stack

ReactTypeScriptViteThree.jsTailwind CSSFirebaseLeafletVitest

Full list of features

  • 3D orbital UI
  • First-person + bird’s-eye
  • Planned vs actual
  • Adherence
  • Weekly recap
  • Training load (ACWR)
  • Ramp-rate risk
  • Easy-pace discipline
  • Shoe mileage
  • Injury escalation
  • Finish-time predictor
  • Goal paces
  • CTL-ATL-TSB curve
  • Auto PRs
  • GPX import
  • Route map
  • Per-km splits
  • Run weather
  • Best-effort segments
  • Injury Gantt calendar
  • Consistency heatmap
  • Command palette
  • Fair pace
  • Cloud sync / backup

The “why” / Am I mad?

You know the drill: every time you meet a fellow runner, they’re like “Are you on Strava?” and I have to tap into the very core of my being to muster the strength not to do an eyeroll. I get it - the community aspect is great, but I don’t really need kudos, nor do I need to know how many miles Valtteri Bottas rides on his bike every weekend.

I use it for tracking, and that’s pretty much it. But when I injured my hip flexor and was forced to sit at home and dwell on my fate (cue the Squidward watching SpongeBob and Patrick from his window), I started looking deeper into Strava. It didn’t take long for questions to appear:

  • Why can’t I enter my custom plan?
  • Why can’t I log injuries?
  • Why does the interface remind me of early 2010s Facebook so much?
  • How can I know if I’m adhering to my own unique, already existing plan?

Another thing is - I have a specific goal that I’m training for - the Copenhagen Marathon on May 9, 2027, and logically, I would prefer everything in my tracking to orbit (pun very much intended, you’ll see why soon) around that.

I like Gunna more than Runna

One glimmer of hope was when I recalled that Runna is now owned by Strava, so I couldn’t help but try and see what all the fuss was about. I consult with a coach (one that doesn’t reside in a data center, mind you); I came in skeptical that this was just another mass-market generic plan trying to be a jack of all trades.

While I liked the in-house physio library, I had to hit the brakes when I heard about post-injury plans that adapt to my injury history. Pardon my French, but I’d rather watch The Big Bang Theory reruns while tied to a chair than trust the health and wellbeing of my joints, knees, muscles, and other body parts to what is most likely a one-size-fits-all algo.

It’s not a doctor, not a coach, and most definitely not an experienced long-distance runner, plus it turned out that my overtraining skepticism wasn’t unwarranted.

Was I going to sit and complain?

Short answer: No.

Long answer: While I was recovering, I also took time to make another connection about Strava - the socially-focused UI is built to have you spend time on the app. Personally, I love relaxing and decompressing after my run, so I was in need of something calming to look at. Since I was watching a space documentary at the time, I was in no shortage of inspiration.

The RB.RUN dashboard: the star at the centre with a full readout of vitals, telemetry, subsystem status, injuries and personal bests, every stat derived from one log of what actually happened.
The dashboard: every run, injury, shoe and session is a data point, and they all talk to each other.

But when I realized that every single thing that’s tracked is a data point, and that as long as there is logic between those points and a way for them to ‘talk,’ then it hit me: why would I need to rely on Strava? I can build my own.

Oh, what’s that? Strava clamped down on API access back in late 2024? Not a problem, they still allow .gpx exports and that just so happens to be everything I need.

You could say I could’ve just whipped up some slop in half an hour and called it a day, but this would be something I would be looking at almost every day and a companion on the journey that I’m currently on.

Plus, it wouldn’t be fun if it were easy, right?

I’m not Dr. Frankenstein, but I’m creating a monster

I’m far from a career developer - I mostly dabble in content and SEO, but over the last couple of months I’ve built a stack of tools with AI doing the keystrokes, along with a couple of other APIs making the magic work.

With this one, I wanted the opposite: I wanted the data to talk to each other, not to me through a token meter. So I named the things that actually matter to a runner:

  • What runs happened?
  • What injuries happened?
  • Is the load feeding the injuries?
  • How long until the race?
  • Are my shoes still usable?
  • Am I over/undertraining?

Once I built that intelligence, it was time to convert it into plain arithmetic in the browser. And since there would be no AI sending me insights about my data, I could rest easy knowing that I’ve avoided a potential LLM-induced Achilles tear. I’m not really Kevin Durant, so prevention is the way to go.

Want a monster of your own? I take commissions.

LET'S TALK →

Numbers lie, too

That’s also why I scrapped the “recovery score” I’d sketched. While the caveman logic of big number vs small number is soothing and seems useful - it isn’t science; it’s arithmetic dressed up to make me feel safe before the next run.

I’d be inventing a number and then trusting it, which is the exact move I built this thing to escape. I wanted clear facts that talk to each other, nothing I’d be embarrassed to show to someone who knows more than me.

Underneath, one idea I kept circling: all the data must be interconnected. I’ve achieved this by building the whole logic around a single log of what actually happened: runs, missed sessions, shoes, injuries. Then, everything else (adherence, risk, the finish-time prediction) is re-derived from it on demand.

Look at missed runs as an example, as they’re nothing more than an IF statement:

IF a scheduled run is in the past and no run with a corresponding date has been submitted, THEN it counts as a missed run.

Because of this, there’s literally nothing to drift out of sync. If I change one run, delete another, or accidentally double-submit? No biggie, since the whole instrument repaints from the same source of truth.

A man with a plan

The second pillar is the plan I developed with my coach. Due to my history, we threw out the textbook “don’t add more than 10% a week,” so the regimen we built deliberately spikes in places, and that’s NOT something Runna would know to suggest.

So the app measures my ramp against my plan’s own intended jump, and only complains when reality outruns or lags behind the plan.

Injuries are the signature feature, and I built them properly, because health is the whole game. I’m in my late 20s, not quite geriatric, but old enough that “am I pushing too hard?” is a real question with a question my ego sometimes won’t let me answer honestly.

So I catalog them: log how a run felt, log the niggle in the knee, and let the patterns surface. Because my runs already record shoes and my injuries carry a date and a body part, the raw material to spot a recurring niggle lives in one place - so I can look back and notice when a flare-up keeps coming from the same pair. Strava scatters that across a feed; mine keeps it together.

Judging a book by its cover

Initially, I went for a clean, glassy look because I wanted it to be useful. But then, I realized: I’m the only user, and I have free rein to tweak it according to my preferences. Running is my happy place, especially eating pasta and unwinding after a run, so why would I stare at a spreadsheet?

So I rebuilt the whole thing as a 3D solar system you fly through, like a cockpit. It all starts with an entry animation, as you’ve reached your coordinates and stumbled upon a strange solar system.

The entry animation: you reach your coordinates and stumble upon a strange solar system.

Your instruments’ readings are off, but the science crew on the ship assumes it’s a nascent solar system, with matter still getting twisted and turned by cosmic forces.

The instruments read as a nascent solar system, matter still getting twisted and turned by cosmic forces.

Every planet is a section, with the two perspectives the first one, because if I can’t see everything at a glance, the whole system collapses (it literally does, more on that in a bit!).

Two perspectives on the same system: the first-person cockpit and the bird’s-eye that shows everything at a glance.

And just like in Star Trek: Voyager, the exploration has only begun, and each of the bodies orbiting this strange Orange giant star has its own part to play in what’s to come.

What would Isaac Asimov think?

Aside from this being my own personal quest to hyperpersonalize my workout tracking, it’s also an homage to two other things I love: Star Trek and Mass Effect.

The last-run sentry: a little Borg cube, a little ARC Raiders, standing guard over the run behind you.

The story is simple: picture a young solar system, planets still coalescing and being twisted by gravity. The sun is shimmering in its instability while being watched over by sentries sent by a civilization far up the Kardashev scale to scan it for resources and guard it from interlopers. You’re not quite an enemy, but they’re watching you.

I wanted them ominous and foreign; a little Borg cube, a little ARC Raiders, but each telling me something important about my past and future runs.

The next-run sentry: the same foreign menace, turned to face the run ahead of you.

Here comes the fun part: the cursor is a gravity pole the particles can’t ignore, and a real black hole curves matter inward, followed by a big bang spitting it out afterwards.

You can also cause major and minor planet destruction events, with all matter behaving the way you’d expect it to in space.

Likewise, there are three filters to increase the level of immersiveness.

I can’t write shaders, so I directed them by metaphor and the very humble astrophysics I know until everything fell into place. Hence, I kept repeating to myself: find a style and refine it, don’t chase realism.

Working inside that limit was the least glamorous part. It felt, a little, like betraying the vision. So the hardest call was to stop: quit polishing, port the real tested engine into the 3D shell, permanently wipe the old frontend, then go for a run and check the imported distances came out right.

Why are you even reading this?

I use it every day. It’s also the piece I’d point to first, because it’s proof I can take a bite that looks too big and chew it down fast. But the reason I’d want a stranger to open it isn’t the engine.

It’s that when someone flies through a planet for the first time, or holds the mouse and watches everything collapse into a singularity, I want them to smile. I wanted the cosmic grandeur - and I wanted it to be fun. The most beautiful things usually are. We don’t really need to go to Mars, but we’re still doing it because it’s cool.

So, am I successfully tracking how my workouts adhere to my plan? Yes. Am I giggling like a pre-schooler while staring at the planets orbiting once I come back from a run? Yes. Is this all because Strava means “horror” in Serbian and “crooked” in Greek, and it’s giving me bad vibes that my brain is trying to swat away unsuccessfully? That I cannot confirm nor deny.

If you’re sitting on a bite that looks too big to chew, I know the feeling.

LET'S TALK →