Final Presentation
Team 9
CSC 450 · Spring 2026 · April 30
Pocket
Gym
A web app that uses your
webcam
to count reps and grade your form, in real time.
Live at
pocketgym.evanmusick.dev
Source
github.com/musickevan1/pocket-gym
Team
Aakriti Bhandari · Kobe Hendrix
Evan Musick · Iggy Shirmen
01
The problem
Why we built this
Most people who work out at home don't know what their
form
looks like.
Bad form is how training stops helping and starts hurting.
Personal trainers cost $80–$150 an hour. Most students can't afford one.
Existing home-workout apps play videos at you. They don't watch you do anything.
A laptop with a webcam is the one piece of hardware most people already own.
02
What we built
As deployed, April 28
Open the app, point a camera at yourself, and start moving.
Real-time skeleton overlay on your webcam feed.
Automatic rep counting and a 0–100 form score per rep.
Spoken cues that correct your form as you move.
Per-session history with a form-quality chart and notes.
03
Architecture
Two tiers · video stays in the browser
The browser does the
computer vision
. The server only stores the results.
Browser tier
Runs in the user's tab. Webcam frames stay on the device.
Webcam
getUserMedia()
→
MediaPipe Pose
WebAssembly · 33 landmarks/frame
→
Angles + classifier
JS port of the Python pipeline
→
Form scorer + overlay
canvas · voice cues · rep counter
↓ POST /api/sessions · JSON summary only
Server tier
Hosted on Render.com · gunicorn behind Cloudflare DNS.
Flask 3.0
thin REST surface
→
Flask-Login
bcrypt-hashed credentials
→
SQLAlchemy
session + workout models
→
Postgres
via DATABASE_URL
04
Form scoring
Rule-based, no training data needed
From 33 keypoints to a single score, every frame.
01
Pose.
33 keypoints per frame.
02
Joint angles.
Eight joints per exercise.
θ = (180/π) · arccos( (A−B)·(C−B) / (‖A−B‖ · ‖C−B‖) )
03
Per-joint score.
Penalty per degree off ideal.
s = max( 0, 100 − 2.5 · |θ
measured
− θ
ideal
| )
04
Overall score.
Weighted average across joints.
05
Tech stack
Two runtimes · one model file
Vanilla JavaScript in the browser.
Flask
in the cloud.
Browser
Pose
MediaPipe Tasks Vision (WebAssembly)
Model
pose_landmarker_full.task
UI
Vanilla JavaScript, no framework
Charts
Server-rendered SVG via Jinja
Voice
Web Speech API (text-to-speech)
Server
Web
Flask 3.0
Auth
Flask-Login + bcrypt
ORM
SQLAlchemy
DB
SQLite (dev) · Postgres (prod)
Hosting
Render.com + Cloudflare DNS
06
Sprint progression
3 sprints · 8 weeks
From a Python prototype to a deployed web app, in three increments.
Sprint
Window
What landed
Sprint 1
Mar 6 — Mar 26
Core pipeline
Sprint 2
Mar 27 — Apr 9
Users and data
Sprint 3
Apr 10 — Apr 28
Browser pipeline + production deploy
07
Live demo
Switch to the browser
See it
in motion.
pocketgym.evanmusick.dev
08
What we learned
From three sprints of building this
Four things we know now that we didn't know at the start.
The browser is a real runtime for ML.
The same code in two languages drifts.
A live URL finds bugs that
localhost
never will.
How a project introduces itself matters.
09
Team
Backlog ownership across the project
Four people. One product backlog.
Evan Musick
PM · DevOps · Pose
Project scaffold & dev environment
Pose estimation pipeline
PE-01..03
User preferences
UM-14
Production deployment
Pose-math unit tests
Aakriti Bhandari
Tracking · Auth
Rep counting state machine
RT-10
Set tracking
RT-11
Account creation & login
UM-12
User profiles
UM-13
Progress charts
DA-21
Iggy Shirmen
Classifier · Audio
Joint angle calculation
PE-04
Exercise classifier
ER-05
Additional exercises
ER-06
Workout history log
DA-15
Audio form coach
FA-18
Kobe Hendrix
Form scoring · UX
Ideal angle ranges
FA-07
Real-time form scoring
FA-08
On-screen correction tips
FA-09
Post-workout summary
DA-16
10
If we did it over
Honest retrospective
Four things we'd do differently next time.
Browser-first from day one.
Test the Python and JS versions against the same inputs.
Stand up the deploy in Sprint 1.
Build a labeled dataset for the classifier.
CSC 450 · Final Presentation · Team 9
Questions
?
Live
pocketgym.evanmusick.dev
Source
github.com/musickevan1/pocket-gym