Inspiration

Most people who train alone have no one watching their form. A personal trainer costs a lot. Fitness apps mostly count reps you type in yourself, or they count every bounce and half rep as a full one. We wanted a coach that actually watches you: one that counts only reps that reach full depth, tells you why a rep didn't count, and gives you an honest summary at the end. It should run on hardware you already own, a laptop or phone camera. We also wanted training to feel less like a chore, so we turned the same rep counter into games you can play against friends.

What it does

G.R.I.T. (Guided Repetition Intelligence Training) is an AI strength coach for squats and push-ups. The name describes what it does: it guides every repetition and adds intelligence to how you train. It turns any laptop or phone camera into a training partner. It counts your reps, holds you to good form, coaches you while you train, and tracks your progress over time.

A workout, start to finish

  1. Sign in and pick an exercise. Choose squats or push-ups, put your device on the floor or a shelf, and step back until your whole body is in view.
  2. Train. Pose tracking runs on your device and measures your joint angles 30 times a second: knees for squats, elbows for push-ups. Only those angles are sent to our server. Your video is never uploaded or stored.
  3. Get feedback as you go. Your rep count updates the moment a rep counts. Short coaching cues appear when the coach spots a pattern. If you step out of frame, the app tells you to move back into view rather than guessing.
  4. Finish and get your report. Your stats appear right away, followed by a written coach report a few seconds later.

Rep counting you can trust

  • Full reps only. A rep counts only when you reach the bottom of the movement and return to the top. Half reps and reps that are too fast don't count, and the app tells you why, so you know what to fix.
  • One attempt per descent. Wobbling near the bottom can't log several failed attempts for one movement.
  • Protected against glitches. Camera tracking sometimes misreads a limb for a frame or two. The counter smooths the angles, ignores impossible ones, and checks that the left and right sides agree, so a glitch can't add a fake rep.
  • Measures every rep. Each rep records its depth, how long the lowering and rising took, and the difference between your left and right sides.

A coach that watches your form

  • Live cues. The coach compares each rep with your first few. If your reps get shallower as you tire, or one side keeps bending more than the other, it gives a short cue. A problem has to show up in two reps in a row before you get a cue, and the coach waits several reps before repeating the same one, so it doesn't nag.
  • Safety first. A Pain / stop button stops all technique coaching immediately and tells you to rest. The report at the end then gives the same advice.
  • End-of-workout report. Gemini reads your session's stats and writes a short personal report: what went well, what came up, and one thing to focus on next time. Every report is checked so it can't invent numbers or give medical advice. If a check fails, the app shows a standard report built from the same data.

Progress and history

  • Streaks. A daily workout streak with your best streak so far, and a reminder when you haven't trained today.
  • Weekly activity. A chart of your workouts and reps over recent weeks, plus totals for workouts, reps and time trained.
  • Personal records. Your best set and your fastest Rep Racer finish.
  • Workout history. Every workout, grouped by day. Open any workout to see its stats, coach report, each coaching note in order, and a rep-by-rep table of depth and time. You can delete a workout permanently if you want.

GRIT Games: Rep Racer

Rep Racer turns your workout into a race. The server counts reps for games with the same counter used in normal workouts, so a rep in the game is a real rep and every race also appears in your history.

  • Solo Goal: hit a target number of reps before the clock runs out.
  • Personal Best: race a ghost replay of your own best attempt.
  • Live 1v1: share a room code and race a friend in real time, each on your own camera.
  • Local 2-Player: two people, one camera. Player 1 is on the left side of the screen and Player 2 on the right.
  • Practice: a keyboard mode (Space = one rep) for learning the game. It's clearly labelled and never saved.

Spine wearable (prototype)

A compression shirt with four motion sensors down the back: one between the shoulder blades, and three along the mid back, lower back and base of the spine. Comparing neighbouring sensors shows how much each section of the back bends during a rep. It's designed to catch an upper body that leans too far forward in a squat, a rounding lower back, or sagging or raised hips in a push-up. It plugs in over USB or connects wirelessly, and the app saves its readings with each workout. The coaching for it has been tested on simulated data so far, not yet on real lifts.

How we built it

  • Client: Expo and React Native with Expo Router and TypeScript, running on the web. MediaPipe Pose runs on the device and turns camera frames into joint angles.
  • Backend: FastAPI, with a WebSocket for each workout. The client sends angles about 30 times a second, and the server sends back events: rep counted, rep rejected, coaching cue, tracking status.
  • Rep engine: a deterministic state machine over joint angles. It uses hysteresis thresholds, ignores low-confidence frames, smooths angles with a short median filter, and drops a side whose angle is physically impossible. A rep only completes after you've held the top position briefly.
  • AI: Gemini only writes the report after the workout. Everything during the workout (counting, rejecting, cues) is rule-based, so it's fast, testable, and never waits on a model. Reports are cached per workout and rate-limited, and the API key stays on the server.
  • Data: Supabase for accounts, workouts, reps and coaching notes, with row-level security so you only see your own data. Tiger Data (TimescaleDB) stores the wearable's high-frequency sensor readings. The two databases share each workout's ID.
  • Hardware: a Seeed XIAO ESP32-S3 hub with one BNO085 and three MPU-6050 sensors on a shared I2C bus. The three MPUs use the same address, so we switch between them with each chip's AD0 pin. Readings reach the laptop over USB or wirelessly over ESP-NOW.
  • Tests: more than 600 offline server tests, covering the rep counter, coaching rules, the WebSocket, security and the games, plus unit tests for the client's logic.

Challenges we ran into

  • Pose tracking glitches. MediaPipe sometimes loses a limb for a frame or two, and a knee angle can jump from 170° to 40° and back. Early versions counted those spikes as reps. We added a glitch guard: a median filter, a plausibility check on each side, a check that the left and right sides agree, and a minimum rep duration. On our recorded push-up data, this cut false reps and false rejections sharply.
  • One attempt per descent. Wobbling near the bottom used to log several "too shallow" attempts for one movement. We changed it so a rep attempt only ends after you've been back at the top for a short time.
  • Deciding where the AI goes. We first wanted the LLM giving live cues. But model latency during a set is too slow, and AI advice about pain isn't safe. We kept the live coaching deterministic and gave Gemini the job it does well: summarizing a finished workout.
  • Two people, one camera. For local 2-player mode, MediaPipe doesn't keep detected people in the same order between frames. We assign players by which side of the screen they're on, so stepping out of frame and back in keeps your side.
  • Three identical sensor chips on one bus. The three MPU-6050s have the same I2C address. We wired each one's AD0 pin to its own select line so the hub reads one at a time.
  • Working as a team on one repo. Four people worked on the client, server, games and hardware at the same time. Shared message contracts (docs/event-contracts.md) and strict ownership of directories kept merges manageable.

Accomplishments that we're proud of

  • A rep counter strict enough to trust. It refuses half reps and glitches, and it always tells you why a rep didn't count.
  • Privacy by design: no video is uploaded or stored, only joint angles.
  • A clean split between deterministic coaching and AI reporting. The app still works fully with the AI turned off.
  • Multiplayer Rep Racer, both online 1v1 and two players in front of one camera, using the same rep counter as normal workouts.
  • A working multi-sensor spine wearable built from scratch.
  • More than 600 automated server tests.

What we learned

  • Real pose data is much noisier than simulated data. Filtering and plausibility checks matter as much as the main algorithm.
  • LLMs work best here as a reporter after the workout, not as the decision-maker during it. Keeping rules and AI apart made both easier to test and to trust.
  • Writing the message contracts first let the client, server and hardware work move in parallel without stepping on each other.
  • Embedded work takes patience: I2C address conflicts, sensor calibration, and wireless links all need careful bench testing.

What's next for G.R.I.T.

  • More exercises: lunges, deadlifts and overhead press. The rep engine is designed so a new exercise is mostly a config change (docs/adding-an-exercise.md).
  • Wearable in the live coach: use the spine sensor's readings in real-time form cues and validate them on real lifts.
  • Native mobile app: bring on-device pose tracking to iOS and Android, not just the web.
  • More GRIT Games: new modes, leaderboards, and challenges among friends.
  • Smarter reports: compare each workout with your history to show trends over weeks, not just one session.

Built With

Share this project:

Updates

Submission history