Skip to content

After Effects expressions

After Effects expressions: a copy-and-paste cheat sheet

Most After Effects projects lean on the same dozen expressions: wiggle, loopOut, a bounce, a delayed follow, time-based rotation, a remap with linear() or ease(), randomness and a slider to drive it all. Here is each one ready to paste, with a line on what it does. In After Effects you Alt-click (Option-click) a property's stopwatch and type. Each snippet also says whether it runs as written in Premation's expression engine — checked against the interpreter's own function table — and, when it does not, the version that does.

DownloadSource on GitHub

Free · AGPL-3.0-only · Windows, macOS & Linux

Before you paste into Premation

  • Where expressions go

    Premation's expression editor is in the Graph panel (Window ▸ Panels ▸ Graph Panel): pick a property of the selected layer and type. Alt+Shift+= adds an expression to the selected property and opens the editor, as in After Effects. Source Text takes one through Layer → Text → Source Text Expression….

  • One expression, not a script

    Premation evaluates a single JavaScript expression: no semicolons, no variables, no if blocks and no // comments. Most multi-line After Effects expressions fold into one line with the ternary operator (condition ? a : b); the rewrites below show how.

  • Each axis is evaluated on its own

    On Position, Scale or Anchor Point the expression runs once per axis, and value is that axis's number, not an array. An array result is read by axis — the first item drives X, the second Y — so After Effects' value + [100, 0] becomes [value + 100, value], and value[1] becomes value.

  • Controls are ctrl('Name')

    After Effects reads a Slider Control as effect("Slider Control")("Slider"). Premation's expression controls — Slider, Angle, Point, Colour, Checkbox, Dropdown, Layer, added from the Animate menu — are read by name: ctrl('Slider Control'). effect() is not defined.

  • Other layers by name

    There is no index and no transform group. Read another layer with thisComp.layer('Leader').position, or one property at any time with layerAt('Leader', 'x', time - 0.1).

  • Same answer every render

    Expressions run in the native engine's own interpreter, never a JavaScript eval, so the viewport, an export and a command-line render agree. wiggle() and random() are seeded per layer and property, so two exports of one project match.

Wiggle

wiggle(frequency, amplitude) adds smooth random motion around the property's value: frequency in wiggles per second, amplitude in the property's units.

Wiggle — works in both
wiggle(2, 30)
Wiggle X only — After Effects
[wiggle(2, 30)[0], value[1]]
Wiggle X only — Premation
[wiggle(2, 30), value]
Wiggle from sliders — After Effects
wiggle(effect("Frequency")("Slider"), effect("Amount")("Slider"))
Wiggle from sliders — Premation
wiggle(ctrl('Frequency'), ctrl('Amount'))

Loop keyframes: loopOut and loopIn

The expression to repeat keyframes. loopOut() repeats the keyframed animation after the last keyframe; loopIn() does the same before the first. In Premation both loop the whole first-to-last keyframe range: the second argument After Effects accepts (how many keyframes to loop) is ignored.

Repeat forever (cycle is the default)
loopOut()
Cycle
loopOut("cycle")
Ping-pong: forward, then backward
loopOut("pingpong")
Offset: each loop starts where the last ended
loopOut("offset")
Continue at the last keyframe's speed
loopOut("continue")
Loop before the first keyframe
loopIn("cycle")

Spin and oscillate with time

time is the current time in seconds, so multiplying it gives a constant rate. Math.sin gives a back-and-forth.

Rotate 360° per second
time * 360
Spin on top of the keyframed rotation
value + time * 90
Sway ±15° once per second
value + Math.sin(time * 2 * Math.PI) * 15
Pulse opacity between 0 and 100
50 + Math.sin(time * 4) * 50

Bounce and inertial bounce

An inertial bounce lets a property overshoot and settle after a keyframe, using the speed it arrived with. The classic After Effects version is a short script with variables, so it does not run in Premation; the single-expression version below does the same after the last keyframe and also runs in After Effects.

Inertial bounce — After Effects (script form)
amp = 0.05; freq = 4; decay = 8;
n = 0;
if (numKeys > 0) {
  n = nearestKey(time).index;
  if (key(n).time > time) n--;
}
if (n == 0) {
  value;
} else {
  t = time - key(n).time;
  v = velocityAtTime(key(n).time - thisComp.frameDuration / 10);
  value + v * amp * Math.sin(freq * t * 2 * Math.PI) / Math.exp(decay * t);
}
Inertial bounce after the last keyframe — Premation (and After Effects)
numKeys === 0 || time <= key(numKeys).time ? value : value + velocityAtTime(key(numKeys).time - 0.001) * 0.05 * Math.sin((time - key(numKeys).time) * 4 * 2 * Math.PI) / Math.exp((time - key(numKeys).time) * 8)
Decaying bounce from time 0, on a single value such as Rotation — works in both
value + Math.sin(time * 12) * 40 / Math.exp(time * 4)

Delay and follow another layer

A follower that copies a leader's motion a beat late. After Effects users usually chain layers with index - 1; Premation has no index, so name the leader.

Follow with a 0.1 s delay — After Effects
thisComp.layer(index - 1).transform.position.valueAtTime(time - 0.1)
Follow with a 0.1 s delay — Premation
[layerAt('Leader', 'x', time - 0.1), layerAt('Leader', 'y', time - 0.1)]
Follow rotation with a delay — Premation
layerAt('Leader', 'rotation', time - 0.1)
Follow with no delay — Premation
thisComp.layer('Leader').position
This property, half a second ago — works in both
valueAtTime(time - 0.5)

Stepped motion: posterizeTime

Makes a smooth expression update only a few times a second, for a hand-animated feel. In After Effects posterizeTime(fps) is a statement placed before the expression; in Premation it returns the stepped time, which you pass where the time goes.

Wiggle at 8 updates per second — After Effects
posterizeTime(8); wiggle(2, 30)
Wiggle at 8 updates per second — Premation (and After Effects)
wiggle(2, 30, 1, 0.5, posterizeTime(8))
Play the keyframes on twos at 24 fps — Premation
valueAtTime(posterizeTime(12))

Clamp and remap: clamp, linear, ease

clamp(value, min, max) keeps a number inside limits. linear(t, tMin, tMax, a, b) maps t from one range onto another; ease(), easeIn() and easeOut() do the same with a curve (Premation's ease() is a smoothstep).

Keep a value between 0 and 100
clamp(value, 0, 100)
0 → 360 over the first two seconds
linear(time, 0, 2, 0, 360)
Eased 0 → 100 between 1 s and 3 s
ease(time, 1, 3, 0, 100)
Drive X from a 0–100 slider — After Effects
linear(effect("Progress")("Slider"), 0, 100, 0, 1920)
Drive X from a 0–100 slider — Premation
linear(ctrl('Progress'), 0, 100, 0, 1920)
Remap a whole position — After Effects
linear(time, 0, 1, [0, 0], [960, 540])
Remap a whole position — Premation
[linear(time, 0, 1, 0, 960), linear(time, 0, 1, 0, 540)]

Measure a layer: sourceRectAtTime

sourceRectAtTime() returns a layer's own bounds — top, left, width and height — at a time, which is how motion adapts to content instead of typed numbers. Premation measures only the layer the expression is on; there is no thisComp.layer(…).sourceRectAtTime().

Anchor point at the centre of a text layer's text — works in both
[sourceRectAtTime().left + sourceRectAtTime().width / 2, sourceRectAtTime().top + sourceRectAtTime().height / 2]
Box that fits another text layer — After Effects only
s = thisComp.layer("Title").sourceRectAtTime(); [s.width + 40, s.height + 20]

Random values: random and seedRandom

random(min, max) returns a new number every frame. seedRandom(seed, true) fixes it, so a layer keeps one random value. In Premation seedRandom returns 0, so it is added in front of random() inside the one expression. Without seedRandom, Premation already seeds each layer and each axis differently.

Jitter a single value (Rotation, Opacity) every frame — works in both
value + random(-5, 5)
One fixed random number — After Effects
seedRandom(5, true); random(0, 100)
One fixed random number — Premation
seedRandom(5, true) + random(0, 100)
A fixed random position per layer — After Effects
seedRandom(index, true); random([0, 0], [thisComp.width, thisComp.height])
A fixed random position — Premation (use a different seed per layer)
[seedRandom(5, true) + random(0, thisComp.width), random(0, thisComp.height)]

Which ones work in Premation

ExpressionWhat it doesWorks in Premation
wiggle(2, 30)Smooth random motion around the valueYes
[wiggle(2, 30)[0], value[1]]Wiggle one axis onlyNeeds rewrite: [wiggle(2, 30), value] — value is per axis
loopOut() / loopOut("cycle")Repeat the keyframes after the last oneYes
loopOut("pingpong" / "offset" / "continue")Loop back and forth / stack / keep goingYes
loopOut("cycle", 2)Loop only the last few keyframesPartly: the count is ignored; the whole range loops
loopIn("cycle")Repeat the keyframes before the first oneYes
time * 360Constant rotationYes
value + Math.sin(time * 2 * Math.PI) * 15Oscillate around the valueYes
Inertial bounce (script form)Overshoot and settle after keyframesNeeds rewrite: single ternary expression (above)
thisComp.layer(index - 1).transform.position.valueAtTime(time - 0.1)Follow the layer above with a delayNeeds rewrite: no index or transform — layerAt('Leader', 'x', time - 0.1)
valueAtTime(time - 0.5)This property's own earlier valueYes
posterizeTime(8); wiggle(2, 30)Stepped, low-frame-rate wiggleNeeds rewrite: wiggle(2, 30, 1, 0.5, posterizeTime(8))
clamp(value, 0, 100)Keep a number inside limitsYes
linear(time, 0, 2, 0, 360) / ease(…)Remap one range onto anotherYes, with numbers; for arrays, one linear() per axis
[sourceRectAtTime().left + sourceRectAtTime().width / 2, …]Centre the anchor on a layer's contentYes (own layer only)
thisComp.layer("Title").sourceRectAtTime()Size a box to another layerNo: only the expression's own layer can be measured
seedRandom(5, true); random(0, 100)A fixed random valueNeeds rewrite: seedRandom(5, true) + random(0, 100)
value + random(-5, 5)Per-frame jitterYes
effect("Slider Control")("Slider")Read a Slider ControlNeeds rewrite: ctrl('Slider Control')
degreesToRadians(45)Degrees to radiansNeeds rewrite: 45 * Math.PI / 180

Questions

What is the wiggle expression in After Effects?
wiggle(frequency, amplitude) — for example wiggle(2, 30) shakes a property about twice a second by up to 30 units. Optional arguments add octaves of detail, set how much each octave is scaled, and give the time to sample, which is how posterizeTime() can be passed in.
What is the expression to loop keyframes in After Effects?
loopOut() on the keyframed property. It cycles by default; loopOut("pingpong") plays back and forth, "offset" stacks each repeat on the last, and "continue" carries on at the final speed. loopIn() loops before the first keyframe instead.
How do I make a bounce with an expression?
Use an inertial bounce: after a keyframe, add the arrival velocity multiplied by a sine wave that dies away with Math.exp(). The cheat sheet above has a script form for After Effects and a one-line form that also runs in Premation.
How do I link an expression to a slider?
Add a Slider Control to the layer, then read it: effect("Slider Control")("Slider") in After Effects, or ctrl('Slider Control') in Premation. A slider can be keyframed, which animates the expression's input rather than the property itself.
Do After Effects expressions work in Premation?
Many run as written — wiggle, loopOut, loopIn, valueAtTime, velocityAtTime, key(), clamp, linear, ease, random, Math — because Premation's interpreter implements After Effects' expression functions. Script-style expressions with semicolons or variables, effect(), index and vector maths on value need the one-line rewrites shown on this page.
Can I turn an expression into keyframes?
Yes. In After Effects use Animation ▸ Keyframe Assistant ▸ Convert Expression to Keyframes; in Premation, Animation → Convert Expression to Keyframes. Both sample the expression across the range and write ordinary keyframes you can edit by hand.