Jump to content


MotionPath plugin - follow motion guide path changes at runtime

Go to solution Solved by akapowl,

Recommended Posts

I am using an existing CodePen to exemplify the problem.

If one uses inspect element and manipulates directly the motion guide / path definition, then the motionPath plugin still uses the previous definition.

Is there a way to make it follow dynamic transform of the motion path ?

I am planning to animate the motion path itself.

See the Pen GRdGYqe by iongion (@iongion) on CodePen

Link to comment
Share on other sites

Hello iongion,


maybe this thread can help with that.


Link to comment
Share on other sites

They are close, but I am altering the svg path definition points programatically. Only some of them due to the constraints.

What I have found working is re-initializing the entire timeline when path definition changes.

But the experience is not that smooth.

Link to comment
Share on other sites

Hi @iongion,


Can you please provide a minimal demo of what you're trying to do .Based on what you are describing the thread @akapowl mentioned has a lot examples that animate the path using code and the element following such path keeps animating without any issues. Perhaps you're struggling with something else, but right now is a bit harder to see it.


Happy Tweening!

  • Like 1
Link to comment
Share on other sites

  • Solution


Yes, a minimal demo of what you have tried so far would really help, as we currently don't even know how/when you want to change the path definitions.


I cooked up a demo of my own in between, although it is not really minimal, as most of what's going on in the code there is the logic behing it all. The logic for this pen is based on @mikel's example in that thread I linked to earlier.



You're probably right about re-initializing the entire timeline when the path definitions change;


That is what is happening here in the sync() function - it gets the current progress of the current tween, kills that tween then, and in the end creates a new tween (this happens here for each of my circles), which onUpdate of the path-changing tween will basically get overwritten for the entire duration of that path-changing tween (which is being triggered on click), so the circle visually moves along with the changing path in the end.

See the Pen eYrKXOr by akapowl (@akapowl) on CodePen


  • Like 2
Link to comment
Share on other sites

Thanks guys, will try to make a minimal example.

The example from @akapowl did help a bit.


I actually don't understand why the svg path & guide are not followed after alteration/changing by the user using the control points.

The const guide is what changes its points over time by user performing actions on a bezier curve (the svg path behind the guide variable)

The location of the circle is constrained by the timeline time and bezier curve alteration.




What works is to intercept whenever the bezier curve changes and re-animate (re-create) the gsap timeline.

I thought it is not needed, I thought there is something to tell the tween to re-parse the svg path once it is altered.

In your demos it appears to do so by default, I don't understand why it doesn't do it in my approach.


I am using a senseless setPath dependency just to recreate the tween, I suspect it might be heavy with many tweens.


  useLayoutEffect(() => {
    const durationFrames = frameEnd - frameStart;
    const durationSeconds = durationFrames / framerate;
    const duration = durationSeconds * 1000;
    const guide = `#ProgressIndicatorMotionPath-${id}`;
    const targetProps = {
      transition: "linear",
      motionPath: {
        path: guide,
        align: guide,
        autoRotate: false,
        alignOrigin: [0.5, 0.5],
        // immediateRender: true,
        // curviness: 1.5,
    const startTime = (frameStart / framerate) * 1000;
    const ctx = gsap.context(() => {
      const tween = gsapTimeline.to(ref.current, targetProps, startTime);
      tweenRef.current = tween;
    return () => ctx.revert();
  }, [path, id, frameStart, frameEnd, framerate, gsapTimeline]);

  percentageRef.current = currentFrame / framesCount;

  const onMotionGuideChange = useCallback((e: any) => {
    if (tweenRef.current) {
      const current = tweenRef.current.progress();
  }, []);


Link to comment
Share on other sites

I don't have time right now to read through the entire thread, but I wanted to chime in and clarify that a motionPath doesn't constantly re-parse and re-check positioning on an SVG element or something - there's a bunch of work up front to parse the data into Bezier numbers that can be quickly interpolated. It must rip through the values and calculate intermediary data that ensures that speed is constant even though Bezier path plotting isn't naturally. It sounds like maybe you're expecting that when you start a motionPath animation, it would constantly (on every tick) re-parse all the data and check for any changes that occurred since you began the tween. That is not the case - it'd be terrible for performance. We put a big priority on performance around here :)


So if you CHANGE your path data and you want that reflected in the animation, you could invalidate() it to force it to re-parse the data on the very next render. 

Link to comment
Share on other sites

Oh man, that is it, it was as simple as that, I've replaced all the seek / pause with timeline.invalidate() after path changes!

Using gsap and nothing else since flash days!

  • Like 1
Link to comment
Share on other sites

Love hearing that! 🙌

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.