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 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.