Appearance
Data Tracks
Data Tracks are timeline lanes with a built-in SVG curve editor for keyframe-based animation. You draw a curve directly in the timeline, and Exaplay interpolates values between keyframes and transmits them to external systems (lighting consoles, control systems, custom hardware) over OSC, UDP, TCP, ArtNet, to the Operator Control Panel — or writes them straight into one of Exaplay's own values: a shader parameter, a volume, a clip's position (see Driving Exaplay's own values).

What Are Data Tracks?
A Data Track is a timeline lane containing keyframes. The lane renders an interactive SVG curve showing the interpolated path between keyframes. At playback time the engine evaluates the curve and transmits the value to the configured output destination.
Creating a Data Track
- Right-click anywhere in the Timeline dropzone area.
- Choose Add Data Track from the context menu.
- The new track appears in the Timeline. Open the Inspector to configure its properties:
- Name — human-readable label
- Color — track row accent colour
- Min / Max Value — numeric range of the curve
- Interpolation —
LinearorStep - Output — format, address, port, and protocol-specific settings
Editing Keyframes with the SVG Curve Editor
The curve editor is embedded directly in the Data Track row in the Timeline.
| Action | Result |
|---|---|
| Double-click on the curve area | Adds a new keyframe at that position and value |
| Click a keyframe handle | Selects the keyframe — its frame and value appear in the Inspector for precise editing |
| Drag a keyframe handle | Moves the keyframe in time and value |
| Right-click a keyframe handle | Opens its menu: copy/paste that keyframe's value, copy/paste the whole curve, or delete the keyframe |
| Arrow Left / Right | Nudge selected keyframe ±5 frames (hold Shift for ±1 frame) |
| Arrow Up / Down | Nudge selected keyframe value ±1 % of range (hold Shift for ±0.1 %) |
| Delete / Backspace | Remove the selected keyframe |
| Escape | Deselect the current keyframe |
A value label (e.g. f30: 0.75) appears next to the handle while dragging or when a keyframe is selected. Keyframes are always kept sorted by frame number.
Keyframe Inspector
When a keyframe is selected, the Inspector panel shows:
| Property | Description |
|---|---|
| Frame | The frame number of the keyframe (editable) |
| Value | The value at this keyframe (editable, clamped to track min/max) |
Track Appearance
- The track name is shown prominently in the track's left sidebar panel, coloured with the track's accent colour.
- The curve line and keyframe handles use the track's accent colour (
ui_color), which can be changed in the Inspector.
frame 0: value = 0
frame 30: value = 1
frame 60: value = 0
→ value ramps up to 1 and back to 0 over 60 framesInterpolation Modes
| Mode | Behaviour |
|---|---|
| Linear | Straight ramp between keyframe values (drawn as straight segments, not a spline) |
| Step | Value jumps immediately at each keyframe (no interpolation) |
Output Types
| Format | Description |
|---|---|
| OSC | Sends a float to the configured IP, port, and OSC path |
| UDP | Sends a raw UDP datagram with the current value |
| TCP | Sends a formatted command string over a TCP connection |
| ArtNet | Writes the value into an ArtNet universe/channel |
| Control Panel | Displays the current value as a read-only readout in the Operator Control view |
| Exaplay value | Writes the value into one of Exaplay's own properties — a shader parameter, a volume, a clip position — addressed by the same dotted path the TCP set: syntax uses, scaled onto a target range. See Driving Exaplay's own values. |
Inspector Properties
| Property | Description |
|---|---|
| Name | Human-readable track label |
| Color | Accent colour shown in the track row |
| Min Value | Lower bound of the curve range |
| Max Value | Upper bound of the curve range |
| Interpolation | Linear or Step |
| Output › Format | OSC, UDP, TCP, ArtNet, Control Panel, or Exaplay value |
| Output › Address | Destination IP address (OSC / UDP / TCP / ArtNet), or a named route such as $Console — a variable that carries host:port sets the port too |
| Output › Port | Destination port number |
| Output › OSC Path | OSC message address (e.g. /fixture/1/dimmer) |
| Output › Command | TCP command template |
| Output › Universe | ArtNet universe number |
| Output › Channel | ArtNet channel number (1–512) |
| Output › Control Target | Control Panel item ID |
| Output › Target | Exaplay value: the dotted path of the value to drive, e.g. comp1.media3.realtime.params.u_speed. The field completes the path as you type it (the project tree, then the object's values) and the ⚡ wizard browses the project for one |
| Output › Scaling | Exaplay value: how the curve's value becomes the written one — Out range (the track's Min–Max onto Out Min–Out Max), Factor (value × factor + offset) or As drawn (written unchanged) |
| Output › Out Min / Out Max | Exaplay value, Out range mode: the range the track's Min–Max is scaled onto. Filled in automatically when the picked property has a known range (0–100 for an opacity or a volume) |
| Output › Factor / Offset | Exaplay value, Factor mode: the multiplier and the offset applied to the curve's value |
| Output › Restore on stop | Exaplay value: when on (default), the property gets the value it had before the curve first wrote to it back as soon as the track lets go — the composition stops, the track is hidden or deleted, the target changes |
| Output › Status | What the engine reports. Exaplay value: the resolved target, a release, or why nothing is written. OSC / UDP / TCP / ArtNet: the address the track is sending to — or the $variable this machine does not define, in which case nothing is sent |
| Output › Rate (Hz) | Maximum send rate, 1–120 Hz |
Driving Exaplay's own values
Everything a Data Track can send to a lighting desk it can also send to Exaplay itself. With Output › Format set to Exaplay value, the curve drives one property of any object in the show — the same properties the Inspector edits and the TCP set: syntax addresses — so a timeline can move a clip, ride a volume, sweep a shader parameter or blink a layer, with no external controller in the loop.
Target
Target is a dotted path in the same grammar as the TCP/UDP dotted commands: the object's tree path, then the property.
comp1.media3.realtime.params.u_speed a generative source's parameter
comp1.audio.volume a composition's volume (0–100)
comp1.track1.media2.mapping.x a clip's horizontal position (px)
Main Show.alpha a composition by NAME (varnames win)
comp1.media3.show a clip's visibility (on/off)- The field completes the path as you type it, the way the cue editor completes a command: type
comp1.and the composition's tracks, groups, clips and cues are listed, then the object's own values — its position, size, opacity and volume first, then everything else. A listed object or value group takes a.and keeps going; a value completes the path. Arrow keys move through the list, Enter or Tab pick, Escape closes it. - The ⚡ wizard next to the field browses the same project tree (compositions, tracks, groups, clips) and lists the values an operator drives, by their plain names and with the range each one will be scaled to: Opacity, Volume, Position X / Y, Size W / H, Rotation, Visible — plus every parameter of the generative source that clip actually runs, named and ranged from its catalog. The list describes the object you picked: a composition or a track offers its own opacity and volume and no position. Anything else the object carries — colour correction, a crop corner, an EQ band, or a new key inside an existing group such as
realtime.vars.<name>(the show-control hook a generative source's bindings read) — is typed into the Other value field below the list, or into the Target field itself, which still completes every path in the dictionary. - A line pasted from a cue script or the TCP docs works as it is:
comp1.set:audio.volume=80names the targetcomp1.audio.volume; the verb and the argument are ignored. - The
project.prefix is optional —project.comp1.audio.volumeandcomp1.audio.volumename the same value, and the field completes through either.
Scaling
The curve is drawn in the track's Min Value – Max Value range. Scaling picks how a curve value becomes the written one:
| Scaling | Written value | Use it for |
|---|---|---|
| Out range (default) | the track's Min–Max scaled linearly onto Out Min – Out Max, clamped to that range | one 0–1 curve driving anything — and the range is filled in for you (below) |
| Factor | curve value × Factor + Offset, not clamped | your own arithmetic: a 0–1 curve × 100, a metre curve × 1000 into millimetres |
| As drawn | the curve value, unchanged | a curve drawn in the property's own units — set the track's Min / Max Value to that range and the editor shows the real numbers |
Out Min / Out Max are filled in when the target is picked (typed, completed or chosen in the wizard) whenever the property has a known range: an opacity or a volume is 0–100, a rotation 0–360, a size stored as a percent 0–100, a generative source's parameter its catalog range (plasma's Speed is 0–4).
A position or size in pixels is ranged too, against the surface that clip is positioned on — the field it is mapped to, else the screen it is routed to — so a 0–1 curve on Position X lands on 0 – 1664 for a clip on a 1664×832 LED wall, not on 0 – 1. That size is read from the clip itself, so it is right on every machine and every wall; where it cannot be read (an older engine, an object with no position at all) the range is left alone rather than guessed. A property nobody can range — a variable — leaves it alone as well; set it yourself, or switch to Factor or As drawn.
| Curve (Min–Max) | Scaling | Written |
|---|---|---|
| 0 – 1, at 0.5 | Out range 0 – 1920 | 960 — a clip moved to the middle of a Full HD screen |
| 0 – 1, at 0.75 | Out range 0 – 100 | 75 — a volume or an opacity at 75 % |
| 0 – 255, at 255 | Out range 0 – 100 | 100 — a DMX-style curve riding a 0–100 property |
| 0 – 1, at 1 | Out range 100 – 0 | 0 — inverted (Out Min above Out Max is allowed) |
| 0 – 1, at 0.3 | Factor 100, Offset −50 | -20 — the operator's own arithmetic, never clamped |
| 0 – 100, at 37 | As drawn | 37 |
The target's own type and unit decide the rest: an on/off property switches on in the upper half of the curve's range and off below it (whatever the scaling); a size stored as a percent (mapping.w = 100%) is written as a percent (50%), so driving it to 0–100 scales the clip instead of shrinking it to pixels — switch the size to pixels in the clip's Inspector first if pixels are what you want; everything else receives the value as it is, at full precision. Positions (mapping.x/y) are in pixels of the screen the clip is placed on.
Sweeping a generator's parameter
Point Target at a generative clip's parameter — comp1.track1.media1.realtime.params.u_speed, or pick it in the ⚡ wizard, which lists the parameters of the source that clip actually runs and fills in their catalog range. A 0 → 1 curve then sweeps Speed across 0–4, Audio react across 0–1, and so on, live on the next frame.
The same parameters are drivable from Tracking and from a TCP / OSC / cue-script line (comp1.track1.media1.set:realtime.params.u_speed=2.4) — one grammar, three sources. A parameter you want several things to feed can instead be bound to a variable in the clip's Inspector (realtime.vars.<name>), and then the curve, the tracker or the desk drives that one variable.
Moving a clip across the screen
Draw a 0 → 1 ramp over 5 seconds, set Target to comp1.media3.mapping.x and Out Max to the screen width (1920). Add a second Data Track for mapping.y to move diagonally. The clip's Inspector shows the position following the curve while the composition plays — and the clip is back where you placed it when the composition stops.
Scaling a clip
Target comp1.media3.mapping.w (Size W (scale)): with the size stored as a percent the out range is filled with 0–100 and a 0 → 1 curve grows the clip from nothing to its full size. Add mapping.h on a second track to keep the aspect ratio.
What happens on the engine
- The write takes the same path as an Inspector edit or a TCP
set:line, so it applies live on the next frame — a shader parameter, a fader, a position, a visibility switch all react immediately; nothing reloads. - The curve is evaluated while the composition plays; an unchanged value is not re-written (a flat curve costs nothing), and after a pause the value is re-asserted when playback resumes, so the curve always owns the property while it runs.
- The property gets its original value back when the track lets go. The value it had before the curve's first write is remembered, and written back when the composition stops (a pause holds), when the track is hidden or deleted, or when the Target or the Format is changed — so a clip a curve slid across the screen is back where you placed it, and a volume a curve ducked is back at its fader. Restore on stop switches this off for a show that wants the last written value to stick. A value the curve created itself (a new
realtime.vars.<name>) has no original and is left as written. - The written value becomes the property's value exactly as if you had set it yourself — while the curve runs it is what the project saves, and on a multiclient rig every engine evaluates its own copy of the track from its own synced clock, so all machines follow without any extra sync.
- Status reports what the engine resolved:
driving media3.realtime.params.u_speedwhen the write lands,released media3.image.alpha — back to 100when the track let go,target not found: …for a mistyped object,property not found: … on …for a mistyped property (a property inside a group the object has never declared is refused rather than silently created). The engine log carries the same line, once per change. - Rate (Hz) still applies; a rate below 120 Hz simply thins the writes.
