Skip to main content

Programming

  • Can do with expressions

  • Can do with the javascript

  • Can do with UI

Expressions

loopOut("pingpong")
source_text.text.sourceText.style.setFontSize().setFillColor()

You can use linear() to remap a range, like this:

input = effect("Slider Control")("Slider");
inputLow = 0;
inputHigh = 100;
outputLow = -100;
outputHigh = 100;

linear(input,inputLow,inputHigh,outputLow,outputHigh)
After Effects Expression

IF YOU WANT TO ADD EXPRESSIONS, DO IT AT THE BOTTOM OF THE DOCUMENT

Inertial Bounce is like making your moves "rubbery." Layers will overextend, then settle into place on position and rotation keyframes.

// Inertial Bounce (moves settle into place after bouncing around a little)
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}


//Takes 3d space of layer and converts to 2d screen space

thisComp.layer("Light 1").toComp([0,0,0]);

//Takes 2D position (not world space) and uses it to position 3D objects in screen

L = thisComp.layer("Null 1");
value + fromCompToSurface(L.position);




Jumpy Wiggle 1 makes wiggle skip and hold rather than move fluidly.

// Jumpy Wiggle 1 (moves at a random FPS)
v=wiggle(5,50);
if(v < 50)v=0;
if(v > 50)v=100;
v



Jumpy Wiggle 2 is similar to 1, but works at a defined FPS so your "jump" will happen at a regular pace.


// Jumpy Wiggle 2 (moves at a defined FPS)
fps=5; //frequency
amount=50; //amplitude
wiggle(fps,amount,octaves = 1, amp_mult = 0.5,(Math.round(time*fps))/fps);




Sometimes you just want something to move constantly without keyframing it. Use throw.

// Throw (move at a constant speed without keyframes)
veloc = -10; //horizontal velocity (pixels per second)
x = position[0] + (time - inPoint) *veloc;
y = position[1];
z = position[2];
[x,y,z]

Create an eased repeating motion in constant increments:

f = timeToFrames(time);
line = Math.floor(f/25);
pix = Math.min(f%25,10);
pixe = ease(pix, 0, 10, 0, 60);
value - [0, line*60+pixe]

to make it go up or down just change: value - [0, line*60+pixe] to value +[...


Spin is the same as throw, but for rotation.

// Spin (rotate at a constant speed without keyframes)
veloc = 360; //rotational velocity (degrees per second)
r = rotation + (time - inPoint) *veloc;
[r]

//Autofade: Add to opacity
transition = 20; // transition time in frames
if (marker.numKeys<2){
tSecs = transition / ( 1 / thisComp.frameDuration); // convert to seconds
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)
}

//Snap zoom in and out: apply to scale
snapScale = 300; //percent of scale to zoom

trans = 4; // transition time in frames
trans = trans * thisComp.frameDuration;
inTrans = easeOut(time, inPoint, inPoint + trans, [snapScale,snapScale], [0,0]);
outTrans = easeIn(time, outPoint, outPoint - trans, [0,0], [snapScale, snapScale]);
value+ inTrans + outTrans

// Y Axis Jitter


probability = 8 ; //higher is less likely
pos = 50;
val = random(-probability-2, 1);
m = clamp(val, 0, 1);
y = wiggle(10, pos*m)-position;
value + [0, y[1]]

3D layer invisible while facing backwards to camera (use on Opacity):
if (toCompVec([0, 0, 1])[2] > 0 ) value else 0

Parent Puppet pin to Null (there is a script on AEscripts for this also I believe, haven't used it):
n=thisComp.layer("NullObject_Name");
nullpos=n.toComp(n.anchorPoint);
fromComp(nullpos);

Numbers:
Add a slider and name to 'Value'

places = 3; //number of decimal places desired
val = effect("Value")("Slider"); //sub in the name of your slider here

factor = Math.pow(0.1, places) ;
sign = "";
if (val < 0) sign = "-";

val = Math.abs(val);
whole = Math.floor(val);
fraction = "" + Math.round((val - whole)/factor)*factor;

for (fraction; fraction.length < places+2; fraction+="0");

sign + whole + "." + fraction.substring(2, places+2)

Position from layer above
thisComp.layer(index - 1).transform.position

Number of decimal places
//--Begin Expression

nums = thisComp.layer("Deep Lime Green Solid 1").effect("Slider Control")("Slider");
numOfPlaces = 3;
//--Do not modify below this line

function roundTo(number, places)
{
num = Math.round ( Math.pow(number, places) );
}NUMBER ROUNDING
myNumber = 23.3453255243697978;
round(myNumber, 2);

function round(aNum, dP) {
return(Math.round(aNum*Math.pow(10, dP))/Math.pow(10, dP));
}
num /= Math.pow(10, places);
return num;
}

roundTo(nums, numOfPlaces)

//--End expression

Round decimal
Math.round(your_decimal_number_here)

RANDOM MOVEMENT
//Returns two values by default; [x-pos. y-pos]
segDur = .5;// duration of each "segment" of random motion
minVal = [0.1*thisComp.width, 0.1*thisComp.height];
maxVal = [0.9*thisComp.width, 0.9*thisComp.height];

seed = Math.floor(time/segDur);
segStart = seed*segDur;
seedRandom(seed,true);
startVal = random(minVal,maxVal);
seedRandom(seed+1,true);
endVal = random(minVal,maxVal);
ease(time,segStart,segStart + segDur, startVal, endVal);

Time Output
//Contains rounding + always display 2 digits

min = Math.floor(time);
strMin = String(min);
if(min < 10){
strMin = '0' + strMin;
}

sec = Math.round(((time) - min)*100);
strSec = String(sec);
if(sec < 10){
strSec = '0' + strSec;
}

"18:22:" + strMin + ":" + strSec


Random Letters
//Begin expression
numOfLetters = 25; //Modify me
useSpaces = true; //Modify me
changeEveryFrame = true; //Modify me

//Don't modify below this line

seedRandom(index, !changeEveryFrame)
//--
function genLetter( ) {
r = random(65, 90);//from a to z
return String.fromCharCode( r );
}
s = "";
for(i = 0; i < numOfLetters; i++)
{
s += genLetter();
if(useSpaces)
s += " ";
}
s
//End expression

Loop
//Looping Script
freq = 0.6;
amp = 5;
loopTime = 10;
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)


Random Position HOLD

holdTime = .5; //time to hold each position (seconds)
minVal = [0.1*thisComp.width, 0.1*thisComp.height];
maxVal = [0.9*thisComp.width, 0.9*thisComp.height];

seed = Math.floor(time/holdTime);
seedRandom(seed,true);
random(minVal,maxVal)
Smooth Keyframes
smooth(width = .2, samples = 5, t = time)

Creating Trails
delay = 5; //number of frames to delay

d = delay*thisComp.frameDuration*(index - 1);
thisComp.layer(1).position.valueAtTime(time - d)

OR
thisComp.layer(index+1).transform.position.valueAtTime(time-.1)



Wiggle X axis only

[wiggle(5,30)[0],value[1]]

Wiggle Y axis only

[value[0],wiggle(1,100)[1]]


Smooth Wiggle
http://forums.adobe.com/message/1799293#1799293

seedRandom(time*5);
wiggle(0,100);

Copy size and rescale from layer above
thisComp.layer(index - 1).scale-[7,7]



Copy rotation from layer below and rotate 22.5
thisComp.layer(index+1).transform.rotation+22.5



Copy position from layer above
thisComp.layer(index-1).position


Keep x at 960, move Y X time * 100 pixels

[960, position[1]+time*-100]



Lock a layer to the exact centre of the comp (very useful for rotoscoping where you accidentally nudge the layer all the time)

On the (2D, comp size) layer’s Position:
[comp.Length/2, comp.Height/2]


Time delay from layer above
thisComp.layer(index+1).transform.position.valueAtTime(time-.1)

Wiggle in one direction only
Wiggle Y Only:

[value[0],wiggle(1,100)[1]]

Wiggle X Only:

[wiggle(5,30)[0],value[1]]

Wiggle X and Y separately:

[wiggle(5,30)[0],wiggle(1,100)[1]]


Loop Types
loopOut("pingpong") // ABCD(CBABCDCBA)
loopOut("continue") // ABCD(EFGHIJKL)
loopOut("Cycle") // ABCD(ABCDABCD)


Range Mapping
input = effect("Slider Control")("Slider");
inputLow = 0;
inputHigh = 100;
outputLow = -100;
outputHigh = 100;

linear(input,inputLow,inputHigh,outputLow,outputHigh)


For when you want burn in text to automatically display the layer name (i.e. render out tiff sequence first, then making a QT w/ name burn in).

Make text layer, add expression to 'source text'.

function pad(number, length) { var str = '' + number; while (str.length < length) { str = '0' + str; } return str; } var theLayerName = thisComp.layer(index+1).name; var theLayerNameSplit = theLayerName.split('.'); theLayerNameSplit[0];

To change which layer is read for the name, change the (index+1) to (index+2) and so on.


Counting numbers with comma:

startCount = 0;
endCount = 11689;
countDur = 1.2;
s = "" + Math.round(linear(time,0,countDur,startCount,endCount));

if (s.length > 3){
s.substr(0, s.length -3) + "," + s.substr(-3);
}else{
s
}


Oscillate Rotation

Use Expression Control angles or sliders forfrom, “to”, and an Expression
Control slider assigned to “period” for fine control. You can apply these to any layer.
Change “linear” to “ease” for smoother interpolation.
by Michael Natkin & Brian Maffitt


from = -45; //one end of your oscillation
to = 45; //the other end of your oscillation
period = 1.5; //time between oscillation points (multiply by 2 for a round trip)
t = time % (period * 2);
if (t > period) t = 2 * period - t;
linear(t, 0, period, from, to)


Grayscale Value to x,y Data
(x&y outputs will range from 0-100)

sourceLayer = thisComp.layer(“layer");
sampleSize = [1,1];
samplePoint = transform.position;
color= sourceLayer.sampleImage(samplePoint,sampleSize);
x=color[0]*100
y=color[0]*100
[x,y]


Percentage Counter With Slider Control:

slider = effect("Slider Control")("Slider");
numDecimals = 0;
commas = false;
dollarSign = false;
percentSign = true;
s = slider.value.toFixed(numDecimals);
prefix = "";
suffix = "";
if (s[0] == "-"){
prefix = "-";
s = s.substr(1);
}
if(dollarSign) prefix += "$";
if(percentSign) suffix = "%";
if (commas){
decimals = "";
if (numDecimals > 0){
decimals = s.substr(-(numDecimals + 1));
s = s.substr(0,s.length - (numDecimals + 1));
}
outStr = s.substr(-s.length, (s.length-1)%3 +1);
for (i = Math.floor((s.length-1)/3); i > 0; i--){
outStr += "," + s.substr(-i*3,3);
}
prefix + outStr + decimals + suffix;
}else{
prefix + s + suffix;
}







Rounding Numbers:

Math.round(value)
rounds the number

Math.ceil(value)
rounds up

Math.floor(value)
rounds down

Scaling 3d layers while moving active camera:

cam = thisComp.activeCamera;
distance = length(sub(position, startPoint.position));
scale * distance / cam.zoom;






Value change over time

value = "Hello";
if (time >= 1){
value = "Goodbye"
}



Smooth Credits (Or constant motion on the Y Axis)

Apply this to position and then move the anchor point to position your credits. Change S to change the speed or direction of the credits
t = time;
fr = t/thisComp.frameDuration;
x = value [0];
s = -6; //Speed in pixels per frame
[x, fr*s]




Center the Anchor Point in a text layer - automatically adjusts with changes

value-[0,this.sourceRectAtTime(time).hei­ght/2]

The same, but both axis
x = this.sourceRectAtTime(time).left+this.sourceRectAtTime(time).width/2;
y = this.sourceRectAtTime(time).top+this.sourceRectAtTime(time).height/2;

[x, y]


Random Grid Movement
http://www.motionscript.com/expressions-lab-ae65/random-grid-movement.html

move objects randomly along a grid to a new position on the grid.
Try applying this expression to the position property of a square solid and then duplicated the solid a bunch of times.
Note that the number of rows is calculated from the number of columns and that the objects come to rest at the intersection of rows and columns.
Adjust the number of columns, hold time, minimum and maximum cycle time to suit your needs.


columns = 23.41; //number of columns in grid
tHold= .2; //hold time (must be less than tmin)
tMin = 1; //minimum cycle time (can't be zero)
tMax = 1.2 //maximum cycle time

gap = this_comp.width/columns;
origin = [gap,gap];
xGrid = columns - 1;
yGrid = Math.floor(this_comp.height/gap) - 1;

start = 0;
end = 0;
j = 1;

while (time >= end){
j += 1;
seedRandom(j,true);
start = end;
end += random(tMin,tMax);
}
targetX = Math.floor(random(0,xGrid));
targetY = Math.floor(random(0,yGrid));
seedRandom(j-1,true);
x = random(); //this is a throw-away value
oldX = Math.floor(random(0,xGrid));
oldY = Math.floor(random(0,yGrid));

if(targetX == oldX && targetY == oldY){
origin + [oldX,oldY]*gap;
}else if (time - start < tHold){
origin + [oldX,oldY]*gap;
}else{
deltaX = Math.abs(targetX - oldX);
deltaY = Math.abs(targetY - oldY);
xTime = (end - start - tHold)*(deltaX/(deltaX + deltaY));
yTime = (end - start - tHold)*(deltaY/(deltaX + deltaY));
if (time < start + tHold + xTime){
startPos = origin + [oldX,oldY]*gap;
targetPos = origin + [targetX,oldY]*gap;
easeOut((time - start - tHold)/xTime, startPos, targetPos);
}else{
startPos = origin + [targetX,oldY]*gap;
targetPos = origin + [targetX,targetY]*gap
easeIn((time - start - tHold - xTime)/yTime, startPos, targetPos);
}
}



Offset one axis separately for linked comps in 3D space

thePos = comp("MainComp").layer("Your3DLayer").transform.position;
[thePos[0]+offset, thePos[1]+offset, thePos[2]+offset]


IMPACT BOUNCE (bounce back after impact, like slamming doors, bouncing ball) You can apply it to Position, but it will work with any key-framed parameters (scale, opacity etc)

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



Adjust a single value (parameter) of an effect on a layer, the further away the layer is from the camera. For this example, it was applied to 'brightness', to make the layer paler as it moves into the distance:

C = thisComp.activeCamera;
start = 2500;
end = 25500;
d = length(toWorld(anchorPoint),C.toWorld([0,0,0]));
linear(d,start,end,0,100)

'start' is the distance the layer is from camera that the expression begins.
'end' is the distance that the expression reaches maximum effects.

The red numbers indicate the minimum and maximum values returned for any parameter. Change the '100' to '60' (for example) and 'brightness' will never go higher than 60.




Links position value of effects (corner pin, beam etc etc) to postion of Null (or any layer be it 2d or 3d)
Apply this to position value in Effect:
target = thisComp.layer("Layer"); // Layer is the layer your want to get the position value from
fromComp(target.toComp(target.anchorPoint));




Oscillate a value with Math.sin

amp = 3; //sine wave amplitude (pixels)
freq = 0.5; //oscillations per second

x = amp*Math.sin(freq*time*2*Math.PI);
[x]


Looping Wiggle:

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)


http://www.motionscript.com/design-guide/looping-wiggle.html


COUNTING NUMBERS (above 1 Million)
Create a new text layer. Add the following expression to source text. Adjust the variables to do whatever you need.

//begin code

startTime = 0; //seconds
endTime = 5; //seconds
beginCount = 0;
endCount = 2000;
hasCommas = true;
//--dont modify below here----------------
function addCommas ( s ){
if( s.length <= 3 )
return s;
else
return s.substring(0 , 3) + "," + addCommas(s.substring(3, s.length));

}
function reverse( s ){
newStr = "";
for(i = s.length-1; i >= 0; i--)
newStr += s.charAt(i)
return newStr;
}

val = Math.round (linear(time, startTime, endTime, beginCount, endCount) );
if( hasCommas )
reverse (addCommas(reverse( val + "" )))
else
val


//end code


// CODE FOR SPLITING LAYERS

// store all keytime values into arrayKeyTimes;

// then take the in and out point values
var inPointValue = layer.inPoint;
var outPointValue = layer.outPoint;

for (var i = 0; i<=n; i++) {

layer.duplicate();
layer = thisComp.layer(1);
layer.inPoint = (i == 0) ? inPointValue : arrayKeyTimes[i-1];
layer.outPoint = (i < n) ? arrayKeyTimes(i) : outPointValue;

}

Copy the expression, Alt-Click the Scale stopwatch, Paste):
n = 0;
if (marker.numKeys > 0){
n = marker.nearestKey(time).index;
if (marker.key(n).time > time){
n--;
}
}

if (n == 0){
value;
} else {
max_dev=20; // max deviation in pixels
spd=35; //speed of oscillation
decay=10; //how fast it slows down
t = time - marker.key(n).time;
s = max_dev*Math.sin(spd*(t))/Math.exp(decay*t);
value + [s,s];
}
So wherever you place a marker you'll get the old squish and squash. Hit the asterisk (*) key on the numeric pad to drop a marker wherever you are on the timeline.
Note: No marker, no squish and squash. Five markers give five squish and squashes.
Also if you're talking a diferent expression, just drop that in below the }else{.
by Mike Clasby (yikesmikes)

More Natural Easing
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){
v = velocityAtTime(key(n).time - thisComp.frameDuration/10);
amp = .05;
freq = 2.0;
decay = 4.0;
value + v*amp*Math.sin(freq*t*2*Math.PI)/Math.exp(decay*t);
}else{
value;
}



Evenly distribute layers between 2 other layers
n = thisComp.numLayers;
if (n > 2){
p1 = thisComp.layer(1).transform.position;
p2 = thisComp.layer(n).transform.position;
linear(index,1,n,p1,p2)
}else{
value
}

SCRIPT TO FLIP OBJECT BASED ON VELOCITY


//plug this into SCALE
if (transform.position.velocity[0] <=0){
[-value[0], value[1]]
}
else{
[value[0], value[1]]
}

STEREO CAMERA RIG FIX

///////////STEREO RIG FIX - Be sure to set the 3d stereo rig units to pixels, not percentage
///// L camera is + N, R camera is - N
N = thisComp.layer("Stereo 3D Controls").effect("3D Glasses")("Scene Convergence");
[value[0] + N, value[1]]



// Layer Autofacing camera

L = comp("COMPNAME").layer("Camera 1");
u = fromWorldVec(L.toWorldVec([1,0,0]));
v = fromWorldVec(L.toWorldVec([0,1,0]));
w = normalize(fromWorldVec(L.toWorldVec([0,0,1])));

sinb = clamp(w[0],-1,1);
b = Math.asin(sinb);
cosb = Math.cos(b);
if (Math.abs(cosb) > .0005){
c = -Math.atan2(v[0],u[0]);
a = -Math.atan2(w[1],w[2]);
}else{
a = (sinb < 0 ? -1 : 1)*Math.atan2(u[1],v[1]);
c = 0;
}
[radiansToDegrees(a),radiansToDegrees(b),radiansToDegrees(c)]

TIME EXPRESSION

countspeed = 1;
clockStart = 0;

function times(n){
if (n < 10) return "0" + n else return "" + n
}

clockTime = clockStart +countspeed*(time - inPoint);

if (clockTime < 0){
minus = "-";
clockTime = -clockTime;
}else{
minus = "";
}

t = Math.floor(clockTime);
h = Math.floor(t/3600);
min = Math.floor((t%3600)/60);
sec = Math.floor(t%60);
ms = clockTime.toFixed(3).substr(-3);
minus + times(h) + ":" + times(min) + ":" + times(sec) + "." + ms





maintain stroke weight
(modified from Adam Plouff)
if(hasParent){
p =Math.abs(parent.scale[0]) ;}
else{p=100;}
s = Math.abs(transform.scale[0]);
scaleFactor = 100/s;
PscaleFactor = 100/p;
value*scaleFactor*PscaleFactor;

PULSE EFFECT
//Change Freq for times per sec and amp for how hard you want the pulse. Adjust value at bottom to x,x to effect both x and y values.
freq = 2;
amp = 15;
x = amp*Math.sin(freq*time*Math.PI*2);
value + [x,0]



Move along X over time

vel = -25; //speed of the movement.
[vel*time+value[0], value[1]]


Follow “leader” layer position with added time delay.

Put expression in Position of all following layers.
All follower layers must be placed directly beneath the leader layer.
If the leader layers layer-number is other than 1, replace the (1) in the expression.
Tip: If you delete the delay value number and pickwhip “value” of an expression slider effect (for example a slider in the leader layer) you can easily change the delay of all follower-layers at the same time.

delay = 0.5;
leader = thisComp.layer(1);
leader.transform.position.valueAtTime(time - delay*(index-leader.index));

This expression can be applied to any property, just change the word “position” to “scale”, “opacity”, or any desired property.
ADD: How to make this work with wiggle on the same layer? wiggle and this cancel each other out.