init: initial commit
- ticker / QR ad overlay / break slide graphics (1920×1080) with all geometry derived from one shared module (src/shared/obs-geometry.mjs) - OBS scene-collection generator (scripts/generate-obs-scenes.mjs) and a read-only in-dashboard setup verifier, both driven by the same module - en/sr dashboard i18n selected via bundle config; configschema.json with neutral first-run defaults seeded from optional branding config - install.sh / systemd user service / update.sh for venue deployment - reference OBS scene collection + profile from a real venue as fixtures
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
# 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.
|
||||
- **Choreography / OBS** — connection status, mode/phase badges, countdown to
|
||||
the next automatic transition, timing configuration, break-slide content,
|
||||
and manual controls: show ad now, skip ad, break toggle.
|
||||
- **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)
|
||||
Reference in New Issue
Block a user