Follow these matches

New matches start ticked. Untick any you don't want to hear.

Match filter checkboxes

No matches loaded yet.

Matches

Press Start to load matches.

Diagnostics

Announcement log

No announcements yet.

To do

  • P2: tied-at-hill-game vanish — the leader-at-hill-game disappearance is now caught (announces the win using the last-known leader), but a match that vanishes while tied at hill-game stays silent because we can't infer the winner. Wu's 18-17 win over Murphy on 4 May was the exact case: tied 17-17 going into the decider, then disappeared before the page polled. To handle it properly: when a tied-at-hill-game match vanishes, fire a single follow-up API call (via the worker proxy) to fetch its current state by ID, then announce the real winner. Need a worker route accepting ?id=N and proxying to https://api.snooker.org/?id=N. Page calls it once on the vanish, parses the WinnerID, fires the announcement. Has cost: extra request per vanish event, but rare.
  • P3: wake-on-sleep behaviour now reads current state instead of flooding catch-up announcements. Test cross-platform on Wednesday during Seniors R1: close laptop mid-match, reopen 5 minutes later, confirm "One match in play. Round 1. Drago 3, Farebrother 2." reads instead of every frame change since sleep. Also test iOS Safari (visibility events) and Android Chrome (pageshow.persisted).
  • P2: verify Seniors round numbers as the tournament progresses. R1 = round 7 confirmed (Wed 6 May data). R2 / QF / SF / F currently assumed as 8 / 9 / 10 / 11 — verify when matches at those stages first appear in the API and adjust the lookup tables in formatRound, formatRoundSpeech, framesToWinTarget, nextRoundMilestone, reachedMilestone, deciderPhrase, and semifinalRoundFor.
  • P2: persistent header / SPA-style navigation. Currently clicking Info or Contact does a full page reload, which kills the announcer's audio, polling timer, and speech queue. The header (with Start/Stop, settings, current match panel) should stay put when navigating between Home / Info / Contact - only the content area below changes. Recommended approach: progressive enhancement (option C from the discussion) - intercept nav link clicks with JS, fetch the new page's content via fetch(), swap the content area in-place. Falls back to full reload if JS is off. Each page keeps its own worker route for direct URL access. Care needed for: browser back/forward (use history.pushState), per-page inline scripts running on swap (Info/Contact have their own IIFEs - either re-run or skip the script swap and just swap markup), focus management for accessibility (announce route change to screen readers).
  • P2: handle the Seniors black-ball shootout properly. Tied 3-3 / 6-6 / 9-9 currently fires "Tied at three-all. Black-ball shootout for the match." which is right for the moment — but the next poll the API will likely report a 4-3 score (or similar) and the win announcement will read as if a normal frame was won. Worth confirming what snooker.org reports post-shootout (frame 7 with single-point score? Just sets WinnerID?) and if needed announcing the shootout winner explicitly: "X wins the shootout" rather than "X took frame 7".
  • P3: persistent server-side log of announcements (KV-backed) so we can review what was said when nobody had the page open. Categorise by trigger (score change vs interval vs manual).
  • P3: empty-state messaging when the picker shows nothing. Currently says "No matches in play." which is technically true but unhelpful when (e.g.) WC has just finished and Seniors starts tomorrow. Better: "Seniors starts tomorrow at 7 pm — Drago vs Farebrother and Steadman vs Neal Jones" or similar bridge text. Could share logic with the Start-button readout's next-session detection.
  • P4: consider enabling HSTS in Cloudflare SSL/TLS settings. Closes one of the Security Insights warnings. Held off because it's effectively irreversible (browsers cache the policy for the configured max-age) and the marginal protection over "Always Use HTTPS" is narrow. If enabling: start with max-age 1 month, do NOT tick preload, do NOT tick includeSubdomains until thought through.

Tips & credits

Keep this tab open in the background. Your browser must remain open for speech to work, and on mobile the screen may need to stay on.

Data credit: All match data is provided by snooker.org, maintained by Hermund Ardalen. This tool would not exist without his generosity in providing API access.