Freebee Ads docs

Engineering docs

Hit for Six — the cricket wall (contract v1.7)

Last updated Oct 20, 2018 · 8 sections

A floor-to-ceiling portrait LED wall in a mall with a kiosk (a tablet) beside it. Shoppers scan the wall's QR and get a 4-digit code on their phone (and on WhatsApp when configured). They queue at the kiosk in person, enter the code, and pick one of the 10 sponsor packs at a time; the wall plays each ball and the pack flips to reveal 0 / 1 / 2 / 4 / 6 / OUT. The super over ends at 6 balls or the first out. Highest runs of the day tops the leaderboard. (v1.7.1 — this replaced the v1.7 phone picker and its notifications: no push, no phone-side timing, the queue is physical.)

This document is the design the code follows. Protocol detail is in API_CONTRACT.md §v1.7; the engine is web/public/cricket.html; the phone page is web/app/play/[screen]; the backend is app/services/cricket.py + app/api/cricket.py; the shell plan is §6.

1. Why it works, and the two rules that make it fair

  • The screen is the stage and the phone is the controller. Stadium "big screen" games draw crowds because everyone can see whose turn it is.
  • The ad canvas is the stadium: the pack tiles, the boundary boards, the batter's helmet / jersey / bat, the scoreboard sponsor, the "Brite Super Six" sting.
  • Picks are blind. Every innings gets a fresh shuffle of the config's bag (default 4×0, 5×1, 4×2, 3×4, 2×6, 2×OUT over 20 packs). Values are sealed server-side when the player locks their picks and only revealed by the wall. Nothing the player can see tells them where the sixes are.
  • The server scores. The wall reports an innings, but runs are re-derived from the sealed balls before any prize is minted. A tampered wall cannot inflate a score.

Expected score with the default bag ≈ 9 runs over 6 balls; max 36; ~45 % of innings end in an OUT before the sixth ball. Tune bag per campaign.

2. The turn, timed

stepwhoseconds
intro card / walk-in clipwall2.6 (or clip)
per ball: pack flips 1.6 → ball bowled 0.9 → clip or procedural shot 3–9 → score 0.5wall6–12
result card with QRwall7

≈ 50–70 s per innings → 50–70 innings an hour on one wall. Players pick while they wait, so a turn is only the watching part. For peak hours set balls to 3 in the config.

3. Queue rules (v1.7.1)

  • A ticket (queued) is a session with a 4-digit code, good for 30 min.
  • The kiosk claims a code → playing. One innings per wall; a second claim while someone bats is refused with their name, so the person in the queue just waits.
  • The kiosk sends one pick at a time; the server reveals the sealed value and the wall plays it; the next pick unlocks only after the wall reports it has shown the ball. An innings idle for 90 s closes as it stands.
  • No notifications anywhere. The phone mirrors the innings and ends with the scorecard + claim link.

3a. Queue rules (v1.7, phone picker — retired)

  • queued → ready (called) → playing → done.
  • A player is only called once their picks are sealed; players without picks keep their place but cannot be promoted.
  • Called players have turn_timeout_s (default 25) to tap Play. No tap → skipped; the phone shows "missed your turn, join again".
  • A started innings the wall never reports is expired after 180 s.
  • The wall polls every 2 s; phones poll every 2 s while live. Push (WhatsApp / Web Push) is a later upgrade; the phone buzzes with the Vibration API when called.
  • One player per wall at a time. MAX_QUEUE = 200.

4. Prizes, names and sharing

  • Prize bands by runs (prizes[].min_runs), highest band first, walking down when a band's daily_budget is spent. The 0-run band is what everyone gets.
  • A prize is minted through the spin ledger (a Spin row with symbol_key = "cricket" + a WinToken), so the wallet, OTP, coupons, redeem and metrics from v1.5 are unchanged. The phone's result screen links to /w/claim/{token}.
  • Names are moderated before insert (app/services/moderation.py): normalise (accents, leet, repeats) → URL / phone rejection → block list (English + Hindi / Telugu / Tamil / Urdu in Latin script; MODERATION_EXTRA_WORDS env extends it). Strict on purpose: a false reject costs one retry.
  • No photos on the wall in v1. Players pick an emoji avatar. The share card (GET /v1/play/sessions/{id}/card.png) is a server-rendered PNG with name, runs, balls, rank, venue — shared through the phone's native share sheet.
  • Rule 3 holds: a session stores a display name and an emoji only. Rows feed the day's leaderboard; a cleanup job can purge rows older than 7 days.

5. Assets a sponsor uploads (portal → Creatives → Cricket wall)

keyrequiredwhere it shows
logoyesheader, "Scoreboard by", callout sting
heroyesportal card / attract
packyesthe 20 tiles on the wall and the picker on every phone
boardnoscrolling boundary-board strip
scoreboard_logo, helmet_logo, jersey_logo, bat_stickernothe player card (helmet / chest / bat anchors)
batter, stadiumnooverride the template's batter cutout / stadium still
clip_six, clip_four, clip_outnostadium clips per ball (fall back to the procedural shot)
clip_dot, clip_single, clip_double, clip_walkinnomore clips

Clips carry no logos; the wall overlays the sponsor's. Demo set: Brite (fictional detergent) in web/public/cricket/brite/; clips generated with Seedance from one start frame so the batter stays consistent.

6. Native player shell (step 4 — plan)

The browser player is enough for the pilot. For a wall that must run for weeks, a thin native shell wraps the same HTML5 engines:

  • Flutter (the repo already has mobile/), targets Android boxes and Windows mini PCs on HDMI; Linux for free.
  • Boots on power-on, full screen, watchdog that restarts the web view on a hang (no gody:stats for 120 s), reload at a slot boundary after an update.
  • Downloads and caches the whole content pack (clips, packs, engines) on schedule refresh; plays the ad loop and attract mode fully offline.
  • Offline queue of plays / events exactly as the browser player (storage.ts semantics), drained in batch_seq order.
  • Polls the cricket queue only; when the API is unreachable the wall shows the attract mode with "come back in a moment" and the phone says the screen is offline.
  • Remote: version + logs in GET /v1/ops/fleet, "reload" and "update" commands via the heartbeat body.

Not started: the Flutter SDK is not installed on the build machine. Estimate 2 weeks once the pilot proves the game.

7. Open items

  • Web Push / WhatsApp nudge when a player is called.
  • Per-day leaderboard prize (top of the board at closing) — needs an ops action.
  • Purge job for cricket_sessions older than 7 days.
  • Portal preview of the wall in ops approvals plays the local simulator (cricket.html without a host) — fine for approval, says so in the UI.
Cricket design · Docs