Back to the work

Side project Full-stack / 2026

BadmintonRecords

Match archive for my badminton club: rally-by-rally tagging, a live scoreboard over YouTube, and an ffmpeg highlight cutter.

  • Nuxt 4
  • Supabase
  • Tailwind
  • ffmpeg
badminton-records.vercel.app
Badminton Records, home screen
Demo

01Overview

A match archive for U.S. Talence Badminton, the club I play at. We film our games and post them on YouTube. This site turns those videos into matches you can browse: every rally is tagged, the score sits on top of the video, and the best points can be cut into a highlight film.

02What it does

  • Imports the club's YouTube uploads as matches. Re-running the import is safe and never overwrites a match that's already been tagged.
  • A keyboard-driven tagger for logging a match rally by rally. Every key can be rebound, and it handles AZERTY layouts properly.
  • A scoreboard drawn over the video that follows playback, so it never shows a score the viewer hasn't reached yet.
  • Player lookup against the French federation's public records, widening its search from our roster to the club to all of France.
  • Reel: turns starred rallies into a highlight film, with a soundtrack trimmed to its loudest section, rendered by ffmpeg.

03Architecture

Nuxt 4 with Supabase for auth and Postgres, styled with Tailwind 4. The scoring engine and the reel model live in shared/ as plain TypeScript with no framework code, so Vitest tests them without a browser or a database. The reel is a single ReelProject object: the preview, the saved .reel file and the render request all read it, so what you preview is exactly what gets rendered.

04The hard parts

  • YouTube's fullscreen button only fullscreens the iframe and leaves the scoreboard behind. A fullscreenchange handler moves fullscreen to the wrapper around the video instead.
  • ffmpeg filter graphs fail late and with vague errors. The arguments are built by a pure function and checked in unit tests before anything is spawned.
  • Long downloads and renders run as background jobs the browser polls, so reloading the page doesn't kill an eleven-minute export.
  • The palette has only two colours, club crimson and ink, and still passes contrast checks in light and dark themes.