Project Info
This project did not submit a demo video on Devpost.
Pro-grade game-film analysis across sports — for the teams that could never afford it.
Inspiration
Team sports are played everywhere, but tactical analysis is a luxury — pro clubs pay six figures for analytics platforms and analysts. Amateur, college, and youth teams film every game, then that footage just sits there. The teams with the most to learn have the least access to the tools that teach it. We set out to prove the foundational layer of sports analytics — knowing where every player is, every frame — could be built for free, shown to be correct, and work across sports.
What it does
MotionCast is an analyst's workspace for game film, built for multiple sports. You upload match video, pick your sport — soccer, basketball, or American football — and it automatically detects and tracks every player, plus the ball, casting them onto a 2D top-down view. It adds team differentiation, ball possession, and motion trails, then surfaces everything in a club dashboard (xG, win probability, pressing intensity, matchups). We've tracked real footage across all three sports with the same pipeline. Accuracy is rigorously validated on soccer: we score our tracking against professional ground-truth annotations with a real HOTA number, so the data feeding every view is measurably trustworthy. What's real today: the React frontend, multi-sport player + ball tracking (soccer, basketball, football), team/possession/trails, and HOTA-validated accuracy on soccer. The dashboard's predictive models (xG, win-prob) are the next layer on top of the tracking we've proven.
How we built it
Frontend: a React/Vite analyst app — landing → guided film upload (file → sport → game details → review) → dashboard, in a dark lime-accent theme. Sport selection drives the labels and models. Tracking: built on SAM 3.1 (HF Transformers) for segmentation/tracking, plus a Roboflow-sports-based pipeline for ball tracking, team differentiation (color clustering), possession, and motion trails. The same model tracks people and the ball regardless of sport — which is why basketball and football work without sport-specific rewrites. Swappable backend: everything depends only on an abstract SamBackend interface, with a hosted SAM path and a no-GPU GSR-replay backend that runs the whole pipeline on a laptop and acts as a "perfect tracker" upper bound ($\text{HOTA}\approx 1.0$) to sanity-check the eval. Data + detector validation: a self-contained reader for SoccerTrack v2's GSR annotations (COCO, ~2.6 GB/match) and a GSR → YOLOv5 converter + Colab run to prove the data was sound, with labels normalized as $x_c=\frac{x+w/2}{W},\ y_c=\frac{y+h/2}{H}$ and panorama-aware augmentation. Eval: we never reimplement metrics — we shell out to the official GSR-HOTA scorer, where $\text{HOTA}=\sqrt{\text{DetA}\cdot\text{AssA}}$ balances detection against identity consistency over time.
Challenges we ran into
A coordinate-space rabbit hole: GSR boxes floated in the sky above the pitch. The cause wasn't math — panorama_2nd is a substring of calibrated_panorama_2nd, so we were silently drawing correct boxes on the wrong (calibrated) video. Fixed with an explicit exclude filter. Drive download quotas on the multi-GB files — worked around by mounting our own Drive in Colab. No GPU, huge 4K video, ephemeral Colab — handled with deferred imports, strided sampling, a hosted backend, and the no-GPU replay path.
Accomplishments we're proud of
A polished React analyst UI; multi-sport tracking demonstrated across soccer, basketball, and football with one pipeline; ball tracking, team differentiation, possession, and trails; HOTA-validated accuracy with an eval harness that never fabricates a number; and a subtle data bug debugged honestly instead of papered over.
What we learned
Tracking is the hard, foundational part of analytics — and proving it with HOTA matters more than a shallow feature. A well-chosen tracking foundation generalizes: the same model that tracks a soccer pitch tracks a basketball court and a football field. Validate the data before the model — our overlay checks caught a coordinate bug that would've trained YOLO on grass and sky. And $\text{HOTA}=\sqrt{\text{DetA}\cdot\text{AssA}}$ forced us to care about identity over time, not just per-frame detection — the association problem every sport shares.
What's next
Wire the dashboard's predictive models (xG, win probability, pressing) onto the tracked coordinates we already produce; ground-truth accuracy eval for basketball and football (soccer has it today); a calibrated homography minimap; and event spotting for auto-highlights — all toward one goal: pro-grade film analysis any team, in any sport, can run on their own footage, free.
AI-Hackathon — Soccer Game-State Analysis (SAM 3.1 → Minimap → HOTA)
Full-pitch panoramic match video → Meta SAM 3.1 segments + tracks every player/goalkeeper/referee → live 2D tactical minimap → evaluated against SoccerTrack v2 GSR ground truth (real HOTA, never fabricated). Instrumented for reliability (Sentry), eval/observability (Arize), and semantic search (Redis).
Mission framing: accessible tactical analysis for amateur/university teams who can't afford pro analytics — the dataset is amateur matches.
See CLAUDE.md for the full architecture, dataset facts, phase
ordering, and working agreement. See PROGRESS.md for live status.
Quickstart
make setup # venv + editable install (.venv) with dev tools
source .venv/bin/activate
make test # ruff + pytest (no GPU/data needed) — should be green
make gpu # CUDA check (fails loud if no GPU)
make frame MATCH=117093 # download from Drive mirror + print a real GSR frame
Or the explicit commands: pip install -r requirements.txt, then
python -m src.data.download --match 117093 [--no-videos] and
python -m src.data.inspect --match 117093. Data comes from the link-public Google Drive
mirror by default (no auth); use --source hf for the gated HF copy (HF_TOKEN).
notebooks/demo.ipynb imports from src/ and holds no logic.
Compute / GPUs: see docs/COMPUTE.md. Team & branches: see CLAUDE.md §10.
Layout
src/
config.py # single source of truth (config.yaml + .env)
data/ # download.py (one-match HF) + loader.py (GSR/BAS reader) + inspect.py
utils/gpu.py # CUDA check, fails loud
model/ # SAM 3.1 backend abstraction (local | api) — Phase 1
tracking/ pitch/ events/ eval/ obs/ store/ # per-phase modules
pipeline.py # end-to-end orchestration entrypoint
notebooks/demo.ipynb # the thing we run for judges
outputs/ frontend/ # gitignored artifacts / web app (last phase)
All reusable logic lives in src/; notebooks and the frontend import it. Heavy
artifacts (videos, weights, data/, outputs/) are gitignored and stay local.
Dataset
SoccerTrack v2 · docs · Hugging Face · paper.
- Dev match 117093. Real mirror match IDs (verified by listing it; the docs' assumed
117091–117100 don't match the files):
117092, 117093, 118575, 118576, 118577, 118578, 128057, 128058, 132831, 132877. Split 80/10/10: train (8) · eval132831· test132877. - Mirror carries
gsr/ bas/ raw/ videos/(nomot/) → eval with GSR HOTA (python -m src.evaluation.gs_hota …); we do not reimplement metrics.
Attribution: SoccerTrack v2 is licensed CC BY 4.0 (A. Scott et al.). Dataset code is MIT. No player names — IDs are jersey-number based.
Sponsors (each toggleable in config.yaml, none on the critical path)
Sentry (reliability) · Arize (eval/observability) · Redis (vector search) · Anthropic / Claude Code (build layer).
Analysis
View
Metric
- 22
- 10
- 3
- 1
- 1
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- HTMLIn code
- Hugging FaceIn code
- PythonIn code
- PyTorchIn code
- RedisIn code
- Node.jsClaimed
- ReactClaimed
- TypeScriptClaimed
5 of 8 appear in the indexed code. 3 claimed on Devpost could not be matched to code, which may simply mean the tool leaves no trace in the repository.
AI coding agents
- Claude CodeConfig · Commits
- CursorCommits
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
374 KB
Source files
87
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
wheredawoodat949/AI-Hackathon
107 files · 39.0 MB · @ 777458f
Structure
Interface
1 file · 1%Screens, components and styles rendered to the user.
Application logic
60 files · 56%Domain rules, services and shared utilities.
+12 moreData & schema
5 files · 5%Schema definitions, migrations and data access.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- Python67%
- Markdown30%
- YAML1%
- HTML1%
- Shell0%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
requirements.txt
pypi · 18- accelerate
- arize
- fal-client
- gdown
- huggingface_hub
- jupyterlab
- numpy
- opencv-python
- pillow
- python-dotenv
- PyYAML
- redis
- requests
- roboflow
- scipy
- sentry-sdk
- torch
- transformers
pyproject.toml
pypi · 7- gdown
- huggingface_hub
- numpy
- python-dotenv
- PyYAML
- +2 more
sports/examples/basketball/requirements.txt
pypi · 2- kagglehub
- ultralytics
sports/examples/flag_football/requirements.txt
pypi · 2- kagglehub
- ultralytics
sports/examples/soccer/requirements.txt
pypi · 2- gdown
- ultralytics
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.