A live, classroom-wide basketball data app for an after-school program that teaches data science to kids. A teacher starts a session, students join with a code from any device, and the whole class plays a tabletop mini-basketball game through two structured rounds. Every shot gets tracked by court zone, then each kid sees their own color-coded heat map and stats, turning a game they just played into data they can actually read.
Prefer motion? There's a full video walkthrough too.
flowchart TD
A["🟢 LOBBY<br/>students join with a 6-char code + nickname"] -->|"Teacher starts round 1"| B["🏀 SOLO ACTIVE<br/>tap a zone, record made or missed (x20)"]
B -->|"Teacher ends round, shows review"| C["📊 SOLO REVIEW<br/>personal heat map + stats"]
C -->|"Teacher forms teams"| D["🤝 TEAM STRATEGY<br/>compare heat maps, plan shots"]
D -->|"Teacher starts allocation"| E["🎯 ALLOCATION<br/>split team shots per player"]
E -->|"Teacher starts sabotage"| F["💣 SABOTAGE<br/>block rival hot zones"]
F -->|"Teacher starts team shooting"| G["🏀 TEAM ACTIVE<br/>shoot as a team, blocked zones enforced"]
G -->|"Teacher shows results"| H["🏆 TEAM REVIEW<br/>team heat map + leaderboard"]
Every screen advances in lock-step the moment the teacher moves the session forward: no refresh, no re-join.
- Live multi-device sessions : Students join with a 6-character code, no login.
- Teacher-driven state machine : One tap advances every connected screen in real time.
- Tap-a-zone : Shot input on a 6-zone half-court, with undo.
- Solo round : Individual shot tracking with a per-zone scoring system.
- Team round : Auto-pairing, shot allocation, and a "sabotage" mechanic that blocks a rival team's zone.
- Heat Maps : Personal, team, and class-wide heat maps color-coded by make/miss percentage.
- Leaderboard : Shows top 5 players and teams.
- Random Name Generator : Kid-friendly nickname generator (e.g.
SpeedyHooper). - Resilient sessions : Teacher heartbeat, disconnect detection, and idle timeouts auto-recover stranded students.
- Practice Mode : Offline single-device play with no Firebase required.
| Stage | Tooling |
|---|---|
| Language | TypeScript |
| UI | React 18 |
| Build / dev server | Vite |
| Database & real-time sync | Firebase Firestore (serverless, onSnapshot listeners) |
| Hosting | Firebase Hosting |
| Export | html2canvas + jsPDF |
| Unit / component tests | Vitest + Testing Library |
| Integration tests | Firebase Emulator |
| End-to-end tests | Playwright |
This started as a way to replace the clunky Google Forms + Sheets workflow the program used to collect shot data; but the real goal was bigger: give low-income kids a fun, visual way to understand their own data. A spreadsheet doesn't teach a 12-year-old anything; a heat map of their own shooting does. So the whole design leans into the game itself, then quietly turns it into a data-science lesson at the end.
I wrote a detailed PRD first and built around a single session state machine. Every screen is just a function of the current session status, which the teacher controls. The frontend is intentionally backend-free: Firestore's onSnapshot listeners (wrapped in a useSession hook) push every state change to every device, so the teacher tapping "Start Team Shooting" instantly moves the whole class forward. The hardest parts were all about liveness: keeping many student and teacher screens perfectly in sync, handling the messy reality of a teacher closing their laptop mid-session (heartbeats, beforeunload, timeouts, and idle detection so kids never get stranded), and designing a two-round game (zone scoring, team shot allocation, and a sabotage mechanic) fun enough to keep kids engaged while still producing clean data.
Guiding principle: simple and playful for the kid in front of the screen, even when the sync logic behind it isn't.
- Modeling a real-time multi-user app around Firestore
onSnapshotlisteners and a fully serverless (no-backend) architecture. - Designing a simple, playful, Kahoot-style UI that actually works for 10–14 year olds.
- Testing concurrency for real Firestore emulator tests, multi-user simulations, Playwright E2E, and a bot script that hammers a session with 25 fake students.
- Writing Firestore security rules to validate every write and protect data integrity without a traditional backend.
- No authentication : Anyone with a code can join. Fine for a supervised classroom, but real auth (or per-class teacher accounts) would harden it for wider use.
- Open Firestore reads : Rules currently allow public reads on sessions. Scoping reads to participants would tighten privacy.
- No session history / data export per student : Results live only for the session. Persisting longitudinal data would let kids track progress over weeks.
- Single teacher per session :No co-teacher or multi-class admin view yet. An admin panel is the natural next step as the program scales.
- Fixed shot limits and zones : Scoring and zone layout are hard-coded; making them teacher-configurable would support different game variants.
git clone https://github.com/pieroevcc/Basketball-Data-Collection-Web-App.git
cd Basketball-Data-Collection-Web-App
npm install
npm run devOpen http://localhost:5173. Without Firebase configured, the app still runs in Practice Mode (offline, single device).
🔧 Firebase setup (for live sessions)
Create a .env file in the project root (see .env.example) with your Firebase web-app config:
VITE_FIREBASE_API_KEY=your_api_key
VITE_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your_project_id
VITE_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
VITE_FIREBASE_APP_ID=your_app_id
VITE_FIREBASE_MEASUREMENT_ID=your_measurement_id # optionalThese values come from your Firebase Console → Project Settings → Your apps. The app reads them at startup; if the core keys are missing it silently falls back to Practice Mode.
🚢 Deploy to Firebase Hosting
npm install -g firebase-tools
firebase login
npm run build
firebase deployFirestore rules and indexes ship from firestore.rules and firestore.indexes.json.
🧪 Running the tests
npm test # unit + component tests (Vitest)
npm run test:emulator:ci # integration tests against the Firestore emulator
npm run test:e2e # Playwright end-to-end tests
npm run test:all # everythingThe emulator and bot scripts need the Firebase CLI installed.
Built for a non-profit after-school program teaching data science through a tabletop basketball game.