Naar inhoud
Inloggen

/docs · CueLab · Deep

Cuelijst-data ontwerpen die een reorganisatie overleeft

Een cuelijst is eerst een datamodel en pas daarna een UI. Behandel hem ook zo.


De meeste cuelijst-software behandelt de cuelijst als een UI-artefact: een tabel in spreadsheet-stijl waarin elke rij een cue is, elke kolom een eigenschap, en de gebruiker tekst in cellen typt. Dat werkt prima totdat je de show wilt herordenen, het script wilt vertakken, cues wilt delen met een andere operator of wilt migreren naar een ander hulpmiddel.

Een cuelijst die eerst als datamodel is ontworpen (waarbij de UI de projectie is en niet de bron van waarheid) overleeft al die bewerkingen probleemloos. Hier is het schema dat werkt.

De minimaal levensvatbare cue

interface Cue {
  id: string;              // stable, never changes
  index: number;           // display position; can change
  type: CueType;           // 'audio' | 'video' | 'lighting' | 'scene' | 'note'
  label: string;           // human-readable name
  description?: string;    // longer note for the operator
  duration?: number;       // seconds, optional
  trigger: TriggerSpec;    // when to fire
  payload: unknown;        // type-specific data
}

Vijf velden verdienen hun plek:

  • id: een UUID of korte string. Stabiel bij hernoemen, herordenen en bewerken. Verwijzingen tussen cues gebruiken de id, nooit de index.
  • index: de weergavevolgorde. Verandert voortdurend. Behandel dit nooit als identiteit.
  • type: het soort cue. Wordt door de UI gebruikt om naar de juiste renderer te routeren.
  • trigger: wanneer de cue afgaat. Zie hieronder.
  • payload: alles wat typespecifiek is. Audiocues dragen bestandspaden en niveaus; lichtcues dragen kanaal/waarde-paren.

Triggers als somtype

Een cue kan afgaan op:

type TriggerSpec =
  | { kind: 'manual' }                                  // operator hits GO
  | { kind: 'after'; previousId: string; delay: number } // chained
  | { kind: 'absolute'; t: number }                      // at clock time t
  | { kind: 'timecode'; t: number }                       // at SMPTE/MIDI time
  | { kind: 'event'; eventName: string };                 // external signal

De meeste apps herleiden alle triggers tot “manual” omdat de UI de rest niet ondersteunt. Zodra je triggers als een volwaardig somtype codeert, kun je geketende reeksen, tijdgebonden cues en event-gestuurde cues bouwen zonder de UI voor elk daarvan te wijzigen.

Waarom dit ertoe doet: het reorganisatieprobleem

De meest voorkomende faalwijze in cuelijst-tools is de reorganisatie. Je besluit scène 3 te verplaatsen naar na scène 5. In een UI-first tool sleep je de rij naar beneden. In een data-first tool verwissel je de indices.

Nu: wat met al die verwijzingen? Als cue 17 (“muziek uitfaden aan het einde van scène 3”) naar cue 12 verwijst via de index, dan heeft jouw verplaatsing die zojuist gebroken. Als hij verwijst via de id, dan is de verplaatsing een no-op voor de keten: cue 17 gaat nog steeds af na cue 12, ongeacht waar ze in de weergavevolgorde belandden.

Dit is het soort dingen dat je 10 minuten voor showtime te grazen neemt. Door het schema rond stabiele ids te bouwen, elimineer je een hele klasse incidenten.

Versiebeheer

Elke cuelijst heeft een versie nodig. Een nieuw triggertype toevoegen zou oude bestanden niet mogen breken; er een verwijderen zou ze niet stilletjes mogen corrumperen. Het pragmatische patroon:

{
  "schemaVersion": 2,
  "cues": [ ... ],
  "metadata": { ... }
}

En in je loader:

function loadCueList(json: unknown): CueList {
  const v = (json as { schemaVersion?: number }).schemaVersion ?? 1;
  if (v === 1) return migrateV1ToV2(json as CueListV1);
  if (v === 2) return json as CueListV2;
  throw new Error(`Unknown cue list schema version: ${v}`);
}

De 10 minuten die je nu aan migratie besteedt, besparen je later 10 uur “we kunnen het bestand van de vorige show niet openen”.

Wat er in metadata thuishoort

Dingen die geen cues zijn maar wel van belang zijn voor de show:

  • Naam van de show, datum, operator(s)
  • Standaard audio-device-ID’s (zodat de cuelijst probleemloos opent op een andere machine)
  • Globale regels (bijv. “alle cues faden in 200ms in tenzij anders aangegeven”)
  • Tags / categorieën die in deze show worden gebruikt

Houd payload-gegevens buiten metadata. Als het per cue is, hoort het thuis in de cue.

Waarom niemand dit doet

De meeste cuelijst-tools zijn een spreadsheet plus een Go-knop. Ze werken omdat shows grotendeels lineair zijn, faalwijzen operator-gestuurd zijn, en de gebruikersgroep klein genoeg is dat een robuust schema geen concurrentievoordeel oplevert.

CueLab’s standpunt is dat dit op zijn kop staat. Het schema is het product; de UI is de projectie. Zodra het datamodel solide is, kun je de Go-knop op vijf verschillende manieren bouwen (voor een streamer, voor een podcastproducer, voor een live-eventteam) zonder de fundering te herschrijven.

Dit is het saaie, belangrijke werk dat het verschil maakt tussen een tool die je voor één show gebruikt en een die je tien jaar gebruikt.

Verwant