2D to 3D Null
Attaches a 2D layer's position to a 3D Null layer's screen position.
Apply to: Position (2D
// Attach a 2D position a 3D Null
thisComp.layer("3D Layer Name").toComp([0,0,0]);
Auto Fade
Automatically fades the layer in and out based on its In/Out points. You can also override the fade timing using markers (1st marker for fade in end, 2nd marker for fade out start).
Apply 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)
}
Auto Fade (Marker Duration)
Fades a layer in and out based on a marker's duration. Requires a marker with a duration and comment 'Highlight'.
Apply to: Opacity
// Fade a layer in and out using markers to set the duration
fadeFrames = 6; m = 0; t=time;
if(marker.numKeys > 0) {
m = marker.nearestKey(time).index;
tag = marker.key(m).comment;
if(tag == 'Highlight'){
tMin = marker.key(m).time;
tMax = tMin + marker.key(m).duration;
if(t < tMin){
linear(time, tMin - framesToTime(fadeFrames), tMin, 0, value);
} else {
linear(time, tMax - framesToTime(fadeFrames), tMax, value, 0);
}
} else {
value;
}
} else {value}
Auto Orient Y Only
Orients a layer towards the camera or target, but rotates only around the Y axis (useful for 2.5D billboards).
Apply to: Orientation / Y
delta = toWorld(anchorPoint) - thisComp.activeCamera.toWorld([0,0,0]);
radiansToDegrees(Math.atan2(delta[0],delta[2]))
Auto Rotate with Position
Automatically rotates a layer based on its position relative to the composition center.
Apply to: Rotation
var adj = 20; // adjust for rotation level
var posX = transform.position[0];
var posY = transform.position[1];
var comW = thisComp.width/2;
var comH = thisComp.height/2;
value+((posX-comW)/adj)+((posY-comH)/adj);
Bounce Expression
Adds an elastic bounce effect to properties based on velocity. Controls for elasticity, gravity, and max bounces are available.
Apply to: Position, Scale,
// variable e - controls the elasticity of the bounce
// variable g - controls the gravity acting on your object
// variable nMax - the maximum amount of bounces that are allowed
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
Center Anchor (Text)
Keeps the anchor point vertically centered on a text layer, even as the text changes.
Apply to: Anchor Point
// Make the anchor point always vertically centered on a text layer
y=value[1]-sourceRectAtTime(time).height/2;
[0,y]
Clicky Rotation
Creates a stop-motion style rotation effect by posterizing time.
Apply to: Rotation
// Posterize the expression result
posterizeTime(12);
time * 36;
Conditional Logic Examples
A reference sheet for using If/Else statements and ternary operators in expressions.
Apply to: Reference Only
// https://www.goodboy.ninja/expressionscheatsheet#conditions
if (true) {
// do this
} else {
// do that
}
A == B // A is equal to B
A === B // A is equal value and equal type B
A != B // A is not equal B
A !== B // A is not equal value or not equal type B
A > B //A is greater than B
A < B //A is less than B
A >= B //A is greater than or equal to B
A <= B //A is less than or equal to B
time == 10 // will be true only when the current time is 10 seconds
10 == 10 && 0 == 0 // true, because both are true
10 == 10 && 0 == 10 // false, because the second statement is false
10 == 10 || 0 == 10 // true, because at least one of the statements are true
// Rotation Control
var checkbox = //pickwhip to your checkbox
if (checkbox.value) {
time * 360;
} else {
value
}
// Ternary Operator (One-liner if/else)
// condition ? doThisIfTrue : otherwiseDoThis
time >= 5 ? 90 : -90
Control with Checkbox
Enables or disables a property value using a Checkbox Control effect.
Apply to: Any Property
// Apply to property you want to control
value * effect("Control Name")("Checkbox");
Countdown Timer
A full-function countdown timer supporting days, hours, minutes, and seconds, with formatting options.
Apply to: Source Text
// How many days, hours, minutes, and seconds you want to count down?
days_to_count = 253;
hours_to_count = 17;
minutes_to_count = 04;
seconds_to_count = 57;
// Number of seconds to hold the countdown timer at full
// before it starts counting down
offset_seconds = 0;
// Include minutes in the display?
// true or false
include_minutes = true;
// true to include leading zeroes in front of single-digit values,
// to keep text in same location
include_leading_zeroes = true;
// Integer of decimal places to include, counting fractional seconds
// If 0, only whole seconds will be displayed
decimal_places = 2;
// allow_negative_times
// true to allow the countdown to run past 0,
// false to hold the timer at 0 seconds.
allow_negative_times = false;
//////////
//
// Time code calculations
//
// the "time" to actually start the countdown
i = inPoint + offset_seconds;
//calculate total seconds in the countdown
seconds_to_count = minutes_to_count * 60 + seconds_to_count;
// decimal (float) of number of seconds remaining
// uses i start the countdown at the inpoint of the clip
seconds_remaining = seconds_to_count - time + i;
if (seconds_remaining > seconds_to_count)
{
// If we haven't gotten out of the offset_seconds period,
// reset the timer to full.
seconds_remaining = seconds_to_count;
}
if(!allow_negative_times)
{
// If we've passed zero seconds and user has chosen
// not to allow negative times, reset time to 0.
if(seconds_remaining < 0) seconds_remaining = 0;
}
// Calculate number of minutes (int) remaining
minutes_remaining = Math.floor(seconds_remaining / 60);
//reduces seconds to less than 60
decimal_seconds_remaining = seconds_remaining - 60 * minutes_remaining;
// Multiplier for placing decimal place in the correct spot
decimal_multiple = Math.pow(10, decimal_places);
// move decimal to the right and chops remainder
decimal_seconds_remaining = Math.floor(decimal_seconds_remaining * decimal_multiple);
// prepare the seconds for display - puts the decimal point back where it belongs
display_seconds_remaining = decimal_seconds_remaining / decimal_multiple;
// If we are at an even second and the user wants the decimal places
// displayed, tag the decimal point on to the string.
if (0 == decimal_seconds_remaining % decimal_multiple && decimal_places > 0)
{
display_seconds_remaining = display_seconds_remaining + ".";
}
// Calculate trailing zeroes for decimal fractions
if(decimal_places > 0)
{
for (a = 1; a <= decimal_places; a++)
{
if(!(decimal_seconds_remaining % Math.pow(10, a)))
{
// Add appropriate trailing zeroes if we are showing decimals.
display_seconds_remaining = display_seconds_remaining + "0";
}
}
}
if(decimal_seconds_remaining < decimal_multiple * 10 && include_minutes)
{
// if we are under 10 seconds and displaying minutes,
// add a leading 0 to the seconds
display_seconds_remaining = '0' + display_seconds_remaining;
}
if(include_minutes && minutes_to_count >= 0 && minutes_remaining < 10 && include_leading_zeroes)
{
display_minutes_remaining = '0' + minutes_remaining;
} else {
display_minutes_remaining = minutes_remaining;
}
//////////
//
// Build the final display string
//
days_to_count + "d " + hours_to_count + ":" + display_minutes_remaining + ':' + display_seconds_remaining
Create Path Examples
Examples of creating and modifying paths via expressions. Includes squares, circles, and tangent controls.
Apply to: Path Property
// Basic Square
var thePoints = [ [0,0], [100,0], [100,100], [0, 100] ];
createPath(thePoints);
// Circle (Sine/Cos)
var segments = 50;
var theRadius = 250;
var finalPoints = [];
for (var i=0; i<segments; i++) {
var progress = i /segments;
var x = Math.sin(progress * Math.PI * 2);
var y = Math.cos(progress * Math.PI * 2);
var finalPoint = [x,y] * theRadius;
finalPoints.push(finalPoint);
}
createPath(finalPoints);
Delay with Slider
Delays the animation keyframes by a specific amount of seconds controlled by a slider.
Apply to: Any Animated
delay = thisComp.layer("Controls").effect("Delay")("Slider"); // (in seconds)
valueAtTime(time-delay)
Distribute Layers
Automatically distributes layers horizontally based on the composition width and layer count.
Apply to: Position
var x = thisLayer.index / (thisComp.numLayers+1) * thisComp.width;
[x, value[1]];
Dropdown Menu Control
Links a layer's visibility (or value) to a specific item in a Dropdown Menu Control.
Apply to: Opacity / Any
// Add a Number [1,2,3] to layer name to match dropdown index
select = thisComp.layer("CONTROLS").effect("Dropdown")("Menu");
(select == parseInt(thisLayer.name[0])) ? value : 0;
Expand Linked Path
Expands the points of a linked path (mask) by a set amount, effectively offsetting the path shape.
Apply to: Path
var sourcePath = mask("Mask 1").maskPath;
var expandWidth = 20;
var expandHeight = 20;
var points = sourcePath.points();
var inTangents = sourcePath.inTangents();
var outTangents = sourcePath.outTangents();
var isClosed = sourcePath.isClosed();
// Calculate Center
var sumX = 0, sumY = 0;
for (var i = 0; i < points.length; i++) {
sumX += points[i][0];
sumY += points[i][1];
}
var center = [sumX / points.length, sumY / points.length];
var expandedPoints = points.map(function(pt) {
var offsetX = pt[0] - center[0];
var offsetY = pt[1] - center[1];
var scaledX = offsetX > 0 ? offsetX + expandWidth : offsetX - expandWidth;
var scaledY = offsetY > 0 ? offsetY + expandHeight : offsetY - expandHeight;
return [center[0] + scaledX, center[1] + scaledY];
});
createPath(expandedPoints, inTangents, outTangents, isClosed);
Finger Opacity (iOS Touch)
Calculates opacity for a virtual finger based on manual position keyframes, simulating touch interactions. Fades out when idle.
Apply to: Opacity
// IOS Virtual Finger Opacity Logic
var maxOpacity = 66.666;
var minOpacity = 0;
var maxIdle = 3.0;
var fadeTime = 0.5;
var fadePadFrames = 4;
// (Full code in source) -> See original file for complete logic as it is long.
// Simplified version for display:
var nextKey = 0, prevKey = 0, returnValue = maxOpacity;
// ... (Logic to detect keyframes and fade in/out) ...
returnValue;
Finger Position (iOS Touch)
Calculates position for a virtual finger based on tap keyframes, handling drags and taps automatically.
Apply to: Position
// iOS Virtual Finger Position Logic
// Interpolates between keyframes with specific ease/linear logic for drags vs taps.
// ... (Logic to detect keyframes and interpolate) ...
returnValue;
Finger Touching State
Calculates if the finger is touching the screen based on position keyframes (short distance = touching).
Apply to: Checkbox Control
// Detects touches based on keyframe proximity
var nextKey = 0, prevKey = 0, returnValue = 0;
// ... logic ...
returnValue;
Frozen Random Number
Generates a random number that doesn't change over time (seeded by layer index).
Apply to: Any Property
seedRandom(index,true);
myValue = random(50);
Get Current Date
Returns the current date formatted as MM/DD/YY.
Apply to: Source Text
d = new Date(Date(0));
divider = "/"
yearLength = 2;
function padZeros(n){
if(n <= 9) return "0" + n;
return n
}
yearTrim = (yearLength===2) ? 2 : 0;
"" + padZeros(d.getMonth()+1) + divider + padZeros(d.getDate()) + divider + d.getFullYear().toString().substring(yearTrim,4);
Hold Keyframes Logic
Manually implements hold keyframe behavior via expression.
Apply to: Any Animated
var nearest = nearestKey(time);
var isInThePast = nearest.time <= time;
isInThePast ? nearest : key(nearest.index-1);
Ignore Parent Rotation
Counter-rotates the child layer so it stays upright regardless of parent rotation.
Apply to: Rotation
value - parent.transform.rotation
Ignore Parent Scale
Maintains the visual scale of the child layer, countering any scaling from the parent.
Apply to: Scale
s = [];
parentScale = parent.transform.scale.value;
for (i = 0; i < parentScale.length; i++){
s[i] = (parentScale[i]== 0) ? 0 : value[i]*100/parentScale[i];
}
s
Inertial Bounce
Moves settle into place after bouncing around a little, based on the velocity of incoming keyframes. Great for organic motion.
Apply to: Position, Scale,
// Inertial Bounce
// Moves settle into place after bouncing around a little
amp = 0.04;
freq = 3.0;
decay = 10.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
}
Inherit Parent Opacity
Directly copies the parent's opacity value.
Apply to: Opacity
(hasParent) ? parent.opacity : value;
Inherit Parent Opacity (Editable)
Multiplies parent opacity with local opacity, allowing for relative adjustments.
Apply to: Opacity
(hasParent) ? (parent.opacity/100) * value : value;
Limit Text Width
Scales text down if it exceeds a maximum width defined by a slider.
Apply to: Scale (on Text
maxW = effect("max-width")("Slider");
sourceW = sourceRectAtTime(time,true).width;
s = (sourceW > maxW) ? 100 * maxW / sourceW : 100;
[s, s]
Linear Color Blend
Blending between two colors using a slider or time.
Apply to: Color Property
var slider = slider;
var red = [1,0,0,0];
var blue = [0,0,1,0];
linear(slider * 0.01,red,blue)
Linear Remap Examples
Examples of remapping ranges using `linear()`.
Apply to: Any Property
linear(value, rangeStart, rangeEnd, newRangeStart, newRangeEnd);
linear(time, 0, 10, -90, 90); // 0-10s -> -90 to 90 degrees
// Remap to Color
linear(time, 0, 10, [0,0,0,0] , [1,1,1,1]);
Load External File (Advanced)
Loads and evaluates an external .js file from a hardcoded path. Use with caution.
Apply to: Any Property
try {
myPath = "~/Desktop/source.js"; // Path to your file
$.evalFile(myPath);
} catch(err) {
"MISSING";
}
Loop a Wiggle
Seamlessly loops a wiggle expression over a specific duration.
Apply to: Position, Scale,
frequency = 2; // wiggles per second
amplitude = 40; // amount of pixels to wiggle
secondsToLoop = 3; // time to loop in seconds
// --------
t = time % secondsToLoop;
wiggle1 = wiggle(frequency, amplitude, 1, 0.5, t);
wiggle2 = wiggle(frequency, amplitude, 1, 0.5, t - secondsToLoop);
linear(t, 0, secondsToLoop, wiggle1, wiggle2)
Loop In and Out
Loops the animation both before the first keyframe and after the last keyframe.
Apply to: Any Animated
loopIn() + loopOut() - value;
Loop Path Keyframes
Seamlessly loops keyframes on a Path Property for shape layers or masks. Behaves like standard loopOut('cycle') but for paths.
Apply to: Path, Mask Path
// Seamlessly loop keyframes on a Path Property
// Behaves like loopOut('cycle')
if (numKeys > 1 && time > key(numKeys).time) {
t1 = key(1).time;
t2 = key(numKeys).time;
span = t2 - t1;
delta = time - t2;
t = delta % span;
valueAtTime(t1 + t)
} else {
value
}
Looping Wiggle
A custom function to create a seamless looping wiggle effect.
Apply to: Position /
function loopingWiggle(frequency, amplitude, loopDuration){
var t = time % loopDuration;
var wiggle1 = wiggle(frequency, amplitude, 1, 0.5, t);
var wiggle2 = wiggle(frequency, amplitude, 1, 0.5, t - loopDuration);
return linear(t, 0, loopDuration, wiggle1, wiggle2)
};
loopingWiggle(2,5,10);
Maintain Stroke Width
Keeps the stroke width visual constant even when the layer is scaled up or down.
Apply to: Stroke Width
value / length(toComp([0,0]), toComp([0.7071,0.7071])) || 0.001;
Math.pow (Exponential Growth)
Demonstrates using Math.pow to create exponential acceleration.
Apply to: Rotation /
Math.pow(time, 4); // time * time * time * time
// Accelerates rotation exponentially
Math.sin / Waves
Using Sine waves to create oscillating motion (back and forth).
Apply to: Rotation /
var loopDuration = 5; // seconds per loop
var degrees = 45; // max amplitude
degrees * Math.sin(Math.PI * 2 * time / loopDuration);
Move in Circle
Moves a layer in a perfect circle.
Apply to: Position
var loopDuration = 5;
var circleRadius = 250;
var waveLogic = time * 2 * Math.PI / loopDuration;
var x = Math.sin(waveLogic) * circleRadius;
var y = Math.cos(waveLogic) * circleRadius;
value + [x,y];
Posterize + Wiggle
Combines posterizeTime with wiggle for a stop-motion jerky shake.
Apply to: Position /
f = 2; // fps
a = 10; // amount
posterizeTime(f);
wiggle(f, a);
Random Movement
Adds random noise to the position.
Apply to: Position
var max = 50;
var randomX = random(-max, max);
var randomY = random(-max, max);
value + [randomX, randomY];
Reduce FPS
Simulates a lower frame rate for the layer.
Apply to: Position /
posterizeTime(12); // Desired FPS
value
Rolling Circle Physics
Automatically rotates a circle as it moves horizontally, simulating rolling.
Apply to: Position
r = (thisLayer.sourceRectAtTime().width)/2;
s = thisLayer.transform.scale[0];
compensation = (s-100)*.01;
cr = r + compensation * r;
circumference = 2*Math.PI*cr;
[value[0]+(circumference/360)*thisLayer.transform.rotation,value[1]]
Scale to Fixed Width
Scales a layer to always be a specific pixel width.
Apply to: Scale
w = 600; // target width
s = 100*w/thisLayer.width;
[s,s]
Scale with Bounce
An alternative to Inertial Bounce, specifically designed for scaling with decay.
Apply to: Scale
rate = 200;
rampDur = value[0] / rate;
freq = 3;
decay = 15;
w = freq * Math.PI * 2;
// ... (Logic for in/out bounce) ...
// See full source for conditional logic
[s,s]
Shape to Null Position
Links a Shape Layer's position to a Null, maintaining its relative position (like parenting but cleaner for some rigs).
Apply to: Position (Shape
// Control shape layer position with a Null
control=thisComp.layer("Control NULL"); // your controller null
controlPos = control.toComp(control.transform.anchorPoint);
fromComp(controlPos)
Show/Hide with Dropdown
Controls visibility based on a specific value from a Dropdown Menu Control.
Apply to: Opacity
// Rename layer to start with [1] or [2] etc.
select = effect("Dropdown Control")("Menu").value;
Simple Delay (Index)
Delays animation based on layer index. Great for staggering animations across multiple layers.
Apply to: Any Animated
delay = 5; //number of frames to delay
d = delay*thisComp.frameDuration*(index - 1);
thisComp.layer(1).rotation.valueAtTime(time - d)
Simulated Pen Tilt
Calculates tilt angle for a pen layer based on its velocity, adding a slight bounce.
Apply to: Rotation
// Calculates rotation based on velocity vector
// See full code in source for complete physics logic
var nextTime = framesToTime(timeToFrames(time) + 1);
var delta = valueAtTime(nextTime) - value;
// ... (Logic to calculate angle from delta) ...
tilt;
Sine Curve Position
Moves a layer in a sine wave pattern across the screen.
Apply to: Position
var a = 500 * time; // X movement
var b = 50 * Math.sin(time * 20) + thisComp.height/2; // Y oscillation
[a, b]
Snap to Grid
Snaps position or rotation to a stepped grid (e.g., every 20px or 15deg).
Apply to: Position /
var stepSize = 20;
// Auto-detect array vs single value
function snap(theValue, theStepSize) {
if (Array.isArray(theValue)) {
var result = [];
for (var i=0; i<theValue.length; i++) {
result.push(Math.round(theValue[i] / theStepSize) * theStepSize);
}
return result
}
return Math.round(theValue / theStepSize) * theStepSize;
};
snap(value, stepSize);
Split Text Words
Simple text splitting logic for isolating words.
Apply to: Source Text
var text = thisComp.layer(3).text.sourceText;
var words = text.split(" ");
words[0] // Returns first word
Squash and Stretch
Adds a squash and stretch deformation effect based on sinusoidal oscillation with decay.
Apply to: Scale
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]
Stay Within Range (Clamp)
Restricts a value so it never goes below min or above max.
Apply to: Any Property
clamp(value, min, max);
// Clamp Position to Comp Logic
clamp(value, [0,0], [thisComp.width,thisComp.height]);
Time At Value Function
Advanced function to find the time when a property matches a specific value.
Apply to: Source Text /
function timeAtValue(targetValue, targetRepetition, targetProperty) {
var time = 0;
var repetition = 0;
while (time < thisComp.duration) {
if (targetProperty.valueAtTime(time, false) == targetValue) {
repetition++;
}
if (repetition == targetRepetition) {
return time;
}
time += thisComp.frameDuration;
}
return null;
}
Trigger (Pointer Layer)
Changes a value based on the proximity of a "Pointer" layer.
Apply to: Scale / Opacity
pointer = thisComp.layer("Pointer");
hoverStart = 100; // Distance to start effect
hoverEnd = 20; // Distance to max effect
maxValue = 5;
L = length(toComp(anchorPoint), pointer.toComp(pointer.anchorPoint));
C = clamp(hoverStart-L,0,hoverEnd);
value + C*maxValue
Trigger Anim (Marker)
Triggers an animation (0 to 100) whenever a marker with a comment is encountered.
Apply to: Any Property
var markerComment = thisLayer.marker.nearestKey(time).comment;
var markerTime = thisLayer.marker.nearestKey(time).time;
var animDur = (1 / 30) * 6; // duration
if (markerComment == "") {
linear(time, markerTime, (markerTime + animDur), 0, 100)
} else {
value = 0
}
Trigger Audio (Marker)
Plays (re-times) an audio layer start time based on a marker position.
Apply to: Time Remap (on
layerDuration = thisLayer.source.duration;
if (marker.numKeys > 0) {
m = marker.nearestKey(time).index;
if (marker.key(m).time > time) m--;
if (m > 0) {
markerTime = marker.key(m).time;
if (time < markerTime + layerDuration) {
linear(time, markerTime, markerTime + layerDuration, 0, layerDuration);
} else 0
} else 0
} else value;
Trigger Generic Template
A boilerplate template for triggering any action at marker times.
Apply to: Any Property
n = 0;
if (marker.numKeys > 0) {
n = marker.nearestKey(time).index;
if (marker.key(n).time > time) {
n--;
}
if (n == 0) {
value;
} else {
t = time - marker.key(n).time; // time since marker
// Do Stuff with 't'
value
}
} else { value; }
Typewriter Effect
Reveals text character by character based on time.
Apply to: Source Text
var startAt = 0;
var endAt = 9;
var maxLetters = Math.floor(linear(time, startAt, endAt, 0, value.length));
value.substring(0, maxLetters);
Unknown
Apply to: Any
// Bu kodu Rotation (Dönüş) kısmına yapıştırın
var speedFactor = 0.1; // Dönüş hızını buradan ayarlayabilirsiniz
var accumRotation = 0;
for (i = 0; i <= timeToFrames(time); i++) {
var deltaT = framesToTime(i);
var v = position.velocityAtTime(deltaT);
accumRotation += length(v) * framesToTime(1);
}
value + (accumRotation * speedFactor);
Value At Time Explainer
Explanation and example of `valueAtTime()` to get a property's value from the past/future.
Apply to: Any Property
// Get value 0.2 seconds ago
var delay = 0.2;
var targetProp = thisComp.layer("Other Layer").transform.position;
targetProp.valueAtTime(time - delay)
Wiggle Between Values
Constrains a wiggle to stay strictly between a minimum and maximum value.
Apply to: One Dimensional
min = -10;
max = 50;
freq = 5;
amp = Math.abs(max-min)/2;
offset = (max+min)/2;
wiggle(freq, amp) + offset;
Wiggle One Dimension
Wiggles only one dimension (X axis by default) while keeping the other fixed.
Apply to: Position, Scale
// Constrain wiggle to One Dimension (X)
// For Y dimension only, change last line to [value[0], w[1]]
frequency = 2;
amplitude = 10;
w = wiggle(frequency, amplitude);
[w[0], value[1]]