Overview

When you need to write more complex conditions or expressions than is possible with just the COGS UI tools, you can use "Computed Conditions" or "Computed Values".

COGS 5.7 and above

As of COGS 5.7, Computed Values are written in ECMAScript 2023 (a.k.a. JavaScript).

COGS 5.6 and below

COGS 5.6 and below uses JEXL, a JavaScript-like expression language. For JEXL documentation click here.

Migration

If you're migrating an existing project from COGS 5.6 or below see Migrating from JEXL.

Getting started

Anywhere it’s possible to use Computed Values or Computed Conditions, when you switch away from the UI template, the code input box will be populated with the code that is being used under the hood when using the UI tools. This is a good way to get started in understanding how to write Computed Values and Computed Conditions.

For example:


becomes

Examples

Version Expression
5.7 → pre_show.in_progress Pre-show phase is in progress
5.7 → scene.variables.score.value * 10 The player’s score multiplied by 10
5.7 → !this.value Invert on/off value

Computed Conditions vs Computed Values

There are two main places Computed Conditions and Computed Values can be used and they have slightly different uses:

Computed Conditions

Computed conditions are in the WHEN of a behaviour, in the condition section of an IF/THEN/OTHERWISE, or in a LOOP. You should write an expression that evaluated to true or false. In the case of a WHEN condition, the behaviour will run when the condition returns true but was previously false.

Computed Values

When writing computed values to display as values (such as in a scene dashboard widget), you should write an expression that returns a value of the correct type. e.g. for a “Text widget” on a dashboard, the expression should return a string type.

Syntax

COGS computed values are written in ECMAScript 2023 (a.k.a. Javascript).
All computed values must be synchronous. i.e. async/await and Promise are not supported.

ECMAScript/Javascript is widely used, for example in your web browser, and there are many resources for learning. We recommend starting with W3Schools or MDN Web Docs.

Global Values

When writing a computed value, COGS makes globals values available which allow you to refer to channels values, scene variables, etc.. What exactly is available is tied to the context, e.g. In a "Scene" behaviour you have access to scene with the current scene's context.

Version Value Type Description Availability
4.7 → this User Value The value being set When updating a value
pre_show.in_progress Boolean True if currently in pre-show
4.11 → channels.KEY User Value The current value of channel KEY
4.11 → devices.NAME.config.KEY Boolean, String, or Number Config Value of KEY for device NAME (Only custom Media Master)
4.11 → devices.NAME.event.KEY User Value or {} Event value of KEY received from device NAME (Only custom Media Master)
4.12 → devices.NAME.state.KEY User Value Value of state with KEY sent to device NAME (Only custom Media Master)
5.4 → devices.NAME.connected Boolean Whether the device NAME is currently connected to COGS
4.7 → audio.FILE.playing Array of Media Locations An array of outputs the audio FILE is playing on
e.g. ["local:audio_player", "remote:My Speaker"]
4.7 → audio.FILE.paused Array of Media Locations An array of outputs the audio FILE is paused on
4.7 → audio.FILE.stopped Array of Media Locations An array of outputs the audio FILE is not playing on
4.7 → video.FILE.playing Array of Media Locations An array of outputs the video FILE is playing on
e.g. ["local:audio_player", "remote:My Screen"]
4.7 → video.FILE.paused Array of Media Locations An array of outputs the video FILE is paused on
4.7 → video.FILE.stopped Array of Media Locations An array of outputs the video FILE is not playing on
4.9 → osc.message?.address String Address of the OSC message received
e.g. "/foo/bar"
4.9 → osc.message?.arguments Array of number, string, or boolean Arguments of the OSC message received at the address
e.g. ["one", 2]
4.11 → plugins.ID.config.KEY User Value Config value of KEY for plugin with ID Custom plugin enabled
4.11 → plugins.ID.event.KEY User Value or {} Event value of KEY received from plugin with ID Custom plugin enabled
Plugin event received
4.12 → plugins.ID.state.KEY User Value Value of state with KEY sent to plugin with ID Custom plugin enabled
5.0 → midi.commands.note_off 8 Number constant of the "note off" MIDI command. MIDI plugin enabled
5.0 → midi.commands.note_on 9 Number constant of the "note on" MIDI command. MIDI plugin enabled
5.0 → midi.commands.key_pressure 10 Number constant of the "key pressure" MIDI command. MIDI plugin enabled
5.0 → midi.commands.control_change 11 Number constant of the "control change" MIDI command. MIDI plugin enabled
5.0 → midi.commands.program_change 12 Number constant of the "program change" MIDI command. MIDI plugin enabled
5.0 → midi.commands.channel_pressure 13 Number constant of the "channel pressure" MIDI command. MIDI plugin enabled
5.0 → midi.commands.pitch_bend 14 Number constant of the "pitch bend" MIDI command. MIDI plugin enabled
5.0 → midi.message?.device_id String The ID of the MIDI input device which we have received a message from MIDI plugin enabled
MIDI message received
5.0 → midi.message?.type "channel", "sysex", or "system" Type of MIDI message that has been received MIDI plugin enabled
MIDI message received
5.0 → midi.message?.command Number The command number for the message that has ben received. Can be compared with the number constants in midi.commands. 8 to 14 for "channel", 240 for "sysex", and 244 to 255 for "system" MIDI plugin enabled
MIDI message received
5.0 → midi.message?.data Array of Numbers Data for the MIDI message that has been received. What these mean will change based on the command and type MIDI plugin enabled
MIDI message received
5.0 → midi.message?.channel_number Number Only given when midi.message.type is "channel". Number from 1 to 16 MIDI plugin enabled
MIDI message received
5.0 → midi.message?.channel_index Number Only given when midi.message.type is "channel". Number from 0 to 15 MIDI plugin enabled
MIDI message received
5.0 → midi.message?.manufacturer_id Array of Numbers Only given when midi.message.type is "sysex". Is an array of either 1 or 3 numbers which identifies the manufacturer of the system extension MIDI plugin enabled
MIDI message received
5.0 → midi.message?.is_msc Boolean Only given when midi.message.type is "sysex". Will be true when the message is detected as being an MSC message MIDI plugin enabled
MIDI message received
5.0 → midi.message?.raw Array of Numbers The raw bytes of the entire MIDI message received MIDI plugin enabled
MIDI message received
4.13.6 → timer.duration Number Total duration in ms of the timer configured in the Timer plugin Timer plugin enabled
4.13.6 → timer.remaining Number Time in ms remaining on the timer
Cannot be used to trigger a behaviour
Timer plugin enabled
5.0 → zigbee.devices.NAME.address String The network address of the Zigbee device for device NAME Zigbee plugin enabled
5.0 → zigbee.devices.NAME.state.KEY Boolean, String, or Number The value of state with KEY for Zigbee device NAME Zigbee plugin enabled
5.0 → zigbee.devices.NAME.action String The action just received for Zigbee device NAME Zigbee plugin enabled
Zigbee action received
4.12 → show.time_elapsed Number Time in ms since the show started
Cannot be used to trigger a behaviour
Show
show.in_progress Boolean True if currently in a show Show
show.finished Boolean True if currently finished show Show
show.cancelled Boolean True if currently cancelled show Show
show.variables.KEY User Value The show variable KEY Show
show.values.KEY Return value of expression Current value of show value KEY Show
4.13 → scenes.NAME.* See scene.* below Refers to another scene in the project with NAME Show
scene.in_progress Boolean True if scene is in progress Scene
scene.finished Boolean True if scene is finished Scene
scene.skipped Boolean True if scene is skipped Scene
scene.cancelled Boolean True if scene is cancelled Scene
scene.variables.KEY User Value The value of scene variable KEY Scene
scene.values.KEY Return value of expression Current value of scene value KEY Scene
5.6 → when.* Global Values A copy of all Global Values when the “WHEN” condition of the behaviour was triggered. See below for details. Behaviour actions

when Context

In behaviour actions, the global values for when a behaviour was triggered is available to the actions that run within that behaviour, prefixed with when..

For example, if you have a behaviour which is triggered when an OSC message is received, you can access the OSC message inside the behaviour actions with when.osc.message.*.

when. is only available inside behaviour actions (anything after the "DO..."). when. is not available inside the behaviour trigger condition (the "WHEN...") or for computed values.

Utility Functions

As well as the standard ECMAScript/Javascript functions, COGS includes several built-in functions for manipulating values. These are available in all contexts.

Version Transform Description Example Result
5.7 → count(items, value) How many items of given value are in the array count([1,1,2,3,1], 1) 3
5.7 → pickRandom(items) Pick a random item from an array pickRandom(["A","B","C"] "A", "B" or "C"
5.7 → randomValue(userValue) Pick a random value for the given User Value randomValue(this) Any valid value
5.7 → randomValue(userValue, { differentValue: true }) The same as randomValue but chooses a value that is not the current value randomValue(this, { differentValue: true }} Any valid value
5.7 → matchesOscAddress(string, pattern) Match the OSC address pattern matchesOscAddress("/foo/1", "/foo/[0-9]") true

User Values

User values allow you to access metadata about the underlying value.

On/Off

Key Required Value
type "boolean"
value Boolean value

Text

Key Required Value
type "string"
value String value

Number

Key Required Value
type "number"
value Number value
min 𐄂 Minimum allowed value (inclusive)
max 𐄂 Maximum allowed value (inclusive)
integer 𐄂 true if only whole numbers are allowed, otherwise false

Option List

Key Required Value
type "option"
options Array of all possible string values
value String value, always one of options

Media Locations

Media locations are strings that represent the local machine or a Media Master.

Local audio output is represented as local:audio_player.
Remote media outputs are represented as remote:NAME where NAME is the name you have given the Media Master.

Migrating from JEXL

Upgrading your project to COGS 5.7 will automatically convert JEXL Computed Values and Computed Conditions to ECMAScript. When writing new Computed Values and Computed Conditions, keep in mind you are now writing ECMAScript.

Many of the JEXL operators in COGS 5.6 can be written simply in vanilla ECMAScript. For example:

JEXL (COGS 5.6) ECMAScript (COGS 5.7)
x | length x.length
x ^ 2 Math.pow(x, 2) or x ** 2
x | round Math.round(x)
x | floor Math.floor(x)
x | ceil Math.ceil(x)
x | abs Math.abs(x)
x | min Math.min(...x)
x | max Math.max(...x)
x | all(1) x.every((item) => item == 1)
x | toJSON JSON.stringify(x)
x | fromJSON JSON.parse(x)
x[.key == 3] x.filter(({key}) => key == 3)
devices.foo.event.press.value devices.foo.event.press?.value
Important: press may be undefined
plugins.foo.event.press.value plugins.foo.event.press?.value
Important: press may be undefined
osc.message.arguments[0] osc.message?.arguments[0]
Important: message may be undefined

Some JEXL utilities COGS 5.6 have been ported to ECMAScript. See Utility Functions.

JEXL (COGS 5.6) ECMAScript (COGS 5.7)
x | count(true) count(x, true)
x | pickRandom pickRandom(x)
x | randomValue() randomValue(x)
x | matchesOscAddress("/foo/[0-9]") matchesOscAddress(x, "/foo/[0-9]")

Automated Migration

When upgrading your project to COGS 5.7, all JEXL Computed Values and Computed Conditions will be automatically converted to ECMAScript.

⚠️ Exceptions

JEXL supports indexing into the first object in an array by omitting the [0]. e.g:

[{ foo: 1 }, { bar: 2 }].foo // 1

is equivalent to:

[{ foo: 1 }, { bar: 2 }][0].foo // 1

However this is not the case using ECMAScript (COGS 5.7 and above). In ECMAScript will be undefined because foo is not a property of an array:

[{ foo: 1 }, { bar: 2 }].foo // undefined

During automatic migration COGS will not insert the [0] because the functionality may be ambiguous depending on the data. In this case COGS will leave the computed value as [{ foo: 1 }, { bar: 2 }].foo and you may need to check your expression logic is correct after upgrading your project.