Jump to content

akapowl last won the day on March 21

akapowl had the most liked content!


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by akapowl

  1. Well, as with everything, the devil is in the detail, which is why it is very hard to give general recommendations for a more complex scenario like yours. Since you are concerned about things not working when reloading the page when it's scrolled down, you might want to reconsider the general approach of how you implement the change of the backgroundColor, too, because the way you are doing it in the demos you posted, things will not work as you might intend in that case. One logical problem is the following: You are changing the playstate of pre-built timelines with.to() tweens in callbacks of ScrollTriggers, when the page is loaded at the very bottom, ScrollTrigger will make sure that those callbacks get called. So now you have multiple tweens being called quickly one after the other, which are all tweening on the same property of the same element, so you are creating conflicting tweens. When you scroll back up then, the .to() tween is supposed to be reversed, but it will probably reverse back to the color that it was at the time when that tween was being created - which very likely is not the color you'd expect but some value of a color in between all those colors. Creating your tweens upfront can be quite the tricky scenario to begin with, when you are going to tween on the same property of the same element with multiple different instances. So one way you could prevent all those logical hurdles, would be to create the tweens in the callbacks directly instead of pre-building them. Then you could either use .fromTo() tweens to make sure you always tween from one specific color to another specific color, when the callback runs, or .to() tweens with overwrite set to 'auto' to prevent conflicts I mentioned above. In this pen with the lottie-scrolltriggers handling the pinning themselves, things seem to work fine even if I create those ScrollTriggers before all the lottie-scrolltriggers, but your mileage may vary. https://codepen.io/akapowl/pen/gOjKLqy
  2. It's actually really hard to replicate in the first place because when refreshing the page, it doesn't always stay at the position it was before. Your latest demo for instance works fine for me every time - but I can see it starts up top when reloaded and then jumps to the position it was before later on. How about these two pens? (both are on the latest version - best fork them and view in codepen's debug mode) This one sort of represents your scenario - for each section there's one instance created for pinning the wrapping container and then later the LottieScrollTrigger instance for the animation triggering on the child of the container - I can recreate the issue you described there - all positions of the animation-triggering shift for me when reloaded at the bottom of the page e.g. https://codepen.io/akapowl/pen/jOpKqXW If on the other hand I only use the LottieScrollTrigger for both, pinning and triggering of the animation, I can not replicate the issue any more. Does that work for you, too, or can you still replicate that behaviour with this pen? https://codepen.io/akapowl/pen/abjKZwa
  3. Out of curiosity I was tinkering a bit and I noticed some differences in behaviour in between versions of GSAP/ScrollTrigger but I'm actually not sure if things that occured for me are those that you are mentioning. Could you check if this version of your codepen does behave any different for you? It is reverted back to GSAP and ScrollTrigger 3.11.1 https://codepen.io/akapowl/pen/VwBdKvv
  4. Hi there. Your ScrollTrigger is set to end 10,000 pixels after it starts - but since you are not pinning anything, you will never actually have that much height to scroll through on your page. So you might want to change something with that regard. In this fork of your pen you can see that ScrollTrigger actually works just like you tell it to, if there is enough scrollable space; I just set a min-height to the body to demonstrate that. https://codepen.io/akapowl/pen/dyjKGVX Consider having another look at the ScrollTrigger docs - with regard to end it might also be helpful to have a look at endTrigger. https://greensock.com/docs/v3/Plugins/ScrollTrigger Also it sounds to me, that you actually want two tweens of a timeline to trigger at the same time, so you might want to have a look at how to use the position parameter of tweens on a timeline.
  5. Usually it is best to create your ScrollTriggers in order of the appearance of the elements on the page. ScrollTrigger needs to process the page from top to bottom, so ScrollTriggers further down the page have information about what is going on above, as layout might have been shifted before, which they need information about in order to calculate correctly, where to trigger. Imagine you have a forEach loop creating a bunch of ScrollTriggers for multiple sections on your page. Then, in your code after that forEach loop, you create a ScrollTrigger that is pinning something in between those sections - that pinning will cause the positioning of the elements that come later on, to shift. But since you have already created the ScrollTriggers for some of those elements further down the page before you created the pinning ScrollTrigger, and now in hindsight due to the pinning their position on the page gets shifted down, the calculations made by ScrollTrigger for those elements will not be correct anymore. See the problem? Of course often times it is more convenient to use loops and quickly itterate over multiple elements, but that often is where problems can occur, and that's what .sort() / refreshPriority are there for to help out with. Now again, I'm not saying that this is the cause of your issue - just wanted to give you a heads up on that, because it should be something to be aware of, when constructing your JS like you are.
  6. Hello @Palke - welcome to the GreenSock forum. I myself can not replicate the behaviour you mentioned with the instructions you gave - on Windows 11 neither in the latest Firefox, Chrome or Opera - so this might be something browser or OS specific. I think, adding some information about the browser and OS you are using might help the Admins find out what's causing that.
  7. Sorry, but no, I can't do that - that is a bit too much of a favour to ask. I'd keep it with what Cassie suggested; start with a blank canvas, add things to it piece by piece, test test test, and when things break, you will have a better angle on what might have caused it. Creating ScrollTriggers out of order of their appearance on the page (like especially inside forEach loops creating pinning ScrollTriggers) can become very tricky quite quick. I suspect, in a complex scenario like that, you might have have to consider the use of refreshPriority and/or .sort() in one way or another; but that is just a suspicion from a quick glance, nothing I can guarantee. https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.sort()
  8. Hey all. I think, using the string syntax for start / end with only one parameter, like you do throughout your codepen demo, @Gigi1303, is actually not valid ( as in e.g. start: "top" for instance ) and is bound to lead to problematic behaviour. You can use a singular value as a number (not in string form) and it will translate to the absolute scrollposition on the page or as a relative value in case of the end, like "+=100%". But other than that, when you use the string syntax, you are supposed to give two parameters, as in "top top" with the first referring to the element and the second referring to the viewport (as explained in the ScrollTrigger docs). Maybe try and change that in combination with the other suggestions you've already gotten, and see if it helps. For confirmation, here is @GreenSock mentioning this in one other thread (among many):
  9. You can find it in that other thread I mentioned earlier.
  10. Alright, I see. Then you'll probably need some sort of calculation anyway. Just for inspiration, here is an alternative. I make use of the endTrigger here, so I can use one trigger-element for the start and another trigger-element for the end. Also I get the values directly in the start function, so there's no need to re-populate any variable on resize. The calculation there is based on the padding of the section plus the offsetHeight of the subtitle + the 32px you mentioned you wanted in between the pinned elements. As a sidenote: I had to add a fixed height to the h2, as your h2s are empty and things got a bit wonky when pinning the intro element. Maybe this will help somehow. https://codepen.io/akapowl/pen/gOjzmmX endTrigger String | Element - The element (or selector text for the element) whose position in the normal document flow is used for calculating where the ScrollTrigger ends. You don't need to define an endTrigger unless it's DIFFERENT than the trigger element because that's the default.
  11. Update: I also tried to make an example that is a bit more condensed, to make it at least a little bit easier to see through what's going on there. @Rodrigo would you mind having a look at this if you find the time, to see if this is somewhat acceptable from the React side of things? https://codesandbox.io/s/gsap-scrolltrigger-with-locomotive-scroll-in-react-ux8nlv Worth mentioning on the side: Since elements and even whole sections kept disappearing on me when scrolling, I added a suggested sort of workaround to that known locomotive-scroll issue to the end of the styles.css
  12. So, @Pollux Septimus, I've had some more tinkering with this, and I think I've come to a working outcome ( but since I am not too familiar with React in particular, I give no guarantee that this is the holy grail when it comes to this). Point 3) of what I mentioned still stands - do not use locomotive-scroll's data-scroll-section attribute for the reasons mentioned. Point 1) looks like it boils down to the double-rendering in React's Strict mode from v18 upwards - so just like you do with GSAP's .context(), you will need to do some sort of clean-up to prevent multiple instances of loco-scroll to be created. So now I added return () => { locoScroll.destroy() ScrollTrigger.removeEventListener('refresh', lsUpdate); } to the end of the useEffect of your custom useLocoScroll hook. Point 2) can apparently not really be avoided, but React offers you some way to workaround the problem that this boild down to. The way I understand things, you probably shouldn't be using a useEffect but rather a useLayoutEffect for your custom hook: taken from here: https://kentcdodds.com/blog/useeffect-vs-uselayouteffect Those things changed, I landed on this, which appears to be working just like intended. Does that work better for you? https://codesandbox.io/s/st-loco-react-dtw1q4
  13. I was just tinkering with the custom hook solution by the other user, and think I found all the causes of problems now - am just about to reply there with the sandbox I've landed on. Give me a second.
  14. Hello all, I hate to be the party-pooper and if I am wrong with this, or out of line, I beg your pardon, but I just wanted to mention that using the approach in the thread, that @Rodrigo mentioned might not be the best idea, since it appears to be rather problematic for a couple of reasons mentioned in this other thread by the same user from a couple of days later. Now again, I really don't want to call out anybody, but I also wouldn't suggest their approach as a solution (at least for the time being), so I thought this was worth mentioning. Might be worth also making a note of that in the thread where the use of that hook is suggested?
  15. Hello. That is the case, because you populate your variables with the relevant values once on load, and then always work with the same variables without ever updating their values. If you want things to be recalculated on resize, you will need to get the relevant values again on resize (best on the revert event of ScrollTrigger) and repopulate your variables. Here's an example for that - although I'm not sure this is what you really want as those values for the start can become (or in some cases depending on window/image size already are) contradicting to the end of 'bottom bottom' you have there, which will be reached before the start in a vast majority of cases, the way I see it. So maybe explain what it is you are trying to achieve, and we can see if there is a better way to do it !? https://codepen.io/akapowl/pen/VwBXWOm
  16. Sorry, but I don't have the time to wade through all that logic, especially since I can't even imagine what outcome you expect and your initial setup in combination with the elements then suddenly jumping off-screen before tweening in, doesn't make that much sense to me. Also it is quite a bit out of scope from what to expect from this forum, please see the Forum Guidelines. From what it looks like to me, you are creating your timelines upfront and then only adding more and more tweens to them when calling your functions - not sure how much that does affect things, but that doesn't look quite right to me. I'm also not sure you need functions to begin with; couldn't you just create your timelines upfront and iterate through those pre-made timelines in your logic. For your convenience, here is a rather simple example with the logic transfered to click-events rather than scrolling. https://codepen.io/akapowl/pen/OJwvXYz
  17. As you can see from the logs I added in the onUp and onDown callbacks, Observer's onUp works just fine - what fails is your custom logic. You are getting an error in console that points you to what is wrong funcs[index] is not a function If you log out the different indexes you are working with, you will notice that you are pointing towards an item of an array with a negative value for the index in multiple occasions, and arrays inherently do not have / work with negative indexes. So you will need to rework your logic with that regard, to make it work. BTW, you have a typo in your Observer: targer --> target https://codepen.io/akapowl/pen/poZLjpZ Edit: One suggestion I have is taking a look at GSAP's utility methods. Here is an example of how you could e.g. use .wrap() to wrap around your variable value to the last one in your array, if it becomes negative. Click anywhere on the body in this example to decrease the variable I'm working with by 1. https://codepen.io/akapowl/pen/QWBmjJB ... the wrapping also works in the positive direction, btw. https://codepen.io/akapowl/pen/QWBmyLJ
  18. Welcome to the GreenSock forum. First off, I would suggest having a look at ScrollTrigger's normalizeScroll function, which should help with what you are trying to achieve. But as an answer with regard to your scenario: Since your body is not going to be the scroller element anymore in a case as such, you will probably have to define the current element that is now your scroller. This is from the docs: scroller String | Element - By default, the scroller is the viewport itself, but if you'd like to add a ScrollTrigger to a scrollable <div>, for example, just define that as the scroller. You can use selector text like "#elementID" or the element itself. If neither of the suggestions does help in your case, please provide a minimal demo that showcases your issue. I'd also suggest reading up on those threads if you want to stick to your solution as it comes with some side-effects that you might want to consider.
  19. Hello there. So, if you don't want the confetti to play for a certain duration of time, don't make it request a new animationFrame depending on wether a certain amount of time has passed - but instead make it dependent on wether a certain scenario is the case / condition is met. You could e.g. set up a boolean variable (playConfetti in this case below) and toggle that variable to true/false depending on wether you enter or leave the section. When you enter the section, also call the function that plays the confetti - inside that function call the requestAnimationFrame only when the playConfetti variable is true (checked with the if condition that earlier had the check on the time passed, in your demo). Something like this maybe: https://codepen.io/akapowl/pen/NWByZqg
  20. The only thing I can tell you for sure, is that you should call a ScrollTrigger.refresh() after you have created your ScrollTriggers when useing ST with locomotive-scroll, as is also noted in the demo on the .scrollerProxy() docs-page - right now you are only doing it after you created the smooth-scrolling instance and the scrollerProxy(). [...] // after everything is set up, refresh() ScrollTrigger and update LocomotiveScroll because padding may have been added for pinning, etc. ScrollTrigger.refresh(); Apart from that, there can be dozens of reasons for your issue - might be that you need to make sure your images are loaded before you create your ScrollTriggers (or call a .refresh() after they are fully loaded) but it might as well be something very different; possibly not even related to ScrollTrigger. After applying the suggested fixes to your current demo, I can not see the behaviour you mentioned at all. Since we can not really offer advice from looking at screenshots, because there are just too many possible problem-sources in a complex scenario like this, please add a minimal demo showcasing your issue, if you need further assistance on this.
  21. I think the reason for why it doesn't work properly after a page-transition, boils down to the fact, that for a certain period of time within barba's lifecycle, both, the old and the new container will live together in the DOM. Now while you are initiating your new locomotive-scroll instance everytime with reference to the new barba-container, your scrollerProxy is only being created with reference to '.smooth-scroll', which will be available in both, the old and new container at that time - and since the old container sits above the new in the DOM tree at that time, you will be referencing the old container's .smooth-scroll with that. You can check the difference between the two elements you are targetting by logging out console.log(smoothScroll.parentElement.getAttribute('data-barba-namespace')) vs. console.log(document.querySelector('.smooth-scroll').parentElement.getAttribute('data-barba-namespace')) in your initSmoothScroll function. So you can either simply just change the element you are targetting in your scrollerProxy to be the same you are targetting when creating your locomotive-scroll instance, or alternatively just remove the old barba-container at the proper time since you don't need it for your type of page-transition anyway. Both options resolved things for me. Hope they do for you, too. Thanks for the heads-up btw @Cassie - was scratching my head for a minute or two there, before I saw that.
  22. While this doesn't seem to affect anything, it sure is problematic - there is occasions when you can get both instances to scroll, and if they both report back different data to ScrollTrigger, I assume ST is going to be very confused and you won't see the results you expected at some point. I simply just added some custom console.log('...')s to the hooks you are using. That line you mentioned is not what I was talking about though. I was referring to locomotive-scroll's data-scroll-section attribute, which according to their docs can help improve performance for locomotive-scroll - but as I said, it will most likely cause conflicting behaviour with ScrollTrigger. Here are some examples in vanilla JS to show how the points I mentioned above do create issues. [Edit: Keep in mind, that those examples need to be opened in a seperate window, because with a viewport as narrow as the preview's iFrame, locomotive-scroll will default back to native browser scrolling] This is the basis for all the examples; here with native browser scrolling - works fine, all good. https://codepen.io/akapowl/pen/yLqpZxK This here is the same example but with locomotive-scroll's default behaviour implemented, not using the data-scroll-section attribute - works fine. https://codepen.io/akapowl/pen/bGjazzR And here is that exact same example, only with the data-scroll-section attribute added to the individual sections (similar to what you are doing in your demo) - this is what I meant with my 3)rd bullet point. As you can see, things become problematic with the pinning ScrollTrigger there, on the second section. https://codepen.io/akapowl/pen/qBypvWW Last, but definitely not least, here is that basic locomotive-scroll example again, but this time with the order of creation messed up. In this example I create the ScrollTriggers first, before I even initialize locomotive-scroll and set up the scrollerProxy etc. - again, not working too well. https://codepen.io/akapowl/pen/XWBVGrG So all in all, I think that's where (at least some of) your problems stem from, although I'm not saying that this is definitely all, as I didin't have the time to check every single bit in your code. The biggest sources of your problems seem to be a) React - its double-calling in Strict Mode and its order of creating your page in general; and b) locomotive-scroll and its data-scroll-section attribute that isn't really compatible with ScrollTrigger.
  23. I'm not sure, I understand what you mean by 'in stages'. It would help if you could elaborate a bit on what it is you expect to happen. I connected your timeline to the scrubbing ScrollTrigger you had there, which I thought was what you wanted to happen. Scrub will always stretch out the connected animation over the scroll-distance between your start and end. If you want to just toggle the playstate of an animation, have a look at toggleActions instead of scrub in the docs.
  24. Hello there. That's because you never hooked your timeline up to your ScrollTrigger in the first place. Also, your element's top will never actually reach the top of the window to start scrubbing it, as you don't have that much scrollable space. Another thing to consider is that when you set your end to 'bottom bottom', it means 'end when the bottom of the element hits the bottom of the viewport', which happens waaay earlier than the start in your case. So you might want to reconsider your start and end, too. The docs have some quite good explanations on start and end, and all the other properties like animation e.g. https://greensock.com/docs/v3/Plugins/ScrollTrigger As another sidenote: In a fromTo tween, duration and delay do only go in the To part of the fromTo. Apart from that, I don't think the delay property even does serve a purpose on tweens scrubbed by ST (I might stand corrected). But at least the duration will definitely pretty much do nothing on a scrubbed tween, if you only have that one tween anyway . Here is your timeline being scrubbed over the distance it is in viewport, just to give you an idea for how to approach it. https://codepen.io/akapowl/pen/LYBezNq
  25. Hello there. I am no React expert, so I won't be able to help much with that side of things, but here are some things I noticed. 1) From what I can tell you from a quick glance, there appears to be something wrong with how you're setting up locomotive-scroll, since you are creating multiple instances of it (possibly because of the double-call shenanigans of React ?) - I suppose that will create conflicts with ScrollTrigger - not saying that this is the only or true source of the issues you are facing, but to me that definitely something you might want to fix. 2) I'm not sure how much this following does affect things, but the fact that your ScrollTriggers are being created, before your locomotive-scroll instance was created, doesn't look right to me either - it should be the other way around; first the locomotive-instance should be created (with the relevant ScrollerProxy etc.), then the ScrollTriggers. 3) One thing that I can tell for (pretty much) sure though, is that ScrollTrigger, but at the very least ST's pinning, will not work properly with locomotive's data-scroll-section attribute, which you appear to be using. Locomotive-scroll will apply transforms to that section for the smooth-scrolling effect when you use it, which will interfere with what ScrollTrigger does to that section. In a smooth-scrolling scenario as such (using transforms), the pinType will have to be used as 'transform' to create the pinning-effect; but those transforms applied by ST will probably contradict with the transforms locomotive-scroll applies to that section. See the problem? When that attribute is removed from your Section component things at least appear to be working better. https://codesandbox.io/s/broken-flower-qnzb6v?file=/src/components/Section/index.jsx Yet, things stop working again as soon as I disable StrictMode for React. Which I think mioght be because of the order of creation not being correct, as mentioned in 2) I hope this will help a bit with getting things sorted. One more thing: I just now realized, you are using locomotive-scrol v4 - they made some changes to how loco-scroll works, which also affect how the ScrollerProxy needs to be set up. That's also something you might need to consider.