Back to projects
Mar 20, 2026
5 min read

Pitscope: Motorsport Analytics

A data analytics dashboard for Formula 1 racing, built as a web application.

Pitscope showing the 2026 Miami Grand Prix with podium results, a race gap-to-leader chart, and a pit strategy timeline

Race Data

After each event of a race weekend, a job collects data from the Jolpi.ca Formula 1 API. Results are stored as Parquet files in Google Cloud Storage.

Live race telemetry is collected in real-time during races from OpenF1. This data is rebroadcast to the UI to power real-time leaderboards and driver performance metrics.

Tech Stack and Infrastructure

  • Software Platform
    • SvelteKit — dashboard UI
    • Python — data collection pipeline
    • DuckDB — efficient queries to parquet datasets
  • Infrastructure
    • Google Cloud Storage
      • Raw F1 data stored in Parquet data files
    • Google Cloud Run
      • Easy deployment for containerized applications
      • Jobs for scheduled data collection
      • Real-time data relay service
      • Historic data service with caching
      • Auto-scaling (zero usage while idle, at the cost of a small startup-delay when waking up)
    • GitHub Actions
      • Push to GitHub and everything else is automatic: container build, deploy to Cloud Run
  • Data

Building with AI

I built this almost exclusively with agentic coding tools. I opened Neovim a handful of times — mostly to change some word choice.

The user experience of the dashboard is far richer than anything I’d produce by hand in a reasonable amount of time. I’m not entirely happy with it, but that’s to be expected. Garbage prompt in, garbage result out — I’m a quantitative trading and research engineer who has always been just good enough at UI to make something usable when needed. The model raises the ceiling, but it doesn’t change the floor.

Things get out of hand fast. The model will snap its fingers and thousands of lines change. A few prompts later, the interface is just different than it was, and sort of messier. The ease of adding a new feature can be intoxicating — the model makes things that look decent, but you still have to guide it toward something usable. It takes real time to clean things up. Just like by-hand software development.

I quickly learned that an iterative, plan-first approach works far better than chat-style prompting. Work with the model on a plan, in natural language, then have it execute. It went further than that — results got noticeably more predictable when I didn’t just describe what I wanted, but suggested how. Name the library to use. Outline the algorithm. Point at the approach. The model is better at filling in details than choosing a direction. Compare that to a flow of prompts making single changes “add a button here” and “put a label there” or “actually, move them to a single line side-by-side” — bad news.

One of the joys of building this was answering real questions about the data quickly and sharing the results with others in a meaningful way. It was also a chance to try tools I’d normally avoid investing in — SvelteKit, D3.js — since they aren’t central to my day-to-day. Reading the code the model produces, learning from it (and its mistakes), turns out to be a surprisingly effective way to pick up a framework. I couldn’t stand up an app like this from scratch without consulting the docs, but I’d be fearless doing it by hand in the future.

I’d classify what I did somewhere between prompt engineering and vibe coding. I had some direction — not a complete picture, but enough to steer. And I did enjoy the ride, watching in the browser as the application changed while the agent worked.

Seeing the deployment loop come together was especially satisfying. Describe what you want in plain language, iterate with the model until it’s right, push the changes, and an automated pipeline builds the container and ships it. The entire process, end to end, driven by natural language and automation. Which also makes the need for safety-by-design painfully obvious — the model will confidently deploy a broken result just as easily as a good one. Guard rails aren’t optional when the path from idea to production is this short.

Still under active development. The agent and I aren’t done yet.

Starting app…