Final Presentation Team 9
CSC 450 · Spring 2026 · April 30
PocketGym
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

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.

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.
Live workout view 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.
WebcamgetUserMedia()
MediaPipe PoseWebAssembly · 33 landmarks/frame
Angles + classifierJS port of the Python pipeline
Form scorer + overlaycanvas · voice cues · rep counter
↓ POST /api/sessions · JSON summary only
Server tier
Hosted on Render.com · gunicorn behind Cloudflare DNS.
Flask 3.0thin REST surface
Flask-Loginbcrypt-hashed credentials
SQLAlchemysession + workout models
Postgresvia DATABASE_URL

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.

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

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
See it in motion.
pocketgym.evanmusick.dev

Four things we know now that we didn't know at the start.

  1. The browser is a real runtime for ML.
  2. The same code in two languages drifts.
  3. A live URL finds bugs that localhost never will.
  4. How a project introduces itself matters.

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

Four things we'd do differently next time.

  1. Browser-first from day one.
  2. Test the Python and JS versions against the same inputs.
  3. Stand up the deploy in Sprint 1.
  4. Build a labeled dataset for the classifier.
CSC 450 · Final Presentation · Team 9
Questions?