Inspiration

My parents have watched TV on a Fire TV Stick for a few years. It’s the biggest screen in their home, and they use the remote without a second thought. When I looked at what that screen offered for exercise, I found videos: someone in a studio counting reps they might or might not be doing.

That left a gap. Fitness apps on Fire TV play videos at you. None can see you, and Fire TV gives apps no camera. Phone apps can check your form, but they coach you on a 6-inch screen you can’t read mid-squat. Most home workouts count reps, even though finishing your reps isn’t the same as doing them well.

So I started with one question: could the TV coach from what actually happened? Spot a fault, suggest one drill for it, then re-test and say honestly whether anything changed. For my parents to use it, three things were requirements from the start: no account, no cloud, and no video ever leaving the home.

What it does

CleanRep turns an Android phone into the eyes and the Fire TV into the coach. The Fire TV remote controls the whole experience.

  1. Pair. Scan the QR code on the TV with your phone. Both screens show the same 4-digit number; approve it on the TV. On the first scan, the TV also gives the phone its app, so there’s no store or laptop involved.
  2. Plan. Answer three safety questions and select the equipment you have. CleanRep then builds a short plan from 11 movements: squats and their drills, squat jumps, push-ups, glute bridges, a plank, and a bridge hold.
  3. Move. Prop the phone to your side. It tracks your pose on the device while the TV shows a live rep count, a ✓ or a fault marker after each rated rep, and a brief message such as Not counted: bend deeper when an attempt doesn’t count.
  4. Fix one thing. After the set, the TV shows what was measured, one plain sentence about it, a rest timer, and a drill for the main fault. For shallow squats, that might be Box squat to chair.
  5. Re-test, honestly. Repeat the same movement. The comparison can report improved, no change, or not enough data.

A few things are built into every session:

  • It abstains when the view is unclear. A rep it can’t see well is counted but not rated.
  • Privacy is part of the design. No accounts, no names, and no video uploads. The phone’s camera view, with a posture overlay, can appear on the TV over your Wi-Fi only. It stays in the TV’s memory for at most 2 seconds and is never stored. Turn that view off and only numbers leave the phone. Sessions expire after two hours; End and delete removes a session straight away.
  • The session can carry on without a phone. If you don’t have an Android phone, remote-only mode lets you count reps with − and + and keeps the whole session. If the phone disconnects, the TV retains the history. If the TV app closes, reopening it resumes the session.

How we built it

The key decision was simple: the Fire TV app is the server. Without a cloud service, the session has to live somewhere in the home. The TV is the device that’s always there.

  • A session server inside the TV app. It’s written in plain Java 8 with no dependencies, so it runs on Fire OS’s Android 7.1 and up. It handles pairing, roles and tokens; plans, sets, faults, drills and re-tests; and a JSON store with compare-and-swap. Its HTTP and TLS listeners are hardened against slow, oversized and malformed clients. The server began as a Python reference implementation on a laptop. I ported it to Java, then checked the port by replaying 419 recorded requests from 8 journeys and comparing every response.
  • TV screens. TypeScript runs in a WebView, with screens designed for 1920 × 1080 and controlled entirely through the D-pad.
  • A small phone app. It loads pages from its own packaged https:// origin, giving the camera the secure context it needs without an internet certificate. Every request to the TV uses HTTPS, pinned to the TV’s self-signed certificate. The certificate’s fingerprint arrives in the QR code.
  • Pose tracking. MediaPipe Pose Landmarker Lite runs in a worker on the phone. Rep detection and fault checks follow deterministic rules, with a four-state machine for each rep: top, descending, bottom and ascending. Every verdict can be traced to a rule, and the coach abstains when the view is unclear.
  • Tests. The suite includes 98 Java tests for the server, including real TLS handshakes against the phone app’s own pinning code; 11 tests for the phone app; 149 Vitest tests; and 10 Playwright journeys that drive the TV using D-pad keys only.
  • How I worked. I built CleanRep with coding agents: Claude Code, OpenAI Codex and the Google Antigravity CLI. Each worked in a sandbox with its own worktree. A coordinating Claude Code session reviewed, tested and merged each change; I made the product decisions and ran the devices. The demo video’s narration uses an AI voice from ElevenLabs.

Challenges we ran into

  • A camera needs a secure context, but a TV on home Wi-Fi has no trusted certificate. Plain HTTP pages can’t open a phone’s camera. I tried a laptop server with a local certificate authority, then AWS hosting, before settling on the current setup: a server inside the TV app and a tiny phone app with its own https:// origin and a pinned connection. That problem is what led CleanRep to become fully local.
  • There’s no Fire OS emulator, and I had no Fire TV at hand. I tested on the Android TV emulator running Android 11, which Amazon recommends for Fire OS 8. Its WebView updated itself mid-week, and its Google Cast service was already using port 8443, which the server needed. CleanRep has not yet run on a physical Fire TV. The demo shows the Fire OS app running on that emulator with a real OnePlus Nord 4 on home Wi-Fi. The emulator is clearly captioned throughout.
  • WebView sizing. By default, a WebView lays out at 960 × 540 CSS pixels, while Amazon’s web-app guide specifies 1920 × 1080.
  • A crash with the camera view enabled. The TV app crashed once during a set on a 1 GB emulator. I added a renderer-crash handler that rejoins the session. The crash hasn’t recurred at 2 GB.
  • Android 7.1 limits. The server can’t use java.util.Base64, java.time or java.nio.file, so the build rejects those APIs before compiling.

The friction log records each issue, including versions, exact errors and workarounds.

Accomplishments that we're proud of

  • A complete coaching loop. A fault leads to a drill, followed by an honest re-test on the big screen.
  • A server inside a TV app. The Java port was checked response by response against the reference server it replaced.
  • Privacy that can be checked. The server rejects any request field named like an image, frame or landmark. Sensor requests are capped at 2 KB, and a Playwright journey inspects every request body the phone sends.
  • Setup designed for my parents. Scan, compare four digits, press approve. The TV gives the phone its app, with no store, account or laptop needed.
  • A way to continue without a camera. Remote-only mode keeps the same session.

What we learned

  • Pose estimates can rank reps, but they aren’t clinical measurements. CleanRep labels depth as estimated and abstains when the view is unclear. An honest not enough data is more useful than a confident wrong answer.
  • TV design leaves little room. Every action must be reachable with the D-pad, and the coach banner must never cover the count.
  • A small app with a pinned connection was simpler and safer than any certificate scheme for a phone talking to a TV.
  • Building for specific people makes decisions easier. Whenever I asked, “Would my parents do this?”, accounts, cloud sync and extra setup steps fell away.

What's next for CleanRep

  • Test on a real Fire TV. Start with my parents’ Fire TV Stick, then measure rep accuracy with real people and report the number of participants.
  • Protect the first scan. Derive the pairing number from the TV’s certificate so the very first scan is protected too.
  • Prepare a release build with no debug logging.
  • Add more exercises and a front view for knee tracking.
  • A Vega OS version. New Fire TV Sticks run Vega OS. The TV screens are already web code; the first step is to check whether a Vega app can host the session server for the phone on the home network.

Built With

Share this project:

Updates

Submission history