Tween Expressions
A tween expression drives any tween property — position, opacity, scale, color adjustments, and more — with a mathematical formula instead of static keyframe values alone. Expressions are evaluated on every frame, so tween values respond to show variables, external inputs, and math functions.
Expressions make presentations interactive, data-driven, and externally controllable.
How Expressions Work
Every tweenable effect in WATCHOUT has an expression field alongside its keyframe data. At runtime, the system first interpolates the keyframe curve at the current time to produce a base value called tweenValue. This value is then passed into the expression, which can transform, replace, or augment it.
The expression language is a mathematical formula evaluator that supports standard arithmetic, mathematical functions, and variable references. The expression must resolve to a single numeric value, which becomes the final tween output for that frame.
Setting an Expression
To add an expression to an effect:
- Select a cue that has the desired effect applied.
- In the Properties panel, expand the effect's properties.
- Locate the Expression field.
The expression field varies depending on the tween type:
- Single-value effects (Opacity, Blur, Crop, Color adjustments, Volume, etc.) have one Expression field.
- Scale effects have separate X Expression and Y Expression fields.
- Position effects have separate X Expression, Y Expression, and Z Expression fields.
Leave the expression field at its default value (tweenValue) to pass the keyframe-interpolated value through unmodified.
The tweenValue Variable
The built-in variable tweenValue represents the keyframe-interpolated value at the current point in time. This is the default expression for all tweenable effects — when the expression field contains tweenValue (or is empty), the effect behaves as if no expression is set, outputting the pure keyframe value.
You can use tweenValue in more complex expressions to modify the keyframed animation:
tweenValue * 2— doubles the keyframed valuetweenValue + 10— offsets the keyframed value by 10tweenValue * myVariable / 100— scales the keyframed value by an external variable
For position effects, the same concept applies per axis: the X expression receives the X component of the interpolated position as tweenValue, the Y expression receives the Y component, and so on.
Expression Syntax
The expression evaluator is the fasteval library. It supports:
Arithmetic operators: +, -, *, /, % (modulo), ^ (power)
Comparison and logic: <, >, <=, >=, ==, !=, and (or &&), or (or ||), ! (not). A comparison returns 1 when true and 0 when false.
Built-in math functions: sin(), cos(), tan(), asin(), acos(), atan(), abs(), log(), ceil(), floor(), round(), sign(), min(), max()
The log() function takes an optional base as its first argument: log(2, val) is the base-2 logarithm of val. With one argument, log(val) uses base 10.
Constants: write pi() and e() with parentheses.
Expressions are case-insensitive. TweenValue, tweenvalue, and TWEENVALUE all refer to the same variable.
There is no if() function, no ternary (? :), and no sqrt(), log10(), or built-in time variable. For a square root, use value^0.5. For a conditional, multiply by a comparison: because a comparison returns 1 or 0, (x > 5) a + (x <= 5) b gives a when x is above 5 and b otherwise.
Division-by-zero safety. If an expression divides by a variable that could be zero, add a small offset: tweenValue / (divisor + 0.0001).
Variable References
Expressions can reference show variables (defined in the Variables panel) by name. This is what makes expressions truly powerful: you can bind any tween property to an external input.
For example, if you have a show variable called faderLevel that is controlled by an OSC input, you could write:
- Opacity expression:
faderLevel— directly maps the fader to opacity - Position X expression:
tweenValue + trackerX— offsets the keyframed position by a tracking variable - Scale X expression:
max(tweenValue, minScale)— clamps the scale to never go below a variable-defined minimum
When a variable referenced in an expression changes (because an external system sent a new value via OSC, ArtNet, MIDI, etc.), the tween output updates immediately on the next frame. This enables real-time interactive control without modifying the show's timeline.
All variables referenced in an expression must exist in the show's Variables panel. If an expression references an unknown variable, WATCHOUT reports an "Unknown input" error when you enter the expression.
Interaction with Keyframes
Expressions and keyframes are not mutually exclusive — they work together:
- The keyframe curve is evaluated first to produce
tweenValue. - The expression is then evaluated with
tweenValueavailable as a variable. - The expression's result becomes the final output.
This means you can use keyframes to define the base animation and an expression to modulate it. For instance, keyframes might define a smooth opacity fade from 0 to 100, while the expression tweenValue * masterDim / 100 allows an external dimmer to scale the entire animation.
If you want the expression to completely replace the keyframe value, simply write an expression that doesn't reference tweenValue (e.g., just myVariable). In this case, the keyframe curve is still computed but its value is ignored.
Practical Examples
Externally controlled opacity: Set the Opacity expression to oscFader1 where oscFader1 is a show variable mapped to an OSC input. A lighting console or control surface can now directly control the cue's opacity in real time.
Position tracking: Set the Position X expression to trackerX and Y expression to trackerY, where these variables come from a tracking system (via OSC or similar protocol). The cue follows the tracked object in real time.
Scaled animation: Keyframe a position animation along a path, then set the expression to tweenValue * intensity / 100 where intensity is a variable. The animation plays its keyframed path but the displacement is scaled by the external value.
Creative Application Examples
WATCHOUT has no built-in clock variable. To drive time-based math, keyframe a linear ramp on the effect (for example 0 at the start of the cue, rising steadily) and use tweenValue as the time base.
Dynamic motion — oscillation: With a rising ramp on the effect, use centerX + sin(tweenValue speed) amplitude as a Position X expression to swing an element back and forth. speed and amplitude are show variables.
Dynamic motion — multi-axis floating: Combine sine waves of different frequencies for organic movement: baseY + sin(tweenValue 0.5) 20 + sin(tweenValue 0.7) 15.
Interactive controls — MIDI-driven position: Map a MIDI controller to a position range: minPosition + midiValue * positionRange, where midiValue is a show variable bound to a MIDI CC input.
Interactive controls — on/off cross-fade: Show or hide an element from a state variable: isActive * masterOpacity. When isActive is 1 the element shows at masterOpacity; when 0 it is hidden.
Relationship to Timeline Expressions
Tween expressions and timeline trigger expressions are different features that serve different purposes:
- Tween expressions (this article) control the value of a tween property. They are evaluated continuously on every frame and produce a numeric result that drives a visual property (position, opacity, color, etc.).
- Timeline trigger expressions (covered in the Timeline Triggers and Expressions article) control the playback state of a timeline. They are evaluated as boolean conditions that trigger play, pause, or stop actions on timelines.
Both systems use the same expression language and can reference the same show variables, but they operate at different levels of the system.