# X11 OBS Overlays (static)

Served at **https://overlay.x11-sports.com** via `npx serve` (see `ecosystem.config.js`).

## Local dev

From this folder (`overlay/`, not `overlay/overlay/`):

```bash
npm run dev
```

Opens **http://localhost:3000**. Set `VITE_OVERLAY_URL=http://localhost:3000` in `x11-sports/.env` and restart the React app so copy-links match.

Avoid bare `npx serve` without `-l 3000` — if port 3000 is busy, `serve` picks a random port (e.g. 64396) and admin copy-links will not match.

Do **not** use `serve -s` (single-page mode) — it serves `index.html` for missing files and tournament links would all jump to the scoreboard.

Extensionless paths (e.g. `/tournament/compact`) are rewritten to `.html` internally. Prefer **`.html` URLs** from the admin UI so behavior is obvious in OBS.

Always include query params (`matchId`, `auctionId`, `theme`, optional `api`). A path alone with no query will load an empty overlay.

## Correct URLs (copy from admin UI)

Examples (use `npm run dev` so the port is **3000**, matching `VITE_OVERLAY_URL`):

- `http://localhost:3000/tournament/compact.html?matchId=208`
- `http://localhost:3000/tournament/compact?matchId=208` (same page via rewrite)
- `http://localhost:3000/auction/summary.html?auctionId=1`

Avoid old paths like `/overlay/?matchId=…` — those only show the full scoreboard.

On `localhost`, the overlay auto-uses `http://localhost:5000` as the API (no `api=` query required). Restart the backend after CORS changes.

## OBS setup

- Browser Source size: **1920×1080**
- Background: transparent (default in all pages)
- One URL per overlay type = one Browser Source (toggle independently)

## Tournament (match)

| Page | URL |
|------|-----|
| Full scoreboard | `/tournament/scoreboard.html?matchId={id}&theme=classic` |
| Compact | `/tournament/compact.html?matchId={id}&theme=dark` |
| Minimal | `/tournament/minimal.html?matchId={id}&theme=light` |

Legacy: `/overlay/index.html?matchId={id}` redirects to the full scoreboard.

Polls `GET /api/matches/{id}/details` every 1.5s.

## Auction

| Page | URL |
|------|-----|
| Summary | `/auction/summary.html?auctionId={id}&theme=classic` |
| Live bid | `/auction/live-bid.html?auctionId={id}` |
| Banner / Booster / Penalty / Jodi / Fortune wheel | `/auction/{type}.html?auctionId={id}` |

- Summary: `GET /api/auctions/{id}/summary` (heartbeat 30s when socket connected, else 5s)
- Live bid: `GET /api/overlay/auction/{id}/live` (heartbeat 30s / else 1.5s)
- Activities: `GET /api/overlay/auction/{id}/activity` (heartbeat 30s / else 1s)

**Real-time:** each auction page connects to Socket.IO on the API host, emits `join:auction`, and refetches immediately on `overlay:activity`, `overlay:live`, or `auction:player_sold`.

## Query params

- `theme`: `classic` | `dark` | `light`
- `api`: backend origin for local dev (e.g. `http://localhost:5000`)

## Admin UI

Configure themes and copy links from the main app:

- Tournament: Ultimate → Live step
- Auction: Auction panel → OBS overlays
