• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Possible to Set a Limit to loopOut Cycles?

Explorer ,
Aug 18, 2022 Aug 18, 2022

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!

TOPICS
Expressions , How to , Scripting

Views

2.6K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Explorer , Sep 02, 2023 Sep 02, 2023

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

...

Votes

Translate

Translate
Community Expert ,
Aug 18, 2022 Aug 18, 2022

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;

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Aug 18, 2022 Aug 18, 2022

Copy link to clipboard

Copied

Dan! That's brilliant. Thanks SO much! Works like a charm.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Aug 19, 2022 Aug 19, 2022

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"). 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 02, 2023 Sep 02, 2023

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!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 02, 2023 Sep 02, 2023

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)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 02, 2023 Sep 02, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 02, 2023 Sep 02, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 02, 2023 Sep 02, 2023

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. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 02, 2023 Sep 02, 2023

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?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 03, 2023 Sep 03, 2023

Copy link to clipboard

Copied

No error, but also no loops. Everything plays like there is no expression. Look a tthe screenshot.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 03, 2023 Sep 03, 2023

Copy link to clipboard

Copied

Of course the screenshot shows how I want it to be, not how it is now.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 03, 2023 Sep 03, 2023

Copy link to clipboard

Copied

Change loopKey1 to 3 and loopKey2 to 5.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 03, 2023 Sep 03, 2023

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!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 03, 2023 Sep 03, 2023

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)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 03, 2023 Sep 03, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 03, 2023 Sep 03, 2023

Copy link to clipboard

Copied

No, the expression fills those numbers in by finding the green keyframe and the red keyframe (no markers required).

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 03, 2023 Sep 03, 2023

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?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 03, 2023 Sep 03, 2023

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)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 04, 2023 Sep 04, 2023

Copy link to clipboard

Copied

Ok, but is it possible that anything after the loop starts exactly where the keyframes are? Check out the screenshot attached.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 04, 2023 Sep 04, 2023

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)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 04, 2023 Sep 04, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 04, 2023 Sep 04, 2023

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)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Sep 04, 2023 Sep 04, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 05, 2023 Sep 05, 2023

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)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines