
After Effects
Expressions
-
Inertial Bounce (Created by Dan Ebberts at motionscript.com)
n = 0;
if (numKeys > 0){
n = nearestKey(time).index;
if (key(n).time > time){
n--;
}
}
if (n == 0){
t = 0;
}else{
t = time - key(n).time;
}
if (n > 0 && t < 1){
v = velocityAtTime(key(n).time - thisComp.frameDuration/10);
amp = .05;
freq = 4.0;
decay = 8.0;
value + v*amp*Math.sin(freq*t*2*Math.PI)/Math.exp(decay*t);
}else{
value;
}
-
Bounce Back (Created by Dan Ebberts at motionscript.com)
e = .7;
g = 5000;
nMax = 9;
n = 0;
if (numKeys > 0){
n = nearestKey(time).index;
if (key(n).time > time) n--;
}
if (n > 0){
t = time - key(n).time;
v = -velocityAtTime(key(n).time - .001)*e;
vl = length(v);
if (value instanceof Array){
vu = (vl > 0) ? normalize(v) : [0,0,0];
}else{
vu = (v < 0) ? -1 : 1;
}
tCur = 0;
segDur = 2*vl/g;
tNext = segDur;
nb = 1; // number of bounces
while (tNext < t && nb <= nMax){
vl *= e;
segDur *= e;
tCur = tNext;
tNext += segDur;
nb++
}
if(nb <= nMax){
delta = t - tCur;
value + vu*delta*(vl - g*delta/2);
}else{
value
}
}else
value
-
On your layer opacity apply this script to make it blink, you can also customize the syntax if it blinks too fast.
blinkSpeed=15;
n= Math.sin(time*blinkSpeed);
if(n<0) 0 else 100;
-
Here is the expression to autoscale a text box in After Effects, that should save you a lot of time.
first expression should be applied to the size of your rectangle shape and the second should be added to the anchor point of your rectangle shape.
/* add this expression on the size of your rectangle shape */
box=thisComp.layer("dfd").sourceRectAtTime();
Width=box.width;
Height=box.height;
p=effect("Slider Control")("Slider");
x=Width+p;
y=Height+p;
[x,y]
/* add this expression on the Anchor Point of your rectangle shape */
box=thisComp.layer("dfd").sourceRectAtTime();
Width=box.width;
Height=box.height;
Top=box.top;
Left=box.left;
p=effect("Slider Control")("Slider");
x=Width/-2-Left;
y=Height/-2-Top;
[x,y]
-
...credit for this script is due to Aaron Fisher on creative cow, who posted it in response to the question of whether there was an easier way to do exponential scaling of objects when you either did not have the option to handle them as 3d objects (or didn't want the render hit), and when you want to avoid the tedious use of the "exponential scale" keyframe assistant.
I am using it for pan/zoom type effects on photos, and it allows me to work faster as you just set two or more keyframes for scale and the expression handles the interpolation of scale between them so that scaling looks like 'zooming' properly (options are linear, ease, easIn or easeOut)
There can be four versions of this script just by changing the one line which determines the interpolation (see comments). I have not modified the script otherwise, except in adding those comments which I just added myself as I worked my way through it, not being an expert scripter myself.
//
/* checking if there are at least two keys; and
if the last key's time value is greater than current time; and
if we are presently at or later than the first key */
if (num_keys >1 && key(num_keys).time > time && key(1).time <= time){
// set var k to be the index of the nearest key; then
k = nearest_key(time).index;
// if that nearest key is less or equal to present time
if (key(k).time <= time) {
// set var a to that value
a = k;
} else {
// otherwise set var a to that value -1
// so: a will always be the value of the key to the left of present position
a = k-1;
}
// and b will always be the value of the key to the right of present position
b= a+1;
/* next four lines set a_val and b_val
to the first array value for each of the keys in which
we are presently between (i.e. the x value);
and a_time and b_time to the time values for those keys*/
a_val = key(a)[0];
b_val = key(b)[0];
a_time = key(a).time;
b_time = key(b).time;
// quick corrections if the a or b values happen to be zero
if(a_val == 0) {
a_val = .1;
}
if (b_val == 0) {
b_val = .1;
}
/* now the real math occurs here; options are:
linear, ease, easeIn, easeOut -- see second line:*/
x = Math.log(b_val) / Math.log(a_val);
exp = linear(time, a_time, b_time, 1, x);
val = Math.pow(a_val, exp);
[val, val];
}else{
value;
}
-
Here is a beautiful expression that mimic a ball bounce with gravity and elasticity options, many thanks to school of motion for the script please go to their website for more detail on this specific bouncing expression.
e = .7; //elasticity
g = 5000; //gravity
nMax = 9; //number of bounces allowed
n = 0;
if (numKeys > 0){
n = nearestKey(time).index;
if (key(n).time > time) n--;
}
if (n > 0){
t = time - key(n).time;
v = -velocityAtTime(key(n).time - .001)*e;
vl = length(v);
if (value instanceof Array){
vu = (vl > 0) ? normalize(v) : [0,0,0];
}else{
vu = (v < 0) ? -1 : 1;
}
tCur = 0;
segDur = 2*vl/g;
tNext = segDur;
nb = 1; // number of bounces
while (tNext < t && nb <= nMax){
vl *= e;
segDur *= e;
tCur = tNext;
tNext += segDur;
nb++
}
if(nb <= nMax){
delta = t - tCur;
value + vu*delta*(vl - g*delta/2);
}else{
value
}
}else
value
-
Here is a super cool expression to make your layer bounce like jello or gelatin.
timeToStart = .5;
if (time > timeToStart) {
maxDev = 30; // max deviation in pixels
spd = 30; //speed of oscillation
decay = 1.0; //how fast it slows down
t = time - inPoint;
x = scale[0] + maxDev*Math.sin(spd*t)/Math.exp(decay*t);
y = scale[0]*scale[1]/x;
[x,y]
}
else {
value;
}
-
amp = .1;
freq = 2.0;
decay = 2.0;
n = 0;
if (numKeys > 0){
n = nearestKey(time).index;
if (key(n).time > time){
n--;
}}
if (n == 0){ t = 0;
}else{
t = time - key(n).time;
}
if (n > 0 && t < 1){
v = velocityAtTime(key(n).time - thisComp.frameDuration/10);
value + v*amp*Math.sin(freq*t*2*Math.PI)/Math.exp(decay*t);
}else{value}
-
Change your layer to a 3D Layer and use this expression to wiggle on the Z axis.
a =wiggle(0,0);
b =wiggle(0,0);
c = wiggle(5,95);[a[0],b[1],c[2]]
-
Wiggle Simple Expression
wiggle(5,10)
The 1st number 5 define the number of time your layer will wiggle per second. This case it move 5 time in 1 second
The 2nd Number 10 define the how much it will move up and down this case 10 pixels
wiggle(8,120)
/////////////////////////////////////
Start & Stop wiggle expression
With a slider control you can easily control your wiggle start and stop motion.
wiggle(thisComp.layer("Null 1").effect("Slider Control")("Slider"),10)
/////////////////////////////////////
Hold Wiggle Expression
If you want to pause your wiggle this expression should do it. The code allow you to stop the wiggle at frame 100
stopFrame = 100;
t = Math.min(time,framesToTime(stopFrame));
wiggle(13,20,1,.5,t)
/////////////////////////////////////
Wiggle Height Vertical expression.
With this Wiggle expression you can animate vertically on the Y axis.
org=value; temp=wiggle (8,40); [org[0],temp[1]];
/////////////////////////////////////
Wiggle Horizontal
Here is an expression to Wiggle Horizontally on the x axis.
org=value; temp=wiggle (5,120); [temp[0],org[1]];
/////////////////////////////////////
Wiggle Seamless Loop Expression
This wiggle expression allow you to loop perfectly. Just don’t forget to adjust the loopTime base on your composition timeline
freq = 1;
amp = 110;
loopTime = 3;
t = time % loopTime;
wiggle1 = wiggle(freq, amp, 1, 0.5, t);
wiggle2 = wiggle(freq, amp, 1, 0.5, t - loopTime);
linear(t, 0, loopTime, wiggle1, wiggle2)
-
The bounce expression is great because it only takes two keyframes to create a bounce. After Effects will interpolate the velocity of your layers' movement to help determine how the bounce will work. The math that goes into making this bounce expression is pretty darn nerdy.
e = .7; //elasticity
g = 5000; //gravity
nMax = 9; //number of bounces allowed
n = 0;
if (numKeys > 0){
n = nearestKey(time).index;
if (key(n).time > time) n--;
}
if (n > 0){
t = time - key(n).time;
v = -velocityAtTime(key(n).time - .001)*e;
vl = length(v);
if (value instanceof Array){
vu = (vl > 0) ? normalize(v) : [0,0,0];
}else{
vu = (v < 0) ? -1 : 1;
}
tCur = 0;
segDur = 2*vl/g;
tNext = segDur;
nb = 1; // number of bounces
while (tNext < t && nb <= nMax){
vl *= e;
segDur *= e;
tCur = tNext;
tNext += segDur;
nb++
}
if(nb <= nMax){
delta = t - tCur;
value + vu*delta*(vl - g*delta/2);
}else{
value
}
}else
value
-
//Apply to position
delay = 5; //number of frames to delay
d = delay*thisComp.frameDuration*(index - 1);
thisComp.layer(1).position.valueAtTime(time - d)
//Apply to Opacity
opacityFactor = .75;
Math.pow(opacityFactor,index - 1)*100
-
This is a set of simple expressions that will position four lines at the edges of a rectangular layer and maintain their relationship to the rectangle as it moves and scales.
In this example, the rectangle is named "master", the vertical lines are thin solids the height of the comp, and the horizontal lines are thin solids the width of the comp.
Apply the following expression to the position property of the lower horizontal line:
m = thisComp.layer("master");
[width/2,m.position[1] + (m.height/2)*(m.scale[1]/100)]
Apply the following expression to the position property of the upper horizontal line:
m = thisComp.layer("master");
[width/2,m.position[1] - (m.height/2)*(m.scale[1]/100)]
Apply the following expression to the position property of the right vertical line:
m = thisComp.layer("master");
[m.position[0] + (m.width/2)*(m.scale[0]/100),height/2]
Apply the following expression to the position property of the left vertical line:
m = thisComp.layer("master");
[m.position[0] - (m.width/2)*(m.scale[0]/100),height/2]
-
Problem: How to make an object follow another object in only 1 of the 3 dimensions (X, Y or Z) and leave the other two as is.
otherposition = this_comp.layer("name of the other layer").position;
[position[0], position[1], otherposition[2]];
[0], [1], and [2] relate to the x, y and z values contained in a three dimensional property. So we're defining each one separately, but
putting them back together in the format [x, y, z].
-
// Start the wiggle effect at 25.19 seconds
if (time > 25.19) {
wiggle(3, 20)
} else {
value
}
-
thisLayer.toComp([0,0])+ thisProperty.value (no rotation)
V2
thisLayer.toComp([value[0], thisLayer.sourceRectAtTime().top + value[1]]);thisLayer.toComp([value[0], thisLayer.sourceRectAtTime().top + thisLayer.sourceRectAtTime().height + value[1]]);
-
loopIn("cycle") will repeat your animation before the keyframes in your timeline. The animation will end at the last keyframe.
loopOut("cycle") will repeat your animation after the keyframes in your timeline. The animation will end with your composition.
loopOut("continue") will take the last two keyframes of your animation, and continue that stroke indefinitely.
loopOut("pingpong") will carry your animation forwards and backward through the keyframed positions.
loopOut("offset") will bring the entire animation along. The animation will repeat itself starting from the last keyframed point.
Loop Path animation
valueAtTime(time % key(numKeys).time)
//////////
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();
-
loopOut(type="cycle",numKeyframes=0)
-
Squash and Stretch
This exercise demonstrates how you can use an expression to apply "squash and stretch" to an object. For this experiment, I imported two Illustrator graphics. I moved their anchor points to the bottom so that the stretching occurs relative to the "floor" of the comp. I keyframed the falling action and split each layer at the point it reaches the floor. I added the following expression to the scale property of each of the stationary pieces:
maxDev = 13; // max deviation in pixels
spd = 30; //speed of oscillation
decay = 1.0; //how fast it slows down
t = time - inPoint;
x = scale[0] + maxDev*Math.sin(spd*t)/Math.exp(decay*t);
y = scale[0]*scale[1]/x;
[x,y]
The formula for "x" is just applying a decaying sine wave to the original scale. "y" is calculated to keep the area of the layer constant.
Adjust the deviation, speed and decay parameters as needed.
-
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.
-
"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.
(https://www.goodboy.ninja/expressionscheatsheet#Creatingadelaybetweenlayers)
-
This is a very simple expression that is used to tie a camera's focal distance to the position of an object (the ghost in this case). As the ghost moves towards and away from the camera, the other object in the comp goes in and out of focus in a depth-of-field affect.
Apply the following expression to the camera's Focus Distance property:
L = thisComp.layer("ghost.ai");
P1 = L.position - position;
P2 = toWorldVec([0,0,1]);
dot(P1,P2);
Substitute your layer's name for "ghost.ai"
The expression includes a little vector math (dot product) to account for the fact that the camera focuses on a plane and the layer that you use to determine the focal distance might not be directly in front of the camera.
-
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
————————-
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:
45 * Math.sin(Math.PI * 2 * time) // gets a number between 0 and 1, then multiplies it by 45 degrees;
————————————-
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);
-
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;
—————-
(.)- 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);
-
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];
-
Inverse Kinematics
This is a pair of rotation expressions you can use to implement inverse kinematics (IK) in After Effects. This code is based on expressions developed by Brian Maffitt for his wonderful "Total Training for After Effects" DVD series. I've modified them somewhat to allow anchor points to be inset from the edge of the objects.
IK allows you to position a chain of objects based on the movement of the object at the end of the chain. For example, moving a hand would cause the upper and lower arm components to rotate at their joints to accomodate the hand's movement.
Here's the code for the rotation of the upper arm:
A = toWorld(anchorPoint);
L = thisComp.layer("lowerArm");
B = L.toWorld(L.anchorPoint);
L = thisComp.layer("Null 1");
C = L.toWorld(L.anchorPoint);
L = thisComp.layer("hand");
H = L.toWorld(L.anchorPoint);
a = length(A,B);
b = length(B,C);
c = length(H,A);
x = (a*a - b*b + c*c)/(2*c);
beta = Math.acos(clamp(x/a,-1,1));
D = H - A;
delta = Math.atan2(D[1],D[0]);
radiansToDegrees(delta - beta);
And here's the code for the rotation of the lower arm:
B = toWorld(anchorPoint);
L = thisComp.layer("upperArm");
A = L.toWorld(L.anchorPoint);
L = thisComp.layer("Null 1");
C = L.toWorld(L.anchorPoint);
L = thisComp.layer("hand");
H = L.toWorld(L.anchorPoint);
a = length(A,B);
b = length(B,C);
c = length(H,A);
x = (a*a - b*b + c*c)/(2*c);
y = c - x;
alpha = Math.acos(clamp(y/b,-1,1));
beta = Math.acos(clamp(x/a,-1,1));
radiansToDegrees(alpha + beta);
The math behind these is somewhat complex, but if you know trig it's kind of fun to figure out how it works.
Here's the way you set this up. First, import the pieces for your IK chain (note that if you need to scale the pieces you should do that first in another application, because it will screw up the angle calculations if you do it in your comp). Also note that these expressions assume that your pieces start out horizontal. If they start out vertical, you will need to adjust the upper arm expression by subtracting 90 degrees from the result, by changing the last line to this:
radiansToDegrees(delta - beta) - 90;
Next you need to move the anchor points to the joints (move the upper arm's anchor point to the sholder, the lower arm's to the elbow and the hand's to the wrist). Next you align the pieces to form your chain. Then create a null layer ("Null 1" in this example) and position it so its anchor point is at the same place as the hand's anchor point. Now make the upper arm the parent of the lower arm, and the lower arm the parent of the null. Note that the hand has no parent. Now apply the expressions for rotation.
If you've done everything right, you should be able to move the hand around in the comp and the arm will follow.
To get the mirror image solution (so the the arm pieces bend the other way) you would change the last line of the upper arm expression to:
radiansToDegrees(delta + beta);
and change the last line of the lower arm expression to:
-radiansToDegrees(alpha + beta);
-
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.
-
Automatic Fade
The automatic fade expression is useful when you don’t want to bother a create keyframes for a fade animation.
transition = 20;
if (marker.numKeys<2){
tSecs = transition / ( 1 / thisComp.frameDuration);
linear(time, inPoint, inPoint + tSecs, 0, 100)
- linear(time, outPoint - tSecs, outPoint, 0, 100)
}else{
linear(time, inPoint, marker.key(1).time, 0, 100)
- linear(time, marker.key(2).time, outPoint, 0, 100)
}
-
Lock a layer's position without locking the layer.
Add an expression to position and enter this:
[160,120] aka[Value,value]
Works with other values too. Eg Transparency
Accordion with Code Snippet
// After Effects script example
var comp = app.project.activeItem;
if (comp instanceof CompItem) {
var layer = comp.selectedLayers[0];
if (layer) {
layer.property("ADBE Transform Group").property("ADBE Position").setValue([640, 360]);
alert("Position set to [640, 360]");
} else {
alert("Please select a layer.");
}
} else {
alert("Please select a composition.");
}