At a glance spread 3:55–4:55 (60s)
Evan
~4:55
Architecture · Tech stack · Retro · Mobile + DevTools demo
Aakriti
~4:40
Problem · Built · Team · Sign-in/Reg + Summary demo
Iggy
~4:05
Sprints · Learned · Switch + Profile demo
Kobe
~3:55
Intro · Form scoring · Conclusion · Curls + Bad-rep demo
Talking points per slide · keep it tight
01
Intro
Kobe · 25s
- Greet audience, introduce team: Aakriti, Iggy, Evan, Kobe
- "PocketGym — a web app that uses your webcam to count reps and grade your form, in real time, with no special hardware"
- Live:
pocketgym.evanmusick.dev
Aakriti — what's the problem?
02
The problem
Aakriti · 35s
- People work out at home — phone propped on books, no mirror, no coach
- What they lose isn't the workout, it's feedback: depth, form, count
- Personal trainer is expensive; webcam isn't
Here's what we built.
03
What we built
Aakriti · 45s
- Open the app, pick exercise, point webcam at yourself
- Skeleton overlay, automatic rep count, 0–100 form score per rep
- Voice cue when form slips ("drive up slightly, your left knee is too bent")
- Session lands in workout history with chart + notes field
- 5 exercises live: squat, push-up, bicep curl, overhead press, deadlift
Evan will explain how this is wired together.
04
Architecture
Evan · 60s
- Two tiers
- Browser tier does all CV: webcam → MediaPipe Pose (WebAssembly) → 33 landmarks → angles → classifier → form scorer → overlay
- All ML happens in the user's tab. Video frames never touch our server. Privacy by default; cheap hosting
- Bridge:
POST /api/sessions sends a small JSON summary at session end
- Server tier: Flask 3.0 + Flask-Login + SQLAlchemy → Postgres (SQLite in dev)
Kobe — how does the form scoring layer work?
05
Form scoring
Kobe · 60s
- Rule-based — no model training, no labeled dataset
- Four steps every frame: pose → joint angles → per-joint score → weighted average
- Joint angle:
θ = (180/π)·arccos((A−B)·(C−B)/(‖A−B‖·‖C−B‖))
- Per-joint score:
s = max(0, 100 − 2.5·|measured − ideal|)
- Ideal ranges tuned by hand against test cases
- Trade-off: hand-tuned rules vs needing thousands of labeled videos
Evan — give the audience the tech stack.
06
Tech stack
Evan · 35s
- Browser: MediaPipe Tasks Vision (
pose_landmarker_full.task), vanilla JS, server-rendered SVG charts via Jinja, Web Speech API
- Server: Flask 3.0, Flask-Login + bcrypt, SQLAlchemy, SQLite dev / Postgres prod
- Deploy: Render.com behind Cloudflare DNS + TLS
- No build step, no React — boring on purpose
Iggy — walk us through the sprints.
07
Sprint progression
Iggy · 50s
- Sprint 1 (Mar 6–26): core pipeline — pose, angles, classifier, form scorer; Python prototype against a webcam
- Sprint 2 (Mar 27–Apr 9): users + data — accounts, login, profiles, history, per-set form charts
- Sprint 3 (Apr 10–28): the big shift — ported entire pipeline to JS for browser, deployed to Render, Cloudflare DNS, UAT on live URL
- That's what's deployed today
Now we'll show it running.
08
Live demo
ALL · ~10 min
- Each presenter drives their own segment — see the demo segments table below
- Pre-flight: tab open at
/auth/login, webcam tested, backup recording in second tab, volume up
- If anything fails: switch to backup recording, narrate, return to slides. Don't apologize, don't troubleshoot live
Here's what this whole project taught us.
09
What we learned
Iggy · 60s
- Browser is a real ML runtime: WebAssembly + MediaPipe = 30+ fps pose inference, no GPU, no install
- Same algorithm in two languages drifts: Python prototype + JS production diverged on tweaks; needed shared test fixtures
- A live URL finds bugs
localhost never will: TLS-only camera permission, mobile viewport quirks, voice API differences
- How a project introduces itself matters: README + landing page rewrites changed how new users + graders engaged
Aakriti — who built what?
10
Team
Aakriti · 35s
- Read the four cards aloud
- Evan: scaffold, pose pipeline (PE-01..03), user prefs, production deploy, pose-math test suite
- Aakriti: rep counting (RT-10), set tracking (RT-11), accounts (UM-12), profiles (UM-13), progress charts (DA-21)
- Iggy: joint angles (PE-04), classifier (ER-05), additional exercises (ER-06), history log (DA-15), audio coach (FA-18)
- Kobe: ideal angles (FA-07), form scoring (FA-08), correction tips (FA-09), post-workout summary (DA-16)
Evan — what would we do differently?
11
If we did it over
Evan · 50s
- Browser-first from day one — Sprint 1+2 of Python prototype cost us time we then spent porting in Sprint 3
- Test Python and JS versions against the same fixtures — caught the drift late; a shared video-in/scores-out fixture would have caught it in Sprint 2
- Stand up the deploy in Sprint 1 — Render, DNS, TLS, mobile bugs only show up live; treat the deploy as a feature
- Build a labeled dataset for the classifier — rule-based works, but a trained model could be more accurate and easier to extend
Kobe — close us out.
12
Conclusion
Kobe · 2–3 min
- Recap in one breath: webcam-only, real-time form coaching, privacy-by-default, 5 exercises live in production
- Honest about scope: rule-based scoring (not ML), 5 exercises (not 50)
- Live at
pocketgym.evanmusick.dev · source at github.com/musickevan1/pocket-gym
- Thank the audience, open for questions
Demo segments slide 8 · 8 segments · 10:00 sharp
1
Sign in + Registration walk-through
Aakriti · auth/register
90 s
2
Exercise demo (curls — 3 good reps, form scoring shown)
Kobe · scoring
90 s
3
Bad rep — score reacts + voice cue
Kobe · scoring (Iggy on audio)
60 s
4
Switch exercise (push-up via classifier)
Iggy · classifier
90 s
5
Mobile view + production URL on phone
Evan · responsive/deploy
90 s
6
DevTools Network — no video frames leave device
Evan · architecture proof
60 s
7
End → Summary chart + History page
Aakriti · chart/UI
75 s
8
Profile + voice toggle → wrap to slides
Iggy · audio/profile
45 s
If demo runs long: cut 6 (DevTools) + 8 (Profile) first · Always keep 2, 3, 4 (showcase form scoring + classifier).
Hand-off chain don't break the chain
Kobe→
Aakriti→
Aakriti→
Evan→
Kobe→
Evan→
Iggy→
ALL (demo)→
Iggy→
Aakriti→
Evan→
Kobe