2: After Effects Expressions for Beginners - How they work with keyframes
There is a big misconception among beginners: That adding an expression meant giving up on keyframes for that property. Expression on, keyframes irrelevant. That's wrong, and once you see why, after effects expressions get a lot more useful. The good ones don't replace your animation. They build on top of it.
This part covers how expressions and keyframes interact, the basic math you'll use constantly, and the three expressions that do most of the work in real projects: wiggle, time and loopOut.
Pre-expression and post-expression values
Every animatable property in After Effects has two values on any given frame:
The pre-expression value is what the property would be without the expression. Either a static number you typed, or whatever your keyframes say at that moment.
The post-expression value is what comes out after the expression has done its thing.
Adobe compares this to effects, and it's the clearest way to think about it. A layer has its original pixels, an effect processes them, you see the result. Same idea, just with numbers. The Timeline colors tell you which one you're looking at: blue for pre-expression, red for post-expression.
Using value to build on your keyframes
Inside an expression, the pre-expression value is simply called value. Put this on Rotation:
value + 90Without keyframes, the layer sits at its current rotation plus 90°. Now keyframe Rotation from 0° to 45°. The same expression turns that into an animation from 90° to 135°. Your keyframes still run the show. The expression just offsets them.
This is the pattern behind a lot of template work: animate the feel of the motion with keyframes, then let expressions shift, scale or mirror it.
You can also read individual keyframes. key(1).value returns the first keyframe's value, key(2).value the second, and so on. numKeys always equals the number of keyframes on the property, so this always grabs the last one:
key(numKeys).valueHandy when another property needs to know where an animation is going to end up, before it gets there.
Basic math in After Effects expressions
Before you learn a single function, get comfortable adding math to the end of an expression. These operators do most of the work:
+ and - add and subtract
* and / multiply and divide
* -1 inverts: clockwise becomes counterclockwise, left becomes right
Want something twice as strong? Add 2. Half as strong? / 2.
Adobe's help page has a nice combined example: adding / 360 100 converts a 0–360 range into 0–100. That's exactly what you need when a rotation dial should drive a percentage.
A real-world case: two gears, the second one spinning the opposite way. Link the second gear's Rotation to the first (Part 3 shows how) and add * -1:
thisComp.layer("Gear A").transform.rotation * -1wiggle(): random motion without the keyframe Clusterfuck
The most famous expression in After Effects.
Also the most abused.
wiggle(2, 30)The first number is the frequency (wiggles per second).
The second is the amplitude: the maximum deviation, in the property's own units.
Pixels for Position, degrees for Rotation. So this moves a layer twice per second, up to 30 pixels away from where it would otherwise be.
"Where it would otherwise be" is the important part. wiggle works off the pre-expression value. On a static property set to 0, wiggle(10, 10) hovers between -10 and 10. On a keyframed property, the wiggle rides on top of your animation as secondary motion. You don't have to choose.
Some honest advice: most wiggles I see in the wild are way too big. wiggle(1, 4) on a title reads as a gentle float. wiggle(5, 50) reads as a kinetic typography video from 2009. Start small and work up.
To wiggle only one axis, for example horizontal jitter on Position without any vertical drift, split the result:
w = wiggle(3, 20);
[w[0], value[1]]time: for things that never stop
time returns the current composition time in seconds. On its own, on Rotation:
timeThat spins the layer by 1° per second, which you'll barely notice. Multiply it:
time * 40Now it's 40° per second, forever, no keyframes. Loading spinners, background shapes, gears, clock hands.
Two small upgrades I use almost every time. Adding value keeps whatever starting rotation you set by hand instead of snapping to 0:
value + time * 40And if the layer starts later in the comp, subtract its in-point so the rotation starts when the layer actually appears:
value + (time - inPoint) * 40loopOut(): repeat your keyframes until the end of the layer
Keyframing a repeating animation cycle by cycle is tedious and fragile. Change one thing and you're fixing it twelve times. Animate one cycle instead, then add:
loopOut("cycle")The animation now repeats after your last keyframe until the end of the layer. loopOut() without an argument does the same thing, since "cycle" is the default. There's also loopIn(), which loops before the first keyframe. You'll use loopOut far more often.
The loop types worth knowing:
"cycle" repeats from the first to the last keyframe. For a seamless loop, your last keyframe should match your first, otherwise the animation visibly snaps back.
"pingpong" plays forward, then backward, then forward again. No matching keyframes needed. Great for swinging, breathing and blinking.
"offset" repeats the cycle but stacks the change each time. Animate a layer moving 100 px to the right and it keeps moving another 100 px per cycle. Underrated, and perfect for step-by-step motion like a ticking second hand.
"continue" doesn't loop at all. It keeps the property going at the speed of the last keyframe. Useful when something should drift off screen.
One thing that trips people up: loopOut needs at least two keyframes to loop. Without them it just returns the static value. No error, no loop, only confusion.
Combining loopOut and wiggle (the right way)
Say you want a looping bob with some organic randomness on top. The obvious attempt:
loopOut("cycle") + wiggle(2, 10)That roughly doubles your position, because wiggle() returns the full value plus the wiggle, not just the wiggle. Subtract value to isolate the noise:
loopOut("cycle") + (wiggle(2, 10) - value)The first time I did this, I spent a solid half hour convinced the layer had teleported off screen for no reason. There was a reason. The reason was me.
Up next
Part 3 is about linking: the pick whip, Copy With Property Links, and how to connect properties across layers and comps without everything falling apart the moment you rename a layer.