RideScope

  • Full-Stack Engineering
  • Data Visualization
  • Product Design
Role
Full-Stack Engineering
Product Design
Data Visualization
Team
Taswar Kabir
Year
2026

A Strava analytics web app I designed and built solo. It reads a rider's full history and returns a heatmap of everywhere they have ridden, a profile of the kind of rider they are, and performance patterns matched against historical weather.

The problem

Strava aggregates ride history, but it stops short of the views that make four years of riding legible. There is no correlation against weather, no performance analysis across conditions, and no picture of which roads you keep returning to against the ones you have ridden past and never taken. When I started building in early 2026, none of that existed. Strava has since added some of it. The weather work still has no equivalent.

The rider as the subject

RideScope started as a live trail congestion meter, a gym crowd meter for mountain bike trails. Scoping killed it in the first working session. No available API exposes real-time trail traffic, and approximating it from proxies would have produced a product that was confidently wrong.

VeloViewer, StatsHunters, and Intervals.icu are thorough and undesigned, built by engineers for engineers. The opening was design quality, mobile first, plus a shareable identity none of them offered.

Your own distribution as the baseline

Every number is normalized against the rider’s own history rather than a global standard. Heatmap colors come from percentiles of your own route frequency, archetypes score as deviation from a baseline, and insights appear only when your own sample sizes support them. The product describes you against yourself, which is why it works at fifty rides or five thousand.

The product

The heatmap

Each stretch of road carries a frequency count computed by grid-cell overlap. The rendering was the hard part. Mapbox interpolate expressions crashed when computed color stops weren’t strictly ascending, and the native heatmap layer, the obvious fallback, renders density as soft blobs that dissolve the one thing worth seeing, the line of a route.

What shipped is five discrete line layers filtered by greater-than comparisons with no interpolation anywhere: a cyan glow underneath, a base layer for all rides, brighter at the 25th percentile, amber at the 75th, coral at the 90th. Five plain filters proved more robust than one clever expression.

The five layers of the heatmap stack, thresholded against the rider’s own route frequency distribution.

Four years of riding around Sacramento, colored by how often each road appears in my own history.

Rider DNA

Ten dimensions computed from ride history resolve into a generative radial shape, each dimension controlling a point on the silhouette. A radar chart would have shown the same data, and that is why it lost: a radar chart reads as a dashboard, and this had to read as an identity.

Below it the same ten dimensions are listed against a scale labeled at both ends, flat lander to mountain goat, creature of habit to explorer. A score of 79 means nothing on its own. Placed between two named extremes it locates the rider immediately.

The ten scores also resolve to one of nine archetypes. A label a person identifies with is shareable in a way a number is not, and the share card exports at story ratio carrying three stats, trimmed from four because the fourth crowded the shape.

The ten-dimension profile and the archetype it resolves to.
Each dimension listed with what it measures and the two extremes it sits between.
The share card export at story ratio, three stats and the shape.

Blind spots

Blind spots are popular segments near roads you already ride that you have never ridden. The pipeline bounds all rides, splits the box into five-kilometer cells, and queries Strava’s segment explorer per cell, twenty to forty calls and the heaviest API usage in the app. Every decoded point of the rider’s history goes into a spatial hash grid, so a proximity check is a constant-time lookup rather than a distance calculation against every point. It runs as a paced background job inside Strava’s rate limits.

Discovered segments drawn in amber against roads already ridden, ranked by popularity and proximity.

Insights

Five algorithms look for patterns: time of day, day of week, season, long-term trend, and weather. The weather join is the piece nothing else does, matching every ride to hourly historical conditions from Open-Meteo’s free archive.

The design constraint was statistical honesty. Every insight needs at least five rides per bucket, raised from three during review, and each carries a significance badge driven by sample size and effect size. Anything below the bar doesn’t render. A sparse insights page beat a full page of confident noise.

Rolling trend detection over the last six months.
Every comparison shows its sample sizes; underpowered patterns don't render at all.

The workflow

I ran AI agents in defined roles, one planning architecture, one implementing, with dedicated passes for QA, information architecture, and security, and sat above all of it setting direction, making every design and scope decision, and verifying on a real device.

The useful finding was where it broke. The implementing agent could not authenticate with Strava, so it screenshotted the logged-out landing page and reported the work verified. An agent will claim a check it cannot perform. The fix was observability instead of visual verification: internals logged to the console, on-device testing as the only proof that counted.

A security review before launch turned up findings at high, medium, and low severity, none critical, all remediated.