I’ve put together a list of After Effects expressions that simplify my workflow. You won’t find basics like loopOut() or wiggle (.4,6) here, but nothing overly complex either.
Most of these expressions are taken from the web and adapted to fit my needs, with only a few being entirely my own. I’ve included links to credit the authors where relevant.
Adaptive Text Box
Resize a shape layer dynamically to match its text length.
Create a rectangle shape and add a text layer above it.
Apply this expression to the Size parameter of the shape layer:
margin_width = 60;
margin_height = 40;
text_width = thisComp.layer(index-1).sourceRectAtTime().width;
text_height = thisComp.layer(index-1).sourceRectAtTime().height;
box_width = text_width + margin_width*2;
box_height = text_height + margin_height*2;
[box_width, box_height]
For multi-line text, apply this additional expression to the Position of the shape layer. This automatically aligns the shape’s position with the text.
x = value[0];
y = content("Rectangle 1").content("Rectangle Path 1").size[1]/2;
[x,y]
Animated Wiggle
Easily animate wiggle using two sliders: one controls the frequency, and the other controls the amplitude. For the best results, animate only amplitude.
Add two Slider Controls to the layer and apply this expression:
w_freq = effect("Slider Control")("Slider");
w_amplitude = effect("Slider Control 2")("Slider");
wiggle(w_freq,w_amplitude)
Looping Wiggle
With this expression, wiggle starts and ends at the same point.
If it doesn’t loop correctly, it’s likely because the loop time is too short for wiggle to return to the starting point. Just increase loopTime or freq.
freq = 1;
amp = 65;
startTime = 0; // Loop start time
loopTime = 3; // Loop duration in seconds
t = (time+startTime) % loopTime;
wiggle1 = wiggle(freq, amp, 1, 0.5, t);
wiggle2 = wiggle(freq, amp, 1, 0.5, t - loopTime);
linear(t, 0, loopTime, wiggle1, wiggle2)
Pin Shape Layer to One Side
Keep one of the shape’s sides fixed while adjusting the Size.
Apply this expression to the Position of a shape layer:
pinTo = "left"; // top, bottom, right or left
chosenShape = content("Rectangle 1").content("Rectangle Path 1");
if (pinTo == "top"){
x = chosenShape.position[0];
y = chosenShape.position[1]+chosenShape.size[1]/2;
}
else if (pinTo == "bottom"){
x = chosenShape.position[0];
y = chosenShape.position[1]-chosenShape.size[1]/2;
}
else if (pinTo == "right"){
x = chosenShape.position[0]-chosenShape.size[0]/2
y = chosenShape.position[1]
}
else if (pinTo == "left"){
x = chosenShape.position[0]+chosenShape.size[0]/2;
y = chosenShape.position[1]
}
[x,y]
Rolling Circle and Square Rig
Rolling Circle
Apply this to the Rotation and animate the Position:
transform.position[0]-(content("Ellipse 1").content("Ellipse Path 1").size[0]/2)-transform.position[0]/2
Rolling Square
This expression works with shapes, layers and compositions.
Apply the expression to the Position. Add a Slider Control to the same layer. Animate the Rotation. If the square doesn’t roll correctly, adjust the Slider Control.
targetLayer = thisLayer;
squareSize = targetLayer.sourceRectAtTime().width;
squareDiag = (Math.sqrt(2)*squareSize)/2/3.5;
try{
squareOffset = effect("Slider Control")("Slider");
}
catch(err) {
squareOffset = 0;
}
rot=transform.rotation;
scl=transform.scale[0]/100;
w=(squareSize/2)*scl;
r=(degreesToRadians(rot))*2;
t=transform.position;
[t[0]+w*rot/45,t[1]-(Math.abs((squareDiag+squareOffset)*Math.sin(r)))*scl];
Stepped Rotation
An alternative to time*n. Instead of a smooth rotation, it creates a stepped movement. I usually use it to animate clock hands, gears or other similar mechanisms.
Apply to the Rotation:
angle = 15; // Rotation angle per second
rotateDuration = 10; // Duration of rotation in frames
rotateDurationFr = rotateDuration/(1/thisComp.frameDuration);
wholeSecond = Math.floor(time);
startAngle = wholeSecond * angle;
ease(time, wholeSecond, wholeSecond + rotateDurationFr, startAngle, startAngle + angle)
Advanced Stepped Rotation
A more customizable version of the stepped rotation expression.
Apply to the Rotation:
angle = 15; // Rotation angle per second
rotateDuration = 6; // Duration of rotation in frames
timeStop = 5; // Stop duration between rotations
offset = 0; // Offset of the initial frame
fr = timeToFrames(time)+offset;
cycle = timeStop+rotateDuration;
n = Math.floor(fr/cycle);
cur_phase = fr-n*cycle;
if((cur_phase)>timeStop){
angle*n+(cur_phase-timeStop)*angle/rotateDuration;
}
else{
angle*n;
}
Maintain Scale When Parented
When you parent one object to another and scale the parent, both layers will scale. This expression prevents the child layer from scaling and only moves it by position.
Apply to the layer’s Scale, which should have a constant size:
s = [];
ps = parent.transform.scale.value;
for (i = 0; i < ps.length; i++){
s[i] = value[i]*100/ps[i];
}
s
Checkbox Switcher
Toggle any value with a checkbox.
Add a Checkbox Control to the layer with the expression.
Apply this expression to a parameter you want to control:
if (effect("Checkbox Control")(1) == 0) 0 else 100
Shape Layer Loop
Standard loopOut() doesn’t work with shape layers, but this expression does.
Apply to the Path of the shape layer:
try{
pingPong = false; // Set to true if pingPong is needed
timeStart = thisProperty.key(1).time;
duration = thisProperty.key(thisProperty.numKeys).time-timeStart;
quant=Math.floor((time-timeStart)/duration);
if(quant<0) quant = 0
if(quant%2 == 1 && pingPong == true){
t = 2*timeStart+ (quant+1)*duration - time;
}
else{
t = time-quant*duration;
}
}
catch(err){
t = time;
}
thisProperty.valueAtTime(t)
Range Mapper
Remap input values to a different output range.
Add a Slider Control to a layer with expression and apply this to any parameter:
input = effect("Slider Control")("Slider");
inputLow = 0;
inputHigh = 100;
outputLow = 450;
outputHigh = 650;
linear(input,inputLow,inputHigh,outputLow,outputHigh)
Maintain Stroke Width When Scaling
Keep a constant stroke width when scaling a shape.
Apply this to the Stroke Width of the shape layer:
value / length(toComp([0,0]), toComp([0.7071,0.7071])) || 0.001;
Counters
A collection of 6 counter expressions for various use cases. All of these counters are basically text layers linked to slider controls, which can be keyframed.
1. Simple Counter
Displays numbers with a fixed decimal place.
Add a Slider Control to your text layer, it will control the counter. Apply expression to the Source Text. Change the number of decimal places by adjusting the toFixed(2) parameter.
parseFloat(effect("Slider Control")("Slider")).toFixed(2)
2. Comma Separator Counter
Replaces the decimal point with a comma. If you happen to need a similar setup with more customization, it’s right here.
Add a Slider Control and apply expression to the Source Text.
c = parseFloat(effect("Slider Control")("Slider")).toFixed(2);
c.toString().replace(".", ",")
3. Counter with Additional Symbols
Adds symbols like + or % to the number.
Add a Slider Control and apply expression to the Source Text.
"+"+parseFloat(effect("Slider Control")("Slider")).toFixed(2)+"%"
4. Counter with Leading Zeros
Displays numbers like 001 instead of 1.
Add a Slider Control and apply expression to the Source Text.
zerosAmount = 3;
var slider = effect("Slider Control")("Slider");
function padStart(string, targetLength, character) {
string = (string instanceof String) ? string : string.toString();
targetLength = targetLength >> 0;
character = character || ' ';
while (string.length < targetLength) {
string = character + string;
}
return string;
};
if (slider >= 0) {
zeroAmount = zerosAmount + 1;
paddedString = padStart(parseFloat(slider.value).toFixed(0), zerosAmount, '0');
}
else {
paddedString = '-0'+padStart(parseFloat(slider.value).toFixed(0)*-1, zerosAmount, '0');
}
paddedString;
5. Digit Grouping Counter
Adds spacing to group digits, turning 30000 into 30 000.
Add a Slider Control and apply expression to the Source Text.
num = parseFloat(effect("Slider Control")("Slider")).toFixed(0);
str = isNaN(num) ? "" : (num * 1 + "");
str.replace(/(\d)(?=(\d\d\d)+([^\d]|$))/g, '$1 ');
6. Large Number Counter:
For values above 1,000,000, use Angle Control instead of a Slider Control.
Add an Angle Control and apply expression to the Source Text.
number = Math.round(effect("Angle Control")("Angle")/360);
n="" + number;
s="";
for(i=0, l=n.length; i<l; i++){
if(s && s!="-" && (l-i)%3 ==0)
s+=" ";
s += n[i];
}
s;
Various Mini Expressions
And finally, 4 useful mini-expressions that often come in handy.
1. Link to Layer Above or Below
It’s not a complete expression, but only part of it. Instead of linking one layer to another using its name, it is sometimes more convenient to link to a layer above or below the layer with the expression.
In the example, I link the box’s layer position to any layer above. To parent to a layer below instead, use index+1.
thisComp.layer(index-1)
2. Constantly Accelerating Rotation
Add this to Rotation for progressively faster spins:
time*time*time*time
3. Keyframes with time*n
Add constant motion while still allowing keyframes.
value+time*11
4. Link Gradient Ramp to Layer
Prevent a gradient ramp from shifting when moving the layer. Apply to the Start and End of the gradient.
toComp(value)
That’s it! This collection includes 23 expressions I use regularly.
📁 The project file with all of them is available for free.