An expression is a small formula that drives an animatable property's value on every frame. You write it in the Expression section of the keyframe panel; this page is the reference for the language itself — the values you can read, the functions you can call, and the syntax the editor accepts. For how to open the editor, enable an expression, and link properties with the pick whip, see Animate with expressions.
Every expression evaluates to a single value at the current time. The last expression in your code is the result. Sequence re-runs the whole formula each frame, so anything that depends on time animates automatically.

Globals#
These values are always in scope. Read them directly by name.
Globals
Note
velocity and speed are also in scope but are reserved — they currently evaluate to 0 and don't yet report a property's rate of change. Don't build a formula that depends on them.
Built-in functions#
Interpolation#
Map an input across a range to an output range. linear and the ease family clamp their result to the val1–val2 range; lerp does not.
linear(t, tMin, tMax, val1, val2)— Straight-line interpolation. Astmoves fromtMintotMax, the result moves fromval1toval2.ease(t, tMin, tMax, val1, val2)— Same mapping with an S-curve (eases in and out).easeIn(t, tMin, tMax, val1, val2)— Starts slow, accelerates.easeOut(t, tMin, tMax, val1, val2)— Starts fast, decelerates.lerp(a, b, t)— Unclamped blend betweenaandbby fractiont.clamp(value, min, max)— Constrainvalueto the rangemin–max.
Noise and randomness#
Random output is deterministic — the same frame always produces the same value — so playback and export match. The seed is derived from the property and the frame.
wiggle(freq, amp, octaves?)— Smooth random motion:freqwiggles per second,ampmaximum deviation.octavesadds finer layers of detail.noise(t)— 1D value noise in the range-1to1.random(min?, max?)— A random number. With no arguments, between 0 and 1.gaussRandom()— A random number on a Gaussian (bell-curve) distribution.
Looping#
Repeat your keyframed animation before the first keyframe or after the last one. The keyframes and current time are supplied automatically — you only pass the mode.
loopOut(mode)— Loop after the last keyframe.loopIn(mode)— Loop before the first keyframe.
mode is one of "cycle" (default — repeat from the start), "pingpong" (alternate forward and back), "offset" (repeat, accumulating the total change each cycle), or "continue" (hold the ending velocity). Omit mode to get "cycle".
Keyframe access#
Read this property's own keyframes.
key(index)— The keyframe at a 1-basedindex, as{ time, value, id }.nearestKey(time)— The keyframe closest totime.valueAtTime(time)— This property's interpolated value at anytime.
Element and property references#
Read another property's value so two properties stay linked. Build a reference by chaining .effect() and .property() from an element:
element("Title Card").effect("seq.video.transform").property("x-position");thisElement— The element the expression lives on.element(name)— Another element, by its name or story-tree path..effect(name)— An effect on that element..property(name)— A property on that effect. This is the value the reference resolves to.
You can chain .valueAtTime(time) onto a property reference to read its value at a specific time rather than the current one.
Dragging the pick whip onto a property writes one of these references for you: a same-element target becomes thisElement.effect(...).property(...), and a different element becomes element("Name").effect(...).property(...). See Animate with expressions for the pick-whip workflow.
Note
References can't form a loop. If property A reads property B, then B can't be made to read A — Sequence rejects a pick-whip drop that would create a cycle with "Would create a cycle in expression dependencies," and validates the same rule for typed references.
Vector math#
Operate on arrays of numbers (for example a [x, y] position).
length(vec)— Magnitude of the vector.normalize(vec)— The vector scaled to length 1.dot(a, b)— Dot product.cross(a, b)— Cross product.
Data sources#
Drive animation from an external data stream (JSON or CSV) attached to the project. Values are linearly interpolated between samples.
data(sourceName, streamName, time)— The stream's value attime.dataKeys(sourceName, streamName)— All time keys in the stream.dataKeyCount(sourceName, streamName)— How many keys the stream has.
Math and array methods#
The full JavaScript Math object is available: Math.sin, Math.cos, Math.abs, Math.floor, Math.round, Math.min, Math.max, Math.sqrt, Math.pow, Math.PI, and the rest.
Arrays support map, filter, reduce, find, indexOf, slice, and includes.
Syntax#
The engine runs a restricted subset of JavaScript — enough to compute a value, nothing that can reach outside the frame.
You can use:
- Number, string, boolean,
null, array, object, and template-literal values - Arithmetic (
+ - * / %), comparison (== != === !== < > <= >=), logical (&& || ??), bitwise (& | ^ << >>), and unary (- ! ~ typeof) operators - The ternary conditional,
condition ? a : b constandletdeclarations, including destructuring- Arrow functions with an expression body, such as
(a, b) => a + b - Multiple statements in a block — the last one is the returned value
You can't use:
- Loops (
for,while),if, orswitch— use the ternary? :instead - Function or class declarations, or
this— usethisElement try/catch/throw, regular expressions,eval,window, ordocument
Execution limits
Each expression runs under a budget — roughly 5 ms of wall-clock time and 50,000 evaluation steps per frame. A formula that exceeds the budget stops with an error instead of stalling playback.
Examples#
Ease a rotation from 0° to 360° over the first five seconds:
ease(time, 0, 5, 0, 360);Add a continuous shake on top of the property's existing animation:
value + wiggle(5, 10);Follow another element's horizontal position so a title tracks a shape:
element("Title Card").effect("seq.video.transform").property("x-position");Drive scale from a slider control on the same element:
const amount = thisElement .effect("seq.utility.slider_control") .property("value");value * amount;Show the property only between 2 and 5 seconds, hidden otherwise:
time >= 2 && time <= 5 ? 100 : 0;Loop a keyframed animation back and forth forever:
loopOut("pingpong");Map an imported speed reading onto a playback range:
const speed = data("telemetry.json", "speed", time);linear(speed, 0, 200, 1.0, 2.5);