
Essential After Effects Expressions List
Unlock the true power of Adobe After Effects with our essential expressions list and cheat sheet. Whether you're a beginner looking to understand AE expressions or a pro aiming to streamline your workflow for After Effects, this guide is for you!
What Are After Effects Expressions?
After Effects expressions are small pieces of code, based on JavaScript, that allow you to automate animations, link properties, and create complex relationships between layers and effects without manually creating hundreds of keyframes. Think of them as mini-programs that tell After Effects what to do with a property over time or based on other properties. Learning After Effects expressions can drastically speed up your workflow and open up a new world of creative possibilities, from simple wiggles to complex text animation expressions.
If you've ever found yourself painstakingly keyframing a repetitive motion or wishing one layer could intelligently react to another, then expressions in AE are your answer. From simple wiggles to complex procedural animations, they are a cornerstone of professional motion graphics and visual effects in After Effects.
The Basics of Using Expressions
Using expressions is straightforward:
1. Add an Expression: Alt-click (Option-click on Mac) the stopwatch icon next to any layer property in the timeline (like Position, Scale, Opacity). This opens the expression editor field.
2. Use the Pick Whip: This spiral icon (@
) lets you visually link properties. Drag it to another property, and After Effects writes the basic linking code for you – a great way to start!
3. Enable/Disable: Click the equals sign (=
) next to an expression field to toggle it on or off.
Quick Navigation: Expression List
Essential After Effects Expressions
Let's break down some of the most useful expressions, from fundamental building blocks to specialized advanced expressions. This After Effects expressions list is designed to be a go-to resource. Some of these expressions or their concepts were inspired by the excellent library at PlainlyVideos.com – check them out for even more ideas!
The legendary wiggle()
creates random, organic-looking movement. It's controlled by frequency (how many wiggles per second) and amplitude (how much the property deviates). Optional parameters include octaves (adds detail), amp_mult (octave amplitude multiplier), and t (base time).
To wiggle a single axis (e.g., Y-axis of Position): [value[0], wiggle(2,50)[1]];
// --- Wiggle Controls ---
var frequency = 2; // Wiggles per second (e.g., 1 for slow, 5 for fast)
var amplitude = 50; // Max amount of change (e.g., 50 pixels for position)
var octaves = 1; // Optional: Layers of detail in the wiggle (usually 1-3)
var amp_mult = 0.5; // Optional: How much an octave affects amplitude (0 to 1)
var timeToWiggleAt = time; // Optional: Base time for wiggle (default is current time)
wiggle(frequency, amplitude, octaves, amp_mult, timeToWiggleAt);
Commonly Applied to: Position, Scale, Rotation, Opacity, Effect Properties

Essential for repeating keyframed animations. loopOut()
affects animation *after* the last keyframe; loopIn()
affects it *before* the first. The type
parameter (e.g., "cycle", "pingpong", "offset", "continue") defines loop behavior. numKeyframes
(default 0 for all) specifies how many keyframes from the end/start define the loop segment.
// --- LoopOut Example (applied after last keyframe) ---
var loopType = "cycle"; // "cycle", "pingpong", "offset", or "continue"
var numKeyframesToLoop = 0; // 0 means all keyframes, 1 means segment between last two, etc.
loopOut(loopType, numKeyframesToLoop);
// --- LoopIn Example (applied before first keyframe) ---
// loopIn(loopType, numKeyframesToLoop);
Commonly Applied to: Any keyframable property (Position, Scale, Rotation, Opacity, Time Remap)

Simply returns the current composition time in seconds. Fundamental for creating animations that progress consistently or at a constant rate.
// Basic time usage (returns current time in seconds)
time;
// Example: Continuous Rotation (apply to Rotation property)
var rotationSpeed = 90; // Degrees per second
time * rotationSpeed;
// Example: Constant Horizontal Movement (apply to Position property)
var initialX = value[0]; // Or a specific starting X value like 100
var speedX = 200; // Pixels per second
[initialX + time * speedX, value[1]]; // Keeps original Y
Commonly Applied to: Rotation, Position, Opacity (for timed fades), driving other expressions

Represents the property's original, pre-expression value (from keyframes or the value set in the UI). Crucial for adding to or modifying existing animations non-destructively.
// Example: Add a small wiggle to existing keyframed position
value + wiggle(0.5, 15);
Commonly Applied to: Any property to modify its existing keyframed animation.
Returns the value of the property it's applied to, but at a specific time `t` (in seconds) you provide, rather than the current composition time. Excellent for creating delays or echo effects.
// --- Delayed Follow Example (apply to Position property of follower layer) ---
var leaderLayer = thisComp.layer("LeaderLayerName"); // Change "LeaderLayerName" to the name of your leader layer
var delayInSeconds = 0.5; // How much time delay
leaderLayer.transform.position.valueAtTime(time - delayInSeconds);
Commonly Applied to: Position, Scale, Rotation, Opacity (to follow another layer with a delay)
Returns the layer's own number in the layer stack (the topmost layer is 1, second is 2, etc.). Very useful for creating automatic offsets or variations across multiple duplicated layers.
// Example: Staggered Opacity for duplicated layers
var baseOpacity = 100;
var opacityDecrementPerLayer = 10; // Each layer below will be 10% less opaque
baseOpacity - (index - 1) * opacityDecrementPerLayer; // (index-1) so first layer is full opacity
Commonly Applied to: Any property to create variations across duplicated layers (e.g., Position offset, Rotation offset, Color variations, Opacity)
Link parts of your expression to Effect Controls (like "Slider Control", "Checkbox Control", "Color Control" found under Effect > Expression Controls) for easy adjustments without editing the code. Add the control to a layer (often a Null named "Controller") and pick-whip to it.
// Example: Control Wiggle Frequency with a slider named "FreqControl" on this layer
var freq = effect("FreqControl")("Slider");
var amp = 50; // Amplitude can still be fixed or linked to another slider
wiggle(freq, amp);
Commonly Applied to: Any expression where you want user-friendly controls for variables (e.g., wiggle frequency/amplitude, color values, checkbox toggles).
Standard trigonometric functions for creating smooth, wave-like or oscillating motions. Angles must be in radians (use degreesToRadians(degrees)
to convert).
// Example: Y Position sine wave movement
var initialY = value[1]; // Initial Y position of the layer
var amplitude = 50; // How high/low the wave goes (pixels)
var frequency = 2; // How many full cycles per second
var yPositionOffset = Math.sin(time * frequency * 2 * Math.PI) * amplitude;
[value[0], initialY + yPositionOffset]; // Keep original X, animate Y
Commonly Applied to: Position (for wave motion), Rotation (for oscillation), Scale (for pulsing), Opacity (for flickering).

random(min, max)
generates a pseudo-random number between min and max (or 0 and min if only one argument). To get a consistent random value per layer that doesn't change over time, use seedRandom(seedValue, timeless = true)
before random()
, often using index
as the seedValue
.
// Example: Random opacity per layer that stays consistent
var minOpacity = 20;
var maxOpacity = 80;
seedRandom(index, true); // Seed with layer index, timeless makes it fixed per layer
random(minOpacity, maxOpacity);
// Example: Random opacity that changes every frame (no seedRandom or timeless=false)
random(20, 80);
Commonly Applied to: Opacity, Position, Scale, Rotation, Color (for random variations), Text Animator Selector Amount.
Powerful interpolation functions. As an input t
(often time
) goes from tMin
to tMax
, linear()
transitions the output from value1
to value2
. ease()
applies an S-curve (ease-in and -out), while easeIn()
and easeOut()
provide one-sided easing.
// Example: Scale from 50% to 100% between time 0 and 2 seconds, with S-curve easing
var startScale = 50;
var endScale = 100;
var startTime = 0;
var endTime = 2;
var s = ease(time, startTime, endTime, startScale, endScale);
[s,s];
// Example: Opacity fades from 0 to 100 between seconds 1 and 3 using linear
linear(time, 1, 3, 0, 100);
Commonly Applied to: Any numerical property for smooth transitions over time or based on a controller (e.g., Opacity, Scale, Position, Rotation, Effect parameters).

Standard conditional logic. If the condition
evaluates to true, the expression returns statement A
; otherwise, it returns statement B
.
// Example: Layer Opacity is 100% after 2 seconds, otherwise 0%
var timeThreshold = 2; // Seconds
if (time > timeThreshold) {
100; // Opacity if condition is true
} else {
0; // Opacity if condition is false
}
Commonly Applied to: Any property to switch between values or behaviors based on conditions (e.g., Opacity, Text Source, Effect enable/disable via checkbox).
A community-favorite script to create natural bounce or spring effects as keyframed animation settles. Adjust amplitude (bounce amount), frequency (bounces per second), and decay (how quickly it fades).
// --- Inertial Bounce Controls ---
var amp = .055; // Amplitude: How much bounce (e.g., 0.01 for subtle, 0.2 for more)
var freq = 1.8; // Frequency: Bounces per second (e.g., 1 to 5)
var decayRate = 5.2;// Decay: How quickly bounce fades (e.g., 3 for slower, 10 for faster)
// --- Inertial Bounce Script (do not edit below unless you know what you're doing) ---
var n = 0;
if (numKeys > 0){
n = nearestKey(time).index;
if (key(n).time > time) n--;
}
var t = (n > 0) ? time - key(n).time : 0;
if (n > 0 && t >= 0){
var v = velocityAtTime(key(n).time - thisComp.frameDuration/10);
value + v * amp * Math.sin(freq * t * 2 * Math.PI) / Math.exp(decayRate * t);
} else {
value;
}
Commonly Applied to: Position, Scale, Rotation (after keyframed movement).

Makes this layer orbit in a circle around a specified "CenterLayerName". Customize radius and speed.
// --- Orbit Controls ---
var centerLayerName = "CenterLayer"; // Name of the layer to orbit around
var orbitRadius = 500; // Radius of the orbit in pixels
var orbitSpeed = 2; // Speed of orbit (higher is faster, negative reverses)
// --- Orbit Script ---
var centerPt = thisComp.layer(centerLayerName).transform.position;
var currentAngle = time * orbitSpeed;
var x = centerPt[0] + Math.cos(currentAngle) * orbitRadius;
var y = centerPt[1] + Math.sin(currentAngle) * orbitRadius;
if (centerPt.length > 2 && transform.position.length > 2) { // If both are 3D
var z = value[2]; // Maintain this layer's Z, or use centerPt[2] to orbit in center's Z plane
[x, y, z];
} else { // For 2D layers
[x, y];
}
Commonly Applied to: Position.

Simulates the classic DVD logo screensaver, making the layer move diagonally and bounce off the composition edges. Speeds are adjustable.
// --- Bounce Controls ---
var horizontalSpeed = 300; // Speed in X direction (pixels per second)
var verticalSpeed = 200; // Speed in Y direction (pixels per second)
// --- Bounce Script ---
var layerRect = sourceRectAtTime(time, false);
var effectiveLayerWidth = layerRect.width * transform.scale[0]/100;
var effectiveLayerHeight = layerRect.height * transform.scale[1]/100;
var compW = thisComp.width;
var compH = thisComp.height;
var minX = effectiveLayerWidth / 2;
var maxX = compW - (effectiveLayerWidth / 2);
var minY = effectiveLayerHeight / 2;
var maxY = compH - (effectiveLayerHeight / 2);
var t = time - inPoint;
var rawX = minX + (t * horizontalSpeed);
var rawY = minY + (t * verticalSpeed);
var bounceCountX = Math.floor(rawX / (maxX - minX));
var bounceCountY = Math.floor(rawY / (maxY - minY));
var finalX, finalY;
if (bounceCountX % 2 == 1){ finalX = maxX - (rawX % (maxX - minX)); }
else { finalX = minX + (rawX % (maxX - minX)); }
if (bounceCountY % 2 == 1){ finalY = maxY - (rawY % (maxY - minY)); }
else { finalY = minY + (rawY % (maxY - minY)); }
[finalX, finalY];
Commonly Applied to: Position.

Creates a spring-like connection where this layer follows a "leaderLayerName" with bouncy, overshooting motion. Adjust rest length, stiffness, and damping. Can be computationally intensive due to its frame-by-frame iterative calculation.
// --- Spring Controls ---
var leaderLayerName = "leader"; // Name of the layer to follow
var restLength = 20; // Desired resting distance between leader and follower anchor points
var springStiffness = 0.1; // Stiffness of the spring (e.g., 0.05 for softer, 0.2 for stiffer)
var dampingFactor = 0.95; // Damping (0 to 1). Lower is more springy, higher is less oscillation.
// --- Spring Script ---
var leader = thisComp.layer(leaderLayerName);
var fDur = thisComp.frameDuration;
var currTime = time;
var pFollower = position.valueAtTime(0); // Follower's initial position (at its inPoint)
var vFollower = [0,0,0]; // Follower's initial velocity
if (position.length === 2) vFollower = [0,0]; // Match 2D/3D for velocity array
for (var t = 0; t <= currTime - thisLayer.inPoint; t += fDur){ // Iterate for duration layer has been active
var leaderTime = thisLayer.inPoint + t; // Time to sample leader
if (leaderTime > leader.outPoint) leaderTime = leader.outPoint; // Clamp if leader ends
if (leaderTime < leader.inPoint) leaderTime = leader.inPoint; // Clamp if leader starts later
var pLeader = leader.transform.position.valueAtTime(leaderTime);
var delta = pFollower - pLeader;
var currentDist = length(delta);
var springForceMagnitude = (currentDist - restLength) * springStiffness; // Hooke's Law
var springForceVector = [0,0,0];
if (currentDist > 0.001) { // Avoid division by zero if coincident
springForceVector = normalize(delta) * springForceMagnitude;
}
if (position.length === 2 && springForceVector.length === 3) { // Ensure vector matches dimension
springForceVector = [springForceVector[0], springForceVector[1]];
}
vFollower = (vFollower - springForceVector) * dampingFactor; // Apply force to velocity, then damp
pFollower += vFollower * fDur; // Update follower's position (integrate velocity)
}
pFollower;
Commonly Applied to: Position.

Creates a position wiggle that loops seamlessly over a defined loopDurationSeconds
. Useful for continuous, random-looking background movements.
// --- Loopable Wiggle Controls ---
var wiggleFrequency = 1; // Wiggles per second
var wiggleAmplitude = 110; // Wiggle amount in pixels
var loopDurationSeconds = 3;// Duration of the loop in seconds
// --- Loopable Wiggle Script ---
var t = time % loopDurationSeconds;
var wiggle1 = wiggle(wiggleFrequency, wiggleAmplitude, 1, 0.5, t);
var wiggle2 = wiggle(wiggleFrequency, wiggleAmplitude, 1, 0.5, t - loopDurationSeconds);
linear(t, 0, loopDurationSeconds, wiggle1, wiggle2);
Commonly Applied to: Position.
Dynamically positions the current layer exactly halfway between two other specified layers, referenced by their stack index (e.g., layer 1 and 2) or by name.
// --- Referencing Layers ---
// Option 1: By Layer Index (1 is top layer, 2 is second, etc.)
var layerA = thisComp.layer(1);
var layerB = thisComp.layer(2);
// Option 2: By Layer Name (uncomment and use instead if preferred)
// var layerA = thisComp.layer("NameOfFirstLayer");
// var layerB = thisComp.layer("NameOfSecondLayer");
// --- Calculation ---
(layerA.transform.position + layerB.transform.position) / 2;
Commonly Applied to: Position.

A simplified 2D physics simulation. Layers respond to gravity and bounce off composition edges (walls), which can be set independently using sliders. It uses an iterative calculation from the layer's in-point, which can become slow for many objects or long durations.
Setup: Create a Null Layer named "PhysicsSettings2D". Add Slider Controls to it named "Gravity Y", "Wall Bounce Factor", "Global Damping", "Min X Wall", "Max X Wall", "Min Y Wall", "Max Y Wall". On each physics object layer, add sliders for "Initial Velocity X", "Initial Velocity Y", and "Radius".
// --- Global Physics Settings (Reads from Null Layer "PhysicsSettings2D") ---
var settingsNullName = "PhysicsSettings2D";
var gravY = 980, wallBounce = 0.7, damping = 0.995; // Defaults
var minXWall = 0, maxXWall = thisComp.width, minYWall = 0, maxYWall = thisComp.height; // Defaults
try {
var settingsLayer = thisComp.layer(settingsNullName);
gravY = settingsLayer.effect("Gravity Y")("Slider");
wallBounce = settingsLayer.effect("Wall Bounce Factor")("Slider");
damping = settingsLayer.effect("Global Damping")("Slider");
minXWall = settingsLayer.effect("Min X Wall")("Slider");
maxXWall = settingsLayer.effect("Max X Wall")("Slider");
minYWall = settingsLayer.effect("Min Y Wall")("Slider");
maxYWall = settingsLayer.effect("Max Y Wall")("Slider");
} catch(err) { /* Use defaults if settings layer or sliders are missing */ }
// --- Individual Object Properties (Reads from sliders on THIS layer) ---
var iVelX = 0, iVelY = 0, radiusThis = 25; // Default radius
try { iVelX = effect("Initial Velocity X")("Slider"); } catch(e){ iVelX = (index % 7 - 3) * 20; } // Default variation
try { iVelY = effect("Initial Velocity Y")("Slider"); } catch(e){ iVelY = -(index % 5) * 50 -50; } // Default variation
try { radiusThis = Math.max(1, effect("Radius")("Slider")); } catch(e){} // Ensure radius is at least 1
// --- Simulation ---
var dt = thisComp.frameDuration;
var p = transform.position.valueAtTime(inPoint); // Start at initial keyframed position or value
var v = [iVelX, iVelY]; // Initial velocity
// Effective boundaries considering object radius
var effectiveMinX = minXWall + radiusThis;
var effectiveMaxX = maxXWall - radiusThis;
var effectiveMinY = minYWall + radiusThis;
var effectiveMaxY = maxYWall - radiusThis;
// Iterate from layer's inPoint up to the current time to simulate physics progression
for (var t = inPoint; t < time; t += dt){
// Apply Gravity (only to Y velocity)
v[1] = v[1] + gravY * dt;
// Apply Global Damping (Air Resistance)
v = v * damping;
// Update Position based on velocity
p = p + v * dt;
// Boundary Collisions & Bounce
// X-axis
if (p[0] < effectiveMinX) {
p[0] = effectiveMinX;
v[0] *= -wallBounce;
} else if (p[0] > effectiveMaxX) {
p[0] = effectiveMaxX;
v[0] *= -wallBounce;
}
// Y-axis
if (p[1] < effectiveMinY) {
p[1] = effectiveMinY;
v[1] *= -wallBounce;
} else if (p[1] > effectiveMaxY) {
p[1] = effectiveMaxY;
v[1] *= -wallBounce;
}
}
p; // Resulting position for the current frame
Commonly Applied to: Position (of 2D layers).

Rotates a 2D layer to always point towards another specified "targetLayerName". An artworkPointingOffsetDegrees
might be needed if the layer's art doesn't point right (0 degrees) by default.
// --- LookAt Controls ---
var targetLayerName = "targetLayer"; // Name of the layer to point towards
var artworkPointingOffsetDegrees = 0; // Adjust if your artwork points up (e.g., 90 or -90), left (e.g., 180) by default
// --- LookAt Script ---
function calculateLookAtAngle(fromPoint, toPoint) {
var deltaX = toPoint[0] - fromPoint[0];
var deltaY = toPoint[1] - fromPoint[1];
var angleRad = Math.atan2(deltaY, deltaX);
return radiansToDegrees(angleRad);
}
var thisLayerPosition = transform.position;
var targetPosition = thisComp.layer(targetLayerName).transform.position;
calculateLookAtAngle(thisLayerPosition, targetPosition) + artworkPointingOffsetDegrees;
Commonly Applied to: Rotation (of a 2D Layer).

Orients a 3D layer (or camera) so its Z-axis points from a "viewPointLayerName" (or its own position) towards a "targetLayerName" in 3D space, using After Effects' built-in lookAt()
.
// --- 3D LookAt Controls ---
var targetLayerName = "Target"; // Name of the layer to look AT
var viewPointLayerName = "Point"; // Name of layer defining the viewpoint.
// If this layer IS the viewpoint, use thisLayer.name or an empty string.
// --- 3D LookAt Script ---
var targetObj = thisComp.layer(targetLayerName);
var fromPosition;
if (viewPointLayerName == "" || thisComp.layer(viewPointLayerName) == thisLayer) {
fromPosition = toWorld(transform.anchorPoint); // This layer is the viewpoint
} else {
var viewPointObj = thisComp.layer(viewPointLayerName);
fromPosition = viewPointObj.toWorld(viewPointObj.transform.anchorPoint);
}
var targetPosition = targetObj.toWorld(targetObj.transform.anchorPoint);
lookAt(fromPosition, targetPosition);
Commonly Applied to: Orientation (of a 3D Layer or Camera).

Applied to a child layer's Rotation, it maintains its own world-space rotation, effectively counteracting rotation inherited from its parent.
// --- Ignore Parent Rotation Script ---
if (hasParent) {
value - parent.transform.rotation;
} else {
value; // No parent, so just use its own rotation
}
Commonly Applied to: Rotation.

Creates a realistic decaying pendulum swing on Rotation. Customize frequency (swings per second), initial amplitude (degrees), and decay rate.
// --- Pendulum Controls ---
var swingFrequency = 1.0; // Swings per second (e.g., 1 full back-and-forth per second)
var initialAmplitude = 45; // Initial swing angle in degrees (e.g., 45 degrees to each side)
var decayRate = 0.5; // How quickly swing dampens (0 = no decay, higher = faster stop)
// --- Pendulum Script ---
initialAmplitude * Math.sin(time * swingFrequency * Math.PI * 2) * Math.exp(-decayRate * time);
Commonly Applied to: Rotation.

Counteracts a parent layer's scale transformations to keep this child layer's visual size consistent as if it were not parented or its parent was at 100% scale.
// --- Maintain Scale Script ---
var newScale = [];
if (hasParent) {
var parentScale = parent.transform.scale.value;
for (var i = 0; i < parentScale.length; i++){ // Works for 2D or 3D scale
if (parentScale[i] === 0) { // Avoid division by zero
newScale[i] = value[i]; // Or some large number if you want it to "disappear"
} else {
newScale[i] = value[i] * 100 / parentScale[i];
}
}
} else {
newScale = value; // No parent, so use its own scale value
}
newScale;
Commonly Applied to: Scale.
Creates a rhythmic scaling pulse. Controls include speed, amount, base scale, phase, and mode (symmetric grow/shrink, grow only, or shrink only).
// --- Pulse Controls ---
var pulseSpeed = 1.0; // Cycles per second (e.g., 1.0 for one full pulse per second)
var pulseAmount = 20; // Percentage of scale change (e.g., 20 means ±20% if mode is 0)
var baseScaleValue = [100, 100]; // Resting scale [X,Y] or [X,Y,Z] for 3D layers
var phaseOffsetCycles = 0.0;// Shifts start point of pulse (0 to 1, e.g., 0.25 starts at peak)
var pulseMode = 1; // 0 = grow & shrink; 1 = only grow from base; 2 = only shrink from base
// --- Pulse Script ---
var angle = (time * pulseSpeed + phaseOffsetCycles) * 2 * Math.PI;
var rawOffset;
if (pulseMode == 0) { rawOffset = Math.sin(angle) * pulseAmount; }
else if (pulseMode == 1) { rawOffset = ((1 - Math.cos(angle)) / 2) * pulseAmount; }
else if (pulseMode == 2) { rawOffset = -((1 - Math.cos(angle)) / 2) * pulseAmount; }
else { rawOffset = Math.sin(angle) * pulseAmount; } // Fallback
var finalScale = [];
for (var i = 0; i < baseScaleValue.length; i++) {
finalScale[i] = baseScaleValue[i] + rawOffset;
}
finalScale;
Commonly Applied to: Scale.

Dynamically fades a 3D layer's opacity based on its distance from the active camera, between a defined startFadeDistance
and endFadeDistance
.
// --- Fade Controls ---
var startFadeDistance = 500; // Distance (pixels) from camera where fade begins (100% opacity closer than this)
var endFadeDistance = 1500; // Distance (pixels) from camera where layer is fully faded (0% opacity further than this)
// --- Fade Script ---
var camPosition;
try {
camPosition = thisComp.activeCamera.toWorld([0,0,0]);
} catch (err) {
var compWidthForDefaultCam = thisComp.width * thisComp.pixelAspect;
var defaultCamZ = (compWidthForDefaultCam/2) / Math.tan(degreesToRadians(19.799)); // Approx 50mm lens
camPosition = [thisComp.width/2, thisComp.height/2, -defaultCamZ];
}
var layerPosition = toWorld(anchorPoint);
var distanceToCam = length(camPosition, layerPosition);
linear(distanceToCam, startFadeDistance, endFadeDistance, 100, 0);
Commonly Applied to: Opacity (of a 3D Layer).

Adjusts a stroke's width to counteract the layer's 2D scale transformations, making the stroke appear visually consistent even if the layer is scaled.
// --- Maintain Apparent Stroke Width Script ---
// No user-editable variables needed for this typical implementation.
// It divides the original stroke 'value' by a measure of the layer's current scale.
var scaleFactor = length(toComp([0,0]), toComp([0.7071,0.7071]));
if (scaleFactor === 0) scaleFactor = 0.001; // Avoid division by zero
value / scaleFactor;
Commonly Applied to: Shape Layer Stroke Width, Text Layer Stroke Width (if using layer styles).

Dynamically control text properties like font, size, color, and tracking using text.sourceText.style
methods (AE 17.0+). Chain methods for complex styling. Per-character styling (AE 25.0+) uses optional startIndex
and numOfCharacters
arguments in many styling methods.
// Example: Changing Font, Size, and Fill Color
text.sourceText.style
.setFont("Impact")
.setFontSize(120)
.setFillColor([1, 0.5, 0]); // Orange: [Red, Green, Blue] values 0-1
// Example: Adding a Stroke and Changing Text Content
var styleObj = text.sourceText.style;
styleObj = styleObj.setStrokeColor([0.2, 0.8, 0.2]); // Green stroke
styleObj = styleObj.setStrokeWidth(5);
styleObj = styleObj.setApplyStroke(true); // Important to make stroke visible
styleObj = styleObj.setTracking(20);
styleObj.setText("Styled with Expressions!"); // This must be the last style modification if changing text content
Commonly Applied to: Source Text (to control its styling attributes).

Use conditional logic within an Expression Selector to apply an animator's effect to only specific characters based on their textIndex
(0 for first char, 1 for second, etc.).
// --- Targeting Controls ---
// Example: Affect only the first 3 characters (indices 0, 1, 2)
var charactersToTarget = 3;
if (textIndex < charactersToTarget) {
100; // Full effect
} else {
0; // No effect
}
// Example: Affect characters from index 2 up to (but not including) index 5
var startIndex = 2; // Third character
var endIndex = 5; // Affects up to character before this index (i.e., characters at index 2, 3, 4)
if (textIndex >= startIndex && textIndex < endIndex) {
100; // Apply full animator effect
} else {
0; // No effect for other characters
}
Commonly Applied to: Text Animator > Expression Selector > Amount.

Targets every Nth character using an Expression Selector. You can control the interval (N) and an offset to change the starting point (e.g., to select even or odd characters).
// --- Nth Character Selector Controls ---
// Apply this to a Text Animator's Expression Selector > Amount property.
var nthValue = 2; // Select every 2nd character (for every other character)
// Change to 3 for every 3rd character, etc.
var startOffset = 0; // 0 to start with the Nth character (e.g. if Nth=2, characters 1,3,5... using 0-based textIndex)
// 1 to start with the (Nth + offset) character (e.g. if Nth=2 & offset=1, characters 0,2,4...)
// --- Nth Character Script ---
if (nthValue <= 0) nthValue = 1; // Prevent division by zero or negative values
if ((textIndex + startOffset) % nthValue == 0) {
100; // Apply full animator effect to this character
} else {
0; // No effect for other characters
}
Commonly Applied to: Text Animator > Expression Selector > Amount.
Automatically scales a text layer proportionally to ensure it fits within predefined width and height boundaries. Useful for MOGRTs where text length can vary.
// --- Dynamic Text Scaling Controls ---
var maxWidthBoundary = 500; // Desired maximum width for the text
var maxHeightBoundary = 100; // Desired maximum height for the text
var overallScalePercentage = 100; // Additional overall scale (100 = no change from fit)
var measureAtCurrentTime = true; // true: measure text at current time; false: measure at time 0
// --- Scaling Script ---
var timeToMeasureAt = measureAtCurrentTime ? time : 0;
var textRect = sourceRectAtTime(timeToMeasureAt);
var currentTextWidth = textRect.width;
var currentTextHeight = textRect.height;
var widthScaleFactor = 1;
var heightScaleFactor = 1;
if (currentTextWidth > 0) widthScaleFactor = maxWidthBoundary / currentTextWidth;
if (currentTextHeight > 0) heightScaleFactor = maxHeightBoundary / currentTextHeight;
var finalFitScaleFactor = Math.min(widthScaleFactor, heightScaleFactor);
var s = finalFitScaleFactor * overallScalePercentage;
if (currentTextWidth === 0 || currentTextHeight === 0) { s = overallScalePercentage; }
else if (finalFitScaleFactor >= 1 && overallScalePercentage < 100) { s = overallScalePercentage; }
else if (finalFitScaleFactor < 1) { s = finalFitScaleFactor * 100 * (overallScalePercentage / 100); }
else { s = overallScalePercentage; }
[s, s];
Commonly Applied to: Scale (of a Text Layer).

Adjusts a layer's anchor point to one of nine logical positions (e.g., center, top-left) based on its content's bounding box (sourceRectAtTime
). While extremely useful for text layers, it can also apply to shape layers or other layers where sourceRectAtTime
provides meaningful dimensions. Ensures consistent transformations like scale or rotation, regardless of content changes.
// --- Anchor Point Control ---
// Choose a number from 1 to 9 for anchorPosition:
// 1=Top Left, 2=Top Center, 3=Top Right
// 4=Middle Left, 5=Middle Center, 6=Middle Right
// 7=Bottom Left, 8=Bottom Center, 9=Bottom Right
var anchorPosition = 5;
var measureAtCurrentTime = true;
// --- Anchor Point Script ---
var timeToMeasureAt = measureAtCurrentTime ? time : 0;
var layerRect = thisLayer.sourceRectAtTime(timeToMeasureAt);
var L = layerRect.left;
var T = layerRect.top;
var W = layerRect.width;
var H = layerRect.height;
var xAnchor, yAnchor;
switch(anchorPosition){
case 1: xAnchor=L; yAnchor=T; break;
case 2: xAnchor=L+W/2; yAnchor=T; break;
case 3: xAnchor=L+W; yAnchor=T; break;
case 4: xAnchor=L; yAnchor=T+H/2; break;
case 5: xAnchor=L+W/2; yAnchor=T+H/2; break;
case 6: xAnchor=L+W; yAnchor=T+H/2; break;
case 7: xAnchor=L; yAnchor=T+H; break;
case 8: xAnchor=L+W/2; yAnchor=T+H; break;
case 9: xAnchor=L+W; yAnchor=T+H; break;
default: xAnchor=L+W/2; yAnchor=T+H/2;
}
[xAnchor, yAnchor];
Commonly Applied to: Anchor Point (primarily for Text or Shape Layers).
Converts a numerical value from a "Slider Control" (representing total seconds) on the same layer into an HH:MM:SS timecode format on a text layer.
// --- Timer Control ---
// Add a "Slider Control" effect to this text layer.
// The slider's value will be interpreted as total seconds.
var totalSecondsInput = Math.round(effect("Slider Control")("Slider").value);
// --- Timer Script ---
var hrs = Math.floor(totalSecondsInput / 3600);
var mins = Math.floor((totalSecondsInput % 3600) / 60);
var secs = totalSecondsInput % 60;
function addLeadingZero(n) {
return n < 10 ? "0" + n : "" + n;
}
addLeadingZero(hrs) + ":" + addLeadingZero(mins) + ":" + addLeadingZero(secs);
Commonly Applied to: Source Text (of a Text Layer, requires a Slider Control).

Makes this text layer completely mirror both the text content and all styling (font, size, color, etc.) from another specified source text layer.
// --- Source Layer ---
// Change "SourceTextLayerName" to the actual name of your source text layer.
var sourceLayer = thisComp.layer("SourceTextLayerName");
// --- Copy Script ---
var sourceStyle = sourceLayer.text.sourceText.getStyleAt(0, time); // Gets style from 1st char of source at current time
sourceStyle.setText(sourceLayer.text.sourceText.value); // Applies source style and text content
Commonly Applied to: Source Text (of a Text Layer).

Learning Resources
Diving into After Effects expressions can seem daunting, but there's a wealth of knowledge available to help you learn and troubleshoot:
Official Adobe After Effects Expressions Language Reference
This is the definitive guide from Adobe. It provides comprehensive details on all available functions, objects, and syntax. It's an excellent resource for understanding the core mechanics and discovering new possibilities.
Dan Ebberts' MotionScript.com
A legendary and foundational resource in the After Effects community. Dan provides incredibly detailed explanations, practical examples, and solutions to common (and uncommon) animation problems using expressions. Many widely-used expressions originated or were popularized here.
Plainly's After Effects Expressions Library
A great collection of useful expressions for various tasks, often with clear explanations and use cases. A good place to find ready-to-use snippets and learn new techniques.
Adobe After Effects Community Forum
A great place to ask questions, share your work, and get help from fellow users and Adobe staff. If you're stuck on an expression, chances are someone in the community can offer guidance or point you to a solution.
YouTube Tutorials
Many motion designers and After Effects educators share tutorials on YouTube. Channels like School of Motion, Ukramedia, Workbench, Ben Marriott, and Jake Bartlett (among many others) cover expressions, from beginner introductions to advanced techniques.
Conclusion
After Effects expressions are a deep and powerful feature that can significantly enhance your animation capabilities and efficiency. Start with the basics like wiggle()
, loopOut()
, and time
, and gradually explore more complex possibilities, including text animation expressions and dynamic styling. Happy animating!