Projects

Professional

Chasemates – Real-Time Offroad Race Timing

I built a race timing system for offroad events, where the network usually isn't there when you need it.

Chasemates live race map tracking competitor positions across an offroad course
Discipline
Full Stack, Mobile Dev, Web Dev
Timeline
December 2024 – May 2026
Stack
React NativeExpoNode.jsSocket.ioPostgreSQLPrismaMapboxDockerGithub ActionsPythonNginxAWSTypescriptReact Native SkiaReanimated

Overview

Offroad races happen where the signal doesn't reach, so I designed Chasemates offline-first from the start. Marshals mark competitors through as they pass, over Socket.IO when there's a connection and a plain HTTP fallback when there isn't, and every spectator sees the animated Mapbox map update the moment it lands.

The hard part was making the field side feel like a game rather than a form. I put walkie-talkie audio between marshals on LiveKit and wrote the chat and race animations in React Native Skia and Reanimated so the whole thing stays at 60fps on the cheap Android phones marshals actually carry.

Behind it I run Node, Express, Prisma and PostgreSQL on EC2, with a small Python service using rembg to cut backgrounds out of profile photos and FFmpeg to normalise dispute video. It's all Dockerized behind Nginx with GitHub Actions doing the deploys, and it's live on the Play Store.

Highlights

  • Real-time race timing with Socket.IO (HTTP fallback for offline venues); live Mapbox maps for spectators.
  • Walkie-talkie audio between marshals via LiveKit; real-time in-app chat.
  • Player registration and Stripe payments; guest/spectator mode without login.
  • React + TanStack Router + React Query admin web dashboard for event and course management.
  • Node.js / Express / Prisma / PostgreSQL on AWS EC2; Dockerized with Nginx and GitHub Actions CI/CD.
  • Python microservice (rembg) for profile background removal; FFmpeg for dispute video quality handling.
  • Mono-repo with shared TypeScript types and hooks across mobile, web, and backend. Published on Google Play.

Screens

Live race tracking

Marshals mark player progress live via Socket.IO (HTTP fallback), reflected instantly on animated Mapbox maps for all spectators.

A race in progress in Chasemates, with competitor markers moving along the plotted course
The Chasemates phone app streaming a live race stage to spectators

Audio & chat

Walkie-talkie audio between marshals using LiveKit; real-time chat system with heavy game-like animations built on React Native Skia and Reanimated.

Chasemates app screen showing the in-race timing view
Chasemates app screen showing the real-time team chat
The marshal app on a phone, with the walkie-talkie control and checkpoint list

Admin & backend

React + TanStack Router admin dashboard for event management and map drawing; Node.js/Express/Prisma/PostgreSQL on AWS EC2 with Dockerized Nginx and GitHub Actions CI/CD.

The Chasemates admin dashboard for managing events, competitors and course maps

In Action & Field Testing

Real-world usage of Chasemates during offroad racing events, providing reliable offline tracking, dashboard monitoring, and communication for marshals.

Chasemates running on-site at a live offroad race event
Kevin Roan using Chasemates trackside during a real offroad race
Chasemates app screen showing an event's competitor list
Chasemates app screen showing checkpoint marking controls for marshals
Chasemates app screen showing stage results after a run
Chasemates app screen showing the spectator race overview
The Chasemates mobile app on a phone, showing a competitor's race profile