Staggering animation is one of the most common technique used in Motion Design. It's good to know this technique because you need not manually copy and paste keyframes from one layer to another and offset the timing. Instead you can animate one element, and make all the other layers reference that animation with an offset timing.
Generally, when we want to stagger or offset animations in time for a series of layers, we can make use of the layers' index number and the valueAtTime property.
Basic setup
// Copying animation of a layer, and start it at inPoint of layerthisComp.layer(index+1).transform.position.valueAtTime(time-inPoint)// Using delayoffset =1;thisComp.layer(index+1).transform.position.valueAtTime(time-offset)
Referencing index animated layer
tgt =thisComp.layer("main").transform.position // target layer & propdelay =5; //number of frames to delaydelay*=thisComp.frameDuration*(index -1); // convert to timetgt.valueAtTime(time - delay)
// alternatively you can do it this insteaddelay =framesToTime(5); //convert to time method 2thisComp.layer(1).position.valueAtTime(time - delay)
Cascading index referencing
delay =5; //number of frames to delayd = delay*thisComp.frameDuration;thisComp.layer(index -1).position.valueAtTime(time - d)
Absolute index referencing
It is always best practice to use absolute index referencing, because you do not run the risk of your animation being affected if I were to add a new layer to the composition causing all the layers' index number. The simple way to absolute reference is to:
Create a Null layer or use your mainanimated layer, usually named "start"
Make sure the layers you want to offset is underneath this "start" layer
Get the absolute index number by subtracting the Start layer index from the layer index number
Now you can use that value to calculate the delay offset
var startLayer =thisComp.layer("startLayer");var myIndex = index-startLayer.index;delay =5; //number of frames to delayd = delay*thisComp.frameDuration*(myIndex -1);thisComp.layer(1).position.valueAtTime(time - d)
Scripts
Adding auto-orientation
strt =0; //start time of template motionend =4.0; //end time of template motiont =thisComp.layer("template");offset = (t.effect("offset")("Slider")/100)*(index -1);travel =linear(t.effect("travel")("Slider")/100,strt,end);if (travel <= offset){ vect =t.position.velocityAtTime(0);}else{ vect =t.position.velocityAtTime(travel - offset);}lookAt(position, position + vect)
Following the Null's Orientation
strt =0; //start time of template motionend =4.0; //end time of template motiont =thisComp.layer("template");offset = (t.effect("offset")("Slider")/100)*(index -1);travel =linear(t.effect("travel")("Slider")/100,strt,end);u =t.toWorldVec([1,0,0],travel - offset);v =t.toWorldVec([0,1,0],travel - offset);w =t.toWorldVec([0,0,1],travel - offset);sinb =clamp(w[0],-1,1);b =Math.asin(sinb/thisComp.pixelAspect);cosb =Math.cos(b);if (Math.abs(cosb) >.0005){ c =-Math.atan2(v[0],u[0]); a =-Math.atan2(w[1],w[2]);}else{ a =Math.atan2(u[1],v[1]); c =0;}[radiansToDegrees(a),radiansToDegrees(b),radiansToDegrees(c)]
Case studies
Distance-based
Omni-directional
tgt =thisComp.layer("control");// d = length(L.transform.position, transform.position);d =length(thisLayer.toWorld(transform.anchorPoint),tgt.toWorld(tgt.transform.anchorPoint));delay =thisComp.layer("control").effect("maxDelay")("Slider");offset =linear(d,0,2000,0,delay);time-offset;