"Chalk" is bettor slang for the favorite, and the chalkboard was the original odds board, the thing on the wall of every Vegas book before LED grids. I wanted that board back, but in the living room.

The game is on the TV. The odds are on a phone. Every time a line moves or a score flips you look down, and the big screen, the one surface actually built for a board, shows none of it. Chalkboard puts the board where the game is: a 10-foot UI for Fire TV that shows every game's score, line and movement at a glance from the couch. It's a sportsbook's big board, minus the sportsbook. There is no wagering, no links to books, and nothing on screen describes a way to bet.

What it does

Chalkboard sorts games into three buckets: upcoming, live and final. Each card shows the moneyline for every outcome (including the draw in soccer), consensus win probability, the spread and total, and an arrow on any price that moved. Live cards carry the score; final cards are graded against the closing line ("CIN −1.5 Covered", "Over").

Press OK on a card and the game-detail screen answers the five questions a bettor actually asks, in order: what's the number, did it move (open → now → close, on a step chart with key-number crossings), where's the best price, how much is the hold, and, live, is the favorite covering. A book-by-book grid sits beneath.

Board mode turns the whole screen into an auto-cycling rotation-number grid.

How I built it

Backend (Laravel). A scheduler polls an odds API, stores every odds snapshot locally, freezes closing lines the moment a game goes live, and exposes a read-only API. The TV app never calls the vendor, so upstream credit usage is independent of audience size. Polling is adaptive: every two hours when nothing is within a day, every few minutes during a live window, and a credit governor reads the x-requests-remaining header after each call and stretches intervals if burning ahead of pace.

The backend also precomputes the entire board payload, so the client does no odds math. Consensus probability, best line, movement direction and grades all arrive ready to render.

Client (React Native for Vega OS). TypeScript strict, with the data layer built around ETags and Cache-Control-driven polling. The design is deliberately spare: charcoal canvas, off-white type, tabular numerals on every number, and amber reserved for one thing only, the price. On a cold launch the app chalks itself onto the board: four tally strokes, an amber strike, the wordmark, and an underline that draws as real progress and completes only when the board data has arrived. No spinner, and no animation that lies about readiness.

Challenges

The vendor never returns a finished game's odds. Closing lines have to be captured by me at kickoff, from my own snapshots. That turned out to be the feature: line movement comes from my history, not a paid historical endpoint.

Vega OS is new, and the emulator is not the device. I bought a Fire TV Stick and re-measured every assumption on hardware. Debug builds abort after exactly eight minutes of foreground time (reproduced on Amazon's own hello-world template and reported). App-state events stop reaching the component tree after the second background trip, a platform bug Amazon has since confirmed. Timers suspend in the background rather than throttle. The standards file now says "read what runs," because node_modules is not what executes on the Stick.

Designing for ten feet. My first card put percentages above a segmented bar. It couldn't work: the teams stack vertically, the bar runs horizontally, a draw segment has no label slot, and a 2% leg is five pixels wide. The fix was to put the probability on the outcome's row and let the bar be an unlabelled glance element.

What I learned

Measure before you cite. A probe that contradicts a recorded fact is more likely wrong than the fact, but a fact recorded from a crashed app is wrong too; one "constraint" in my notes turned out to be a dead process. Honest UI is a discipline: empty buckets always render so D-pad muscle memory survives; stale data is described in words rather than dimmed; the launch line never finishes before the data does.

Share this project:

Updates

Submission history