# Expressions & Snippets

## Transformation

<figure><img src="/files/l7RzET46Yp2s3k9wNiZQ" alt=""><figcaption></figcaption></figure>

### **Constant Value Drift and Motion**

#### 1. Linear Value Drift Over Time

```javascript
value + time * 50;
```

#### 2. Apply Value Drift to Array Element eg. Position Y

```javascript
value + [0, time * 5];
```

**3. Constant Horizontal Motion From Layer's Start Point**

<pre class="language-javascript"><code class="lang-javascript"><strong>offset = (time - inPoint) * -10;
</strong><strong>x = position[0] + offset;
</strong>y = position[1];
[x, y]
</code></pre>

### Align to X-axis or Y-axis

### X-Axis

<figure><img src="/files/YHOVxGCv6zk2bZ06bkLu" alt=""><figcaption><p>This expression references the X position of the layer above in the Composition panel and adds a fixed increment, resulting in a row of evenly spaced child layers.</p></figcaption></figure>

```javascript
var xOffset = 350;
var prevLayerX = thisComp.layer(index - 1).transform.position[0];
[xOffset + prevLayerX, value[1]];

```

### Y-Axis&#x20;

```javascript
var yOffset = 350;
var prevLayerY = thisComp.layer(index - 1).transform.position[1];
[value[0], yOffset + prevLayerY];

```

### Changing anchor point

```javascript
var s = sourceRectAtTime();

// Top left ↖
[s.left, s.top] // 

// Top center ↑
[s.left, s.top] + [s.width / 2, 0];

// Top right ↗
[s.left, s.top] + [s.width, 0];

// Center left ← 
[s.left, s.top] + [0, s.height / 2];

// Center
[s.left, s.top] + [s.width, s.height] / 2;

// Center right → 
[s.left, s.top] + [s.width, s.height / 2]

// Bottom left ↙

[s.left, s.top] + [0, s.height]

// Bottom center ↓ 
[s.left, s.top] + [s.width / 2, s.height]

//Bottom right ↘
[s.left, s.top] + [s.width, s.height]
```

### Random positioning XYZ

![A series of duplicated layers with random position values](/files/-LvuSO0lKmXxPkXip0IV)

```javascript
// Seed for randomization
var seed = 20;

// Define the minimum values for randomization
var minX = 25;
var minY = 25;
var minZ = -1900; 

// Define the maximum values for randomization
var maxX = thisComp.width;
var maxY = thisComp.height;
var maxZ = 50;

// Set the random seed
seedRandom(seed, true);

// Generate random values within the defined ranges
var randomX = random(minX, maxX);
var randomY = random(minY, maxY);
var randomZ = random(minZ, maxZ);

// Create an array with the random values
[randomX, randomY, randomZ];

```

Alternatively, you can use array variables for a preferred and shorter expression.

```javascript
// Seed for randomization
var seed = 20;

// Define the minimum and maximum values for randomization
var minValues = [25, 25, -1900]; 
var maxValues = [thisComp.width, thisComp.height, 50];

// Set the random seed
seedRandom(seed, true);

// Create an array with the random values
random(minValues,maxValues)

```

## Scale

### Maintain Scale When Parented&#x20;

{% tabs %}
{% tab title="Both" %}

```javascript
var scaleFactor = [];
var parentScale = parent.transform.scale.value;

for (var i = 0; i < parentScale.length; i++) {
    scaleFactor[i] = (value[i] * 100) / parentScale[i];
}

scaleFactor;
```

{% endtab %}

{% tab title="uniform" %}

```javascript
arr = value;
ps = parent.transform.scale.value;
ratio = 100/ ps[0];

arr*ratio;
```

{% endtab %}
{% endtabs %}

**Implementation**

* [Scaling Radial Grid Expression · After Effects Tutorial · Master study: José Peña's "Creativity"](https://youtu.be/8BeI1qXzysU?t=122)

## Rotation

### [Aim constraint](https://creativecow.net/forums/thread/aim-constraint/) by Kevin Camp / Dan Ebberts

{% tabs %}
{% tab title="no parent" %}

```javascript
target = thisComp.layer("Null 1"); // set this to the layer to aim at
p = position - target.position;
radiansToDegrees( Math.atan2( p[1], p[0] ) )- 90
```

{% endtab %}

{% tab title="w/ parent" %}

```javascript
target = thisComp.layer("controls"); // set this to the layer to aim at
p = thisLayer.toWorld(anchorPoint) - target.position;
radiansToDegrees(Math.atan2(p[1], p[0])) - 90
```

{% endtab %}

{% tab title="3D layers" %}

```
target = thisComp.layer("Null 1");// set this to the layer to aim at
lookAt( position, target.position )
```

{% endtab %}
{% endtabs %}

### [Retrieving auto-orientation rotation value](https://forums.creativecow.net/docs/forums/post.php?forumid=227\&postid=15409\&univpostid=15409\&pview=t)

```javascript
L = thisComp.layer("Null 1");
v = L.toWorldVec([1,0]);
radiansToDegrees(Math.atan2(v[1],v[0]))
```

### Auto-orient along path by [Videolancer](https://videolancer.net/expressions/)

```javascript
try{
cornerEase = 3;
p = transform.position;
t = Math.min(Math.max(time,p.key(1).time+.001),p.key(p.numKeys).time);
pre = position.valueAtTime(t-thisComp.frameDuration*cornerEase);
post = position.valueAtTime(t+thisComp.frameDuration*cornerEase);
delta = post-pre;
orient = radiansToDegrees(Math.atan2(delta[0],-delta[1]));
value+orient+180
}catch(err){value}
```

### Ignore Parent Rotation

```javascript
value – parent.transform.rotation
```

## Opacity ✅

### Flickering / Strobe

![](/files/-Lvzv6zr3sH_kO9D4HI-)

```javascript
// VARIABLES
    minSeg = 1.5; //minimum interval (must be > 0) 
    maxSeg = 2.5; //maximum interval (must be > minSeg) 
    
    // flickering duration
    minFlicker = .5; //must be less than minSeg 
    maxFlicker = 1; // must be less than minSeg 
    flickerDur = random(minFlicker,maxFlicker);
    
    //initial conditions
    segEndTime = 0; 
    i = 1; 

// Continuous loop: create a fixed random segment value and add to segEndTime
while (time >= segEndTime){ 
    i += 1; 
    seedRandom(i,true); 
    segEndTime = segEndTime + random(minSeg,maxSeg); 
} 

// Switch back to use the current time as input to the random seed.
seedRandom(1,false); 

// As time > threshold, flicker
if (time > segEndTime - flickerDur){random(0,100) }else{ 100 }

// Source: http://www.motionscript.com/expressions-lab-ae65/swinging-light.html
// Also see: http://www.motionscript.com/mastering-expressions/random-3.html
```

### Random opacity wiggle&#x20;

![](/files/-LxgTeeafXFWIXSvUAVz)

```javascript
// control = thisComp.layer("control"); // connect to null layer with sliders
freq = 1;
amp = 100;
octave = 1;
amp_mult = 3;

wiggle(freq, amp, octave, amp_mult, time)
```

### Random opacity wiggle with flicker&#x20;

![](/files/-LxgTee_fD3Lkg-RBd8A)

```javascript
// control = thisComp.layer("control"); // connect to null layer with sliders
freq = 1;
amp = 100;
octave = 1;
amp_mult = 3;

opacity = wiggle(freq, amp, octave, amp_mult, time)


// VARIABLES
minSeg = control.effect("minSeg")("Slider"); //minimum interval (must be > 0) 
maxSeg = control.effect("maxSeg")("Slider");; //maximum interval (must be > minSeg) 

// flickering duration
minFlicker = control.effect("minFlicker")("Slider");; //must be less than minSeg 
maxFlicker = control.effect("maxFlicker")("Slider");; // must be less than minSeg 
flickerDur = random(minFlicker, maxFlicker);

//initial conditions 
segStartTime = 0;
segEndTime = 0;
i = 1;

// Continuous loop: create a fixed random segment value and add to segEndTime
while (time >= segEndTime) {
    i += 1;
    seedRandom(i, true);
    segStartTime = segEndTime;
    segEndTime = segEndTime + random(minSeg, maxSeg);
}

// Switch back to use the current time as input to the random seed.
seedRandom(1, false);

// As time moves threshold, flicker
if (time > segEndTime - flickerDur) {
    random(0, 100)
} else {
    opacity
}
```

### Random opacity with sin function

![](/files/-LvzqIqZjkIfnahiz4Xp)

```javascript
// Mass flickering
vel = 50;
seedRandom(0,true);
Math.sin(time*vel+random(index))*100;
```

![](/files/-LvzqOfKOBy4vOe8vqGz)

```javascript
// 'Wave flickering'
vel = 50;
seedRandom(0,true);
Math.sin(time*vel+index)*100;

// Combining 
bool = 1;
vel = 50;
seedRandom(0,true);
wave=Math.sin(time*vel+index)*100;
rand =Math.sin(time*vel+random(index))*100;
bool==0 ? wave : rand;
```

### Random opacity turn on

![](/files/-LvuSGW8ej9Hcu5gPtMv)

```javascript
seed = 29;
threshold = linear(time,0,thisComp.duration,0,100); // or Connect to slider to animate switch on & off

seedRandom(seed,true);
randValue = random(0,90);

if(randValue < threshold){
    100;} else 0
```

### Random opacity fade on&#x20;

![](/files/-LvuSL9ktGztg6U8qnuQ)

{% tabs %}
{% tab title="v1" %}

```javascript
seed = 29;
seedRandom(seed,true);
delay = random(0,1);
t = framesToTime(20) // or usethisComp.duration

linear(time, 0+delay,t+delay,0,100)
```

{% endtab %}

{% tab title="v2" %}

```javascript
//VARIABLES
fadeDuration = 1;
maxDelay = .5

//SETUP
seedRandom(index,true);
delay = random(maxDelay);
t = time -(inPoint + delay);

// EXECUTION
linear(t,0,fadeDuration,0,100);
```

{% endtab %}
{% endtabs %}

### Distance-based opacity fade by Animoplex

```javascript
// Distance Based Opacity Fade
// Original: https://helpx.adobe.com/after-effects/using/expression-examples.html
// Full Tutorial: https://www.youtube.com/watch?v=I-Acdl_l9G0&t=14s

startFade = 500;
endFade = 3000;
try {
    C = thisComp.activeCamera.toWorld([0,0,0]);
} catch(err) {
    w = thisComp.width * thisComp.pixelAspect;
    z = (w / 2)/Math.tan(degreesToRadians(19.799));
    C = [0,0,-z];
}
P = toWorld(anchorPoint);
d = length(C, P);
linear(d, startFade, endFade, 100, 0)
```

### Transparent backside of 3D layer

<figure><img src="/files/fhVeoZaN2ajTZwXgwW7h" alt=""><figcaption></figcaption></figure>

```javascript
if (toCompVec([0, 0, 1])[2] > 0 ) value; else 0;
```

## Colour

### [Hexcode from text to color](https://forums.creativecow.net/docs/forums/post.php?forumid=227\&postid=36789\&univpostid=36789\&pview=t)

```javascript
txt = thisComp.layer("Text").text.sourceText;
c = parseInt(txt,16);
r = c >> 16;
g = (c & 0x00ff00) >> 8;
b = c & 0xff;
[r,g,b,255]/255
```

### Random fill

```javascript
// Apply on Color Controls
seed = 20;
seedRandom(seed,true); // change true to 0 for constant change
random([0,0,0,1],[1,1,1,1])
```

## Camera

### [Smoothing rotation of auto-orient along path](https://creativecow.net/forums/thread/smoothing-rotation-of-auto-orient-along-path/)

{% tabs %}
{% tab title="x-rot" %}

```javascript
f = 2; // number of frames before and after to average
v = [0,0];
for (i = -f; i <= f; i++){
v += position.velocityAtTime(i*thisComp.frameDuration + time);
}
v /= (f*2+1);
a = Math.atan2(v[1],v[0]);
radiansToDegrees(a)

// turn off auto-orient
```

{% endtab %}

{% tab title="y-rot" %}

```javascript
//y-rotation for 3d layers

f = 2; // number of frames before and after to average
v = [0, 0, 0];
for (i = -f; i <= f; i++) {
    v += position.velocityAtTime(i * thisComp.frameDuration + time);
}
v /= (f * 2 + 1);
a = Math.atan2(v[0], v[2]);
radiansToDegrees(a)
```

{% endtab %}
{% endtabs %}

## Motion

### Wiggle

![](/files/-LxgwCQvpQ2zgLp0L3b-)

```javascript
// frequency by amplitude = how fast by how much
wiggle(20,30);

[value[0], wiggle(20,30)[1]] // wiggle y-axis only 


// Smooth wiggle — freq,amp,octave,amp_mult
wiggle(20,30,1,2,time)


// Jumpy Wiggle 1 (moves at a random FPS) Makes wiggle skip and hold rather than move fluidly.

v=wiggle(5,50);
if(v < 50)v=0;
if(v > 50)v=100;
v;

// 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);
```

* [Looping wiggle](https://www.motionscript.com/design-guide/looping-wiggle.html)

### Inertial Bounce / Overshoot

```javascript
// Inertial Bounce (moves settle into place after bouncing around a little)
// // Source: https://forums.creativecow.net/docs/forums/post.php?forumid=227&postid=19145&univpostid=19145&pview=t
amp = .05;
freq = 4.0;
decay = 2.0; // springyness
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);

value + v*amp*Math.sin(freq*t*2*Math.PI)/Math.exp(decay*t);
}else{
value;
}
```

### Constant move in either x or y axis / Random walker

```javascript
WIP---
choice = Math.floor(random(0,2));
seedRandom(0,false);
stepx = random(0,50);
stepy = random(0,20);
if(choice ==0){
	value + [stepx,0];} else if( choice ==1){
	value +[0,stepy];}
```

## Carousel

### 2D

### 3D&#x20;

![](/files/-LvfBiUXsAJ1IE2haa_y)

```javascript
/*  There needs to be two layers named 'startCard' & 'endCard'
    This allows rotation value to dynamically change when layers are inserted or removed.
    All duplicates need to be placed within these two layers
*/

//anchor point
radius = 500
value+[0,0,radius]

// Y rotation

startIndex=thisComp.layer("startCard").index; 
endIndex = thisComp.layer("endCard").index;
numpt = startIndex-endIndex+1; // total number of layers
myIndex = index-startIndex;
angle = 360/numpt

myIndex*angle+
```

#### Linking layers' rotation with opacity

#### Using distance & vector position

![](/files/-LvfB_ueezf9KXCBgUob)

```javascript
// Make sure there is a camera 

//Opacity
startVal = 0;
endVal = 100;
fadeAngle = 180;

v = toCompVec([0,0,1]); // layer position to comp position in Z
d = length(toWorld(anchorPoint),thisComp.layer("Camera 1").toWorld([0,0,0]));
c = v[2]/d;
ease(c,Math.cos(degreesToRadians(fadeAngle)),1.0,startVal,endVal)

```

#### Using rotation

{% code title="" %}

```javascript
angle = transform.yRotation%360;
minAngle = 0;
maxAngle = 360;
mid = (maxAngle+minAngle)/2;
if (angle < mid)
  linear(angle,minAngle,mid,100,0)
else
  linear(angle,mid,maxAngle,0,100)
```

{% endcode %}

## Responsive Systems / Setups

### Dynamic-sizing text box / lower-third (depreciated, [see new code](broken://pages/-M2US1FizeipgA17SSOy#2-liner-with-conditional-sizing-left-aligned-text))

```javascript
// Create two text layers named "DATA1" & "DATA2"
// Variables
pad = 50;
xPad = 15;
yPad = 15;

seed = 1 // allow you to change between two text layers

// Making it work
if(seed==1){	
    src = thisComp.layer("DATA1")
    }else {		
        src = thisComp.layer("DATA2")		
        }; 

box = src.sourceRectAtTime(time-src.inPoint); 
[box.width + pad + xPad, box.height+pad +yPad];
```

### Slider with center fade on

![](/files/-Lvk7fplz1EScrLfOht_)

```javascript
v = transform.position[0] // x 
d = length(v,thisComp.width/2);
maxDist= 960;

ease(d,0,maxDist,100,0)
```

## Time Remapping / Playback ✅

![](/files/-LvkAgiEDExUK4lfIkT6)

### Random frame playback

```javascript
// Source Dan Ebbert

fr = 12; // frame rate;

numFrames = 8;

seedRandom(index,true);

seg = Math.floor(time*fr);

f = Math.floor(random(numFrames));

for (i = 0; i < seg; i++)

  f = (f + Math.floor(random(1,numFrames)))%numFrames;

framesToTime(f);
```

### Random delayed/advanced layer playback

```javascript
seedRandom(index,true);
myDelay = random(1,10);
time + myDelay;
```

### Play one frame at a time (without 'float time')

```javascript
fps = 1;
x = framesToTime(Math.round(time*fps))
//There probably is a better way but I cannot figured it out right now.
```

### Random still frame (Good for spriting)

```javascript
//Apply this to a composition with a image sequence inside
seedRandom(0,true);
t= random(0,72);
framesToTime(t);
```

### Playback at every nth frames&#x20;

```javascript
n = 3 // frames
time*n
```

### Hold and play every nth frames \[[source](https://www.reddit.com/r/AfterEffects/comments/59h2v0/is_there_a_way_to_render_every_nth_frame_in_after/?utm_medium=android_app\&utm_source=share)]

```javascript
n = 3;  // play every __ frames
m = 3; // hold each frame ___ times 

f= timeToFrames(timeRemap);

p=Math.floor(f/m);

framesToTime(p*n);
```

## Triggering animations with marker

#### Workflow

1. Create a preComp with all the different types of animation
2. In the main Comp, put an expression on the time remapping of that preComp&#x20;
3. Add markers to trigger animations
4. Learn more
   * [Animoplex tutorial](https://www.youtube.com/watch?v=B_3XS2-VWOM\&t=698s)

```javascript
//https://gist.github.com/animoplex/cecf1c64aec4f2733ecd0edbebf4786d
```

## Staggering animations&#x20;

![](/files/-Lvuf4jS4Nc5XQANBNQg)

```javascript
// Copying animation of a layer, and start it at inPoint of layer
thisComp.layer(index+1).transform.position.valueAtTime(time-inPoint)

// Using delay
offset = 1;
thisComp.layer(index+1).transform.position.valueAtTime(time-offset)    
```

### Radial scale up staggering ✅

![](/files/-Lvud2TcyFlQGLkBX6FC)

{% tabs %}
{% tab title="nsc" %}

```javascript
// VARIABLES + SETUP
target = thisComp.layer("master").transform.scale; 
maxDist = 1000;
maxDelay = 1;

dst = length(transform.position,[thisComp.width/2,thisComp.height/2]);
delay = linear(dst,0,maxDist,0,maxDelay);

// EXECUTION
target.valueAtTime(time-delay)
```

{% endtab %}

{% tab title="OF" %}

```javascript
//apply to scale
target = thisComp.layer("fade");
fade = target.effect("scale")(1);
delay = target.effect("delay")(1)*thisComp.frameDuration;
dist = length(thisLayer.toWorld(thisLayer.anchorPoint), target.toWorld(target.anchorPoint));
seed = seedRandom(15, true)
randomRange = target.effect("random")("Slider");
rand = (random(-randomRange, randomRange))*thisComp.frameDuration;
offset = delay/dist;
s = fade.valueAtTime(time - offset - rand);
[s,s]
```

{% endtab %}
{% endtabs %}

### Effector opacity fade on ✅

![](/files/-LwnI2-VTH1AOJCZ-3JC)

{% tabs %}
{% tab title="nsc" %}

```javascript
//Create a null named "EFFECTOR" 
//Add 2 Slider Control Effects renamed to "maxDist" and "delay"


// EXECUTE
target = thisComp.layer("EFFECTOR").transform
maxDist = thisComp.layer("EFFECTOR").effect("maxDist")("Slider");
maxDelay = thisComp.layer("EFFECTOR").effect("delay")("Slider");

dst = length(transform.position, target.position);
delay = linear(dst, 0, maxDist, 0, maxDelay);

// EXECUTION
target.opacity.valueAtTime(time - delay)
```

{% endtab %}

{% tab title="OF" %}

```javascript


```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.nosleepcreative.com/after-effects/expressions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
