Skip to content

How a Show Is Built

What it hears

Beats and sections are a skeleton. A show built on those alone changes when the arrangement changes and sits still through everything in between — which is most of the record. So the analyser also extracts what the song is playing:

What it findsWhy it is reported that way
ChordsTriads per beat, reported as changes onlyA show acts on the change; an ambiguous beat holds rather than flickering
MelodyThe tune as note eventsWith a sub-octave penalty — without it the tracker follows the bass up whenever the tune rests, and fills every silence with a phantom note
PhrasesNotes grouped into breaths, with the direction of the lineThe gap that ends one is measured in beats, because half a second is nothing at 90bpm and two beats at 160
RepeatsWhere the chorus comes backDeliberately coarse — that is the repetition a show should answer
HitsEach accent, ranked, and which drum it wasA kick and a snare can then be on different lights

Every extractor has a floor below which it says nothing. A confident answer where the audio holds none is the one failure that cannot be recovered downstream.

Four layers, on different lights

A bulb runs one waveform at a time. That is physics, not taste — so two effects overlapping on one fixture means the later one cancels the earlier, and from a sofa that reads as an effect that mysteriously does nothing.

So the automatic show claims whole roles for each layer:

LayerWhat it doesTypically
GroundHarmony, seconds long — the only layer allowed to feel like fadingCandles, strip
PulseThe beat, as a strikeFill
HitsKick and snare, separatelyAccent, mover
VoiceThe melody, placed by pitchKey

A layer only splits a role by naming individual bulbs when it has nowhere else to go — which is what a designer does with six lamps and four ideas.

Swells and strikes

Most lighting effects are swells: they travel smoothly up to a level and smoothly back. That is what “just a bunch of fading lights” describes, and for a long time it was every rhythmic effect BRight had.

A strike is the other half — a jump to the peak with no fade, followed by a saw wave travelling down. A fade still in flight would start the decay from somewhere between the two and lose exactly the attack.

The beat pulse used to peak on the off-beat

A LIFX waveform runs between the bulb’s current colour and the packet’s. A sine anchored on the beat is therefore at the existing level there, and brightest half a period later — so the one effect whose entire job was “the beat” was inverted in every show BRight ever compiled, from the first release. Every shape now declares where in its cycle it is brightest, and the wave starts far enough ahead to land the peak on the moment.

The script is the show

Every compiled show mirrors its script to /config/.bright/shows/, because /data is invisible to Home Assistant and a file nobody can open is not editable.

A script is scenes, each holding effects, plus moments that pin an effect to an instant. There are 22 effect types — wash, fade, build, pulse, strobe, chase, sweep, breathe, sparkle, colour_cycle, rainbow, theater, stab, blackout, melody, harmony, colour_drift, saturate, level, hit, accent, aux.

An effect names a selection (ids, roles, zones, exclude) and everything it does not name is untouched — which is the whole reason a show is built from effects rather than scenes. Most of the room is usually meant to stay still.

Parameters are clamped, never rejected. These files are typed by hand, and a show that refused to compile over depth: 1.2 would be a worse tool than one that reads it as 1.

The mirror is a copy, and the copy is not the record

Editing the mirrored file changes nothing until you import it back. A half-typed JSON file being picked up by a party at 11pm is not a feature. A broken one is reported with the JSON parser’s own line number — the single most useful sentence you can hand somebody who has just edited a thousand-line file.

The editor shows you what it compiled

Not a description of it — the compiler’s own walk. The same code that renders a show to packets renders it to preview frames, so the picture cannot disagree with the room.

Three lanes ride on the waveform’s own ruler: chords as labelled blocks, the melody as a contour against the track’s own pitch range, and the drums with the kick low and the rest high. Underneath, one row per effect — built from the walk rather than the script, which is what tells “this effect produced nothing” apart from “this effect is fine”.

What is left below that is the exceptions: an effect that drives no lights, one whose analysis is too old, one whose waveform another cancels. When the show is fine, that block is empty.

Many shows, one that plays

Every compile is a new version, and one of them is live. Asking the director to try again does not destroy the show you spent an evening editing — naming a version pins it, and the prune eats the oldest unnamed ones and never the live one.

Services

ServiceWhat it does
bright.party_modeStart a party — everything optional, merged over a saved party’s settings
bright.start_partyStart a named saved party. Requires the name, so a typo fails loudly rather than quietly playing the default folder
bright.start_showOne track
bright.stop_showStop, and put the room back

“Back” is not always where it was

Restoring the pre-show snapshot is right when the show interrupted an evening, and wrong at 1am — what people want then is a scene they already have. A party can name one, and it is called instead of restoring. A scene that fails to run falls back to the snapshot, so the room never keeps the party colours.