description: "After Effects Expressions Basics — Keyframes are hand-placed. Expressions are small pieces of JavaScript that drive a property's value with code instead …"---
04 · After Effects Expressions Basics¶
Keyframes are hand-placed. Expressions are small pieces of JavaScript that drive a property's value with code instead — useful for motion that follows a rule (wiggle, loop, link to another layer) rather than a fixed set of keyframes. This module covers writing, linking, and reusing basic expressions.
1. Adding an expression to a property¶
- Alt-click (Windows) / Option-click (Mac) the stopwatch icon next to any property — this doesn't add a keyframe, it opens an expression editor field directly beneath that property in the Timeline.
- Type or paste an expression into the field, then click elsewhere (or
press Enter on the numeric keypad) to apply it. A red expression icon
(
=) replaces the stopwatch to show the property is now expression-driven. - While an expression is active on a property, manual keyframes and the
expression can coexist: use
valueinside the expression to reference the property's own keyframed value and modify it further (e.g. add a wiggle on top of an existing keyframed move).
2. The pick whip for linking properties¶
- Every expression field has its own pick-whip spiral icon. Drag it
onto another layer's property (or another property on the same layer)
to auto-generate the correct reference code — for example, dragging
from one layer's Position expression onto another layer's Rotation
generates
thisComp.layer("LayerName").transform.rotation. - This is the fastest way to link two properties without memorizing exact syntax, and it's how most real-world expressions get started even by experienced users.
3. Common built-in expressions¶
wiggle(freq, amp)— applied to Position, Rotation, or Scale, adds randomized jitter:freqis wiggles per second,ampis the amount of change. E.g.wiggle(3, 20)on Position gives a subtle handheld-camera feel.loopOut()— repeats the existing keyframes on that property indefinitely after the last one. Common types:loopOut("cycle")(repeat identically),loopOut("pingpong")(repeat forward then backward). Useful for a looping background element without duplicating keyframes manually.time— the current comp time in seconds; used to drive continuous motion, e.g.rotation + time * 30spins a layer 30 degrees per second forever without any keyframes at all.- Linking Opacity to audio — apply the Audio Amplitude effect
(Effect > Audio > Audio Amplitude) to an audio layer, then pick-whip a
Scale or Opacity property to
thisComp.layer("Audio").effect("Audio Amplitude")("Left Channel")for basic audio-reactive motion.
4. Expression controllers¶
- Effect > Expression Controls contains several utility effects — Slider Control, Angle Control, Checkbox Control, Color Control — that add no visible effect on their own but expose a single value in Effect Controls meant purely to be pick-whipped into other expressions.
- This lets you build one adjustable "master control" (e.g. a Slider
Control named
Wiggle Amount) that several other layers' expressions reference, so changing one slider retunes an entire animated group at once instead of editing each expression by hand.
5. Cleaning up and troubleshooting expressions¶
- A broken expression shows a warning triangle next to the property in the Timeline; click it to see the JavaScript error message, most commonly a mistyped layer/effect name (expressions are case- and spelling-sensitive to the exact name shown in the Timeline/Effect Controls).
- To remove an expression, Alt/Option-click its stopwatch icon again (toggling it off), or delete the text in the expression field and click away.
- Keep expressions short and named clearly — a project handed to another editor with unexplained pick-whipped expressions everywhere is much harder to hand off than one with a few clearly labeled Expression Controls driving things.
Worked example: an auto-looping background element¶
- In the composited title card from Module 3, add a small decorative shape layer meant to loop subtly behind the headline.
- Keyframe one full rotation (0° to 360°) over 2 seconds using Easy Ease linear (no easing, so the loop is seamless).
- Alt-click the Rotation stopwatch and add
loopOut("cycle")after the existing keyframes so the rotation repeats indefinitely for the rest of the composition without needing extra keyframes. - Add a Slider Control named
Wiggle Amountto the same layer, and set its Position expression towiggle(2, sliderControlValue)(pick-whipped to the Slider Control's value) for an adjustable amount of drift.
Cheat sheet — expressions¶
| Task | Where |
|---|---|
| Add expression to a property | Alt/Option-click its stopwatch |
| Link to another property | Drag the pick-whip spiral icon |
| Randomized jitter | wiggle(freq, amp) |
| Repeat existing keyframes | loopOut("cycle") / loopOut("pingpong") |
| Continuous motion without keyframes | Use time in the expression |
| Adjustable helper value | Effect > Expression Controls > Slider/Angle/Checkbox/Color Control |
| Remove an expression | Alt/Option-click the stopwatch again |
How It Actually Works¶
- An expression is JavaScript re-evaluated fresh on every single frame,
not a one-time calculation cached at the moment you typed it. After
Effects runs the property's expression text through an embedded
JavaScript engine for every frame it renders, with variables like
timeandvaluepopulated for that specific frame before evaluation — which is exactly whyrotation + time * 30produces continuous spinning with zero keyframes:timeis simply a different number each frame, so the expression's output is different each frame, purely as a side effect of being re-run against a changing input. valueinside an expression reads whatever the property's own keyframes (or default) currently resolve to at that frame, before the expression modifies it further — this is why keyframes and an expression can coexist: the keyframe system computes its normal interpolated result first, hands that number to the expression asvalue, and the expression's returned result (which may addwiggle()jitter on top, for instance) is what actually gets rendered. Nothing about adding an expression deletes or bypasses the keyframes underneath it.wiggle()is a seeded pseudo-random function evaluated per-frame at the specified frequency, not literal noise sampled from nothing. Internally it generates smoothly-interpolated random values (technically closer to Perlin-style noise than uniform random) at the rate given byfreq, scaled byamp, and adds that to the property's base value — the "seed" is deterministic per layer/property by default, which is why the same wiggle expression reapplied produces the same-looking jitter pattern rather than a different random result every time you scrub.loopOut("cycle")works by re-reading the existing keyframe data (their values and spacing) past the last keyframe's time, rather than literally copying keyframes into the timeline. It computes elapsed time since the sequence started, takes that modulo the total duration spanned by your keyframes, and looks up what value the original keyframed animation would have had at that equivalent point in its first cycle — which is exactly why editing an original keyframe automatically updates every subsequent loop without touching the expression at all: the loop has no independent copy of the animation, only a formula for reading the same source data repeatedly.- Expression Controls are ordinary effects with exactly one exposed
parameter and no rendering behavior of their own, existing purely to
give pick-whip references something stable to point at. Pick-whipping
from another property to a Slider Control generates a direct property
path (e.g.
thisComp.layer("Name").effect("Wiggle Amount")("Slider")) — changing that slider's value doesn't "broadcast" to every expression referencing it; each dependent expression simply re-reads that one effect's current parameter value every time it's re-evaluated on a new frame, same as reading any other property.
Exercise¶
Add loopOut("cycle") to a rotating or moving decorative element so it
loops indefinitely from a short keyframed cycle, then add a Slider Control
pick-whipped into a wiggle() expression on the same or another layer so
the wiggle amount is adjustable from one place. Confirm both expressions
show no warning triangle and the loop repeats seamlessly on playback.