158 lines
6.6 KiB
Markdown
158 lines
6.6 KiB
Markdown
# nodecg-venue-gfx
|
||
|
||
Broadcast graphics for a venue screen, as a [NodeCG](https://nodecg.dev) 2
|
||
bundle: an always-on scrolling ticker with operator-added TTL messages,
|
||
corner-alternating ads that shrink the live program into a corner, a break
|
||
announcement slide, and automated + manual OBS scene choreography over
|
||
obs-websocket. Built for festivals and concerts; generic enough for any
|
||
single-screen show.
|
||
|
||
- All on-screen text is edited live from the dashboard
|
||
- Support for multiple locales
|
||
- OBS setup is generated. One script emits an importable scene collection, and a
|
||
dashboard panel verifies a live OBS against the exact geometry the graphics
|
||
render from.
|
||
- If OBS dies mid-show, the scheduler keeps running and re-applies the right
|
||
scene the moment OBS comes back. If NodeCG dies, restart it and it comes back
|
||
in live mode with all content intact.
|
||
|
||
## Quick start
|
||
|
||
**Fresh venue machine** (installs NodeCG + this bundle + config + OBS scene
|
||
collection in one go):
|
||
|
||
```sh
|
||
curl -fsSLO https://git.dvdrw.dev/kckljajicevo/nodecg-venue-gfx/raw/branch/master/scripts/install.sh
|
||
bash install.sh
|
||
```
|
||
|
||
**Into an existing NodeCG install:**
|
||
|
||
```sh
|
||
cd <nodecg>/bundles
|
||
git clone https://git.dvdrw.dev/kckljajicevo/nodecg-venue-gfx.git
|
||
cd nodecg-venue-gfx
|
||
npm ci && npm run build
|
||
```
|
||
|
||
Then:
|
||
|
||
1. Write `cfg/nodecg-venue-gfx.json` (see
|
||
[docs/examples/cfg.example.json](docs/examples/cfg.example.json)).
|
||
2. Set up OBS: `npm run obs:scenes` -> import -> done. Details in
|
||
[docs/OBS-SETUP.md](docs/OBS-SETUP.md).
|
||
3. Start NodeCG (`node index.js` from the install root) and open the
|
||
dashboard at <http://localhost:9090>.
|
||
|
||
To run as a service that survives reboots: `scripts/install-service.sh`
|
||
(systemd user unit). To update later: `scripts/update.sh`.
|
||
|
||
## Configuration
|
||
|
||
`cfg/nodecg-venue-gfx.json` in the NodeCG install, validated against
|
||
[configschema.json](configschema.json). Everything is optional:
|
||
|
||
| Key | Default | Purpose |
|
||
| --- | --- | --- |
|
||
| `locale` | `"en"` | Dashboard language (`"en"` or `"sr"`) |
|
||
| `branding.tickerBlurb` | `"Welcome ♪"` | First-run seed for the recurring ticker blurb |
|
||
| `branding.breakHeading` | `"Stay tuned — there's more!"` | First-run seed for the break-slide heading |
|
||
| `branding.sampleQrUrl` | `"https://example.com"` | First-run seed for the sample ad's QR URL |
|
||
| `obs.enabled` | `false` | Connect to OBS and drive scenes |
|
||
| `obs.url` | `"ws://127.0.0.1:4455"` | obs-websocket URL |
|
||
| `obs.password` | `""` | obs-websocket password |
|
||
| `obs.scenes.*` | `MAIN`, `MAIN_AD_TR`, … | Names of the six driven scenes |
|
||
| `obs.transitions.*` | `Move`, `Stinger` | Names of the two transitions |
|
||
| `obs.sources.*` | `TickerOverlay`, … | Names of the shared sources/nested scenes (for the generator + verifier) |
|
||
|
||
`branding.*` values only seed the very first run — after that, everything is
|
||
edited from the dashboard and persists in NodeCG's database. Set
|
||
`obs.enabled: false` to develop without OBS; everything else keeps working.
|
||
|
||
## Dashboard panels
|
||
|
||
- **Ticker messages** — ticker settings (loop blurb, separator, default TTL,
|
||
speed) and message management; each active message shows a depleting fill
|
||
for its remaining time, with renew/remove/inline-edit.
|
||
- **Ads** — CRUD for ads (strip text, column text, column image from the
|
||
Assets dialog, QR URL, enabled), with a live QR preview per row. Each row
|
||
has a "Trigger now" button to force that specific ad onto air immediately
|
||
(enabled or not), bypassing the round-robin — disabled while an ad slot is
|
||
already showing.
|
||
- **Choreography / OBS** — connection status, mode/phase badges, countdown to
|
||
the next automatic transition, break-slide content, and manual controls:
|
||
show ad now (round-robin), skip ad, break toggle.
|
||
- **Timing** — the choreography timing settings: ad interval, ad duration,
|
||
break gap, break ad duration, ads per burst.
|
||
- **OBS setup check** — read-only verification of the live OBS against the
|
||
expected scenes/sources/transforms/transitions, with concrete fixes.
|
||
|
||
Images (ad backgrounds, column images, break background, act logos) are
|
||
uploaded through NodeCG's standard **Assets** dialog.
|
||
|
||
## Graphics (1920×1080)
|
||
|
||
| URL | Default OBS source | Purpose |
|
||
| --- | --- | --- |
|
||
| `graphics/ticker.html` | `TickerOverlay` | Bottom 96 px scrolling ticker |
|
||
| `graphics/ad.html` | `AdOverlay` | QR + headline in the gamma-shaped cutout |
|
||
| `graphics/break.html` | `BreakSlide` | Break announcement slide (ambient motion) |
|
||
|
||
The ticker uses a segment-queue marquee: loop content is snapshotted per
|
||
revolution, so adding/removing messages mid-scroll never causes visual jumps.
|
||
|
||
## Theming
|
||
|
||
- **Colors**: edit the `THEME LAB` block in
|
||
[`src/graphics/index.css`](src/graphics/index.css) — every brand color the
|
||
graphics use is a token there.
|
||
- **Fonts**: the `FONT LAB` block right above it (Margarine is bundled as the
|
||
default; drop a `.ttf`/`.woff2` into `src/graphics/fonts/` to swap).
|
||
- **Geometry** (canvas size, the 70% shrink, ad cutout, OBS transforms):
|
||
[`src/shared/obs-geometry.mjs`](src/shared/obs-geometry.mjs) — one module
|
||
shared by the graphics, the scene-collection generator, and the verify
|
||
panel, so they can never disagree. v1 is fixed at 1920×1080.
|
||
|
||
## Adding a language
|
||
|
||
1. Copy `src/i18n/en.ts` to `src/i18n/<code>.ts` and translate (the `Strings`
|
||
type keeps you honest).
|
||
2. Register it in `src/i18n/index.ts` (`locales`).
|
||
3. Add the code to the `locale` enum in `configschema.json`.
|
||
|
||
## Development
|
||
|
||
```sh
|
||
npm run dev # parcel watch + nodemon restarting NodeCG
|
||
npm run build # one-shot production build
|
||
npm run obs:scenes # regenerate the OBS scene collection
|
||
```
|
||
|
||
Dev mode assumes the bundle lives inside a NodeCG install
|
||
(`bundles/nodecg-venue-gfx`); `nodemon` runs `node ../../index.js`.
|
||
|
||
Rules of thumb:
|
||
|
||
- **Graphics/dashboard** changes: rebuild (or let the watcher do it), then
|
||
refresh the page / OBS browser source. No server restart.
|
||
- **Extension** (`src/extension/`), **types**, or **package.json** changes:
|
||
rebuild **and restart NodeCG** — plain `node index.js` never rebuilds
|
||
anything.
|
||
- Graphics are fixed 1920×1080 canvases — judge them in OBS or a fullscreen
|
||
1080p tab; smaller windows show a crop.
|
||
|
||
## Architecture notes
|
||
|
||
- The scheduler is a state machine over `(mode: normal|break, phase: live|ad)`
|
||
with exactly one pending timer; OBS calls are fire-and-forget, so an
|
||
unreachable OBS never stalls the choreography.
|
||
- Corner alternation and ad round-robin persist across restarts
|
||
(`schedulerState` replicant). On startup the bundle always returns to
|
||
(normal, live) + the main scene.
|
||
- Replicant defaults are only applied when nothing is persisted, so operator
|
||
edits survive restarts.
|
||
|
||
## License
|
||
|
||
[AGPL-3.0](LICENSE)
|