Skip to content

Scripting

Any cue can carry a small JavaScript program. It runs while the cue plays, and it can read and change what the cue is doing — the level of a sound, the words on screen, the colour of a picture.

  • api.md — everything a script can reach: log, time, every, after
  • properties.md — what each cue type exposes as this.<name>
  • examples.md — recipes to copy

Writing one

Select a cue, open the Script tab in the inspector, tick Enabled, and write. A new cue starts from this skeleton:

function onStart() {
    // Called when cue is starting
}

function onTick(delta) {
    // Called on every frame while the cue runs, delta in seconds
}

function onEnd() {
    // Called when cue is ending
}

All three hooks are optional. A script that only needs one declares only that one; a script that declares none is legal and does nothing.

Compiling

Press Compile (or Ctrl/Cmd+S in the editor) to check the script. The panel under the editor says what happened:

  • Successfully compiled — the source parsed, and it is the one the cue will run. The Compile button greys out until you change something.
  • Errors — the list of what went wrong, e.g. SyntaxError: Unexpected token '{'. The last source that compiled is kept, so a broken edit does not lose it.

Compiling checks the syntax without running the script, so pressing it is always safe.

A cue whose script is enabled and does not compile is marked Invalid in the cue list and will not play — the same treatment as an audio cue with no file. Switch the script off and the cue plays again, script and all its errors untouched.

When the hooks run

HookWhen
onStart()The moment the cue starts playing. After its delay, if it has one — a cue stopped while still waiting never starts its script.
onTick(delta)Once per engine frame while the cue plays. delta is the seconds since the previous frame.
onEnd()When the cue is released: it finished, it was stopped, or it is being restarted. Always exactly once, and always paired with the onStart that ran.

Which of these you get depends on how long the cue lives:

  • Cues that stay up (image, text, html, webcam, youtube, visio, screen, multilaunch, playlist) tick until something stops them.
  • Cues with a length (audio, video, fade, fadeall) tick until they end.
  • Fire-and-forget cues (osc, midi, mqtt, http, start, stop, stopall, loadshow) do their work and go. onStart and onEnd both run; there may be no ticks in between.

The script’s own state

Everything the script declares at the top level lives for as long as the cue runs, and the hooks share it:

let flashes = 0;

function onTick() {
    flashes++;
}

function onEnd() {
    log.info('flashed', flashes, 'times');
}

Two cues’ scripts never see each other’s variables, and a cue’s script starts from scratch on every run.

The source is compiled when the cue starts, so editing a script while its cue is playing changes nothing until the next start.

When a script goes wrong

A script is expected to be wrong sometimes, and nothing it does can take the show down:

  • A hook that throws is reported once in the browser console and then dropped for the rest of the run. The other hooks carry on, and the cue keeps playing.
  • A timer callback that throws is reported and dropped, and the hooks are left alone.
  • Anything the script writes is live only. It never touches the saved show.