Home/ Work/Basketball Scoreboard
Creator · 2024 · Sports tech

Basketball Scoreboard

A real-time basketball scoreboard plugin for WordPress — operator panel, live broadcast overlay, and OCR-assisted score reading from a camera feed. Built to run in a gym with no guarantees on the network.

Role Creator
Year 2024
Sport Basketball
Platforms web (admin) · web (overlay)
Domain Sports tech · Real-time · Broadcast
State sync interval
500 ms
polling, change-gated
Input modes
2
manual + OCR camera
Shot clock presets
14s / 24s
FIBA / NBA rules
Foul tracking
5 per team
colour-coded dots

Overview

I built this for basketball. KK Jesenice needed a scoreboard overlay that an operator could run from a WordPress admin panel and project live onto the gym wall or pipe into a streaming setup. The constraint was real: a basketball gym is not a server room. You get a laptop, a projector, and a Wi-Fi router that may or may not survive the match.

The plugin has two surfaces. The operator panel lives in the WordPress admin — it shows quarter, game clock, shot clock, scores, fouls, team logos, and league name. Every field updates every 500 milliseconds over AJAX, but only when something has actually changed; the diff-guard keeps the link quiet on a congested gym network. The overlay page polls the same endpoint and repaints the DOM. Both run on the same codebase; the script detects wp-admin body class to decide which direction to run.

The shot clock is not just a display — it counts down in-browser at 1 Hz, with 14 s and 24 s reset presets wired to single buttons for FIBA and NBA rules. The game clock works the same way. Fouls are tracked per team as five coloured dots: orange through four, red at five. At the resolution and distance of a gym display, colour reads faster than a number.

There is also an OCR mode. If the club already has a physical scoreboard, an operator can point a camera at it (or upload a photo), draw bounding rectangles around the score, clock, and quarter sections, and let Tesseract.js extract the values. Each region has independent preprocessing — threshold, contrast, grayscale toggle, noise removal — because a red LED segment and a white LCD digit need completely different treatment. Konva.js handles the canvas region interaction.

Architecture

~/scoreboard/architecture/system-map.svg
01 — OPERATOR INPUTManual Panelscore · fouls · clocksOCR Camera / ImageTesseract.js · Konva.jsState LayerWordPress · AJAX · Transientssave on change · 500 ms poll · nonce-guarded02 — DISPLAY OUTPUTSOverlay Page/overlay/[slug] · shortcodeOBS Browser Sourcestream · projector03 — IN-BROWSER CLOCKSGame ClocksetInterval 1 Hz · mm:ssShot Clock14s / 24s presets · per-teamWordPress plugin · PHP transients · jQuery AJAX · change-hash guard · rewrite rules · shortcode renderer04 — PLATFORM

Reading the diagram: Two input paths (manual panel and OCR camera) write into a shared state layer — WordPress transients served over AJAX with a 500 ms poll and a diff-guard so idle matches don’t chatter. The overlay page at /overlay/[slug] consumes that endpoint and repaints only on change; it works as an OBS browser source for streaming. In-browser clocks (game clock and per-team shot clocks) run client-side at 1 Hz so a network hiccup doesn’t freeze the display.

Scoreboard display

~/scoreboard/overlay/display-mockup.svg
FANTJE U14 · 1.B SKL · POKAL SPAR3Q07:24KK JESENICE54KK TRIGLAV49

Overlay layout: quarter + game clock on the left, team names with foul dots, and large score numerals. Foul dots are colour-coded — orange through four, red at five — readable at projector distance without squinting at digits.

03 What I delivered · challenges solved

Six things shipped,
three hard ones solved.

Key contributions

  • Built the entire WordPress plugin from scratch — custom post type, admin operator UI, AJAX state layer, and public overlay renderer.
  • Implemented dual input modes: a manual scoreboard panel with ±1 / ±2 / ±3 score buttons and a live OCR path via camera or uploaded image.
  • OCR pipeline uses Tesseract.js on a Canvas 2× up-scaled region with per-region threshold, contrast, and grayscale preprocessing controls.
  • State is persisted via WordPress transients and polled every 500 ms — update is only written when data actually changes, keeping the network quiet.
  • Game clock counts down in-browser; shot clock supports 14 s and 24 s reset presets matching FIBA/NBA rules.
  • Foul dots render in orange up to 4, turn red at the 5th — visible at broadcast distance without reading numbers.
  • Overlay exposed at /overlay/[slug] via custom rewrite rules; embeddable as a shortcode for OBS browser source.

Challenges solved

  • Gym Wi-Fi is unreliable — AJAX polling with a change-hash guard keeps the overlay responsive without hammering the server on a slow link.
  • Scoreboard displays at camera distance; foul count has to read as colour, not digits — designed the five-dot system accordingly.
  • OCR from a physical scoreboard camera needs preprocessing per-region (different brightness zones, LED vs. LCD digits) — tunable sliders per marked region rather than one global threshold.
The constraint wasn't the code — it was the environment. A gym has a projector, a laptop, and Wi-Fi that might work. The system had to be solid enough that none of that mattered.
Davor Majc, Creator
04 Tech stack

What's under the hood.

JavaScriptPHPjQueryWordPressTesseract.jsKonva.jsCanvas APIAJAX
Let's talk

Pripravljeni popraviti, zgraditi
ali skalirati?

30 minut, z mano osebno. Preberem vaš sistem kot dnevniško datoteko in povem, kaj bi naredil najprej. Brez prezentacij, brez prodajnega lijaka.

Davor Majc, ustanovitelj, Numen

What you get on call
→ enostranska diagnostika
→ 2–3 obliki rešitve, razvrščeni po učinku
→ okvirni strošek + časovnica za vsako
→ da/ne — ali sem prava izbira
+386 40 828 474 · Blejska Dobrava, SI