The Expressions Cheat Sheet BETA
for Adobe After-Effects
Start with the basics

What are expressions?

Expressions are simply another way to type in a value

The expression result must, without any exceptions, be a value that the Property can read. However, on the way to that value we can jump hooks, perform incredible math tricks and even fight dragons, as long as at the end of the fight we come back to our senses and give back a value for the property to read.

* I lied about the dragons part, but everything else was true.

Special keywords

Some built-in keywords are actually values!

There are some keywords built into the expression engine that is being converted to other values.
For example the keyword "time" will always give you the current time! How cool is that?

When starting to code a lot of people feel overwhelmed by the amount of information they feel like they don't know, and that's okay. Nobody expects you to know that "time" will give you a number. The easier way to approach this is to ask yourself: "Hmm, I wonder if there's a way to get the current time in an expression".

Asking questions is a great start, because questions can be googled, and answered!

Different properties, different expression results

The expression result should be a value that matches the format of the property value

Multi-dimensional properties like Position and Scale expect an Array of values as the expression result, with a value for each dimension.
On the other hand, single-dimensional properties expect a single value.

Use the image above as a reference for the correct syntax.

Applying / removing an expression

Alt + Click the stopwatch icon

Doing so will open a textbox next to the property, in which you type in your code.

Why can't I change the value after applying an expression?

That's because expression hijacks the original value in favor of a new value. However...

You can use the original value as part of the expression, by adding "value" to your expression results

Functions

F is for friends who do stuff together!

Every time you see "()" at the end of an expression, it usually means this expression is a Function.
A function expression is like a friend behind the screen who solves a problem for you, then hands you back the result.
Sometimes they need you to provide more information on how to do it.
When they do, you provide this information inside the parenthesis.

Think about wiggle().
You tell your friend, wiggle, exactly how much, and how often to wiggle by giving them numbers inside the parenthesis. Then they do the work for you by calculating the final result and give you back a number, or a point in space.

Order of execution

The computer reads your code from top to bottom, line by line. But...

There are a lot of caveats to that, and unless you are planning on going deeper into expressions it's better that you learn by practicing the examples on this page.

Otherwise, google "Javascript order of execution" to learn more.

Expressions are recalculated every frame

Every new frame, the entire thing is recalculated.

You can't gather information over time. Everything you do in code has to exist now and will be recalculated as the timeline progresses.

Is this a JavaScript tutorial?

NO.

This is not by any means an extensive JavaScript tutorial. My goal is for you to be able to use Expressions in After-Effects as quickly and conveniently as possible. Of course, I am going to introduce you to some new concepts in programming, but I am not here to teach you the entire thing, but rather to get you going.
0/0
value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Expression Controls

After-Effects comes with a lot of expression controls. These are considered effects and can be found in the Effects menu, although they do not act on your layer in any way.
Instead, you can use each control as a data point in your expressions.

For example, you can connect multiple color properties from multiple layers to one Color Control. That lets you easily change multiple colors at once.
Sliders and checkboxes are also commonly used to easily update expressions without manually changing them.

These controls like regular controls let you set keyframes, which is also a great way to manipulate your expressions over time.

To add new expression controls, go to Effect -> Expression Controls, then choose the desired one you want to add.

In order to reference a control in your expressions, use the Pickwhip like so:

About that Checkbox Control

The checkbox control returns a value which is either 0 or 1. In JavaScript, 0 and 1 are synonymous to false and true, which means you can use them as a condition (read more about truthy and falsy).
However, in my experience Pickwhiping to the Checkbox Control is sometimes not enough to get it working properly and that's most likely due to precision issues.

A walk-around that works for me is to add ".value" after the Pickwhip result, or put the entire thing inside a Math.round() function.

//Option A:
effect("Checkbox Control")("Checkbox").value;
//Option B:
Math.round(effect("Checkbox Control")("Checkbox"));

Terms used:
Easy
Medium
Hard

Expression Controls

Learn how to control a property using expression controls

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Pickwhip

Adobe coded in an easy way to reference other layers and properties.

It's called the Pickwhip. You may have seen it before in the context of layer parenting.
What the Pickwhip does is lets you visually select which layer / property you want to reference in the expression by dragging a line straight towards it.
Once you let go of your mouse, an address leading to the value of that property will show up in your code.

Reference values from other properties

We can use the Pickwhip to reference the value of a slider in our expression, which will give us a number that we can use to control something else.

Reference properties from other comps

By opening multiple lines you can use the Pickwhip to select a property from a different comp.

While we are at it, I once made a song about parenting in After-Effects.



Terms used:
Easy
Medium
Hard

Pickwhip

Quickly reference properties, layers, and other items.

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Random

random() gives you a random number between 0 and 1

random() // anywhere between 0 and 1. Updates every frame

Random Rotation

Apply this to a Rotation property:

random()

It might not be very obvious, but if you look closely you can see the image is rotating ever so slightly.
The image gets a new random rotation between 0 to 1 degree, which is very little.

Fortunately for us, we can give random a multiplier!

random(360)

Now our Rotation property will be randomly set to anywhere between 0 and 360 every frame. Cool, fuzzy but cool.
Let's tone it down a notch:

random(10);

This is cool, but it almost feels like something is wrong. Oh, I know! Our layer is only leaning to the right. That's because random(10) gives us a number between 0 and 10.
Fortunately for us (we are very lucky today), random is very kind. If we give it two numbers instead of one, it treats them as a range.

random(-10,10);

That should do the trick. Now the layer should rotate 10 degrees to either direction.

Move in random directions

the Position property usually expects two values in an Array. This should do the trick:

var max = 50;
var randomX = random(-max, max);
var randomY = random(-max, max);
value + [randomX, randomY];

Now we can easily specify what is the maximum amount of randomness we want to add to the original value.
The result is very similar to wiggle(), the difference is that wiggle tends to be smoother and transition between new values slowly and across multiple frames.
Random as mentioned before gives you a completely new value every frame, resulting in a much sharper, more brutal transition.

Random Color (Warning: flashing lights)

A color in expressions is usually represented by an array of normalized values (0 to 1), a value for each color channel (Red, Green, Blue, Alpha).
Although alpha is many times ignored in most color properties, for some reason it might be required.

Either way, to create a new random color every frame we can use the expression below:

[random(), random(), random(), 1];

random() is serving us well here because a value between 0 and 1 is exactly what we need.
Uncheck "Pause" to see the color value changing randomly (warning: flashing lights):

Terms used:
Easy
Medium
Hard

Random

random() gives you a new random number every frame, but what if you want a random location on the screen?
Tap to see how this can be achieved.

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Time

Gets the current time on the timeline. That's right!

time // a number which represents the current time in seconds

Rounding down to seconds

As you probably have noticed, the result of "time" is a float, which means it shows the fractional part of the number.
If we want to round our number to only display the current second, like a clock handle, we can do it like so:

Math.floor(time);

Rotate across time

Apply this to a Rotation property and hit preview.

time * 360

Every one second the rotation will finish a 360-degree lap! That's so cool!

To make it easier to manipulate, we can do something like this:

var lapDuration = 2; // in seconds
time * 360 / lapDuration;

Now we can easily change "LapDuration" to decide how long we want our Rotation property to complete one lap.

Rotate faster, then faster and faster and faster...

Try applying this to a Rotation property:

time * time * time * time

Press play. At first, your layer will rotate very very slow, but keep going! It will accelerate and start rotating faster and faster until it's almost too fast for your eye to register to motion properly.
What a cool simple trick right? We are literally multiplying the current time by itself 4 times. By the 2 seconds mark the result is 16 degrees, which is not that impressive. But this increases exponentially, and by the time the timeline hits 10 seconds, we are already at 10,000 degrees! Holy cow.

The exact same expression can also be written down this way:

Math.pow(time, 4)

Math.pow stands for power. We ask our friend, Math.pow() to check for us the result of the current time to the power of 4, which is the same as multiplying time by itself 4 times. Neat!

Terms used:
Easy
Medium
Hard

Time

Gets the current time in the timeline. That's right!

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Wiggle

wiggle takes the original value and modifies it to shake over time. How much shake should it add? How fast should it shake? YOU DECIDE!

wiggle(frequency, amplitude);

Play around with the Amplitude and Frequency sliders to get a hang of what they do:

Frequency
Amplitude

Wiggle listens... Wiggle knows...

Wiggle is always trying to return a value similar to the one the property needs.
On a Rotation property, which is 1 dimensional, wiggle will return a number.
On a Position property or other multi-dimensional properties such as Scale and colors, wiggle will return an array of numbers (one for each dimension)

Wiggle Position

wiggle(5, 45) // [x,y]

Wiggle Position, one dimension only

On a position property wiggle returns two values: [x,y].
We can place the wiggle result in a variable, and then reconstruct a new result, one that retains one of the original value channels.

var w = wiggle(5, 45); // x and y
var result = [ w[0], value[1] ]; // set x from the wiggle result, and y from the original value
result; // apply

To wiggle the Y-axis only:

var w = wiggle(5, 45); // x and y
var result = [ value[0], w[1] ]; // set x from the original value and y from the wiggle result
result; // apply

Wiggle Rotation

wiggle(5, 45) // number

Wiggle Colors

Colors are just arrays, just like points in space. That's why wiggle also works on Color properties.

wiggle(5, 0.5) // [number, number, number, number]

It's important to keep in mind that wiggle manipulates the original value. In order to wiggle a color in the full spectrum you probably want to set the original color value to be perfect gray (#808080) and the  amplitude to 0.5 (like in the code above). Why is that?

Each channel of the color array needs to be a number between 0 and 1. Gray translates to exactly 0.5, which is then manipulated by the wiggle to move 0.5 steps in each direction, which keeps our number in the full spectrum.
That being said I encourage you to experiment with different values and see what happens!

Terms used:
Easy
Medium
Hard

Wiggle

Make a position shake
Rotate something in random directions
Simulate camera hand shake

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Distribute Equal Spaces Between Layers

Create a new empty comp and add a new layer. Then apply this expression to its Position property:

var x = thisLayer.index / (thisComp.numLayers+1) * thisComp.width;
[x, value[1]];

Now as you duplicate the layer multiple times you will see how all layers automatically adjust their x position to create an evenly spaced row.

Congratulations, you're a wizard Harry. Now let's break it down:

thisLayer.index / (thisComp.numLayers+1); // gives us a number between 0 and 1

We divide the current index of the layer with the number of layers of the comp. Notice though that we bumped the number of layers up by one.
That's because we want to keep things centered. The minimum index of a layer is 1. When we divide 1 by 2, we get 0.5, which is exactly half.
This scales up as we add more layers.

You can try omitting the one and see what happens.
Anyway, after having a number between 0 and 1, we multiply it by the comp width:

thisLayer.index / (thisComp.numLayers+1) * thisComp.width; // gives us a number between 0 and the width of the comp

And finally, we assign it to a variable named x, and use the original y value from the property.

//var x = thisLayer.index / (thisComp.numLayers+1) * thisComp.width;
[x, value[1]];

Let's add some colors

I have cleared the comp and copied the Position expression we wrote above, but this time to a shape layer with a fill.
Now let's apply the following expression to the fill:

var blue = [0,0,1, 1];
var red = [1,0,0, 1];
var progress = thisLayer.index / (thisComp.numLayers + 1);
linear(progress, blue,red);

Now duplicate the layer again and look at that:

We are using the same technique of dividing the current index by the number of layers in this comp to get a value between 0 and 1.
Once we have that value, we can use the linear() function to blend between our two arrays of colors progressively. How cool is that?

Caveats

These kinds of rigging examples using the numLayers property work best in isolated comps. If you were to add any extra layer to the comp we just built in the example above, you might screw up your entire logic.
However, used correctly numLayers can be pretty powerful and allow you to create some magical procedural systems that are easy to change and modify later on.

Terms used:
Easy
Medium
Hard

Distribute Equal Spaces Between Layers

If you can get the number of layers in the current comp you can use that number to space them however you want.

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Loop Keyframes

loopOut() will make your keyframes repeat. You must have at least one keyframe for it to work, otherwise, you might get an error!

loopOut();

More powerful than you think

By default, loopOut() just works, as long as your property have some keyframes.

loopOut();

But let's explore some more interesting options this function gives us:

loopOut("pingpong");

Pingpong will literally play your animation back and forth, So if you have a rotation keyframe with the value of 0 and another one with the value 360, using ping pong will animate between 360 and 0, then between 0 and 360, then between 360 and 0 again and so on, like a ping-pong game.

loopOut("offset");

Offset loops your keyframed animation without resetting it. This can be a little trippy so let’s start with an example:
You can keyframe a ball jumping down a single stair, then loopOut(“offset”) will make it keep going down the rest of the stairs, forever (assuming the distance between those stairs are equal).

Think of it this way: If you have a point A and a point B, a normal loopOut() would simply repeat the motion from point A to point B forever. With offset, once it reaches point B, instead of starting over it will keep going from point B to a new point, point C. Where is point C? It is where point B is to point A. The motion is adding up onto itself.

loopOut(“continue”);

Continue is funny, it behaves like shooting an object into space. Once in space, the object does not accelerate or decelerate anymore, it uses its previous momentum to keep going at the same speed.
Continue continues at the very same speed the animation ends in. It will sample the velocity right before the last keyframe and keep your animation going at that same speed forever.

There is more to loop expressions, but these are the basics.

Limitations

Loop out does not work on path keyframes.

Terms used:
Easy
Medium
Hard

Loop Keyframes

Repeat a set of keyframes. But there's a twist!
It turns out you can use loopOut() to loop in many interesting ways.
Tap to find out how

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Comp Width, Comp Height

width and height are two reserved keywords in After-Effects that let you get the width and height of an item.

[thisComp.width, thisComp.height] // [1920, 1080] in a 1080p comp

In After-Effects, the top left corner of the comp is the zero point, where both X and Y are zero.
That means that the bottom right corner of the comp will be the point in which X and Y are equal to the comp dimensions: [width, height].
In a 1080p comp, this point will be set to [1920, 1080]. We can use "width" and "height" in expressions to dynamically get these values.

Naturally, to find the exact center of the comp we will have to divide both width and height in half.

Placing a layer exactly at the center

Try setting a layer's anchor point to its center, then apply this expression to the Position property:

[thisComp.width,thisComp.height] * 0.5;

That's right, dead center baby! Have you ever seen something placed truly in the center? But in the perfect, true center?

Now you can go to your comp's settings and change your comp size. Your layer's position will update to be exactly at the center using the new comp dimensions.

By the way, wondering what the square brackets are for? Look at your position property. It expects both an X and a Y (not to mention Z, but that's a story for another day...).
Your job is to give it back a value with a similar layout, both an X and a Y. [x, y].

Terms used:
Easy
Medium
Hard

Comp Width, Comp Height

Ever wanted to place something exactly at the center of a comp?
If you can get the comp dimensions, you can do exactly that.

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Crashing After-Effects

Code can be unsafe. One of the easiest ways to screw up with code is what's called an infinite loop.
Apply the following expression to any property in order to crash After-Effects:

while(true){}

while() in JavaScript lets you execute a block of code repeatedly as long as the condition inside the parenthesis is true.
This means that it's your responsibility to break out of the loop. If we don't, like in the example above, our code will try to run forever and After-Effects will freeze as a result.
Another way to do that is with a for loop:

for (var i=0; i<Infinity; i++) {}

Using a for loop we can run a code repeatedly until a condition has been met. The condition we set is i < Infinity, which as you can imagine, will never be met.

Sabotaging somebody's project file

Here in the Good Boy Ninja project, everything is about peace and love, but let's say there is someone you war and hate...
You could make After-Effects crash, but only when the timeline is set to a specific amount of time. Something like:

if (time > 10) {
	while(true){
	}
} else {
	value
}

Now every time they will scroll past the 10 seconds mark, their project will crash. Cruel, I know, but doable!

Terms used:
Easy
Medium
Hard

Crashing After-Effects

Zoinks

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Reduce FPS with Posterize Time

posterizeTime() lets you simulate a lower fps than that of the comp, by specifying a number between the paracentesis.

posterizeTime(fps);

Make sure you don't place it at the bottom of your code, as it does not return any value.

Posterize the expression result

Write any additional code underneath your posterizeTime() statement, like so:

posterizeTime(12);
time * 36;

Before:

After:

Because posterizeTime() expects a number, we can even use the pickwhip tool to use a slider value as the new fps.

Value

Posterize time the original value

posterizeTime(12);
value

Terms used:
Easy
Medium
Hard

Reduce FPS with Posterize Time

Much like the "Posterize Time" effect but for the changes in the property's value

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Snap

The trick to achieve the South-Park animation style is to divide a number, round it and then multiply it back the same amount.
This behaves like snapping something to a grid. If we divide and multiply by 20, the spacing between the grid cells will be 20 pixels.

Snapping Position (or other 2 dimensional properties)

// properties you can edit
var stepSize = 20; // Will stick to 20 pixels incremenets

// run
var x = Math.round(value[0] / stepSize) * stepSize;
var y = Math.round(value[1] / stepSize) * stepSize;
[x, y];

Snapping Rotation (or other 1 dimensional properties)

// properties you can edit
var stepSize = 20;

// run
var result = Math.round(value / stepSize) * stepSize;
result;

Bonus: Creating a snap function that can be applied to both kinds of properties

function snap(theValue, theStepSize) {
	
	if (Array.isArray(theValue)) {
		// if the value is an array (like a Position value) apply to each dimension
		var result = [];
		for (var i=0; i<theValue.length; i++) {
				result.push(Math.round(theValue[i] / theStepSize) * theStepSize);
		}
		return result
	}
	
	// otherwise, apply to the value
	return Math.round(theValue / theStepSize) * theStepSize;
	
};

snap(value, 20);

In this example we created a function that snaps a value to a specific increment just like before.
Additionaly, we can use the power of JavaScript to automatically check if the value given to the function is an array, and if it is to snap each value independently and return the result as an array as well.

Terms used:
Easy
Medium
Hard

Snap

Create South-Park like animations with this rounding trick

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Stay within a range with Clamp

clamp() takes a value and makes sure it does not go beyond a certain range.

clamp(value, min, max);

Lock a point inside a rectangle

What's lovely about the clamp() function is that it also accepts arrays. This lets us clamp points in space! For example, if we wanted to make sure our layer can't leave the canvas we can apply the following expression to its Position property:

clamp(value, [0,0], [thisComp.width,thisComp.height]);

That's pretty cool! In order to describe a two-dimensional range we only need two points, the minimum and the maximum.
In this case we specify the top-left corner of the comp ([0,0]) and the bottom-right one (thisComp.width, thisComp.height).

You can modify these values to lock the Position inside any rectangular surface in and outside the view.

Clamp rotation and other one dimensional values

To clamp single-dimensional values to a range simply specify the value and the desired minimum and maximum.

clamp(value, -20, 20);
Terms used:
Easy
Medium
Hard

Stay within a range with Clamp

Lock a value to a specific range

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Layer Index

"index" gives as an index of a layer. In this case, the layer the expression belongs to.

thisLayer.index

Every layer has a number, usually stated to the left of the layer's name. The further down the comp a layer is, the bigger its index.

Rotate by index

Let's tell the layer to rotate based on its index. We're gonna multiply the index by however many degrees we want to spin each layer. Let's use 36 degrees for now, like so:

thisLayer.index * 36

Now select and layer duplicate it (Cmd + D \ Ctrl + D) a bunch of times and behold:

How cool is that?

Why did we use 36 degrees?

In order to finish one rotation lap, we need 360 degrees. Multiplying 36 by the layer index will get us to 360 by the 10th layer.
You can use however many degrees you want.

Using a slider.

Let's do the exact same thing, but instead of hard coding a number of degrees, we're gonna use a slider to set it later on.
We're going to create a new null (Layer -> New -> Null Object) and add a slider to it (Effect->Expression Controls -> Slider Control).

Now we can duplicate our layer a bunch of times. You might notice that nothing seems to happen, but that's okay.
That's probably because your slider's value is set to 0, which results in all rotations being 0.
Play around with the slider and behold:

This method is cool, however, it can be unreliable at times, as the index of the layer can change as you design your comp.
You rarely think about the index of a layer in any meaningful way when working with After-Effects, because reordering layers in the timeline dictates the order in which layers are stacked upon each other.
You can try messing this constellation up by creating a new layer that does not have this expression already, and move it up and down in the timeline.
See how some copies disappear?

Also, if you want to make a change to this expression you would have to do this 9 times, or at least once, and then copy it over to all the other layers.
Programming wise these are not good habits, but within the After-Effects environment sometimes there is no choice but to use a layer's index in an expression.

The layer index is great! Just...messy at times.

Terms used:
Easy
Medium
Hard

Layer Index

Every layer has an index, a unique number.
You can use that number to design and animate complex systems.

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Text Typewriter Effect

We can cap the value of a text layer to a maximum character using time itself, how cool is that?

Using the value of an existing Text Layer

All we need to do is to remap time to the number of letters in our text. Apply the following expression to a Text Layer "Source Text" property

// properties you can change
var startAt = 0; 
var endAt = 9;

// trim the text
var maxLetters = Math.floor(linear(time, startAt, endAt, 0, value.length)); // number
var result = value.substring(0, maxLetters); // trim 
result

From global time to layer time

The effects seem to work just fine. However. the range we set with startAt and endAt is referring to the global comp time and ignores the layer start time. If the layer starts / ends outside the range we set in the expression head, you might not see the effect because it's taking place when the layer is not visible.
To fix this we can use "inPoint" in our expression to make up for the difference, like so:

// properties you can change
var startAt = 0; 
var endAt = 10;

// trim the text
var maxLetters = Math.floor(linear(time, inPoint + startAt, inPoint + endAt, 0, value.length)); // number
var result = value.substring(0, maxLetters); // trim 
result

inPoint is the time in seconds in which the layers start in the timeline. Adding it to our range will make the range relative to the layer itself. COOL!

Terms used:
Easy
Medium
Hard

Text Typewriter Effect

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Waves

The sine wave function is a friend of yours that gives you back a number between -1 and 1.

Math.sin() // a number between -1 and 1

The exact results depends on you. Unfortunately, it expects you to give it a number between 0 and 6.2831.
Wait a minute. That's very specific. 6.2831?
Well it turns out 6.2831 is exactly 2PI, which is the point in which the sine wave results in exactly one lap.

Before you panic, try the examples below:

Rotation

Apply this code to a Rotation property:

 45 * Math.sin(Math.PI * 2  * time) // gets a number between 0 and 1, then multiplies it by 45 degrees;

With a single line of code, we got your layer to rotate 45 degrees back and forth every second. How cool is that?

We are multiplying 2PI with the current time.
When the time is 0 seconds, we are 0 laps into our sine wave. When time is 1 second, we are 1 exactly one lap into our sine wave. And this goes on forever.
This helped us get a number that fluctuates between 0 and 1 repeatedly. We then multiplied it by 45 and got a number between -45 and 45. That's awesome!
The Rotation property expects a number, and a number between -45 and 45 is a number, so we did a good job on that!

For our final expression, we can do something like this:

var loopDuration = 5; // every 5 seconds, or however many seconds you decide
var degrees = 45; // or however many degrees you want
degrees * Math.sin(  Math.PI * 2  * time / loopDuration);

Now we can easily change the value of"loopDuration" in order to determine the duration of one, full lap. This makes for an easy and comfortable sine wave experience!

Position

Coming Soon...

Terms used:
Easy
Medium
Hard

Waves

Want to make something move up and down repeatedly? Use a sine wave!
Want to spin something back and forth? Use a sine wave!
A sine wave is not scary, it's awesome!
Use it to create a repetitive, smooth motion.

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
blend between...

After-Effects offers some great functions to blend between two values. The main two are:

linear();
ease();

What's great about those functions is that they offer very extensive functionality for advanced users, but also give you the option to keep things simple. Let's start with simple :)

The Basics

To blend between 2 items, we need three things:
1. To specify how much we want to blend
2. The first item
3. The second item

Comfortably enough, linear and ease expect you to give them exactly that.

linear(t, itemA, itemB)

Let's have a look at some examples:

Blend between two numbers

Let's try to interpolate between two numbers. Apply this expression to a Rotation property.

linear(0.5, 200, 400) // Result: 300

We are asking linear() to give us the number that is exactly halfway (0.5) between 200, and 400. You guessed it, the result is 300!

Using a Slider as the amount

Because t expects a number between 0 and 1, we can easily use a slider to control it.
We're gonna add a slider to our layer by going to Effect -> Expression Controls -> Slider Control.
Now, let's change our Rotation expression a little bit

var slider = // pickwhip to your slider
linear(slider * 0.01, 200, 400);

Now we can use our slider to blend between 200 and 400:


You might have noticed that we are multiplying the slider value by 0.01. Now, why is that?
Well, linear and ease expect a number between 0 and 1 as the amount, and our slider can easily go beyond this range.
Multiplying the slider value by 0.01 lets us change the slider more comfortably between 0 and 100, instead of 0 and 1.


Blend between two points

linear and ease are powerful, as they can blend between arrays of numbers.
Let's apply the following expression to a Position property:

linear(0.5, [0,0], [500,500]); // Result: [250,250]

We are asking linear() to give us back a point that is halfway between [0,0] and [500,500]. The result is [250,250].
What happens if you add two Null Objects (layer -> new -> Null Object) and set pointA and pointB to their positions?


We can now move each of our nulls around in space, and our layer will stay directly in-between them.
We can also change the t value from 0.5 to any number between 0 and 1 to place our layer in a different spot in-between our nulls. Cool!

Blend Between Colors

linear and ease work on multi-dimensional arrays, which means we can interpolate between colors!

var slider = // pickwhip to your slider
var red = [1,0,0,0];
var blue = [0,0,1,0];
linear(slider * 0.01,red,blue)

(Don't forget to Pickwhip to your slider like in the slider example above).
Now we quickly created a slider that lets us blend between red and blue.


What's cool about these kinds of rigs is that we converted a number (0 - 100) to a color ([x,x,x,x]).
What other numbers do you know? Is "time" a number? How about a Rotation value? Can you make a layer change its color based on its Rotation? How cool would that be?

Remapping the range (advanced)

linear() is very powerful right out of the box, but it also has some hidden superpowers.
To find out about it, let's start with a problem.
Let's say we want to use time itself as the t value. Apply this expression to a Rotation property:

linear(time, 0, 360);

It works, but it works only when the current time is somewhere between 0 and 1. Then, we have 9 seconds of complete and utter nothingness.
We know that linear() expects a t value between 0 and 1, like a percentage almost. But what if we could change that?
What if we wanted our animation to be driven by time but between a different range, something like 3 and 8 seconds.

We can do it like so:

linear(t, rangeA, rangeB, itemA, itemB)

As it turns out, by squeezing two additional values in-between t and our items, we can define a range in which t will perform in.

Now if we apply the following expression to our Rotation property:

linear(time, 3, 8, 0, 360)

Our transition between 0 and 360 degrees will occur as t progresses between 3 and 8 seconds. How cool is that?

linear() vs ease()

linear() lets you blend between two items an amount specified by the t value.
With ease() the same concepts apply, but t is modified behind the scenes to smoothly interpolate between 0 and 1. If that's not clear, let's compare the two:

linear(time, 0, 10, 0, 360);
ease(time, 0, 10, 0, 360);

linear result:

ease result:

Comparing the two, it's easy to see the difference. ease is biased and blends using a secret curve to simulate an easing effect.


Terms used:
Easy
Medium
Hard

blend between...

Blend between two points and get the third point somewhere in between.
Blend between two numbers and get a number in between.
Blend between two colors and get a color in between.

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Delayed animations using Value At Time

"valueAtTime()" grabs the value of a property at a specific time, unlike "value" which grabs the value of a property as it is now.
You specify time as a number inside the parenthesis.

valueAtTime(0)

Creating a delay between layers

In this example, there is no need to parent the layer itself to the main one. We're going to use an expression to grab its Position value.
However, instead of using "value", we're gonna use "valueAtTime()", and instead of specifying a time in seconds, we're gonna use the current time and subtract the amount of delay we want (in seconds).

var delay = 0.2; // seconds
var parentPosition = // parent to the other layer's Position property

parentPosition.valueAtTime(time - delay)

For the "parentPosition" variable value, use the Pickwhip tool to select the parent's Position property, like so:

And we're done! Any change in Position the parent layer will perform, our child layer will perform as well but with a 0.2 seconds delay. How cool is that?

Terms used:
Easy
Medium
Hard

Delayed animations using Value At Time

Gets the value of a property, but at a specific point in time.

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Looping Wiggle

Looping wiggle does not exist in After-Effects, this is a great chance to use wiggle and other functions After-Effects offers to create our own.
The result would look something like this:

// properties you can change
var loopDuration = 1;
var frequency = 1;
var amplitude = 110;


// looping wiggle calculation
var t = time % loopDuration;
var wiggle1 = wiggle(frequency, amplitude, 1, 0.5, t);
var wiggle2 = wiggle(frequency, amplitude, 1, 0.5, t - loopDuration);
linear(t, 0,  loopDuration, wiggle1, wiggle2)

At the top, we have our three main parameters that we can manually set in order to determine how long it takes for our loop to restart, as well as how frequent or how much our layer will wiggle.

What is this long expression? What is going on there?

To create a looping wiggle we are blending between two symmetrical versions of the wiggle() function, using the linear() function.
This lets us end up exactly where we started, then repeat.

Creating our own function

Another cool thing we can do is to convert this code into a function and give it a name that's easy to understand.

function loopingWiggle(frequency, amplitude, loopDuration){
	var t = time % loopDuration;
	var wiggle1 = wiggle(frequency, amplitude, 1, 0.5, t);
	var wiggle2 = wiggle(frequency, amplitude, 1, 0.5, t - loopDuration);
	return linear(t, 0,  loopDuration, wiggle1, wiggle2)
};

Notice that pasting this into After-Effects will result in an error. Why?
That's because functions are like templates, they are sitting there and waiting for us to use them.

Think about the original wiggle expression, somewhere behind the scenes there is a function called wiggle, waiting for you to use it.
We created a very similar function called "loopinWiggle" which takes the same two parameters "wiggle" takes (frequency and amplitude) but then also takes a third parameter, the duration of the loop.
We call it in a similar way we call wiggle, at the end of our code.
Our final expression should look like this:

function loopingWiggle(frequency, amplitude, loopDuration){
	var t = time % loopDuration;
	var wiggle1 = wiggle(frequency, amplitude, 1, 0.5, t);
	var wiggle2 = wiggle(frequency, amplitude, 1, 0.5, t - loopDuration);
	return linear(t, 0,  loopDuration, wiggle1, wiggle2)
};

loopingWiggle(2,5,10); // calling the function

Why a function?

Creating your own functions helps you better understand that expressions in After-Effects are not some random magic.
Now we know that the original wiggle() expression is a function itself.
You don't see its source code because it's built into After-Effects, but it's there, somebody wrote it and it's waiting for you to call it.
You can do the same with functions you make on your own, and that's simply really cool!
Learn more about Functions

Terms used:
Easy
Medium
Hard

Looping Wiggle

Are you trying to create a looping video but wiggle stands in your way?
A wiggle that repeats itself is what you are after.

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Move in a Circle

Moving in a Circle

Apply this code to a Position property:

 // properties you can easily change
var loopDuration = 5;
var circleRadius = 25;
var flip = false;

// move
var flipper = flip ? 1 : -1;
var waveLogic = time * 2 * Math.PI / loopDuration * flipper;
var x =  Math.sin(waveLogic) * circleRadius;
var y =  Math.cos(waveLogic) * circleRadius;
value + [x,y];

So what are we doing here?

We are using the power of sine waves and cosine waves to create a looping, back and forth motion for each dimension.
We then multiply the result by the desired circle radius and add them to the original pre-expression value.

Terms used:
Easy
Medium
Hard

Move in a Circle

Easily move something in a perfect sample using Sine and Cosine waves

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Conditions
if(true){
// do this
} else {
// do that
}

Comparing items

In JavaScript you can easily compare two items using one of the following options:

A == B	// A is equal to B
A === B	// A is equal value and equal type B
A != B	// A is not equal B
A !== B	// A is not equal value or not equal type B
A > B //A is greater than B
A < B	//A is less than B
A >= B	//A is greater than or equal to B
A <= B	//A is less than or equal to B

The shtick here is that comparing two items is like asking the computer a question. The answer will always be either true or false. For example:

 time == 10 // will be true only when the current time is 10 seconds

true or false, that's great! This is exactly what we needed to create an if-else statement.

Using a Checkbox as a condition

Let's make a layer rotate but only when a checkbox is active.
First, we'll add a checkbox by selecting the layer and going to Effect -> Expression Controls -> Checkbox Control.
Now let's add the following expression to our Rotation property:

var checkbox = //pickwhip to your checkbox
if (checkbox.value) {
	time * 360;
} else {
	value
}

Use the Pickwhip tool to select the checkbox, like so:

And that's it! If the checkbox is selected, our layer will spin, otherwise it will maintain its original value.
Try clicking this checkbox to see the result in action:

Cool! Let's try to do the same thing with a Position property.

var checkbox = //pickwhip to your checkbox
if (checkbox.value) {
	var x = random(-15, 15);
	var y = random(-15, 15);
	value + [x,y];
} else {
	value
}

Don't forget to parent to your checkbox like before! Now, when our checkbox is active our layer will shake. Cool!

Rotate, but only if time is bigger than 5 seconds

if(time >= 5){
90
} else {
-90
}

Don't let your eyes off the image. It might take up to 5 seconds for the timeline to reach the 5 seconds mark, but eventually, it will flip.
If the current time is 5 or above, the statement "time >= 5" evaluates to true. In that case, the Rotation property will be set to 90 degrees. On any other occasion, it will be set to -90 degrees.

Rotate, but only every other second

if(Math.floor(time)%2 == 0){
-90
} else {
90
}

Learn more about the Remainder Operator

Learn more about Remainder

Multiple Conditions (this and that)

In Javascript, we can use what's called logical operators to compare multiple items.

&& // and
|| // or

For example:

10 == 10 && 0 == 0 // true, because both are true
10 == 10 && 0 == 10 // false, because the second statement is false
10 == 10 || 0 == 10 // true, because at least one of the statements are true (the first one)

Now let's put this to practice. Place this on a Rotation property:

if(time > 3 && time < 7){
time * 360
} else {
0
}

Now, only when time is bigger than 3 and smaller than 7 our layer will rotate. How cool is that?
We are using the && operator to make sure both conditions are true. It takes only one of them to fail in order to consider the entire thing as false.

Let's try to use the || operator to create the inverted effect:

if(time < 3 || time > 7){
time * 360
} else {
0
}

Cool! with the || operator we only need one of the statements to be true to consider the entire thing true.
When the time is smaller than 3 it's enough to consider the statement true, even though time isn't bigger than 7, and vice versa.

A lot to wrap your head around? Don't panic!

You've just been introduced to a lot of new characters, == && || <= >=, this can feel like a lot at first.
Take a deep breath and try to remember that you are talking to a computer here. All of these symbols represent questions that humans are using in real life.
Is the Apple Red && the Banana yellow? true, the apple is Red and the Banana is yellow.
Is the apple Red || the Banana purple? true, because the apple is red.
Is 5 > 10 ? false, 5 is smaller than 10.

You are already proficient in asking and answering those questions yourself, the logic is very simple, and while the syntax takes some getting used to, I believe in you!

 value == 10 // will only be true if the value of this property is 10
 value == [0,0] // DOES NOT WORK! will be false, because you can't compare arrays with comparison operators
value[0] == 0 && value[1] == 0 // will be true if the value is [0,0]

ternary

As it turns out, there are other ways to ask a question in JavaScript and do something based on the answer.
The ternary operation is a more compact form of an if-else statement:

 condition ? doThisIfTrue : otherwiseDoThis

We ask a question followed by a question mark and a colon. If the answer is true, do what's after the question mark, otherwise do what's after the colon.
For example, we can convert some of our expressions from before into one liners:

time >= 5 ? 90 : -90
Math.floor(time)%2 == 0 ? 90 : -90

As you can see, we are asking the same questions we did in the previous if-else statements we covered. The result should be the same.

Terms used:
Easy
Medium
Hard

Conditions

The value will be 5, but only if (this condition is true)
Otherwise, the value will be 10.
In other words, make the computer work for you.

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Remove Keyframes Transition (Simulating Hold Keyframes)

nearestKey() lets you get the value of the keyframe that is closest to the specified time.

nearestKey(time);

Passing in the variable "time" will get the key that is closest to the time indicator.

Removing keyframes transition (simulating "hold" keyframes)

Let's say we want to temporarily remove the transition between your keyframes. You could right-click your keyframes and choose "Toggle Hold Keyframes" which will do just that, but this method is destructive and you can lose your previous easing data that way.

To get around this issue we can simulate the same effect using an expression, by finding the last keyframe and sticking to its value.

var nearest = nearestKey(time); // get the key closest to the current time
var isInThePast = nearest.time <= time; // ask: is it in the past? true / false
isInThePast ? nearest : key(nearest.index-1); // if it is use it, otherwise get the one before it

Now we can remove / disable the expression in case we want to go back to our original keyframe data.

Terms used:
Easy
Medium
Hard

Remove Keyframes Transition (Simulating Hold Keyframes)

Right-click -> Toggle hold keyframes? Nah. Use this trick instead.

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Bounce
Terms used:
Easy
Medium
Hard

Bounce

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Squash and Stretch
Terms used:
Easy
Medium
Hard

Squash and Stretch

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Remap and Convert
linear(value, rangeStart, rangeEnd, newRangeStart, newRangeEnd);

linear in After-Effects let us blend between values. In its more complex form, it lets us remap a value to a certain range.

I know this can be a little confusing at first, so let's try to look at it from a practical point of view.

Remapping time to degrees

Our timeline here on the website runs from 0 to 10 seconds. If we use the keyword time, we can get a number between 0 and 10 at any given moment.
If we wanted to remap this value into a new range we can use linear to do so.
In this case, we will remap 0 -> 10 into something we can use as degrees, like -90 -> 90

linear(time, 0, 10, -90, 90);

All it does is some math in the background to make sure any value between 0 and 10 will be "stretched" to the new range.

Remapping and Converting

Remapping time to a color

linear lets us remap and convert from numbers to arrays. Let's again remap time, but this time to color.

linear(time, 0, 10, [0,0,0,0] , [1,1,1,1]);

Colors in After-Effects expressions are usually specified in normalized RGBA.
[0,0,0,1] is Black, [1,1,1,1] is white. Because both are arrays of the same size, linear will blend between them. The result is a smooth transition between black and white across time.

Remapping time to points in space

You might notice a pattern with this one. Points in space are arrays as well, just like colors. There is no real difference in the way linear treats those.
Points can be either 2D or 3D, which means arrays of size 2 or 3. Let's go with 2D points:

linear(time, 0, 10, [0,0] , [20,20]);
Terms used:
Easy
Medium
Hard

Remap and Convert


Hey, check this out. We can use time to trigger space. This is some Harry Potter shit right there understand??

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Create a Path

When you are drawing a path with the pen tool, you are placing points on the canvas. Each point has additional two points that help determine the curvature towards the next point, these are called tangents.

The createPath() function allows us to create a path by giving it specific locations in which it will place points, in tangents and out tangents.

createPath(points = [[0,0], [100,0], [100,100], [0,100]], inTangents = [], outTangents = [], isClosed = true)

It also lets us decide whether the path is closed or open by passing a forth argument, true or false.

It's important to know that createPath() expects, at the very minimum, an array of points.
Tangents and isClosed are optional. if you decide however that you do want to use tangents, know that createPath() expects all three arrays (points, inTangents, outTangents) to be of exactly the same size, otherwise it gets crazy and can throw an error at you.

This expression can get hefty. Scroll to the bottom for a disclaimer. Otherwise, check out these examples:

Creating a Square

var thePoints = [ [0,0], [100,0], [100,100], [0, 100] ];
createPath(thePoints);

Dynamic Square

var r = 400;
var thePoints = [ [0,0], [r,0], [r,r], [0, r] ];
createPath(thePoints);

Opening the square

var r = 400;
var thePoints = [ [0,0], [r,0], [r,r], [0, r] ];
createPath(thePoints, [], [], false);

Tangents

var thePoints = [ [0,0], [300,300] ];
var InHandles = [ [800,-800], [600,700] ];
var OutHandles = [ [-600,700], [-500,-100] ];
createPath(thePoints, InHandles, OutHandles);

Creating a circle without tangents

createPath() gives us an inconceivable amount of power.
One thing we can do is use Math.sin() and Math.cos() to create a circle.
You can read more about the relationship between those functions and a circle here, but in the meantime let's just apply this expression to our path:

// Properties you can easily change
var segments = 50;
var theRadius = 250;
var finalPoints = [];


// Create the circle
for (var i=0; i<segments; i++) {
	var progress = i /segments;
	var x = Math.sin(progress * Math.PI * 2);
	var y = Math.cos(progress * Math.PI * 2);
	var finalPoint = [x,y] * theRadius;
	finalPoints.push(finalPoint);
}

createPath(finalPoints);

How did we do that?
We are using a for loop to run a block of code multiple times. Each time we are calculating the position of the new point using Math.sin() and Math.cos(), and push it to an array of points.
Finally, we give this array of points to the createPath() function, which creates the circle.
It's a cool method although somewhat expensive. In order to get a smooth circle, you'd have to crank the number of segments to a pretty high value.
But hey! It works.

Feeling overwhelmed?

createPath() is not beginners friendly and that's because we are working with a lot of data here.
Going by the same "pen-tool logic", every point has two tangents.
createPath() takes the points, the in-tangents and the out-tangents in 3 separate arrays.

The syntax could be quite scary though. An array of arrays? That's a whole lot of square brackets.
Each point is an array by itself [x,y]. An array of points would look something like [ [x1,y1] , [x2,y2] , [x1,y2] ].

If that's not enough, it's important to know that tangents are calculated in a different space than points.
What does that mean? It means that a tangent at [0,0] would not actually be placed at [0,0], but it would be placed exactly on top of the point it belongs to.
That makes each tangent relative to its point.

None of what we are talking about here is beginners friendly, so don't let this get you down. Try following the examples above to get a more practical sense of how to use it instead of trying to figure the barebones of it if you have no intention to start creating complex path expressions as I did with shpr.

Terms used:
Easy
Medium
Hard

Create a Path

Creates a new path by points you specify.
If the famous "Nulls from paths" script uses this expression to create the path, You can do it too.

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Loop Path Keyframes

if (numKeys > 1 && time > key(numKeys).time){
	 var sTime = key(1).time;
	 var eTime = key(numKeys).time;
	 var loopEvery = eTime - sTime;
	 var delta = time - eTime;
	 var finalTime = sTime + (delta%loopEvery);
	 valueAtTime(finalTime);
 }else {
	 value
}

function loopOutPath(){
  if (numKeys > 1 && time > key(numKeys).time){
	  var sTime = key(1).time;
	  var eTime = key(numKeys).time;
	  var loopEvery = eTime - sTime;
	  var delta = time - eTime;
	  var finalTime = sTime + (delta%loopEvery);
	  return valueAtTime(finalTime);
   }else {
		 return value
	}
}

loopOutPath();


Terms used:
Easy
Medium
Hard

Loop Path Keyframes

loopOut() does not work on paths. Let's fix that!

value: 0
value: 45
0s
01s
02s
03s
04s
05s
06s
07s
08s
09s
10s
Create your own functions

Functions are a big part of JavaScript and expressions. You may have even been using them without knowing.

Ever used wiggle() ? wiggle is a function written by people at Adobe.
It's a block of code that WILL do something, but only when you call it.

function yourFunctionName (argument1, argument2) {
  return
};

// your function won't run, unless you call it like so:
yourFunctionName()

From time to time you might encounter code where the function declaration exists AFTER the function has been called, like so:


yourFunctionName()

function yourFunctionName (argument1, argument2) {
  return
};

Code like this will still run just fine because function declarations are moved to the top of their scope before the computer runs the code. That process is called hoisting.

So this is the basic syntax for writing a function. You as a motion designer have the power to make the decision to learn more about this topic.
If you are interested in expanding your knowledge about functions check out this tutorial from W3Schools.

For now, let's focus on practical examples so we can get the hang of it quickly.

Create a function that multiplies a number by 2

this function takes a number and multiplies it by 2.

function multiplyByFucking2(input){
	return input * 2
}

// It won't run, unless we call it
multiplyByFucking2(10); // result: 20
multiplyByFucking2(5); // result: 10
multiplyByFucking2(30); // result: 60

Create a function that gets the comp center

This function gets the comp size and multiplies it by half.

function getTheFuckingCompCenter(){
	return [thisComp.width, thisComp.height] * 0.5;
}

// It won't run, unless we call it
getTheFuckingCompCenter(); // result in a 1080p comp: [960,540]

Check if keyframes exist

// this function will check if keyframes exist using the numKeys variable built into After-Effects. If the number of keys is bigger than 0, the answer is true.

function hasFuckingKeyframes(){
	return numKeys > 0
};

// It won't run, unless we call it
hasFuckingKeyframes(); // result: true or false

Here's a fun idea, let's use this function we have created to fix the built-in loopOut() function.
Using loopOut() will throw an error if keyframes don't exist. But now we can use our new function to check if keyframes exist before we use loopOut() at all.

 if ( hasFuckingKeyframes() ) {
	loopOut()
} else {
	value
}

Or in an even shorter form:

hasFuckingKeyframes() ? loopOut() : value;

Check if something is in view

if either dimension is smaller than 0 or bigger than its corresponding comp dimensions, it's outside the view.

function isInView(x,y) {
	// if x is outside the answer is false
	if (x < 0 || x > width) { return false }

	// if y is outside the answer is false
	if (y < 0 || y > height) {return false }

	// otherwise, the answer is true, it's in view
	return true
};

// It won't run, unless we call it
isInView(0, 20) // result: true or false, depends on the comp size

Terms used:
Easy
Medium
Hard

Create your own functions

Expression Errors

This project contains an expression error: error 1 of 1
X



Expression errors can be frustrating and unclear for non-programmers. Here are some common errors and how to solve them.

Displaying the error

Tap the magnifying glass icon on the orange error bar

This will take you to the property which contains the expression error. Right under the property value, you will see a bright, yellow triangle icon with a "!" sign inside. Clicking it will open the error dialog.

Expression result must be of dimension 2, not 1

Usually happens when applied to a position property, or other 2 dimensional properties.

The property is expecting an Array. An array is a way in JavaScript to make a set of multiple items. If your expression returns a number, let's say "5", the position property will not accept it as it expects a set of two numbers, for example: [5,5]

This error could also be reserved, let's say a Rotation property must be of dimension 1, not 2. In that case, your expression results might be an array, like [5,5], but Rotation only expects a single number, such as 5.

Couldn't turn result into numeric value

Usually means there is a math operation issue in your expression. The error usually occurs around places where Math operations take place, such as "-", "+", "*", and "/".

Scan your expression for math problems, common ones are:
- Dividing by 0 results in infinity, which isn't valid in an expression.
- Trying to perform a math action on non-numbers, for example: "Hello" + 10.
- Syntax errors of built-in variables i.e: Writing Math.Pi instead of Math.PI.

Sometimes using the same expression on a "Source Text" property might help solve the problem, as this kind of property may show you the result as a string instead of resulting in an error. For example, division by 0 as the result of a Source Text property will output "Infinity".

Unexpected Token bracket

JavaScript code expects you to always make sure any bracket, whether (, [, or { has a matching closing bracket: }, ], ).

It's very easy to forget to close a set of brackets. For the computer, the brackets are essential for many operations. Look for brackets that have no matching closing bracket and make sure you close them.

The order is also important for nested brackets, for example:
{( "Something" )} - is correct.
{( "Something" }) - is incorrect, because the curly closing bracket should be placed after the closing round bracket.

You might notice After-Effects may highlight brackets in Red if a closing or opening bracket has not been found.

Effect is missing or does not exist. It may have been renamed, moved, deleted or the name may have been mistyped

You are probably trying to reference an effect that existed before but has been deleted or changed.

Look through your expression for the keyword "effect" and make sure any effect is stated by the correct name, or that it still exists.

Undefined value used in expression (Could be an out of range array subscript?)

Arrays in JavaScript are like lists. Sometimes trying to access an array entry outside of their range can cause an error. Other times, you are trying to access something that isn't an array at all.

Arrays can be confusing for beginners. Take this expression I found on the web:
x = time * 66;
[x[0],value[1]]

The person who wrote this expression knew that a position expects two values in an Array [x,y]. He did the right thing by stating that he wants the original Y value in the second position by writing "value[1]", but the same logic lead them to mistakenly try accessing the variable "x" at index 0.

The variable x, as you can tell, is not an array. Writing x[0] results in After-Effects losing its mind, because x evaluates to a number. This would be like saying 77[0]. This simply makes no sense.

Other times this error happens when you are trying to access an array at a certain index, but there is nothing there. Here is an example:

var arr = ["a","b","c"];
arr[26];

We are trying to access the array at index 26, but this array only has three items. At index 26 there would be nothing, and therefore After-Effects gives you an error.

Check your code for arrays and array entries, the problem usually lies there.

Tip: Changing the expression engine

If your expression is from the web or from a script, it could be the case that it has been written a long time ago, before After-Effects upgraded to the new JavaScript engine. The new engine is more modern but could make older expressions break.

Try going to File -> Project Settings -> Expressions (Tab) -> Expression Engine and try the older Legacy ExtendScript engine. Note that this is not recommended and can result in slower expressions, or break other newer expressions.

Where to go next?

Here is a list of great creators from the web who are kind enough to share their knowledge

Chris Zachary

Chris created an elaborate expressions collection and his website is gorgeous

After Effects Expression Reference

Use the After Effects expression elements along with standard JavaScript elements to write your expressions.

Dan Ebberts

Dan is a freelance script designer with years of experience and a long history of helping other developers in the community in online forums

The Power of Expressions

This book is great if you want to be introduced to JavaScript properly while still focus on expressions and After-Effects. A lot of the concepts in this book can be implemented in After-Effects scripting as well.

Good Boy Ninja's Twitter

Have a question? Mention me on twitter!

W3Schools

Learn JavaScript step by step with live examples

Motion Developer

Feeling ready to step up your game? Learn advanced concepts from this wonderful blog.

The Coding Train

Fall in love with Daniel Shiffman who will teach you visually oriented programming as well as how to find joy in literally anything.