Creative Communities of the World Forums

The peer to peer support community for media production professionals.

Activity Forums Adobe After Effects Expressions Issue with updating a “Trim Paths” offset property value. I am at a loss :/

  • Issue with updating a “Trim Paths” offset property value. I am at a loss :/

    Posted by Thomas Binns on November 13, 2022 at 2:02 am
    1. Hey. I’m somewhat a beginner here with AE expressions. Over the past few days I’ve been working out how to write an expression in the “Trim Paths” offset property. Basically, I have a null with a checkbox as my on/off switch, which tells when the offset property should rotate. Through the null I also control the cycle duration (how many secs for the offset to reach 360) and the starting angle (0). I also have a way that works (if a bit untidy) that returns the previous and next keyframe on the checkbox property. I use this to grab the offset angle 1 frame before the checkbox goes off, so the offset pauses – rather than resets to 0 (my starting angle).

      The problem I am having is that I cannot seem to have the offset update with this, even though when I look at the result (defAngle) through a source text layer and it gives the value I would expect. I can even manually type in the correct value and it works, but that does defeat the point of being dynamic.

      I just cannot work out what the issue is, so any help would be appreciated if possible.

      Here’s the expression in full:

    2. check = thisComp.layer(“Spotlight Control”).effect(“Play (1st key)”)(“Checkbox”);
      cNum = check.numKeys;
      kTime = check.nearestKey(time);

      //to calculate the previous and next keys relative to the current time
      if (kTime.time <= time) { kpNum = kTime.index;
      } else { if (kTime.index – 1 == 0) { kpNum = kTime.index;
      } else { kpNum = kTime.index – 1;
      } };
      if (kTime.time >= time) {
      knNum = kTime.index;
      } else { if (kTime.index + 1 > cNum) { knNum = kTime.index;
      } else { knNum = kTime.index + 1;
      } };
      if(knNum == 1) { prevK = inPoint;
      } else { prevK = check.key(kpNum).time;
      };
      if(kpNum == cNum) { nextK = outPoint;
      } else { nextK = check.key(knNum).time;
      };

      mDur = thisComp.layer(“Spotlight Control”).effect(“Cycle Duration (sec)”)(“Slider”);
      t = time – prevK;
      mID = Math.floor(t / mDur) + 1;
      tStart = mID * mDur;
      tEnd = (mID + 1) * mDur;
      currAngle = content(“Trim Paths 1”).offset;

      if(check == 1 && prevK != inPoint) {
      defAngle = thisComp.layer(“Spotlight Control”).effect(“Angle A”)(“Slider”);
      angleCycle = defAngle + 360;
      } else { defAngle = currAngle.valueAtTime(framesToTime((timeToFrames(prevK) – 1)));

      angleCycle = defAngle;
      };

      linear(t, tStart – mDur, tEnd – mDur, [defAngle], [angleCycle]);

    Thomas Binns replied 3 years, 10 months ago 2 Members · 4 Replies
  • 4 Replies
  • Filip Vandueren

    November 13, 2022 at 11:21 am

    Hi Thomas,

    I think the problem is that inside of the expression, you want to keep track of the result of the same expression at a different time with valueAtTime, and that’s not how expressions work; they can find out the expression result of a different property at any time, but when looking at their own valueAtTime, they only see the originally-set or keyframed value before expressions.

    Because of this, starting/stopping or variably controlling the speed of something using expressions is not straightforward at all.
    Dan has written an excellent article about that many years ago: https://www.motionscript.com/articles/speed-control.html

    IF your cycle duration and angle A are not also keyframed, then this variation on the hold keyframe method described in the article should work:

    spd = thisComp.layer("Spotlight Control").effect("Play (1st key)")("Checkbox");
    n = spd.numKeys;
    cyc = 360/thisComp.layer("Spotlight Control").effect("Cycle Duration (sec)")("Slider").value;
    if (n > 0 && spd.key(1).time < time){
    accum = spd.key(1).value*(spd.key(1).time - inPoint)*cyc;
    for (i = 2; i <= n; i++){
    if (spd.key(i).time > time) break;
    k1 = spd.key(i-1);
    k2 = spd.key(i);
    v2 = spd.valueAtTime(k2.time-.001);
    accum += cyc*(k1.value + v2)*(k2.time - k1.time)/2;
    }
    accum += cyc*(spd.value + spd.key(i-1).value)*(time - spd.key(i-1).time)/2;
    }else{
    accum = cyc*spd.value*(time - inPoint);
    }
    thisComp.layer("Spotlight Control").effect("Angle A")("Slider") + accum;

    If those parameters (cycle duration and startangle) could be keyframed, especially with easing, then stuff gets a lot more complicated.

    Then we’d wind up using the slower brute-force method of stepping through every previous frame by frame to calculate a correct running total (accum) of checkbox.valueAtTime*cyc.valueAtTime + angleA.valueAtTime.

  • Thomas Binns

    November 14, 2022 at 8:09 am

    Hey Filip,

    Thanks for the reply and info! I just tried that code from that speed control article (which is indeed excellent… and a bit beyond me), and it worked exactly how I wanted it to!

    What I am curious about is how intensive would this method be compared to what I was already doing, if you know? Because I do intend to use this animation and apply it to lots of items in my composition.

    (and good point, I’ll refrain from keyframing the other properties)

  • Filip Vandueren

    November 14, 2022 at 10:53 am

    Hey Thomas,

    It shouldn’t be a problem because just like your original code, this method only needs to look at the keyframes, and not every individual frame, the for loop never gets very long, and that’s the thing that would take up most time if it runs into the thousands.

  • Thomas Binns

    November 15, 2022 at 4:00 am

    Good news then.

    Thanks 🙂

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