-
-
The alert history keeps every alert so far, newest first, even after its banner has left the screen.
-
Live radar: 22 players and the ball to scale. Home are filled orange dots, Away sky-blue rings, so colour is never the only cue.
-
Running on the Vega Virtual Device: a live replay of SoccerTrack v2 match 117092 (CC BY 4.0), one frame every 200 ms.
-
Rolling 5-minute stats with ▲/▼ against the previous value. Every number comes from tested pure functions on the edge.
-
Defensive lines and team blocks (Home filled, Away outlined) move on the pitch as the metrics update.
-
30' alert: the text never holds a number. The banner shows the cited values (Away line height 38 m → 31 m) from the edge.
-
Storyboard of the demo video: title, what runs, live radar and stats, the 30' alert, and the halftime report card.
Inspiration
Top clubs pay six figures a year for match analysis. An amateur coach has no analyst at all: halftime decisions are made from memory. Balomer puts the analysis on the screen that is already in the dressing room, a Fire TV.
What it does
A match plays on the Fire TV as if it were live:
- Live 2D radar. All 22 players and the ball move on a pitch drawn to scale. Home are filled orange dots and Away are sky-blue rings, so colour is never the only cue.
- Live stats. Possession, defensive line height, width, depth and compactness over the last five minutes. Each team's defensive line and block are drawn on the pitch, and arrows show the change against the previous value.
- Minute alerts at 15', 30', 60' and 75'. A banner slides in with the numbers behind it, and the matching stats pulse. Every alert stays in an on-screen history.
- Halftime report. Three recommendations, each a problem and one adjustment, each citing the metric, team and period it rests on.
Every screen works with the remote's D-pad alone.
How we built it
- Edge (Python). An ingest command streams SoccerTrack v2 annotations (2 x 2.7 GB of JSON per match, peaking at 136 MB of RAM) into replay files, one frame every 200 ms. A replayer publishes them as live. Every metric and alert is a small pure function with unit tests.
- Relay (FastAPI WebSocket). It forwards every message to the TV, and catches up a TV that connects late with the state so far.
- Fire TV app (React Native on Vega OS). It draws what arrives and holds no analysis logic. All motion uses the core
AnimatedAPI with the native driver. - Agent (Strands + Amazon Bedrock). It reads the first half's metric snapshots and returns structured output. A validator rejects any evidence that is not in the input, any digit in the text and any text that would overflow a card. It asks once more, then shows "report unavailable" instead of an unchecked answer. The agent writes prose; it never writes a number.
- Contracts. Every message is a JSON Schema, and the Python and TypeScript types are generated from them.
- Process. Spec-driven, tests first. CI runs Python and TV checks on every pull request, with one squash-merged PR per task.
Challenges we ran into
- Running the Vega SDK and Virtual Device on Windows through WSL2.
- Vega lays out in dp, so our 1920x1080 design first rendered at twice the size.
- Getting Bedrock model access on our account: verification, model availability, then a payment requirement.
All of it is in our friction log, with the exact error messages.
Accomplishments that we're proud of
- Every number on screen comes from a tested pure function on the edge.
- The agent cannot invent one: evidence is by reference, and the TV resolves it.
What we learned
- Keep the deterministic and the generative apart.
- On TV, focus and shape matter as much as colour.
What's next
- Our own 7-a-side footage through computer vision instead of annotations.
- The full-time report.
- The AWS deployment: IoT Core, DynamoDB and AgentCore.
Data: SoccerTrack v2 (CC BY 4.0).
Built With
- amazon-bedrock
- aws-cli
- claude
- fastapi
- fire-tv
- github-actions
- ijson
- jest
- json-schema
- numpy
- pydantic
- python
- react-native
- soccertrack
- strands-agents
- typescript
- uv
- uvicorn
- vega-os
- websockets
Log in or sign up for Devpost to join the conversation.