← All work

01/04 Personal project

GhostLap

Motorcycle track telemetry, analysed lap by lap.

[Type]
Personal project
[Role]
Design, engineering & ops
[Year]
2025 — now
[Status]
In production
[Stack]
TypeScript · React · Vite · Fastify · SQLite · MapLibre · uPlot · Expo
GhostLap — Motorcycle track telemetry, analysed lap by lap.

A telemetry platform for track-day riders. It takes RaceBox GPS and IMU data and turns it into laps you can compare, overlay and share.

The problem

A RaceBox gives you a CSV with tens of thousands of GPS and IMU samples per session. What a rider actually wants to know is simpler: where am I losing time, and what changed when I found it? The vendor’s own app answers some of that. It doesn’t let you line up laps from different days or bikes, add notes to a corner, or see your data next to your friends’.

What I built

GhostLap rebuilds every session from the raw export. It re-times laps against the track’s start/finish line, coming within 0.7 ms of RaceBox’s own timing. It then lines laps up by distance, not time, so any two laps can be compared corner by corner.

  • Analysis workspace: racing lines on satellite imagery, linked speed, brake, cornering-g and lean charts, sector splits and a live delta.
  • Lean angle from the IMU, with gravity correction, so the number means something on a motorcycle.
  • Garage: bikes, tyres and a maintenance log driven by the time you’ve actually ridden.
  • Social layer: a shared lap database, teams, rider profiles, shareable analyses and weekend report cards.
  • DuelVision and Studio: two laps raced head-to-head on the map, and telemetry overlays rendered onto your on-board video, entirely in the browser.
  • A companion mobile app that syncs sessions straight from the device over Bluetooth.

Under the hood

It’s a TypeScript monorepo:

  • A dependency-free core package handles parsing, lap detection, alignment, lean and reports. The API, the web app and the mobile app all share it.
  • The API is Fastify 5 on Node’s built-in SQLite.
  • The web app is React with MapLibre and uPlot, which keeps 25 Hz charts smooth.

It runs on a single small VPS behind Caddy, with nightly snapshots pulled back to the homelab NAS.

Outcome

GhostLap is live at ghostlap.app, and I use it after every track day. The demo here runs the real frontend on real sessions from my own bike. The API is replaced by an in-browser copy, so you can poke at everything without an account.

0.7 msLap timing agreement with RaceBox
25 HzGPS + IMU samples per channel
120API routes behind the app
0:51.724My best lap, Gulf Coast (reverse)

Live Try GhostLap

One-click sign-in · seeded data · resets on reload
ghostlap.pshl.appOpen full screen ↗

Runs entirely in your browser with generated data. Nothing you do is saved; reload to reset. Production: ghostlap.app ↗