3D Library

A curated library of useful motion design insights, tips and tricks for quick reference and practical guidance

After Effects Expressions Cheat Sheet

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]

© Kalleheikki Kannisto

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)

© Dan Ebberts

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];

Based on Mikey Borup’s expression

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)

© Xinlai Ni

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;
}

© aexpressions

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

© JR Canest

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)

© aexpressions

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)

© Dan Ebberts

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;

© Adam Plouff

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;

Based on Tomas Sinkunas’ expression

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 ');

© Tomas Bumbulevičius

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;

© Chunk Motion

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

© Ben Marriott

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)

© aeexpressions


That’s it! This collection includes 23 expressions I use regularly.
📁 The project file with all of them is available for free.

Fix Noise Loop: Cinema 4D Redshift

When you create a Redshift material with Maxon Noise, sometimes the loop doesn’t work. Here are two steps to solve the problem.

Disable Time Behavior

  1. Go to Render Settings (Ctrl+B)
  2. Switch to Advanced mode
  3. Go to Redshift → System → Legacy and disable Time Behavior

Check Loop Period

  1. Ensure that the FPS in both Project Settings (Ctrl + D) and Render Settings (Ctrl + B) match
  2. The Loop Period for the noise is calculated in seconds. So it should equal the total number of frames divided by the FPS. For example, if your timeline has 60 frames and your FPS is 30, the Loop Period should be 2 seconds.

After these adjustments, your noise should loop correctly.

Bonus tip: Since the first and last frames are identical in a loop, you can render one frame less to avoid repeating the same frame and achieve a smoother transition.

Fix Extrude Shading Issues: Cinema 4D

The Phong Tag can sometimes create strange artifacts or defects, especially noticeable when using Extrude with caps.

To fix shading issues, switch the Phong Tag from Uniform to Angle and Area Weighted or Square Area Weighted.

fix extrude shading cinema 4d

Intro

When I’m working in Cinema 4D, I frequently find myself googling solutions to problems or refreshing my memory on how to do something.

Sometimes the answer is right in the first search result, but other times I end up watching two-hour videos or digging through dead forums in Google’s cache to find an answer to what seems like a simple question. And when I do find a solution, at best, I share it in a work chat, where it reaches just a few people.

So, I decided to create this library to compile useful tips and tricks that can make life easier.