disguise developers

Designer Plugins

Plugins for Disguise Designer software.

Expressions in Disguise

This guide provides an overview of how to use expressions in Disguise to dynamically control layer properties. It covers both the expression syntax and how to apply expressions using the Python API.

For a complete reference on expression syntax and features in Designer, see the Expressions Overview in the Disguise User Guide.


Expression Syntax and Concepts

Expressions in Disguise are powerful tools for creating dynamic and automated visuals. They are evaluated on every frame and can control both numeric and text-based properties of layers.

The Default Expression: self

The self keyword is the default expression for any property. It represents the property’s current animated or keyframed value. You can use it as a base for more complex expressions. For example, self * 2 will double the original value of the property.

System Variables

Disguise provides several built-in variables that you can use in your expressions:

VariableDescription
selfThe original keyframed value of the property.
self.minThe minimum allowed value for the property.
self.maxThe maximum allowed value for the property.
timeThe current track time in seconds since the track started.

Common Functions

Expressions can use a variety of built-in functions to perform calculations and manipulate values. Here are some of the most common ones:

FunctionDescriptionExample
math.sin(x)Sine of x (radians)0.5 + 0.5 * math.sin(time * math.pi)
math.cos(x)Cosine of x (radians)math.cos(time * 2 * math.pi)
min(a, b)Returns the smaller valuemin(1, osc:fader1)
max(a, b)Returns the larger valuemax(0, self - 0.1)
lerp(a,b,t)Linear interpolation between a and b by t (0 to 1)lerp(0, 100, osc:fader1)
clamp(x,a,b)Clamps x between a and bclamp(osc:fader1, 0.1, 0.9)

Conditional Logic with if

You can use if statements to create conditional logic within your expressions. The syntax is if(condition, value_if_true, value_if_false).

ExampleDescription
if(osc:button1 > 0, 1, 0)If the value of osc:button1 is greater than 0, return 1. Otherwise, return 0. This is useful for creating a simple on/off switch.
if(time > 10, self, 0)If the track time is greater than 10 seconds, use the layer’s keyframed value. Otherwise, set the value to 0.
if(module:video.frameNumberDisplay < 50, 0, 1)If the current frame number of the “video” layer is less than 50, return 0. Otherwise, return 1. This can be used to trigger an event at a specific frame.

Advanced Concepts

Accessing Resources and Fields

You can access and manipulate almost any object in your Disguise project using expressions. These objects are referred to as “Resources”.

Identifying Resources

There are two primary ways to identify a resource:

  1. By Name: Use the type:name syntax. For example, projector:"projector 1" refers to a projector named “projector 1”. If the name contains spaces or special characters, it’s best to enclose it in quotes. If not, you can replace spaces and special characters with an underscore (_), like projector:projector_1.
  2. By UID: For a more robust reference that won’t break if the resource is renamed, you can use its Unique Identifier (UID). To get the UID, open the resource’s editor, right-click the title bar, and select “Copy UID”. Then, use the getByUID() function, like this: getByUID(0x123875234).

Accessing Resource Fields

Once you have a reference to a resource, you can access its properties (or “fields”) using the . operator. For example, to get the x position of a projector, you could use projector:projector_1.offset.x.

Here are some common fields:

FieldDescription
descriptionThe name of the resource as a string.
offsetThe position of the object relative to its parent (e.g., offset.x).
rotationThe rotation of the object relative to its parent (e.g., rotation.y).
scaleThe scale of the object relative to its parent (e.g., scale.z).

Note: If you try to access a field that is empty (or None), the expression will fail. You can use an if statement to check if a resource exists before trying to access its fields.

Accessing External Protocols

Expressions can directly access data from external protocols, allowing you to control your visuals with live inputs.

ProtocolSyntaxExample
OSCosc:/addressosc:/d3/helloworld
DMXdmx:universe.address or dmx16:universe.addressdmx:1.1 (8-bit) or dmx16:3.20 (16-bit)
MIDImidi:note or midi:ccmidi:60 (note C4) or midi:cc1 (mod wheel)

Referencing Other Layers and Properties

You can create powerful links between layers by referencing properties from other layers within an expression.

Note: When referencing a layer or resource with spaces in its name, you must replace the spaces with underscores (_). For example, a layer named “video effects” should be referenced as video_effects.

Layer Prefixes

Prefixes help to adapt values to a property’s expected range.

PrefixDescriptionExample
limit::Clamps the result to the property’s min/max range.limit::osc:fader1
scale::Scales a 0-1 input value to a property’s full min/max range.scale::osc:fader1

Data Types and Operators

Expressions support a variety of data types and operators for performing calculations and manipulating data.

Data Types

Data TypeDescriptionExample
NumberCan be an integer or a floating-point number.10, 3.14
StringA sequence of characters."hello", 'world'
BooleanCan be either True or False.True
VectorA 2D, 3D, or 4D vector.V2(1, 2)
ColourAn RGBA colour value.Colour(1, 0, 0, 1)

Operators

OperatorDescriptionExample
+Addition5 + 2
-Subtraction5 - 2
*Multiplication5 * 2
/Division5 / 2
==Equal tox == 5
!=Not equal tox != 5
<Less thanx < 5
>Greater thanx > 5
<=Less or equalx <= 5
>=Greater or equalx >= 5
andLogical ANDx > 0 and y > 0
orLogical ORx > 0 or y > 0
notLogical NOTnot z

Text Formatting

You can format strings within expressions using the format() function or the format:: prefix. This allows you to combine text with dynamic values.

The syntax for the format specifiers is %(flags)(width)(.precision)type.

Example with format() function:

format("Current time: %.2fs", time)

This will display the current time with two decimal places, followed by the “s” character (for seconds).

Example with format:: prefix:

format::"%.2f":time

This will achieve the same result as the format() function example.

Common Format Specifiers:

SpecifierDescription
dSigned integer decimal.
fFloating point decimal format.
sString (or any object, converted with str()).
xSigned integer hexadecimal.

Expression Variables

Variables are powerful tools for sharing values between multiple expressions and for breaking up complex expressions into smaller, more manageable parts.

Variable Definition

Variables can be defined in several ways:

Function Variables

You can create function variables that can be reused in multiple expressions. This is useful for abstracting complex logic. You can even pass parameters to these functions.

Example:

A function variable named maybe_override(value) with the expression if(osc:show.override, value, self) can be used on multiple layers. On one layer, you might use maybe_override(osc:show.field1), and on another, maybe_override(osc:show.field2).


Working with Expressions in Python

You can programmatically set and manage expressions on layer properties using the Disguise Python API. Expressions are typically applied to the FieldSequence of a property.

TaskPython
Set an expression on a layer propertylayer = track.layers[0]
seq = layer.findSequence("brightness")
seq.setExpression("self * 0.5")
This sets the brightness to half of its keyframed value.
Use time to create an animationlayer = track.layers[0]
seq = layer.findSequence("opacity")
seq.setExpression("0.5 + 0.5 * math.sin(time * math.pi)")
Creates a sine wave animation for the layer’s opacity.
Link one layer’s property to anotheremitter_layer = track.layers[0]
receiver_layer = track.layers[1]
receiver_seq = receiver_layer.findSequence("brightness")
receiver_seq.setExpression(f"module:{emitter_layer.name}.brightness")
Links the brightness of receiver_layer to emitter_layer. Using an f-string is a clean way to build the expression.
Set an expression on a text layertext_layer = track.layers[0]
seq = text_layer.findSequence("text")
seq.setExpression(f"'Current time: {time}'")
Displays the current time on a text layer.
Use conditional logic in an expressionlayer = track.layers[0]
seq = layer.findSequence("brightness")
seq.setExpression("if(time > 5, 1, 0)")
Sets the brightness to 1 if the time is greater than 5 seconds, otherwise it is 0.
Clear an expressionlayer = track.layers[0]
seq = layer.findSequence("brightness")
seq.setExpression("self")
Resets the expression to its default, using the keyframed value.
Incorporate external data (e.g., OSC)layer = track.layers[0]
seq = layer.findSequence("brightness")
seq.setExpression("self * (1 - osc:video.emergency_cut_out)")
Multiplies brightness by an OSC input value.

Working with ExpressionVariable Devices in Python

GoalPython
Create an ExpressionVariable devicedevice_name = "My Variables"
device_path = "devices/{}".format(device_name)
var_device = resourceManager.loadOrCreate(device_path, ExpressionVariablesDevice)
device_manager = state.devices
if var_device not in device_manager.devices:
device_manager.devices.append(var_device)
Creates or loads a device, then ensures it is active in the Device Manager.
Add and configure a variablevar_container = var_device.container
# Add a new, empty variable
var_container.variables.append(ExpressionVariable())
# Get a reference to the new variable
new_var = var_container.variables[-1]
# Now, set its properties
new_var.name = "my_variable_name"
new_var.type = ExpressionVariable.FloatType
new_var.defaultFloat = 5
Adds and configures a new variable on the device. Other types include ExpressionVariable.StringType and ExpressionVariable.FunctionType.
Use the variable in another expressionlayer = track.layers[0]
seq = layer.findSequence("brightness")
seq.setExpression("my_variable_name * 2")
This will use the value of “my_variable_name” from the ExpressionVariable device and multiply it by 2.

Practical Examples

Here are a few more examples that combine the concepts covered in this guide to create more complex behaviors.

”Breathing” Effect with math.sin

This example uses a sine wave to create a smooth “breathing” effect for a layer’s brightness.

TaskPython
Create a breathing animationlayer = track.layers[0]
seq = layer.findSequence("brightness")
seq.setExpression("0.5 + 0.5 * math.sin(time * 2)")
This will cause the brightness to smoothly oscillate between 0 and 1.

Advanced Color Control with OSC

This example demonstrates how to control the RGB values of a Colour layer using three different OSC addresses.

GoalPython
Control RGB with OSCcolor_layer = track.layers[0]
color_layer.findSequence("red").setExpression("osc:color.red")
color_layer.findSequence("green").setExpression("osc:color.green")
color_layer.findSequence("blue").setExpression("osc:color.blue")

This allows you to control the red, green, and blue channels of the color layer with separate OSC messages.