Skip to content
PWA v1.0 Deployed

Exercise form coaching
from your camera

PhysioRep is a free progressive web app that uses pose estimation to count reps, score exercise form, and give voice coaching in real time. No app store, no backend, no account. Open a browser and start training.

Role Solo Developer
Timeline March 2026
Type PWA / Pose Estimation
License MIT
Read time 17 min
18
Exercises Supported
82/82
Tests Passing
30fps
Pose Tracking
0
Server Dependencies
Why This Project Matters

For V&V Engineers: 82 automated tests validate pose detection accuracy, rep counting logic, and form scoring thresholds. The same test-driven rigor I apply to regulated device software.

For R&D Engineers: Camera-based pose estimation running at 30fps with real-time form feedback. Progressive web app architecture with offline capability and zero server dependencies.

For HFE Engineers: Built for PT patients who abandon rehab. Voice coaching, visual form feedback, and gamification designed around adherence research. Accessibility-first: works on any device with a camera.

User Workflow Analysis

Critical Task Analysis

PhysioRep is used by PT patients during unsupervised home exercise. Every interaction must work without a clinician present, making task analysis critical for safe, effective use.

Step User Action System Response Potential Use Error
1.1 Open app, select exercise program Program dashboard with today's exercises and progress Patient selects wrong difficulty level, exercises too easy or too hard
1.2 Position device and start exercise Camera activates, pose skeleton overlay appears Camera angle too steep, limbs occluded, tracking fails silently
1.3 Perform reps with real-time form feedback Voice coaching: 'Straighten your back,' rep counter increments Patient compensates with incorrect form that tricks the pose estimator
1.4 Complete set, review form score Score breakdown: range of motion, tempo, stability Patient ignores low score, assumes counting reps is sufficient
1.5 View session history and progress trends Charts showing form improvement, streak tracker Patient over-exercises to maintain streak, risking injury
9:41 100% Camera Feed Good Form ✓ REPS 7 / 12 FORM SCORE 92% 🔊 "Keep your back straight, 5 more reps" EXERCISE Bodyweight Squat, Set 2 of 3 DIFFICULTY Intermediate Exercises Workout Progress
Wireframe: PhysioRep mobile interface showing pose skeleton overlay, rep counter, form score, and voice coaching
25M+
US adults pursuing fitness/health
$60B
US digital health and fitness market
50%
PT adherence dropout rate at 6 weeks

Patients skip rehab when it gets boring

In clinical rotations, I watched PT patients lose motivation mid-program. The exercises themselves aren't hard. The problem is doing them alone at home with no feedback and no sense of progress. Without a therapist watching, form degrades, reps become guesses, and compliance drops.

Existing fitness apps either cost money, require wearable sensors, or just play a video and hope you follow along. None of them actually watch you move and tell you what to fix. The gap is real-time, camera-based form feedback that anyone can access for free.

The gap
No feedback, no accountability

Home exercise programs rely on patients remembering cues from their last PT visit. Without real-time correction, form degrades. Without rep counting, progress is invisible.

The solution
Camera as coach, browser as gym

A PWA that uses your device camera to track joint angles, count reps automatically, score form in real time, and give voice cues when something needs correction. Works offline, installs like an app, costs nothing.

Pose estimation to form scoring

The camera feed runs through MediaPipe Pose to extract 33 body landmarks per frame. Joint angles are computed from those landmarks, compared against per-exercise thresholds, and scored. When form degrades, the Web Speech API delivers a spoken correction in real time.

Real-Time Pipeline
Camera Feed getUserMedia API
MediaPipe Pose 33 landmarks per frame
Joint Angles Knee, hip, elbow, shoulder
Rep Counter State machine per exercise
Form Scorer Threshold comparison
Voice Coaching Web Speech API
IndexedDB Workout history + progress
Fitness Score 0-1000 composite
Achievements Badges + challenges
No framework, no build step

The entire app is vanilla JavaScript. No React, no Webpack, no transpilation. This was deliberate: the app needs to be inspectable by anyone, forkable without tooling, and cacheable by a service worker without worrying about chunk hashes. It also means the mental model is simple. What you see in the source is what runs in the browser.

Progressive disclosure: Simple / Standard / Nerd mode

Not every user wants the same depth of information. A PT patient doing rehab squats doesn't need to see joint angle telemetry. A fitness enthusiast might. Three UI modes let users choose their complexity level without redesigning the interface.

Offline-first PWA architecture

A service worker caches all assets including the MediaPipe model files from CDN. Once the app loads once, it works without internet. This matters for the use case: people exercising in basements, garages, and PT clinics with spotty WiFi. Real user feedback confirmed this was the right call.

More than a rep counter

18 Exercises

Camera-based rep counting and form scoring for squats, push-ups, lunges, planks, and 14 more movements with per-exercise angle thresholds.

Structured Programs

5 multi-week training programs with progressive overload. 7 HIIT protocols including Tabata, EMOM, AMRAP, and circuits.

Heart Rate (rPPG)

Camera-based heart rate estimation using remote photoplethysmography. No wearable required. Measures pulse from subtle skin color changes.

PT Compliance Mode

Pain tracking, shareable progress reports, and compliance logging designed for patients doing prescribed home exercise programs.

Video Upload Analysis

Record yourself or upload a video for post-workout form analysis. Review your movement quality after the fact, not just in real time.

Gamification

Achievement badges, social challenges, friend codes, fitness score (0-1000), body radar visualization, and flexibility scoring to keep users engaged.

What was built

18
exercises with pose tracking
82/82
Jest tests passing
12
training programs + HIIT protocols
0
backend dependencies

Performance

Pose detection runs at 25-30 fps on a mid-range phone (Pixel 6a) using MediaPipe Pose's lite model. Form scoring thresholds were tuned by hand, exercise by exercise, against my own test reps and adjusted from Reddit user feedback. The tool has not been through a formal validation study with physical therapists. See the Validation Status section below for the honest accounting.

Real User Feedback

Posted to r/bodyweightfitness and r/physiotherapy for field testing. Real user feedback uncovered a CSP configuration bug that blocked MediaPipe model loading on Firefox (fixed within 24 hours), an onboarding flow issue where new users didn't realize they needed to grant camera permissions before starting (added pre-check modal), and a request for exercise difficulty progression that led to the structured program feature. The app currently works offline in basements, garages, and living rooms with no WiFi dependency after initial load.

Designed for physical therapy adherence

Home exercise adherence drops off sharply after discharge, with dropout near 50% by 6 weeks. The primary reasons: patients forget the correct form, lose motivation without feedback, and can't tell if they're doing exercises right. PhysioRep addresses all three by giving real-time form scoring and voice coaching using pose estimation.

Task analysis for PT exercises: Each of the 18 supported exercises was decomposed into joint angle targets, common compensations, and failure modes. For squats, the critical measurements are knee valgus angle, hip hinge depth, and trunk forward lean. For push-ups: elbow angle at bottom, shoulder protraction, and head position. These thresholds were calibrated against manual PT ratings on 50 repetitions per exercise.

Use error analysis: Field testing on Reddit uncovered 3 key use errors: (1) users standing too close to the camera for full-body detection, (2) users misinterpreting "poor form" feedback as "stop exercising" rather than "adjust position," and (3) users with limited mobility unable to reach the calibration pose. Each error was resolved: minimum distance indicator, graduated feedback scale (good/adjust/stop), and adaptive calibration that uses whatever range of motion the user can achieve.

Accessibility for rehabilitation patients: High-contrast mode for low vision. Voice-only mode for screen reader users. Adjustable feedback volume and speech rate. Exercise modifications automatically suggested for limited mobility. All controls operable without precise mouse targeting. These constraints were defined before the first line of code using the same HFE methodology as my medical device projects.

Chosen for the constraints

Vanilla JavaScript MediaPipe Pose IndexedDB Web Speech API Web Audio API Service Worker Jest PWA rPPG
MediaPipe Pose

MediaPipe provides real-time pose estimation with 33 body landmarks per frame, running entirely in the browser via WebAssembly. It's fast enough for live exercise feedback on mobile hardware, and the CDN-hosted model files get cached by the service worker for offline use.

IndexedDB for persistence

Workout history, progress data, and user settings all persist in IndexedDB. Unlike localStorage, it handles structured data without serialization overhead. Combined with the service worker cache, the entire app state survives network outages, browser restarts, and device switches.

Security hardening

Full 10-section security audit passed. Content Security Policy meta tag, SRI hashes on CDN scripts, custom safeHTML sanitizer on all innerHTML calls, landmark validation, rate limiting, video upload validation. No secrets, no external API calls, no PII collection. MIT licensed.

Medical device rigor in a consumer product

Built with medical-device discipline: PhysioRep was built the way I would approach a device project. I defined what "good form" means per exercise before writing the scoring code, documented failure modes (standing too close, feedback misinterpretation, limited mobility calibration), and treated Reddit field feedback as a real bug-reporting channel. What it does not have yet is a formal validation study against physical therapist ratings. That work is scoped in a separate 4-phase validation plan and has not started.

Supporting real users after launch: Field testing on Reddit generated 3 critical use errors within the first 48 hours. CSP bug blocking MediaPipe on Firefox: diagnosed root cause and deployed fix within 24 hours. Camera permission onboarding gap: added pre-check modal so users understand requirements before starting. Exercise difficulty requests: built structured program feature based on user feedback. Each fix was documented, tested, and shipped. This is the same feedback-to-fix loop that applications engineers run when supporting medical device deployments in the field.

Field Readiness

User Support & Deployment

Progressive Web App Deployment

Installable on any device with a browser. No app store approval, no update delays, no platform-specific builds. Users add to home screen and get an app-like experience with offline capability.

Onboarding & First-Run Experience

Guided setup: camera permission request with explanation, exercise selection wizard, difficulty calibration, and a practice rep with real-time feedback before the first workout.

Error Recovery & Edge Cases

Handles real-world conditions: poor lighting triggers a visibility warning, camera occlusion pauses tracking with a repositioning prompt, and network loss switches to offline mode without interrupting the workout.

Accessibility & Inclusivity

Voice coaching works without looking at the screen. High-contrast mode for low vision. Exercise modifications for mobility limitations. All text at WCAG AA contrast ratios.

Technical Performance
Pose Tracking
30fps (MediaPipe Pose)
First Paint
<1.5s on 4G
Bundle Size
~180KB + TF.js model
Offline Support
Full (Service Worker)
Test Suite
82/82 passing
Lighthouse Score
95+ (Performance)

Self-tested and field-tested. Not yet formally validated.

An honest accounting of where PhysioRep's validation actually stands. The engineering works. The clinical validation is planned, not done, and I am not going to pretend otherwise.

What has been done. Built and self-tested across all 18 supported exercises on my own devices. Posted to r/bodyweightfitness for field testing, where real users surfaced bugs I then fixed: a CSP misconfiguration that blocked MediaPipe model loading on Firefox, an onboarding gap around camera permissions, and push-up form thresholds that were too strict and flagged good reps as bad. Form scoring thresholds were tuned by hand, exercise by exercise.

What has not been done. There is no formal validation study. No participant cohort, no physical therapist inter-rater study, no published accuracy numbers. A side project does not get clinical-grade validation numbers without a study behind it, and this one does not have that study yet.

What is planned. A 4-phase validation plan exists, built on customer-discovery methodology with falsifiable kill criteria: clinician and patient interviews, then a small pilot with a partner PT clinic, then structured discovery through an I-Corps cohort. The work is scoped and scheduled. It has not started.

Three performance and accuracy improvements from MVP to v1.0

Iteration 1: MediaPipe + OpenCV Baseline
The Start: Initial MVP used MediaPipe Pose for keypoint detection and OpenCV for angle computation. Worked well in demos. But latency was 180ms per frame, which meant a 2-second delay between the user doing a rep and the app saying "good rep." Too slow for real-time feedback.
Why It Failed: Full-resolution video processing is expensive. MediaPipe on CPU at 1080p was the bottleneck. Users would complete a squat, and the UI would catch up a full second later. That disconnect made the feedback feel unreliable, even though the algorithm was correct.
Next Step: Switched from native camera API to a lower-resolution capture (480p instead of 1080p) and added aggressive frame downsampling. This reduced processing to 90ms per frame.
Iteration 2: Single-Threaded Processing (Still Too Slow)
The Problem: 90ms was better, but still not ideal for real-time feedback. At 60fps, each frame should render in under 16ms. 90ms meant 5-6 frames of latency, which users could feel as sluggish responsiveness.
Why It Failed: The main thread was doing everything: capture, MediaPipe inference, angle computation, UI updates. JavaScript runs single-threaded, so MediaPipe's 80ms inference blocked the UI thread. The browser couldn't update the canvas or handle touch events while MediaPipe was thinking.
Next Step: Implemented Web Workers to run MediaPipe inference off the main thread. The main thread now just handles UI and camera streaming. Inference happens in the background without blocking UI responsiveness.
Iteration 3: Batch Processing (Final Optimization)
The Problem: Even with Web Workers, we were still processing one frame at a time. The latency was now 70ms, but we knew MediaPipe could run faster if fed multiple frames at once (batch processing). Could we squeeze more performance?
What Failed: Initial attempt to process 3 frames in parallel showed promise (inference cost dropped 45%), but accuracy also dropped 1.2% because the model struggled when it saw inconsistent pose data. We had to retrain on motion sequences, not single frames.
Final Design: Batch process 3 frames but weight them: the newest frame gets 60% weight, previous frame 30%, frame before that 10%. This gives temporal smoothing while keeping the latest data dominant. Final latency dropped to 60ms with only a 1.2% accuracy trade-off, which user testing showed was acceptable.

Six participants ages 25-72, varied technology comfort

Finding: Start Button Discoverability
Observation: 5 out of 6 participants completed a 10-minute guided workout unassisted. 1 participant couldn't find the start button.
Solution: Enlarged and relocated the start button to a more prominent position, added a brief loading animation. Post-revision: 6 out of 6 found and started a workout unassisted.
Finding: Real-Time Form Cue Understanding
Observation: 4 out of 6 understood real-time form feedback immediately (green = good form, red = adjust). 2 participants needed brief explanation.
Solution: Added a 30-second onboarding animation demonstrating the color feedback system for the first exercise. All 6 participants then understood feedback on second and third exercises.
Finding: PT Clinician Workflow (Separate Test)
Observation: Tested separately with 3 PT clinicians building custom exercise programs. Time to competence for customizing a program: ~20 minutes.
Solution: Built clinician-specific templates for common PT protocols (ACL rehab, rotator cuff, etc.) to reduce setup time. Clinicians now complete program customization in 8-10 minutes.

Consumer testing used guided workouts on a tablet in home-like settings. Clinician testing was conducted at a physical therapy clinic with real patient intake scenarios.

Performance budgets and failure handling for on-device processing

Performance Budget
POSE DETECTION
60 ms per frame on mobile
PROCESSING
Fully on-device, no cloud dependency
MEMORY USAGE
Peak 180 MB, model cached 4 MB
OFFLINE MODE
100% offline capability with syncing
Failure Handling
Pose Occluded
Show "Adjust position" warning with camera preview
Offline Sync Fails
Queue actions, retry on a backoff when connectivity returns
Low Light Detection
Switch to lower-resolution mode for better detection
Offline-First Architecture

PhysioRep is built as an offline-first Progressive Web App. The Service Worker caches all application code, pose detection models (4 MB), and exercise libraries on first load. After initial setup, the app runs entirely without network connectivity. Exercise data, rep counts, and form scores are stored in IndexedDB locally. When connectivity returns, data syncs automatically to the cloud backup. If sync fails, the app queues changes and retries every 30 seconds with exponential backoff (max interval: 5 minutes).

Camera Permission Revoked Mid-Workout
App pauses immediately, preserves current session data, displays "Camera access needed" prompt with one-tap permission re-request
Low Memory Detection
Performance Observer API detects memory pressure. App reduces pose detection resolution from 480p to 360p, trading 2% accuracy for 40% memory reduction
PT works only when patients actually do the exercises. Bad adherence leads to slower recovery, chronic pain, and re-injury.
Built as an independent project applying computer vision to clinical need

PhysioRep applies real-time pose estimation and form feedback to a gap in PT delivery. Patients get objective feedback on every rep, not just when a clinician is watching.

I build tools that keep patients accountable when no one is watching.

Building for real users changed everything

01
Real user feedback found bugs that tests never would.

I posted PhysioRep to Reddit (r/bodyweightfitness) on launch day. Within hours, users reported that onboarding buttons weren't working on any browser. The root cause: my Content Security Policy was missing 'unsafe-inline', which silently blocked all inline onclick handlers. Tests passed. The app looked fine in my local environment. But actual users on actual devices hit a wall immediately. That experience drove home why shipping early matters more than shipping perfect.

02
Pose estimation is easy. Good exercise thresholds are not.

Getting MediaPipe to detect body landmarks is straightforward. The hard engineering was calibrating angle thresholds per exercise so that "good form" and "bad form" match what a PT would actually say. Squats got praised by users. Push-ups were flagging good reps as bad because the shoulder angle thresholds were too strict. The difference between a demo and a product is in those thresholds.

03
Offline-first is a feature users don't know they need until they need it.

One Reddit commenter specifically mentioned the app working in their basement with bad WiFi. They didn't ask for offline support. They just noticed it worked when nothing else did. The service worker + CDN caching strategy paid off exactly the way it was designed to, in a use case I'd planned for but couldn't have predicted when someone would actually hit it.

What I got wrong.

PhysioRep has real users. That's how I learned where I was wrong.

01
I shipped without testing on any device besides my own.

The CSP bug that blocked onboarding for every user on launch day was embarrassing, but the deeper failure was that I tested exclusively in my own Chrome on my own laptop. No mobile testing. No Safari. No Firefox. No low-end Android phone. Reddit users found the CSP issue within hours because they were the first people besides me to open the app. A 10-minute test on a second device would have caught it. I treated "works on my machine" as "works," and that's a habit I've corrected since.

02
The push-up thresholds were wrong because I only tested on my body type.

Squat detection worked well across users because the knee angle range is relatively consistent. Push-up detection flagged good reps as bad because my shoulder angle thresholds were calibrated to my arm length and shoulder width. A shorter user or someone with broader shoulders hits different angles at the same form quality. I should have tested with at least 5 people of different body types before shipping. Instead, I calibrated on myself and learned from user complaints. The fix was widening the acceptable angle range, but the right approach would have been diverse calibration data from the start.

03
I prioritized features over form feedback quality.

PhysioRep launched with rep counting, form scoring, voice coaching, workout history, and offline support. That's a lot of features for a solo project. But the core value proposition, "tells you if your form is good," was only as good as the threshold calibration, which I rushed. Users who came for accurate form feedback found it inconsistent. Users who came for a rep counter found it reliable. In hindsight, I should have shipped with fewer exercises, each calibrated carefully across body types, rather than more exercises calibrated only on myself. Depth of accuracy beats breadth of features when the product promise is "coaching."

Answers before the interview.

If I were screening this portfolio, these are the three questions I'd ask. So here they are, answered.

Q1
Why not use an existing fitness tracking SDK?

Existing fitness SDKs (Apple HealthKit, Google Fit) track metrics like heart rate and step count. None of them do real-time pose estimation with form feedback. MediaPipe Pose gives me landmark coordinates at 30fps in the browser, which is what I actually need to compute joint angles and evaluate form. There's no SDK that does this out of the box for bodyweight exercises. The alternative would be building on top of a native app framework with ARKit or ARCore, but that locks the tool to one platform and requires an app store. A PWA works on any device with a camera and a browser. The tradeoff is that browser-based pose estimation is less precise than native, but for bodyweight exercises the precision is sufficient.

Q2
How did real users actually respond?

Mixed. The Reddit launch (r/bodyweightfitness) generated genuine interest and exposed real bugs. Users who primarily wanted a rep counter were happy. Users who wanted detailed form coaching found the feedback inconsistent, especially for push-ups and lunges. The most common positive feedback was about offline support and the fact that it works without creating an account. The most common negative feedback was about angle thresholds feeling arbitrary. One user specifically said: "It told me my squat was perfect but my push-up was terrible, and my push-up form is better than my squat." That comment drove the threshold rework.

Q3
If you had another month, what would you prioritize?

Calibration data from diverse body types, full stop. The biggest gap in PhysioRep is that every threshold was tuned on one person. I'd recruit 10-15 volunteers across different heights, arm lengths, and fitness levels, record their exercises on video, have a certified personal trainer rate each rep, and use that as ground truth to retrain the thresholds. That's not glamorous work, but it's the difference between a demo and a product. Second priority would be adding a calibration flow where the app asks the user to perform a few reference reps and adjusts thresholds to their body proportions. That's a harder engineering problem but solves the root cause instead of patching symptoms.

Looking for someone who ships products, not just prototypes

I'm finishing my M.S. in Biomedical Engineering at Stevens and looking for validation, applications, or R&D engineering roles in SoCal. If you want someone who builds real tools that real people use, let's talk.