2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00
2026-07-15 19:30:32 +02:00

nodecg-venue-gfx

Broadcast graphics for a venue screen, as a NodeCG 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):

curl -fsSLO https://git.dvdrw.dev/kckljajicevo/nodecg-venue-gfx/raw/branch/master/scripts/install.sh
bash install.sh

Into an existing NodeCG install:

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).
  2. Set up OBS: npm run obs:scenes -> import -> done. Details in 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. 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 — 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 — 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

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

S
Description
NodeCG bundle for live venue single-screen broadcast graphics
Readme AGPL-3.0 336 KiB
Languages
TypeScript 71.8%
JavaScript 15.9%
Shell 6.7%
CSS 4%
HTML 1.6%