Lightshow Editor

Lightshow Editor

The Lightshow Editor is a visual node-graph tool for authoring light shows — animations that drive the cabinet’s LED layouts. You wire a dataflow graph from sources (colors, gradients, noise, images, oscillators) through transforms and compositors, bind the result onto one or more named layouts, and watch it animate in a built-in preview.

Each saved program is a named show with a clock mode: ambient (runs continuously) or clip (a fixed duration, optionally looping). See Node Editor Basics for the shared canvas gestures.

Working with shows

The toolbar’s Show section manages whole shows:

  • A show picker dropdown lists every show as name (mode); picking one loads its graph. A mode badge shows the active show’s mode.
  • New… creates a show — name and mode, plus duration/loop for clip shows.
  • Meta… edits the active show’s mode, duration, loop, and seed.
  • Delete show removes the whole show after a confirmation (it can’t be undone), then loads the next remaining show.

Managing shows needs the live engine; in sample mode you can still build a graph, but show create/switch is unavailable.

The node palette

The Add node palette groups the available kinds by category — rendered in the order Sources → Transforms → Composite → Feedback → Inputs → Outputs — with a legend chip per category:

  • Sources ✦ — Solid, Gradient, Noise, Image, Sprite, Video, LFO (a low-frequency oscillator control value), Time (show time as a control value).
  • Inputs ⊚ — Variable, a game-state variable surfaced as a control value.
  • Transforms ∿ — Colorize, Swatch (sample a palette at a scalar position), Levels, Threshold, Gain, Hue Shift, Warp, Blur, Remap, Mask, and Trim (scale the brightness of just the light devices you name — by device or tag — leaving the rest untouched; its brightness is modulatable).
  • Composite ▤ — Blend (two fields) and Layer (stack any number of fields with a shared blend mode).
  • Feedback ↻ — Feedback (blend the previous frame back in for trails) and Decay (a release envelope over a scalar field).
  • Outputs ◍ — the one entry you don’t place from here: an output is a binding authored by right-clicking a node (see Driving a layout), so the palette parks Output under Show unavailable, greyed with a note naming that gesture instead of offering a node that can’t work.

Ports are shape-coded by data type (for example a filled circle is a color field, a hollow circle a scalar field), so you can read a graph’s dataflow at a glance. Wiring is type-checked — a single scalar value does not feed a scalar field (a per-LED buffer), and no coercion happens.

Editing parameters and modulation

Basic params (numbers, sliders, toggles, selects) edit inline on the node. Rich params (color, palette, asset reference, expression) show an inline button — color and palette buttons lead with a live swatch — that opens an overlay editor. A modulatable param gains an extra ƒ button that opens Modulate…, where you drive it with a cade expression over var.* or wire it from another node’s output.

Driving a layout

A show lights nothing until something drives a layout. Right-click any node that produces a color field and choose “Drive a layout target…” — the form offers the table’s declared layouts as targets plus the compositor controls (blend mode, opacity, priority), with the defaults and blend-mode list read from the engine. Binding draws a → layout sink box after the node on the canvas; running the gesture again on an already-bound node retargets it rather than adding a second binding.

The target list ends with + New layout…, so a show can drive a layout the table doesn’t declare yet without hand-writing it first. Picking it opens a small New layout form asking for a name and a placement modePlayfield position (the layout mirrors where its member lamps sit) or Chain order (an LED strip, evenly spaced) — and on Create the layout is made and the binding lands on it in one gesture. Two things worth knowing before you name one:

  • The name is permanent: shows reference a layout by name, so there is no rename. The engine also owns the naming rules — an invalid or duplicate name is refused, with the reason shown in the toolbar status line, and nothing is bound.
  • A brand-new layout has no member lamps yet, so a show bound to it won’t light anything until lamps are mapped into it.

Creating a layout is an engine write, so the + New layout… entry only appears when the live engine is reachable.

The sink box is a live handle on the binding. Right-click it for:

  • Retarget… — re-point the same node at a different layout.
  • Remove binding — drop the binding while keeping the node and its wires.

Deleting a node that drives a layout also removes its binding — a status line in the toolbar names the target(s) that came unbound so the loss is visible, and undo restores both. Until the show drives something, a persistent notice reads “Nothing is driving a light yet” and names the gesture. The same check follows you out of the editor: a show that drives nothing is flagged in the table page’s diagnostics too, so a lamp bound to an empty show doesn’t dead-end silently.

Which lights a show can drive

Every light on the table is addressable — a GI insert, an RGB insert, and a spotlight alike. A spotlight’s cone, its visible beam, and its housing all follow the colour the show puts on it, exactly as an insert does, so there is no separate class of fixture to think about when you author.

What differs is which ones the harness nags you about. The unbound-lamp warning asks whether a light visibly wants driving — that is, whether it rests below full illumination. A GI insert sitting at full brightness is already lighting the playfield and is not flagged; a lamp or spotlight whose rest brightness is 0 sits dark until a show drives it, and that is exactly the one worth telling you about.

Live preview

A small LED preview panel renders the show’s real per-LED output and animates it live — a generative show plays here as you build it. The preview follows the first output binding’s target layout, so a show needs a driven layout for anything to appear. With no engine or no active show it shows a dark “no output” state.

Following the 3D selection

With Follow 3D selection on (an Options-menu toggle), selecting a light-bound device in the Object Editor correlates and highlights the matching lamp nodes here. You can also jump straight in from the object editor’s right-click Open in editor ▸ Light editor ◐ deep-link, which opens the lightshow editor focused on the device you came from.

Accessibility: colorblind-safe palette

The ⚙ Options menu has two persisted toggles: Colour-blind-safe palette and Output-colour preview. The palette toggle only changes node/port colors (swapping to an Okabe–Ito colorblind-safe set) — it never hides or reveals nodes. Categories stay distinguishable by glyph, label, and port shape in either mode.

Live vs. sample

Backed by the live engine, the editor reads the real node catalog, lists and loads authored shows, and persists every edit through a read-after-write loop (a rejected edit reverts with the reason shown in a red banner). Those edits also survive a reload and sync live to other open windows on the same table.

If the engine can’t be reached the editor falls back to a bundled catalog and a blank document: you get the full palette and can build freely, but edits stay in your browser and show management is unavailable — an empty show picker is the clearest sign you’re in that state.

Picking assets

An asset param on a node — the file behind an Image, Sprite, or Video source — has a Browse… button that opens the asset browser as a picker rather than asking you to type a path.

This picker is narrower than the object editor’s Bind asset…, deliberately. Every lightshow asset param is a visual source, so Browse… lists uploaded images only: no audio, no models, and none of the live table’s own families. You can still type a name or path into the field by hand if what you want isn’t an uploaded image.