disguise developers

Designer Plugins

Plugins for Disguise Designer software.

Track and Sequencing Python Samples

This guide demonstrates how to use the Disguise Python API to work with the Track system, including tracks, layers, field sequences, and key sequences. These concepts are central to timeline-based animation, automation, and show control in Disguise.


Track Operations

TaskPython
Get the current tracktrack = guisystem.track
Returns the main Track object for the current GUI system.
Get the current playhead position (in beats)current_beat = guisystem.player.tCurrent
Get the track’s total length (in beats)track_length = track.lengthInBeats
Convert a time in seconds to beatsbeats = track.timeToBeat(seconds)
Time vs. beats can vary across the track - it is not always a fixed relationship.
Convert beats to secondsseconds = track.beatToTime(beats)
Length in beats from a duration in secondslength_beats = track.timeToBeat(start_seconds + duration_seconds) - start_beats
Useful for layer duration when creating a new layer.

Cues

Direct access to cues is possible via track.cues, which returns a list of all Cue objects on the track. However, it is often easier to work with the Track methods for sections, tags and notes directly.

Cues are unnamed Resources.

Tags

Notes


Layer Operations

A Layer represents a composable element on the Track. Layers are unnamed Resources.

TaskPython
Iterate through all layers on a trackfor layer in track.layers:
Get the number of layersnum_layers = len(track.layers)
Find a specific layer by namemy_layer = next((l for l in track.layers if l.name == "My Layer"), None)
Add a new layer to the tracktrack.addNewLayer(ModuleType, start_beats, length_beats, "Layer Name")
Creates a new layer of the given module type, setting the time extents using start & length.
Get the module type of a layerlayer.moduleType()
Remove a layer from the tracktrack.removeLayer(layer)
Reorder layerstrack.moveLayer(layer, new_index)
Get a layer’s namelayer.name NOTE - Layer is an exception where name is used instead of description
Set a layer’s namelayer.name = "New Name"
Get a layer’s start time (in beats)layer.tStart
Set a layer’s start timelayer.tStart = 16.0
Get a layer’s duration (in beats)layer.tLength
Set a layer’s durationlayer.tLength = 8.0
Enable/disable a layerlayer.enabled = True or layer.enabled = False
Arrow from src into dsttrack.makeArrow(src_layer, dst_layer)

Layer time extents

The most important Layer properties are their time extents: tStart, tEnd and tLength (which is tEnd - tStart). All of these values are in track beats.

The time extents determine when a Layer is active on the Track. When creating or modifying layers, it’s important to set the time extents carefully to avoid unexpected behavior.

Best practices for time extents:

Example - Creating a layer that matches existing layers:

# Find the time range of target layers
target_layers = [l for l in track.layers if l.name.startswith("Video")]
layer_start_beats = min(l.tStart for l in target_layers)
layer_end_beats = max(l.tEnd for l in target_layers)
layer_length_beats = layer_end_beats - layer_start_beats

# Create a new layer with matching time extents
blur_layer = track.addNewLayer(BlurModule, layer_start_beats, layer_length_beats, "Blur Effect")

Example - Creating a timed layer:

# Create a 30-second layer starting at the current playhead
current_time = trackTime()
duration_seconds = 30
duration_beats = track.timeToBeat(current_time + duration_seconds) - track.timeToBeat(current_time)

video_layer = track.addNewLayer(VideoModule, track.timeToBeat(current_time), duration_beats, "Video")

Layer composition

Layers which occupy the same time range (tStart/tEnd) and use mappings which target the same screens compose on top of each other according to the blend modes the layers are set to. To control the blending order of the Layers, the order they appear in their parent (track or container).

The earlier in their parent, the higher in the composition stack the Layer is used, and a layer’s blend mode affects layers “below” it.

If the user references multiple layers, there are 2 scenarios to consider:

  1. The content has some known relationship (e.g. they target different mappings and are used together, or should be blended together): the layers should share some overlap in tStart/tEnd.
  2. The content is independent: the layers should be arranged separately on the track.

Note the above means that there is NO relationship between track position and position in the parent’s layer list! The first layer in the track can be the last item in the list.

Modules

Modules define the different types of layers and their behaviors within a track. Each module defines the specific properties and methods accessible to the Layer.

Do not access the Module object directly. It may be absent or change. Use ModuleConfig and FieldSequence on the Layer instead.

ModuleConfig

The ModuleConfig is accessible via layer.moduleConfig. For certain Module types, this can include specific settings or parameters that control the behavior of the layer. For example, OpenModule has a corresponding OpenModuleConfig which allows for customization of which system properties the Layer can access. The majority of Module types do not use ModuleConfig. It is used for modules that are very generic in nature and require additional configuration to provide dynamic FieldSequence properties on the Layer instance. ModuleConfigs are unnamed Resources.

FieldSequence & KeySequence

Layers are unnamed Resources. They contain field sequences, which represent the sequencable properties on the layer. This is the only way to apply values to Layers.

A KeySequence stores the actual keyframes for a property. All KeySequences have at least 1 keyframe.

Important: Keyframes have a time (t) value that represents a specific beat on the Track, not within the Layer. When setting keyframe times, always use Track time. For example: field_sequence.sequence.setResource(layer.tStart, <resource>).

In the examples below, fseq is a FieldSequence and keyseq is a KeySequence:

TaskPython
Find a sequence for a propertyfseq = layer.findSequence("brightness")
Returns the FieldSequence for the “brightness” property.
List all sequences on a layersequences = layer.sequences
Returns a list of all FieldSequence objects.
Enable multi-keyframe sequencing for a propertyfseq.disableSequencing = False
Only use if the value truly needs to change over time.
Check if a property is sequencedis_sequenced = not fseq.disableSequencing
Evaluate a value at a track beatfseq.eval(track_time_in_beats, default_value)

Working with KeySequence in more detail:

TaskPython
Get the KeySequence for a propertykeyseq = fseq.sequence
Get all keyframe timeskey_times = [keyseq.t(i) for i in range(keyseq.nKeys())]
Returns a list of all keyframe times (in beats).
Get the number of keyframesnum_keys = keyseq.nKeys()
Get the value of a keyframe at a specific indexval = keyseq.key(i)
Returns the Key object at index i.
Get the time of a keyframe at a specific indext = keyseq.t(i)
Returns the time (in beats) of the keyframe at index i.
Insert a keyframekeyseq.insert(i, time_in_beats, key_type)
Inserts a key of type key_type at index i and time time_in_beats.
Insert a keyframe with a KeyContainerkeyseq.insertKeyContainer(time_in_beats, i, key_container)
Inserts a KeyContainer at time and index.
Remove a keyframe at a specific indexkeyseq.remove(i, 1)
Removes the keyframe at index i.
Clear all keyframes except the firstkeyseq.stripToFirstKey()
Float Sequence at indexkeyseq.key(i).v = value
Float Sequence at timekeyseq.setFloat(track_beat, value)
String Sequence at indexkeyseq.setString(i, value)
String Sequence at timekeyseq.setStringAtT(track_beat, value)
Resource Sequence at indexkeyseq.key(i).r = resource_obj
Resource Sequence at timekeyseq.setResource(track_beat, resource_obj)

An example of setting a float sequence to a constant value:

brightness_fseq = my_layer.findSequence("brightness")
assert(brightness_fseq is not None)
# Disable sequencing - value not animating
brightness_fseq.disableSequencing = True
# Set the brightness value on the KeySequence
brightness_fseq.sequence.setFloat(my_layer.tStart, 25.0)

Searching for Media

You can find and reference media assets (like images, videos, or audio files) within your projects using the resource manager.

Finding Media by Name

The examples below show common patterns for finding media. Replace MediaType with the appropriate type (e.g., VideoClip, ImageResource, AudioFile).

TaskPython
List all media assets in a projectall_media = resourceManager.allResources(MediaType)
Find the first media asset which contains ‘search’resource = next(r for r in resourceManager.allResources(MediaType) if 'search' in r.path.filename)