Inspiration

My son is a competitive figure skater. At the rink, his coach replays jumps frame by frame: when the blade leaves the ice, how high he gets, how the landing lands. At home, we had a phone video and a guess.

So I built JumpOnion, a live product that turns a short training clip into a frame-by-frame review and a week of drills. From day one I set one rule: better no diagnosis than a wrong one. A wrong tip doesn't just waste a week. It trains the wrong muscle memory into a child.

I didn't define "right" on my own. A jump coach gave me the most help, advising on the measurements and their definitions. My son's head coach, who also teaches jumps, gave me advice too, and a national-team coach spent hours testing the results with me. Their input is not an endorsement or a claim of validated accuracy.

The TV is where a skating family actually sits together, so for this hackathon I brought JumpOnion to Fire TV.

What it does

JumpOnion TV is a Fire TV app, on Fire OS and on Vega OS, that you drive entirely with the remote. A family connects it to their JumpOnion account once, and the released reviews of the account's main skater reach the TV (this version has no skater switcher):

  • Connect with a code. The TV shows an 8-character code; a parent enters it at jumponion.com/tv while signed in. The TV gets a 30-day read-only pass: it can watch released results, and it can never upload, edit or pay. The parent can disconnect it from the website at any time.
  • Onion skin. The whole jump on one screen: every frame side by side, with the three key frames highlighted: blade leaves the ice, highest point, blade touches the ice. Step through frame by frame with ← →, or jump between key frames with ↑ ↓. It opens with the real clip, then the jump unfolds frame by frame.
  • Zoom in, one stretch at a time. Take-off, early air, peak and opening, landing. The key frames mark where each stretch starts and ends, arrows follow the flight path frame to frame, and a finding is drawn across the whole stretch it belongs to, because a problem never lives in a single frame.
  • Voice, remote and screen together. On Fire OS, on any onion-skin screen, say "Alexa, rewind" to slow the jump down or "Alexa, fast forward" to speed it up (0.25× to 2×, the same steps as the JumpOnion website), "Alexa, pause" to stop on a frame, then step frame by frame with the remote.
  • Last time vs this time. The same jump from two dates, lined up at take-off and compared stretch by stretch, so a family can see progress: April under-rotated, July clean.
  • This week. The training plan for that jump, day by day. Each drill says why it's in this week's plan, gives the steps and a looping animation, then cues for the skater, what a parent should watch, and red lines.
  • Honest limits. Every result carries a line that says what this review can't tell you, such as blade-edge quality from a single camera. Being responsible means giving the limits along with the finding.

How we built it

  • Fire OS app, tested on a real Fire TV Stick 4K Plus: one full-screen Android WebView. The remote's D-pad arrives as key events; Back walks the page history. Plain HTML, CSS and JavaScript, no framework. Everything is sized for a 10-foot screen, with a TV overscan safe area.
  • Vega OS app, tested on a real Fire TV Stick 4K Select: the same pages inside Vega's WebView, wrapped in a small React Native for Vega shell. Vega's WebView loads pages from file://, which the JumpOnion API rightly refuses, so the shell makes the API calls for the page and can reach only the JumpOnion API. The pages are sized in screen units, so the layout held although Vega's WebView sees twice the CSS pixels Fire OS does. One command: npm run vega.
  • Voice that targets the app: the app declares Amazon's voicecommandcontrol permission and keeps its media session's play / pause state in step with the screen. On the real stick, that is what makes Alexa send pause, play, rewind and fast forward to JumpOnion at all. They arrive as media keys or as media-session callbacks (I have seen both on the same stick, three days apart), and either way rewind / fast forward each become one speed step. The remote's own ⏯ ⏪ ⏩ buttons map to the same actions.
  • Pairing the way TV apps do it: a device code, confirmed by the parent on the web, then a 30-day pass. The server accepts that pass only on five read-only routes and refuses any write with it (403); a pass revoked on the website stops working at the next read. The pages are served from a real HTTPS origin inside the app (WebViewAssetLoader), because a file:// page can't make account-linked calls safely.
  • Time, not frames: two clips are rarely sampled at the same rate, so "last vs this" aligns them by time since take-off, not frame number. Frame-number alignment would make one jump look longer in the air when both were 0.33 s.
  • Real results only: the TV shows only finished, released JumpOnion reviews; an offline demo with one skater stays on the home screen. Every frame is checked before a family ever sees a result.
  • Tests guard what a family would notice: 62 tests. For example: a clip without a take-off frame is refused, not guessed; a plan without a daily schedule is never given invented days; a drill without written steps is refused rather than shown as just an animation; a finding lands only on the stretch it belongs to. Two exist only because of the real device: on Fire TV, a video with rounded corners, or a fade-in left applied to the page, plays but shows nothing, so tests forbid both. Several were mutation-checked: break the rule and a test turns red.
  • One command: npm run tv boots the emulator (or uses a connected Fire TV Stick), builds, installs and opens the app.

Before → after: JumpOnion was a web app. The Fire TV app, its remote-first screens and its tests were all built during the submission period (first commit September 26, 2026).

Challenges we ran into

"All tests passing" wasn't the truth. Early on, every test was green. Then I checked the frames myself: 8 of 21 calibration clips weren't showing the skater at all, just the rink behind him. Since then JumpOnion has been rebuilt four times. None of the rebuilds happened because something was broken; each one made the results more correct and more restrained:

  1. Verification rebuilt (March 2026): checks built in layers, so that a frame without a skater can never "pass".
  2. "I don't know" became a valid answer (March): the system declines when the evidence is thin, instead of always producing a number.
  3. Rules first, model last (April): results come from checked frames and fixed rules; the language model only turns them into plain words, and may not invent a number. The switch ran in shadow first: the new path was visible only to me while families kept seeing exactly what they had before. Then I deleted more than 22,000 lines in one day: the path where a model reached its own diagnosis, and a layer that had grown too complex to manage. Deleting is harder than writing: every dependency had to be traced first, and results families had already received had to stay exactly as they were.
  4. One source of truth (July): one timeline, bad cut-outs held back instead of shipped, spending limits that fail closed.

Everyday footage is the hard case. Training clips are filmed from the stands on one phone: dim, shaky, through a net, with other skaters crossing. I tested the popular pose-estimation models; on this footage none was reliable enough to base a judgement on. That's why every frame is checked, and why a frame that doesn't clearly show the skater is dropped, with the report saying so.

Two Fire TV systems. The Vega SDK doesn't run on Windows, so I built for Fire OS first, on the Android TV emulator and then a real stick. For Vega I moved to a Mac and a Fire TV Stick 4K Select. The pages carried over, but three things didn't: an account-linked call from a Vega page is refused (Origin: null), so the app shell now makes those calls; the WebView template leaves out the manifest block Alexa needs, and without it every voice command silently does nothing; and an app without an icon line installs with no icon. Before porting JumpOnion I measured each of these with my open-source probe, so the port itself was small.

The emulator said yes; the real TV said no. On a Fire TV Stick 4K Plus, drill videos played but showed a black screen. The emulator never reproduced it. The causes were two ordinary styling choices (rounded video corners, and a fade-in left applied to the page); both are now forbidden by tests.

A missing permission looks like working voice. My first build was controlled by voice without Amazon's voicecommandcontrol permission, and nothing complained; I found the permission only by re-reading the media-session doc in full. Then the stick updated itself overnight, and without the permission voice stopped reaching the app at all (once, Alexa opened Amazon Music instead). With it, the commands arrived as media keys on October 1 and as the documented media-session callbacks on October 4, on the same Fire OS version, so the app handles both; "pause" on a paused screen correctly leaves it paused. I built a small open-source probe that shows this on any Fire TV. My friction log has 24 entries across both systems, each with what I tried, what happened, a workaround and a suggestion.

Accomplishments that we're proud of

  • A real product with real users: 74 registered users (parents and coaches).
  • The TV never shows a result that wasn't checked, and it always says what it can't tell.
  • The whole app works with the remote alone, from the home screen to a drill's safety notes, and on a real Fire TV you can slow a jump down by voice.
  • One set of screens runs on both Fire TV systems, tested on real sticks: Fire OS on a 4K Plus, Vega OS on a 4K Select. (On Vega, last vs this and zoom in open more slowly, about 4 s.)

What we learned

The valuable part is saying less and saying it right. A confident wrong answer about a child's jump costs a family weeks. The work is in the checking, not in the generating.

What's next

  • Fire TV Appstore release for skating families.
  • More jumps and more "last vs this" history per skater.
  • The same frame-by-frame review for other jump sports (gymnastics, diving).

Exercise animations are AI-generated with Kling, Jimeng and Google Veo.

Open source contribution

Repository: https://github.com/simpleciki/firetv-webview-probe (MIT) · GitHub username: simpleciki · first commit October 1, 2026

What it is. A small Fire TV app, for Fire OS and Vega OS, that measures what a real device delivers to a web page inside a WebView app: which remote keys reach the page and by which path, how each Alexa playback phrase arrives (media key, media-session callback, or the system acting on the page's video), and whether a playing video is actually visible under two everyday styles. A person at the TV answers what they see; the app records what the system reports, and keeps the two apart, because a video element says "playing" either way.

How. The same pages run in a Fire OS WebView app and a Vega WebView app, built twice so one manifest line (the voice permission, or Vega's media block) can be compared on the same device. The result travels inside a QR code: scanning it opens a report page that reads the result from the link itself, so nothing is uploaded. 35 tests, no dependencies (npm test). The README keeps a table of measured devices, and the report page turns any run into a new row.

Why it helps. Each thing it checks cost me an evening, and none of them produced an error: video that plays but shows black on the stick and fine on the emulator, voice that works through the wrong path until an update, and a Vega template that silently drops voice. A developer bringing a web app to Fire TV can see all of this on their own device before shipping, instead of after.

Built With

Share this project:

Updates

Submission history