Professional broadcast graphics for hockey powered by real-time scoreboard data
🚀 Quick Start • ✨ Features • 📺 Overlays • 🔌 API • 📄 License
Click to expand
Release Date: February 2026
| Change | Description |
|---|---|
| 🧠 Adaptive Protocol Parser | Complete parser rewrite with 5 parsing strategies - auto-detects unknown packet formats from real hardware |
| 🔒 Strategy Locking | Parser locks onto the working strategy after 3 consecutive successes for fast, reliable parsing |
| 📐 Multiple Field Layouts | Supports standard 80-byte, short 55-byte (confirmed from real hardware), compact, and wide (3-digit score) layouts |
| 📝 ASCII Text Mode | Parses VCG/VideoStamp+ character generator output (CR/LF delimited ASCII lines) |
| 📚 Documentation Viewer | Browse protocol docs, reference PDFs, and research notes from the web dashboard |
| 🔬 Protocol Research | Compiled reverse-engineering notes from MP-69D decoder, PoC||GTFO, and community sources |
| 📊 Packet Diagnostics | Unrecognized packets get detailed hex/ASCII/byte analysis logged for reverse engineering |
| 🔌 Serial Reader Fix | Serial connect now properly starts the reader thread (previously opened port but never read data) |
| 📼 Serial Recording | Record raw serial data to binary files for offline analysis |
| 🏟️ Real Hardware Validation | 55-byte field map confirmed from 3,130 live packets at Tony's rink (167 unique score patterns) |
If upgrading from v2.2.0:
cd /path/to/SLAP
git pull
./deploy.py
slap restartSLAP captures real-time game data from Trans-Lux FairPlay MP-70 scoreboard controllers and generates professional NHL-style broadcast graphics via CasparCG or OBS Studio.
┌────────────┐ RS-232 ┌──────────────┐
│ Scorekeeper│───────────────────│ Scoreboard │
│ Console │ │ Display │
│ (MP-70) │ └──────────────┘
└─────┬──────┘
│ RS-232 (sniff)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ SLAP Server │
│ ┌──────────────────┐ ┌──────────────────┐ ┌───────────────┐ │
│ │ Serial Parser │───▶│ Game State │───▶│ AMCP Client │ │
│ │ (MP-70 Protocol)│ │ scores, clock, │ │ │ │
│ └──────────────────┘ │ period, penalties│ └───────┬───────┘ │
│ └────────┬─────────┘ │ │
│ │ │ AMCP │
│ ▼ ▼ │
│ ┌──────────────────┐ ┌───────────────┐ │
│ │ Web Dashboard │ │ CasparCG │ │
│ │ (Socket.IO) │ │ Server │ │
│ └────────┬─────────┘ └───────┬───────┘ │
└───────────────────────────────────┼──────────────────────┼──────────┘
│ │
▼ ▼
┌──────────────┐ ┌─────────────────────┐
│ OBS Studio │◀───│ HTML/CSS/JS │
│ (streaming) │ NDI│ Templates │
└──────────────┘ └─────────────────────┘
Dataflow:
- Scorekeeper operates the MP-70 console during the game
- MP-70 sends game data via RS-232 to the physical scoreboard
- SLAP passively sniffs the RS-232 line (no interference with scoreboard)
- Parser decodes the MP-70 binary protocol (scores, period, clock, penalties)
- AMCP Client sends data updates to CasparCG via AMCP protocol
- CasparCG renders HTML/CSS/JS templates with live data
- Web Dashboard provides real-time monitoring and manual override control
For best performance, run SLAP and CasparCG on the same machine:
CasparCG Machine (runs SLAP):
├── RS-232 USB adapter → MP-70 serial sniff
├── SLAP server (localhost:5000)
├── CasparCG server (localhost:5250)
└── HTML templates served locally (zero latency)
│
│ NDI (network)
▼
OBS Machine (powerful workstation):
├── Receives NDI stream from CasparCG
├── Composites overlays onto camera feeds
└── Outputs final broadcast stream
Why this works best:
- Localhost AMCP = zero network latency for graphics
- Single machine handles capture → parse → render
- OBS stays separate for compositing only
- Serial port directly connected to graphics machine
Tip
After installation, SLAP is controlled via the slap command and available in your start menu!
# Clone the repository
git clone https://github.com/sworrl/SLAP.git
cd SLAP
# Run the installer (handles everything automatically)
chmod +x deploy.py
./deploy.py
# After installation, use the 'slap' command:
slap start # Start the server
slap status # Check if running
slap stop # Stop the server
# Open in browser
# https://slap.localhostNote: The installer automatically:
- Installs all prerequisites (Python, nginx, openssl, etc.)
- Creates a global
slapcommand- Sets up HTTPS with self-signed SSL certificate
- Adds SLAP to your start menu
- Configures auto-start on boot
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
SLAP includes a full suite of NHL-style broadcast overlays, all controllable via the web dashboard or API.
| Overlay | URL | Description |
|---|---|---|
| 🏒 Scorebug | /overlay |
Main game scorebug with scores, clock, period |
| 🚨 Goal Splash | /overlay/goal |
Full-screen goal celebration with confetti |
| 🎯 Shot Counter | /overlay/shots |
Shots on goal tracker |
| ⏱️ Penalty Box | /overlay/penalty |
Detailed penalty info display |
| 👤 Player Card | /overlay/player |
Lower third player spotlight |
| 📊 Period Summary | /overlay/period |
End-of-period stats summary |
| 🎬 Game Intro | /overlay/intro |
Pre-game matchup graphic |
| 🥅 Goalie Stats | /overlay/goalie |
Goalie performance display |
| ⚡ Power Play | /overlay/powerplay |
Power play countdown graphic |
| ⭐ Three Stars | /overlay/stars |
Post-game three stars of the game |
| 🔁 Replay Bug | /overlay/replay |
Flashing replay indicator |
| 📰 Ticker | /overlay/ticker |
Scrolling scores crawl |
Add overlays as HTML templates:
PLAY 1-10 [HTML] "https://slap.localhost/overlay"
PLAY 1-11 [HTML] "https://slap.localhost/overlay/goal"
Add as Browser Source:
- URL:
https://slap.localhost/overlay(orhttp://localhost:9876/overlay) - Width: 1920
- Height: 1080
- Custom CSS: (leave empty)
All overlays respond to Socket.IO events for real-time triggering.
- Python 3.8 or higher
- Linux, macOS, or Windows
# Clone or download SLAP
git clone https://github.com/sworrl/SLAP.git
cd SLAP
# Run the installer
chmod +x deploy.py
./deploy.pyThe installer handles:
- System package installation (Python, nginx, openssl, git)
- Python virtual environment creation
- Dependency installation
- HTTPS/SSL certificate generation
- nginx reverse proxy configuration
- Start menu entry creation
- Systemd service for auto-start
| Command | Description |
|---|---|
slap start |
Start SLAP server |
slap stop |
Stop SLAP server |
slap restart |
Restart SLAP server |
slap status |
Check if running |
slap logs |
Show logs (-f to follow) |
slap config |
View/edit configuration |
slap -update |
Update from GitHub |
slap --help |
Show all commands |
Simulation mode is hidden by default in the WebUI. To enable it:
slap -simulation:enable # Show simulation controls in WebUI
slap -simulation:disable # Hide simulation controls (default)slap -https:setup # Configure HTTPS with nginx and SSL
slap -https:remove # Remove HTTPS configurationslap start --port 9876 # Custom port
slap start --debug # Debug logging
slap -serial:/dev/ttyUSB0 # Set serial port./deploy.py --uninstallNote
SLAP works in simulation mode without any hardware. Only need this for live games!
| Item | Description |
|---|---|
| MP-70 Controller | Trans-Lux FairPlay MP-70, MP-71, MP-72, or MP-73 |
| USB-Serial Adapter | Any RS-232 to USB adapter (FTDI recommended) |
| Serial Cable | DB-9 or appropriate connector for your MP-70 |
- Access the MP-70 setup menu
- Navigate to sport-specific setup
- When prompted "VIDEO CHAR?", answer NO for ProLine data (recommended)
- NO = ProLine binary format (STX/ETX framed, default)
- YES = VCG/VideoStamp+ ASCII text format (also supported by SLAP)
- Verify RS-232 output is enabled
- Note which connector (CONN.1, CONN.2, CONN3&4) the cable is on
MP-70 RS-232 Port → Serial Cable → USB Adapter → Computer
Linux:
ls /dev/ttyUSB*
# Usually /dev/ttyUSB0macOS:
ls /dev/tty.usb*
# Usually /dev/tty.usbserial-XXXXWindows:
- Open Device Manager
- Look under "Ports (COM & LPT)"
- Usually COM3 or COM4
Edit src/config/default.json:
{
"serial": {
"port": "/dev/ttyUSB0",
"baudrate": 9600
},
"caspar": {
"host": "127.0.0.1",
"port": 5250,
"enabled": true
},
"web": {
"port": 9876
},
"simulator": {
"enabled": false
}
}| Setting | Description |
|---|---|
port |
Serial port path (e.g., /dev/ttyUSB0, COM4) |
baudrate |
9600 (standard) or 19200 (some firmware) |
| Setting | Description |
|---|---|
host |
CasparCG server IP address |
port |
AMCP port (default: 5250) |
enabled |
Set to false to disable CasparCG |
SLAP stores game history, events, and player statistics in a SQLite database. The database is stored outside the source directory for security:
| Platform | Location |
|---|---|
| Linux | ~/.local/share/slap/slap.db |
| macOS | ~/Library/Application Support/slap/slap.db |
| Windows | %LOCALAPPDATA%\slap\slap.db |
Note
The database is automatically created during ./deploy.py install and includes self-healing - if the database becomes corrupted, SLAP will back it up and create a fresh one automatically.
The dashboard at
https://slap.localhost(orhttp://localhost:9876without HTTPS) provides full control over SLAP.
- Live scorebug preview - See exactly what appears on broadcast
- Preview/Live toggle - Switch between simulation and real hardware
- Score controls - Manually adjust scores with +/- buttons
- Goal buttons - Trigger goal animations
- Clock controls - Set period and game time
- Penalty controls - Add 2-minute or 5-minute penalties
- 🚨 Goal Splash - Trigger home/away goal celebrations
- 🔁 Replay Bug - Show/hide replay indicator
- 👤 Player Card - Display player lower thirds with roster lookup
- 🥅 Goalie Stats - Show goalie save percentages
- 📊 Period Summary - End of period stats
- 🎬 Game Intro - Pre-game matchup graphic
- ⭐ Three Stars - Post-game honors
- ⚡ Power Play - Enhanced PP graphic
- 🎯 Shot Counter - Update SOG display
- 📰 Ticker - League scores crawl
- 🎨 Team Customization - Set team names, colors, and logos
- 📋 Roster Manager - Add/edit player names and numbers
- 🖼️ Logo Upload - Upload custom team logos (PNG, SVG, etc.)
- 📡 Serial Port - Configure MP-70 connection
- 🎬 CasparCG control - Start/stop server, connect AMCP
- 📺 OBS control - Start/stop OBS, connect WebSocket
- 🔗 Connection status - Monitor all integrations
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/state |
Get current game state |
POST |
/api/state |
Update game state |
POST |
/api/goal |
Trigger goal event |
POST |
/api/penalty |
Add penalty |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/overlays |
List all available overlays |
POST |
/api/overlay/goal |
Trigger goal splash |
POST |
/api/overlay/player |
Show player card |
POST |
/api/overlay/goalie |
Show goalie stats |
POST |
/api/overlay/period |
Show period summary |
POST |
/api/overlay/intro |
Show game intro |
POST |
/api/overlay/stars |
Show three stars |
POST |
/api/overlay/powerplay |
Show power play graphic |
POST |
/api/overlay/shots |
Update shot counter |
POST |
/api/overlay/replay |
Show replay bug |
POST |
/api/overlay/ticker |
Show scores ticker |
POST |
/api/overlay/{name}/hide |
Hide any overlay |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/roster |
Get all rosters |
GET |
/api/roster/{team} |
Get team roster (home/away) |
POST |
/api/roster/{team} |
Update team roster |
POST |
/api/roster/{team}/player |
Add player to roster |
DELETE |
/api/roster/{team}/player/{number} |
Remove player |
POST |
/api/roster/{team}/player/{number}/stats |
Update player stats |
POST |
/api/roster/reset |
Reset all game stats |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/teams |
Get team configuration |
POST |
/api/teams |
Update team configuration |
GET |
/api/teams/logos |
List available logos |
POST |
/api/teams/logo/upload |
Upload new logo |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/serial/ports |
List available serial ports |
GET |
/api/serial/status |
Get serial connection status |
POST |
/api/serial/config |
Configure serial port |
POST |
/api/serial/connect |
Connect to serial port and start reader |
POST |
/api/serial/disconnect |
Disconnect from serial port |
POST |
/api/serial/recording/start |
Start recording raw serial data |
POST |
/api/serial/recording/stop |
Stop recording |
GET |
/api/serial/recording/status |
Get recording status |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/docs |
List available documentation files |
GET |
/docs/file/<filename> |
Serve a documentation file |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/simulator/start |
Start simulator |
POST |
/api/simulator/stop |
Stop simulator |
POST |
/api/simulator/reset |
Reset simulator |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/games |
Get recent games (add ?limit=N) |
POST |
/api/games |
Create new game |
GET |
/api/games/current |
Get current in-progress game |
GET |
/api/games/{id} |
Get specific game |
PUT |
/api/games/{id} |
Update game details |
DELETE |
/api/games/{id} |
Delete game |
POST |
/api/games/{id}/end |
End game (status: final/cancelled) |
GET |
/api/games/{id}/summary |
Get full game summary with events |
GET |
/api/games/{id}/events |
Get game events (add ?type=goal) |
POST |
/api/games/{id}/goal |
Log a goal |
POST |
/api/games/{id}/penalty |
Log a penalty |
POST |
/api/games/{id}/shot |
Log a shot |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/stats |
Get player stats (add ?season=YYYY&team=X) |
GET |
/api/stats/leaders |
Get stat leaders (add ?stat=points&limit=N) |
GET |
/api/stats/team/{team} |
Get team win/loss record |
GET |
/api/stats/h2h |
Head-to-head record (add ?team1=X&team2=Y) |
Success:
{
"status": "ok",
"data": { ... }
}Error:
{
"error": "Error message description"
}| Status Code | Description |
|---|---|
| 200 | Success |
| 400 | Bad request (invalid parameters) |
| 404 | Not found |
| 503 | Service unavailable |
SLAP uses Socket.IO for real-time updates.
const socket = io('https://slap.localhost');
// Listen for state updates
socket.on('state_update', (state) => {
console.log('Score:', state.game.home, '-', state.game.away);
});
// Request current state
socket.emit('request_state');
// Update score
socket.emit('update_score', { home: 5, away: 3 });
// Update clock
socket.emit('update_clock', { clock: "12:30" });
// Update period
socket.emit('update_period', { period: "3" });# Get current state
curl https://slap.localhost/api/state
# Trigger home goal
curl -X POST https://slap.localhost/api/goal \
-H "Content-Type: application/json" \
-d '{"side": "HOME"}'
# Set score manually
curl -X POST https://slap.localhost/api/state \
-H "Content-Type: application/json" \
-d '{"home": 3, "away": 1}'
# Add 2-minute penalty to away team
curl -X POST https://slap.localhost/api/penalty \
-H "Content-Type: application/json" \
-d '{"side": "AWAY", "duration": 120}'
# Show player card
curl -X POST https://slap.localhost/api/overlay/player \
-H "Content-Type: application/json" \
-d '{"team": "home", "number": "87", "name": "CROSBY", "duration": 5000}'import requests
BASE_URL = "https://slap.localhost/api"
# Get state
state = requests.get(f"{BASE_URL}/state").json()
print(f"Score: {state['game']['home']} - {state['game']['away']}")
# Trigger goal
requests.post(f"{BASE_URL}/goal", json={"side": "HOME"})
# Update score
requests.post(f"{BASE_URL}/state", json={"home": 5, "away": 2})
# Show player card
requests.post(f"{BASE_URL}/overlay/player", json={
"team": "home",
"number": "87",
"name": "CROSBY",
"duration": 5000
})// Using fetch API
async function triggerGoal(side) {
const response = await fetch('/api/goal', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ side })
});
return response.json();
}
// Using Socket.IO for real-time updates
const socket = io();
socket.on('state_update', (state) => {
document.getElementById('homeScore').textContent = state.game.home;
document.getElementById('awayScore').textContent = state.game.away;
});Tip
SLAP's API works great with Stream Deck and similar control surfaces!
| Button | HTTP Request |
|---|---|
| Home Goal | POST /api/goal with {"side":"HOME"} |
| Away Goal | POST /api/goal with {"side":"AWAY"} |
| Show Bug | POST /api/bug/show |
| Hide Bug | POST /api/bug/hide |
| Replay | POST /api/overlay/replay |
| Player Card | POST /api/overlay/player with player data |
Note
The easiest way is using the built-in installer:
# Install CasparCG (downloads ~105MB)
./deploy.sh caspar-install
# Start CasparCG
./deploy.sh caspar-start
# Check status
./deploy.sh caspar-status
# Stop CasparCG
./deploy.sh caspar-stopThis installs CasparCG to ~/.local/share/casparcg/ which:
- Works on immutable Linux systems
- Doesn't require root/sudo access
- Automatically copies SLAP templates
- Creates a default config for 1080p output
You can also control CasparCG from the web dashboard.
SLAP sends these commands to CasparCG:
| Command | Description |
|---|---|
CG 1-10 UPDATE 1 "{json}" |
Update scorebug data |
CG 1-10 INVOKE 1 "goal:HOME" |
Trigger goal animation |
CG 1-10 INVOKE 1 "show" |
Show scorebug |
CG 1-10 INVOKE 1 "hide" |
Hide scorebug |
The MP-70 controller outputs game data via RS-232 serial connection using a proprietary protocol that varies by firmware, board type, and configuration. SLAP's adaptive parser handles multiple formats automatically.
For comprehensive protocol research, see
docs/PROTOCOL_NOTES.mdand the Documentation page in the web dashboard.
| Parameter | Value |
|---|---|
| Baud Rate | 9600 (standard) or 19200 (some firmware) |
| Data Bits | 8 |
| Parity | None |
| Stop Bits | 1 |
| Flow Control | None |
Tip: If 9600 doesn't work, try 19200. The baud rate varies by firmware version.
The MP-70 has two RS-232 output modes (set via "VIDEO CHAR?" menu):
| Mode | Setting | Format |
|---|---|---|
| ProLine (default) | VIDEO CHAR? = NO | STX/ETX framed binary, 80-byte packets |
| VCG/VideoStamp+ | VIDEO CHAR? = YES | CR/LF delimited ASCII text lines |
SLAP's parser auto-detects the format using 5 strategies, tried in order:
| # | Strategy | Description |
|---|---|---|
| 1 | Type-byte dispatch | Standard MP-70 type bytes: 'C' (clock), 'H' (score) |
| 2 | Alternative type bytes | Other sport-specific indicators (S, G, D, F, B, etc.) |
| 3 | Layout-only | Ignores type byte, tries all field layouts against the packet |
| 4 | ASCII text scan | Regex search for score/clock patterns in readable text |
| 5 | Clock extraction | Finds embedded MM:SS times anywhere in the data |
After 3 consecutive successes with the same strategy, the parser locks onto it for fast processing. If the locked strategy fails (e.g., sport change on controller), it falls back to trying all strategies.
| Layout | Length | Score Fields | Use Case |
|---|---|---|---|
| Standard | 80 bytes | 2-digit scores at [13:15], [29:31] | Default MP-70 hockey |
| Short | 55 bytes | 1-digit scores at [13], [39] + penalty player #s | Confirmed from real hardware |
| Wide | 80 bytes | 3-digit scores at [13:16], [29:32] | Basketball/football |
| Compact | 40 bytes | Tighter field packing | Some firmware variants |
Position Length Field Format
-------- ------ ----- ------
[0] 1 STX 0x02
[1] 1 Type 'C' (0x43)
[2:6] 4 Clock ASCII "MMSS" (BCD-like)
[7:10] 3 Period+Flags Hundreds digit = period (e.g. "160"=P1, "260"=P2, "360"=P3)
... ... Padding (unused)
[last] 1 ETX 0x03
Clock Format: BCD-like packed digits - "1000" = 10:00, "959" = 9:59, "900" = 9:00, "859" = 8:59 (rolls over at century boundaries)
Period: Encoded in C packets (not H packets) at bytes [7:10]. The hundreds digit is the period number.
Position Length Field Format
-------- ------ ----- ------
[0] 1 STX 0x02
[1] 1 Type 'H' (0x48)
[13:15] 2-3 Home Score ASCII digits
[29:31] 2-3 Away Score ASCII digits
[45:46] 1 Period ASCII digit
[52:56] 4 Home Penalty 1 ASCII "MMSS"
[57:61] 4 Home Penalty 2 ASCII "MMSS"
[62:66] 4 Away Penalty 1 ASCII "MMSS"
[67:71] 4 Away Penalty 2 ASCII "MMSS"
[79] 1 ETX 0x03
Note: The "unknown" regions between fields may contain shots on goal, timeouts, or sport-specific data depending on the board type (40+ types supported by the MP-70).
Position Length Field Format
-------- ------ ----- ------
[0] 1 STX 0x02
[1] 1 Type 'H' (0x48)
[2:6] 4 Clock ASCII BCD digits
[13] 1 Home Score ASCII digit (single)
[16:18] 2 Home Pen1 Player Jersey number (ASCII)
[19:22] 3 Home Pen1 Time BCD seconds ("100"=1:00, "059"=0:59)
[22:24] 2 Home Pen2 Player Jersey number (ASCII)
[25:28] 3 Home Pen2 Time BCD seconds
[39] 1 Away Score ASCII digit (single)
[42:44] 2 Away Pen1 Player Jersey number (ASCII)
[45:48] 3 Away Pen1 Time BCD seconds
[48:50] 2 Away Pen2 Player Jersey number (ASCII)
[51:54] 3 Away Pen2 Time BCD seconds
[54] 1 ETX 0x03
Note: Period is NOT in the H packet in this format — it comes from C packets (bytes [7:10]). This layout was confirmed by analyzing 3,130 packets (167 unique H patterns) from a live game. See
docs/DEBUG_LOG_ANALYSIS_2026-02-16.mdfor the full analysis.
For debugging or reverse-engineering the MP-70 protocol:
MP-70 Controller Scoreboard Display
| |
| TX (Pin 3) ----------+---------------> RX
| |
| v
| [Snooper RX]
| USB-Serial Adapter
| (capture only)
Key Points:
- Only connect TX from MP-70 to your snooper's RX
- Do NOT connect your snooper's TX (passive listening)
- Connect GND between all devices
Linux:
stty -F /dev/ttyUSB0 9600 cs8 -cstopb -parenb raw
cat /dev/ttyUSB0 | tee capture.bin | hexdump -CWindows:
- TeraTerm: File > Log > Start logging (binary mode)
- PuTTY: Session > Logging > All session output
# View hex dump
hexdump -C capture.bin | less
# Find packet boundaries
hexdump -C capture.bin | grep "02.*03"SLAP/
├── deploy.py # Python deploy script
├── LICENSE # GPL-3.0 License
├── README.md # This file
└── src/
├── run.py # Main entry point
├── requirements.txt # Python dependencies
├── config/ # Configuration files
│ ├── default.json # Default config
│ └── roster.json # Team rosters
├── slap/ # Python package
│ ├── config.py # Config loader
│ ├── parser/ # MP-70 protocol decoder
│ ├── core/ # Game state & logic
│ ├── output/ # CasparCG & OBS clients
│ ├── simulator/ # Fake serial for testing
│ └── web/ # Flask dashboard
│ ├── app.py # API routes & Socket.IO
│ ├── templates/ # Dashboard HTML (index, docs)
│ └── static/js/ # Local JS libraries
├── templates/ # Broadcast overlay templates
│ ├── scorebug.html # Main scorebug
│ ├── css/
│ │ ├── scorebug.css
│ │ └── overlays.css
│ ├── js/
│ │ ├── scorebug.js
│ │ └── socket.io.min.js
│ ├── overlays/ # Individual overlay templates
│ │ ├── goal.html
│ │ ├── player.html
│ │ ├── goalie.html
│ │ ├── period.html
│ │ ├── intro.html
│ │ ├── stars.html
│ │ ├── powerplay.html
│ │ ├── shots.html
│ │ ├── penalty.html
│ │ ├── replay.html
│ │ └── ticker.html
│ └── Logos/ # Team logo files
└── docs/ # Reference docs (viewable at /docs)
├── MP-70_Manual.pdf
├── MP-70_Quick_Reference.pdf
├── SP-70_Statistics_Controller.pdf
├── pocgtfo-fairplay-reversing.pdf
├── PROTOCOL_NOTES.md
├── DEBUG_LOG_ANALYSIS_2026-02-16.md # Real hardware packet analysis
└── slap_debug_2026-02-16.log # Raw debug log from live game
🔌 Serial Port Issues
Permission denied (Linux):
sudo usermod -a -G dialout $USER
# Log out and back inAll packets "invalid":
- Try both baud rates (9600 and 19200)
- Enable debug logging:
slap start --debug - Start a serial recording from the web UI to capture raw data
- Toggle the VIDEO CHAR? setting on the MP-70 (try both YES and NO)
- Check which connector (CONN.1, CONN.2, CONN3&4) the cable is on
No data received:
- Verify the RS-232 cable is connected (not the 1/4" scoreboard jacks)
- Check cable: straight-through DB-9, pins 2 (RX), 3 (TX), 5 (GND)
- Try different USB port or USB-to-serial adapter
- Try both baud rates (9600 and 19200)
🎬 CasparCG Issues
Connection refused:
- Verify CasparCG server is running
- Check firewall settings
- Verify host and port in config
Template not updating:
- Verify template is loaded:
CG 1-10 INFO - Check channel/layer numbers match config
🖥️ Web Interface Issues
Page not loading:
- Verify SLAP is running:
./deploy.py status - Try different port:
./deploy.py start --port 8888 - Check firewall settings
🐍 Virtual Environment Issues
pip missing or broken:
./deploy.py update # Recreates venv if broken|
Core Systems
|
Web & API
|
Overlays (11 templates)
|
🔊 Audio & Media (Not Implemented)
- Goal horn audio playback
- Siren/buzzer sound effects
- PA announcement integration
- Video replay control (NDI/RTMP switching)
💾 Data & Storage (Partially Implemented)
- SQLite database backend ✅
- Game history & archive ✅
- Season player statistics ✅
- Roster import from CSV/Excel
- Historical game data CSV export
- Career statistics (multi-season)
🔐 Security & Multi-user (Not Implemented)
- User authentication system
- Role-based permissions
- API key management
📱 Extended Interfaces (Not Implemented)
- Mobile companion app
- Stream Deck native plugin
- Discord/Slack notifications
- Multi-game tournament mode
🔌 Future Hardware Support
- Daktronics All Sport 5000
- OES scoreboard protocol
- Generic protocol adapters
This project is licensed under the GNU General Public License v3.0.
See the LICENSE file for details.
Scoreboard Live Automation Platform
Built for hockey broadcast professionals 🏒