Creative Communities of the World Forums

The peer to peer support community for media production professionals.

Activity Forums Adobe After Effects Expressions expression to move from one layers position to another…

  • expression to move from one layers position to another…

    Posted by Pete Menich on July 9, 2023 at 4:50 pm

    I’m trying to cook up an an expression that moves a null from the position of a start layer (index ‘x’), then move to the next layers position (index ‘x+1’) and pause. The null then moves to the next layer (index ‘x+2’) and pause, and so on until the final layer is reached.

    (I’m using shape layers with a rectangle)

    The code needs to define the first layer and the last layers index numbers, moving between every layer in-between the two values.

    The time it takes to move from one layer to the next is dictated by how far the next layer is from the previous layer. So the further a layer is from its previous layer, the longer it takes to to get to the new layer, so the move is a constant speed regardless of the distance between layers.

    (A variable on an slider needs to control the overall speed, acting as a multiplier of the speed).

    How long the null pauses between moves depends on the Y size of the shape layer that is driving the current position of the null. So the the bigger the target layers Y size, the longer it pauses.

    (A variable on an effect slider needs to control the overall pause time, acting as a multiplier of the pause).

    I’ve been trying to use Chat GTP to help me write this and it turns out it knows less than me!

    Current code looks like this…

    // Define the start and end layer indices

    startLayerIndex = 3;

    endLayerIndex = 7;

    // Define the speed multiplier

    speedMultiplier = effect("Speed Multiplier")("Slider");

    // Define the pause multiplier

    pauseMultiplier = effect("Pause Multiplier")("Slider");

    // Define the initial position of the null object

    initialPosition = thisComp.layer(startLayerIndex).transform.position;

    // Define the initial time

    initialTime = 0;

    // Loop through each layer and move the null object

    for (i = startLayerIndex; i <= endLayerIndex; i++) {

    // Define the current layer

    currentLayer = thisComp.layer(i);

    // Define the target position

    targetPosition = currentLayer.transform.position;

    // Convert the target position to the composition's coordinate system

    targetPosition = thisComp.layer(currentLayer.index).toComp(targetPosition);

    // Calculate the distance to the target position

    distance = length(targetPosition - initialPosition);

    // Calculate the time it should take to cover the distance at a constant speed

    moveTime = distance / speedMultiplier;

    // Define the pause time based on the Y size of the current layer

    pauseTime = currentLayer.sourceRectAtTime().height * pauseMultiplier;

    // Move the null object to the target position over the calculated time, then pause for the calculated pause time

    linear(time - initialTime, 0, moveTime, initialPosition, targetPosition) + linear(time - (initialTime + moveTime), 0, pauseTime, targetPosition, targetPosition);

    // Update the initial position and time for the next iteration

    initialPosition = targetPosition;

    initialTime += moveTime + pauseTime;

    }

    anyone got any ideas? I’m wondering if a ‘while’ loop will work better

    Dan Ebberts replied 2 years, 10 months ago 2 Members · 5 Replies
  • 5 Replies
  • Pete Menich

    July 9, 2023 at 5:30 pm

    this kind of works, but the transition and pause duration are not dynamic

    // Set the duration of each transition and pause period in seconds

    transitionDuration = 2;

    pauseDuration = 2;

    // Define the start and end layer indices

    startLayerIndex = 3; // Change this to match the index of the starting layer

    endLayerIndex = 7; // Change this to match the index of the ending layer

    // Calculate the total number of transitions

    totalTransitions = endLayerIndex - startLayerIndex;

    // Calculate the current transition index based on the current time

    currentTransitionIndex = Math.min(Math.floor((time - inPoint) / (transitionDuration + pauseDuration)), totalTransitions - 1);

    // Calculate the start and end layers for the current transition

    startLayer = thisComp.layer(startLayerIndex + currentTransitionIndex);

    endLayer = thisComp.layer(startLayerIndex + currentTransitionIndex + 1);

    startPos = startLayer.transform.position;

    endPos = endLayer.transform.position;

    // Calculate the time elapsed since the start of the current transition

    transitionStartTime = currentTransitionIndex * (transitionDuration + pauseDuration);

    transitionElapsedTime = time - inPoint - transitionStartTime;

    // Use an ease function to animate from the start position to the end position

    ease(transitionElapsedTime, 0, transitionDuration, startPos, endPos);


  • Dan Ebberts

    July 9, 2023 at 7:34 pm

    This is how I’d approach it, although it doesn’t have the sliders, or making the pause proportional to the height of the destination layer (it wouldn’t be hard to add those features):

    spd = 100;  // pixels per second
    pause = .5; // seconds
    startIndex = 2;
    endIndex = 5;
    curIndex = startIndex;
    accumTime = prevAccum = 0;
    while (accumTime <= time){
    curLayer = thisComp.layer(curIndex);
    curRect = curLayer.sourceRectAtTime(time,false);
    curPos = curLayer.toComp([curRect.left+curRect.width/2, curRect.top+curRect.height/2]);
    nextLayer = thisComp.layer(curIndex+1);
    nextRect = nextLayer.sourceRectAtTime(time,false);
    nextPos = nextLayer.toComp([nextRect.left+nextRect.width/2, nextRect.top+nextRect.height/2]);
    v = nextPos - curPos;
    dist = length(v);
    moveDur = dist/spd;
    totalDur = moveDur + pause;
    prevAccum = accumTime;
    accumTime += totalDur;
    curIndex++;
    if (curIndex >= endIndex) break;
    }
    delta = time - prevAccum;
    delta > moveDur ? nextPos : curPos + normalize(v)*ease(delta,0,moveDur,0,dist);
  • Pete Menich

    July 10, 2023 at 9:40 am

    Hey Dan, Amazing!

    The only thing I forgot to mention is that I need it in 3D 😬 – as I’m parenting a camera to the null.

    I seems to work though if the Null stays 2D.

    The dynamic pause is required because the boxes contain text, so the bigger the boxes Y dimension, the more text the box contains and the longer you need to read it.

    Obviously, ChatGTP can’t compete with the Ebbert’s brain!

  • Pete Menich

    July 10, 2023 at 10:29 am

    This seems to do the pause thing…

    spd = effect("speed")("Slider"); // pixels per second

    pause = effect("pause")("Slider"); // pause divider

    startIndex = 3;

    endIndex = 7;

    curIndex = startIndex;

    accumTime = prevAccum = 0;

    while (accumTime <= time){

    curLayer = thisComp.layer(curIndex);

    preLayer = thisComp.layer(curIndex+1);

    curRect = curLayer.sourceRectAtTime(time,false);

    curPos = curLayer.toComp([curRect.left+curRect.width/2, curRect.top+curRect.height/2]);

    nextLayer = thisComp.layer(curIndex+1);

    nextRect = nextLayer.sourceRectAtTime(time,false);

    nextPos = nextLayer.toComp([nextRect.left+nextRect.width/2, nextRect.top+nextRect.height/2]);

    v = nextPos - curPos;

    dist = length(v);

    moveDur = dist/spd;

    pauseDur = 1 + (preLayer.content("Group 1").content("Rectangle Path 1").size[1] / pause);

    totalDur = moveDur + pauseDur;

    prevAccum = accumTime;

    accumTime += totalDur;

    curIndex++;

    if (curIndex >= endIndex) break;

    }

    delta = time - prevAccum;

    delta > moveDur ? nextPos : curPos + normalize(v)*ease(delta,0,moveDur,0,dist);

  • Dan Ebberts

    July 10, 2023 at 3:45 pm

    To make it 3D I think you can just change toComp to toWorld in the the curPos and nextPos definitions.

We use anonymous cookies to give you the best experience we can.
Our Privacy policy | GDPR Policy