Jump to content
Search Community

gsap/react + threeFiber/drei; start pin location issue

Moti test
Moderator Tag

Go to solution Solved by Cassie,

Recommended Posts

Greetings gsap community,

 

I have recently found gsap scrolltrigger plugin and have been hooked ever since. Before I start with my question/s, I would like to thank the people who created gsap and to those who help out in this forum. I am pretty much new to the plugins and to the framework that I am working on so I will try my best to explain the issue

 

I have created a small threejs animation together with html animations like (fake horizontal scroll) found in scroll trigger demos. What i discovered is that the start pin of the other animations is not located properly after the Canvas for the Three model. see (secondContainer) in the demo.

 

Issue: other animation start pin is not in desired location.

 

Minimal Demo: https://codesandbox.io/s/react-canvas-p07dz3?file=/src/index.tsx

 

Note:

1. Actually using Nextjs (have not been able to make the pen/sandbox work) i stole this demo sandbox from topic(see below)

 

2. I have read about pinSpacing/ pinSpacer but i have no luck on making it work due to my inexperience

 

 

Any suggestions/answers are greatly appreciated. Also if this was already answered please point me to the right direction.

 

Regards,

Moti

See the Pen index.tsx by s (@s) on CodePen

Link to comment
Share on other sites

I'm not a React guy, but I think the problems are:

  1. You're creating your ScrollTriggers out of order and you didn't set a refreshPriority to correct for that. You should always create your ScrollTriggers in the order they'd appear on the screen especially when pinning because the pins higher up on the page would push the start/end values of the things below further down. In your case, you're creating the SECOND pin first and at that time, there is no first element at all, so it's the very top thing on the page, thus the start position is 0...and then you create/render your FIRST element which pushes the other one down now, and the pinning should also force it further down still. ScrollTrigger can't know that you're going to do that which is why it's important that you do things in order or set refreshPriority values to reflect things properly. 
  2. The way your app is working causes things to not be in their final position when the window's "load" event fires (which triggers a ScrollTrigger.refresh() which is the think that does all the start/end calculations). So your Content2's useEffect() fires when the App isn't done, and then Content's useEffect() fires and App still isn't done, and then...nothing. When your App finally renders entirely, there's nothing telling ScrollTrigger "hey, do your refresh() now and calculate all the start/end values now that I've finished moving stuff around and rendering". So you could either call ScrollTrigger.refresh() at the end your Content's useEffect() or add something like setTimeout(ScrollTrigger.refresh, 100) but that feels a little hacky to me (it assumes the page will be rendered fully within 100ms). The entire point here is to just make sure you call ScrollTrigger.refresh() when EVERYTHING is done rendering and the page is in its final state. 

Does that clear things up? 

  • Like 1
Link to comment
Share on other sites

Hello GreenSock,

 

Thank you for your response. I was tinkering with the sandbox trying to implement the Scrolltrigger.refresh(), unfortunately I did not get it to work (think i have coded it wrong). I have both tried to call the inside the useEffect and tried to set up a timer; both did not have the desired results.

 

 

Sandbox: https://codesandbox.io/s/react-canvas-forked-72nxi0?file=/src/index.tsx

 

as for your reply

1. Confused on how this works, I think I have created the scrollTriggers in order. Content1 for the 'firstContainer' then Content2  for the 'secondContainer'.

 

I have also created a third one just to test out the scrollTrigger logic and it behaves as expected. The start pin on Content2 waits for the pinSpacer and all is well. However that is not the case for Content1. ( it does have the pinSpacer upon inspecting but it Content2's scrolltrigger just doesnt see it. )

 

2. I have tried to implement Scrolltrigger.refresh() but I did not manage to make it work ( maybe because I had it wrong)

 

 

Regards,
Moti

 

Link to comment
Share on other sites

  • Solution

Heya! 

Just prefacing this with a disclaimer that we're not really the best place to be offering advice on React. The lunch dev community is great though.

---

 

That being said, with my small amount of React knowledge I'll give it a bash.


https://codesandbox.io/s/react-canvas-forked-jst7g8?file=/src/index.tsx

So, yep - you have defined the ScrollTriggers in order visually in the code. That would work fine in vanilla JS as the code gets executed top to bottom (unless you're doing async stuff)

But, you're using React and there's a bunch of stuff happening behind the scenes (That I can't explain or advise on) For whatever reason your second scrollTriggered component is rendering to the DOM before the first so when it calculates all the positions, it's incorrect because the first component doesn't exist yet.

When this happens you have to manually define the order you want them in, and then call ScrollTrigger.refresh()  to sort and calculate the right positions. Ideally you'd call scrollTrigger.refresh when the DOM is done loading but again, I don't really know react... I know there's no DOMLoaded function like in other frameworks. I've just called it at the end of each of your useEffects and it works for now.

 

const Content = () => {
  gsap.registerPlugin(ScrollTrigger);
  const boxRef = useRef();

  useLayoutEffect(() => {
    let tl = gsap.timeline();
    // tl stuff

    let controller = ScrollTrigger.create({
      animation: tl,
      refreshPriority: 1
    });
    ScrollTrigger.refresh()
  }, []);

  return <Box ref={boxRef} />;
};

const Content2 = () => {
  gsap.registerPlugin(ScrollTrigger);
  const secondBoxRef = useRef();

  useLayoutEffect(() => {
    let tl2 = gsap.timeline();
    // tl stuff

    let controller2 = ScrollTrigger.create({
      animation: tl2,
      refreshPriority: 0
    });
    ScrollTrigger.refresh()
 }, []);

  return (
    <div ref={secondBoxRef} className="secondBox">
      test
    </div>
  );
};


if you need more React specific help I suggest popping into that discord. I'm sure someone there will be able to advise.

Hope this helped a little!

  • Like 1
Link to comment
Share on other sites

Hi Cassie,

 

Thanks for the link; I'll check that channel out.

 

Now I understand

 

2 hours ago, Cassie said:

But, you're using React and there's a bunch of stuff happening behind the scenes (That I can't explain or advise on) For whatever reason your second scrollTriggered component is rendering to the DOM before the first so when it calculates all the positions, it's incorrect because the first component doesn't exist yet.

It seems that way.

 

How GreenSock Jack and you explained it now makes sense to me. Thank you both for your time and knowledge

 

2 hours ago, Cassie said:

Hope this helped a little!

It helped a lot. I was already considering to choose between the two components i've created and now I could keep them both.

 

9 hours ago, GreenSock said:

set refreshPriority values to reflect things properly

together with

9 hours ago, GreenSock said:

The entire point here is to just make sure you call ScrollTrigger.refresh() when EVERYTHING is done rendering and the page is in its final state. 

got it working

 

Working sandbox: https://codesandbox.io/s/gsap-reactthreefiber-canvas-working-trq85d

 

 

Again thank you both for time, effort and support. Cheers!

 

-Moti

  • Like 1
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...