Copy link to clipboard
Copied
I've got a composition with a few layers of precomps. I enabled Time Remapping on each and added this script:
loopOut(loop="cycle",numKeyframes=0)
Works great. I'd love to be able to limit the number of times the animation loops, though. Is that possible?
Thanks much!
Hi!
Dan's expression is wonderful but I am wondering is it possible to add an option to it? I want to be able to set the range of the loopOut so it only affects the kyframes within that range. Let's say I have an object and it does this:
1) At the beginning of the comp it changes its position couple of times (no loop needed)
2) In the middle of the comp it jumps and I want to loop this jump 5 times using Dan's expression
3) At the end of the comp the object changes it position couple of times (no lo
...Copy link to clipboard
Copied
Try this instead of loopOut():
nLoops = 10;
if (numKeys > 1){
loopDur = key(numKeys).time - key(1).time;
n = Math.floor((time - key(1).time)/loopDur);
if (n < nLoops){
t = (time - key(1).time)%loopDur;
valueAtTime(key(1).time + t);
}else{
valueAtTime(key(numKeys).time);
}
}else
value;
Copy link to clipboard
Copied
Dan! That's brilliant. Thanks SO much! Works like a charm.
Copy link to clipboard
Copied
Dan's solution is elegant, but I think this one is more useful.
If the first and last frames of the nested comp are identical so you can have an identical loop, and you went to the last Time Remapping keyframe, moved back one frame, set a new TR keyframe, then deleted the last one, so you have a perfect seamless loop try this:
Time remapping works internally on frame numbers. If you convert time to frame numbers, you can multiply the frame number of the Time Remapping keyframe by the number of loops you want. Combine that with an if statement, and you get this.
fr = time / thisComp.frameDuration;
t = key(2).time / thisComp.frameDuration;
nL = 8
if (fr < t * nL)
loopOut();
else
0
That expression will loop the animation eight times and then stop. You can also slide the last TR keyframe left or right in the timeline to change the speed of the loop without modifying the expression.
I attached a sample comp.
It also works with loopOut("ping-pong").
Copy link to clipboard
Copied
Hi!
Dan's expression is wonderful but I am wondering is it possible to add an option to it? I want to be able to set the range of the loopOut so it only affects the kyframes within that range. Let's say I have an object and it does this:
1) At the beginning of the comp it changes its position couple of times (no loop needed)
2) In the middle of the comp it jumps and I want to loop this jump 5 times using Dan's expression
3) At the end of the comp the object changes it position couple of times (no loop needed).
So as you can see I want the loopOut to just affect the middle part of the composition and not affect anything else. Can it be done? Thanks!
Copy link to clipboard
Copied
Something like this maybe:
nLoops = 5;
loopKey1 = 5;
loopKey2 = 8;
t = time;
if (numKeys >= loopKey2){
t1 = key(loopKey1).time;
t2 = key(loopKey2).time;
loopDur = t2 - t1;
if (time > t1){
if (time < t1 + nLoops*loopDur){
t = t1 + (time - t1)%loopDur;
}else{
t = t2 + time - (t1 + nLoops*loopDur);
}
}
}
valueAtTime(t)
Copy link to clipboard
Copied
Thank you! Do I understand correctly? loopKey1 is the placement of the first keyframe of my looped animation, and loopKey2 is the last one? Because I tried that and the loop doesn't work.
Copy link to clipboard
Copied
loopKey1 should be the number of the first keyframe to be looped, and loopKey2 is the number of the last keyframe in the loop.
Copy link to clipboard
Copied
Not sure why but it doesn't work. I use it on position property on a shape layer. Your first expression (one with nLoop only) works well but this doesn't.
Copy link to clipboard
Copied
Are you getting an error message? Is it doing anything at all? How many keyframes do you have, and which ones are defined as loopKey1 and loopKey2?
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Of course the screenshot shows how I want it to be, not how it is now.
Copy link to clipboard
Copied
Change loopKey1 to 3 and loopKey2 to 5.
Copy link to clipboard
Copied
Ok, the loop works. But I don't really get why 3 and 5 values works - can you explain? I guess it has something to do with how many keyframes are the in the whole comp. There is one thing that's strange. The first two keyframes works, but the last two are delayed, they start 56 keyframes later.
Also, when I add any keyframes before my loop it all falls apart, that's why I know it has something to do with the number of keyframes in the comp. I'm afraid that when my comp will have dozens of keyframes it will be extremly hard to count when my loop starts. Is there a possibilty to just point in the expression at which keframe in the comp the loop starts and ends? Thanks!
Copy link to clipboard
Copied
3 and 5 work because the loop is between the 3rd and 5th keyframes. After the looping is finished, it runs everything that happens after the 5th keyframe. One possibly would be to mark the begin and end keyframes with colors. Here's a version where the loop starts with a green keyframe and ends with a red keyframe:
nLoops = 5;
loopKey1 = 0;
loopKey2 = 0;
for (i = 1; i <= numKeys; i++){
if (key(i).label == 9) loopKey1 = i; // green
if (key(i).label == 1) loopKey2 = i; // red
}
t = time;
if (loopKey1 > 0 && loopKey2 > 0){
t1 = key(loopKey1).time;
t2 = key(loopKey2).time;
loopDur = t2 - t1;
if (time > t1){
if (time < t1 + nLoops*loopDur){
t = t1 + (time - t1)%loopDur;
}else{
t = t2 + time - (t1 + nLoops*loopDur);
}
}
}
valueAtTime(t)
Copy link to clipboard
Copied
The solution with the markers would be great but I still need to write the correct LoopKey 1 and 2 for this to work. It doesn't with 0 values.
Copy link to clipboard
Copied
No, the expression fills those numbers in by finding the green keyframe and the red keyframe (no markers required).
Copy link to clipboard
Copied
Oh, sorry, I didn't catch that. Now it works! Only thing left is that shift happening in keyframes after the loop. It complicates things since animating anything after the loop becomes pretty impossibe. Any ideas how to fix this?
Copy link to clipboard
Copied
I'm not sure exactly what you're looking for, but after the looping, this version starts with the keyframe after the red keyframe:
nLoops = 5;
loopKey1 = 0;
loopKey2 = 0;
for (i = 1; i <= numKeys; i++){
if (key(i).label == 9) loopKey1 = i;
if (key(i).label == 1) loopKey2 = i;
}
t = time;
if (loopKey1 > 0 && loopKey2 > 0){
t1 = key(loopKey1).time;
t2 = key(loopKey2).time;
loopDur = t2 - t1;
if (time > t1){
if (time < t1 + nLoops*loopDur){
t = t1 + (time - t1)%loopDur;
}else{
if (numKeys > loopKey2){
t = key(loopKey2 + 1).time + time - (t1 + nLoops*loopDur);
}else{
t = key(loopKey2).time
}
}
}
}
valueAtTime(t)
Copy link to clipboard
Copied
Copy link to clipboard
Copied
I think this will do it:
nLoops = 2;
loopKey1 = 0;
loopKey2 = 0;
for (i = 1; i <= numKeys; i++){
if (key(i).label == 9) loopKey1 = i;
if (key(i).label == 1) loopKey2 = i;
}
t = time;
if (loopKey1 > 0 && loopKey2 > 0){
t1 = key(loopKey1).time;
t2 = key(loopKey2).time;
loopDur = t2 - t1;
if (time > t1 && time < t1 + nLoops*loopDur){
t = t1 + (time - t1)%loopDur;
}
}
valueAtTime(t)
Copy link to clipboard
Copied
That indeed works! Thank you so much! One question - is it possible to make the composition markers to be the indicators where the loop starts and ends? So the Green Composition Marker would indicate start of the loop, and the Red Composition Marker indicate end of the loop. Thanks to that I wouldn't need to add and color every marker on every new layer that I want to include in the loop.
Btw. can expression be copy and paste relatively? So if I make any change to the expression in the original layer, the same change will be made in the layer that the expression was pasted.
Copy link to clipboard
Copied
This version uses the first and second comp markers (not necessary to color them):
nLoops = 2;
m = thisComp.marker;
t = time;
if (m.numKeys >= 2){
t1 = m.key(1).time;
t2 = m.key(2).time;
loopDur = t2 - t1;
if (time > t1 && time < t1 + nLoops*loopDur){
t = t1 + (time - t1)%loopDur;
}
}
valueAtTime(t)
Copy link to clipboard
Copied
The colors would actually work better. Let's say I want to loop 3 different groups of keyframes. Thanks to the colored comp markers I could do this:
1) First loop is between red and green markers
2) Second loop is between yellow and aqua
3) Third loop is between pink and lavender
And so on. And of course aside from the loops all the other keyframes work independently.
Copy link to clipboard
Copied
If I was going to set something up like that , I don't I'd use colors. I think I'd set it up so markers 1 and 2 define the 1st loop area, markers 3 and 4 define the 2nd loop area, etc. So setting it for 2 loops at each of 3 separate loop areas would look like this:
nLoops = 2;
m = thisComp.marker;
t = time;
if (m.numKeys >= 6){
t1 = m.key(1).time;
t2 = m.key(2).time;
t3 = m.key(3).time;
t4 = m.key(4).time;
t5 = m.key(5).time;
t6 = m.key(6).time;
loopDur1 = t2 - t1;
loopDur2 = t4 - t3;
loopDur3 = t6 - t5;
if (time > t1 && time < t1 + nLoops*loopDur1){
t = t1 + (time - t1)%loopDur1;
}else if (time > t3 && time < t3 + nLoops*loopDur2){
t = t3 + (time - t3)%loopDur2;
}else if (time > t5 && time < t5 + nLoops*loopDur3){
t = t5 + (time - t5)%loopDur3;
}
}
valueAtTime(t)