Jump to content
Search Community

React + R3F + GSAP: transitioning between two animations smoothly

dsmooot test
Moderator Tag

Recommended Posts


Hello, folks!

Here's a minimal demo  using stackBlitz. Hopefully it's minimal enough and within the scope of a gsap-related question! :)

Here's the scenario:
-there is a sphere and an empty object which orbit around the center point 
-when clicking the sphere, it tweens from the current position of the empty object to the center point, and vice versa

 

My goal is to have a smooth transition between the click event tween and the orbit tween for the sphere. 

Problem:
There seems to be a jump between the animations... my guess is that, because I'm depending on a value from a ref within my click tween, I am getting values that are a frame behind. 

If anyone has any suggestions or ideas of how to best sync/manage things, any help would be greatly appreciated! 

Cheers,

dsmooot
 

Link to comment
Share on other sites

It looks to me like you're using the wrong end values. You're animating to where the rotating box is NOW (when creating the tween) rather than where it will be by the time the tween's duration completes. So you'd just have to figure out where it will be after that amount of time and animate there.

Link to comment
Share on other sites

Hi, Jack!
Thank you for the reply! I appreciate you taking the time to check it out.

Thinking a little more about it, I realized that it is more manageable to have predictable locations vs tracking the position of an always tweening target, so I created a wrapper component (a <group>) and performed the rotation animation on it instead of the individual objects. That way, the box is actually at a static position along the circle - an easy target for the sphere to tween to. 👍

For reference, here's the updated demo

------

On the other hand, with tracking the anticipated position of a tweening target, is there some approach you might recommend? 
I think of there being a known value at a specific 'progress' value for a tween, but I'm unsure how I'd track that dependent on the completion time of the click tween.
eg. when click tween progress is at 100%, box tween progress will be at 'x' percent, and therefore its position value will be y at that time.

No biggie if there isn't a simple solution (especially it being in context to React), but I figure it might be useful to know for future cases.

Thanks! 🙏

Link to comment
Share on other sites

Hi,

 

I'm not really familiar with RTF so I couldn't advice you on whether or not there is a better way to achieve this. You solution seems simple, easy to follow and doesn't create any performance issue, so: if it ain't broken don't fix it ;)

 

Finally I'd suggest you as a best practice, to add your GSAP instances created in the click handler to a GSAP Context instance. In the case the Sphere component is unmounted midway through the tween, that GSAP instance could be still running causing an error and/or a memory leak. You can easily create a GSAP Context instance in a ref and then call a specific method that does what you're doing in your click handler, like this:

const handleClick = (event) => {
  ctx.current.myClickHandler(event.object.position, isActive);
};

useLayoutEffect(() => {
  ctx.current = gsap.context((self) => {
    self.add('myClickHandler', (position, value) => {
      gsap.to(position, {
        duration: 1,
        x:
        value && emptyRef?.current?.position?.x
        ? emptyRef.current?.position.x
        : 0,
        y:
        value && emptyRef?.current?.position?.y
        ? emptyRef.current?.position.y
        : 0,
        ease: 'none',
        onComplete: () => setIsActive(!value),
      });
    });
  });
  return ctx.current?.revert();
}, []);

Hopefully this helps.

Happy Tweening!

  • Like 2
Link to comment
Share on other sites

2 hours ago, dsmooot said:

On the other hand, with tracking the anticipated position of a tweening target, is there some approach you might recommend? 
I think of there being a known value at a specific 'progress' value for a tween, but I'm unsure how I'd track that dependent on the completion time of the click tween.

I don't have time right now to do it for you, but there are several ways...

  1. Just temporarily set the tween's totalTime(), read the value, then set it back. For example, if you know your click tween has a duration of 1 second, then set the other tween's totalTime() forward by 1, like otherTween.totalTime(otherTween.totalTime() + 1), read the value(s), then set it back so the user will never actually see a jump. 
  2. Do the math. Your rotation is going at 1 full rotation over the course of 30 seconds, so that's 360 / 30 degrees per second. Calculate what it'd be 1 second in the future that way and plug the values in. 

I hope that helps!

  • Like 1
Link to comment
Share on other sites

@Rodrigo Thank you for clarifying the best practice for referencing a tweened object in an event listener! Very helpful information.
When I was writing it out originally, it crossed my mind that it could be a potential issue (referencing outside of the context), and that confirms it! :)

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.
×
×
  • Create New...