Jump to content
Search Community

GreenSock last won the day on March 24

GreenSock had the most liked content!

GreenSock

Administrators
  • Posts

    23,068
  • Joined

  • Last visited

  • Days Won

    815

GreenSock last won the day on March 24

GreenSock had the most liked content!

About GreenSock

Profile Information

  • Location
    Chicago Area
  • Interests
    Volleyball, Basketball, Christian Apologetics, Motorcycling

Recent Profile Visitors

100,140 profile views

GreenSock's Achievements

  1. You're making one of the common ScrollTrigger mistakes - nesting ScrollTriggers inside of a timeline. That can't logically work because you can't have the parent timeline AND the scroll position both control the same playhead(s), as they could be going in different directions. So either separate out each tween into its own individual tween that has a ScrollTrigger on it, OR put your tweens into a timeline that has a ScrollTrigger applied to that timeline. As for once: true, you could do something like this instead: onLeave: self => { let max = ScrollTrigger.maxScroll(window), // record maximum scroll amount, and the current scroll position scroll = self.scroll(); self.kill(true, true); self.scroll(scroll - (max - ScrollTrigger.maxScroll(window))); // adjust the scroll based on how much was lost when self.kill() was called. } https://codepen.io/GreenSock/pen/jORLdmy?editors=0010 (I didn't fix all your nested ScrollTriggers - you'll need to work through those).
  2. No, sorry. But hopefully my description gets you going in the right direction. I'm not sure if it'd be any easier or work the way you want, but another idea is to use DrawSVGPlugin to basically draw a super fat orange stroke, and see if you can do a blur effect on the end of it (you'd likely need to clip/mask the other end to keep that sharp). If you need more help, we do offer paid consulting services which you can contact us about. 👍 Good luck with the project, and thanks for being a Club GSAP member! 💚
  3. That's exactly why - you put it outside the wrapper. Why would you do that? If your goal is to have a position: fixed element (not pinned with ScrollTrigger), that's fine to have it outside the wrapper. Otherwise, it should be inside. https://codepen.io/GreenSock/pen/KKYvbRw
  4. Is that orange "fill" supposed to be gradated like that (feathered/blurred)? That makes things more difficult, but not impossible. I mean in its most simple form, you could place pie-cut segments of orange along the circle, and just animate the opacity in a staggered fashion. If you need it to be gradated in a totally smooth way, you might need to make a .png that's basically HALF of the circle. Make a mask of the opposite half, and animate the rotation of that .png so that it comes into that mask on the other half. Then when that reaches 180 degrees (half the circle), pop that out of the mask and keep going to 360 degrees while you do exactly the same thing with another .png that's half the circle but fully opaque orange. Rinse and repeat until that first one gets to 540 degrees and the other two half-circle .png files are filling the circle. Good luck!
  5. Yeah, that's because you're listening to the window's "scroll" event, but ScrollSmoother gradually applies that. So you're using stale values. Just set up an onUpdate event handler on the ScrollSmoother, and for maximum performance you can leverage a cache boolean to only trigger updates when absolutely necessary: https://codepen.io/GreenSock/pen/RwOZBjp?editors=0010 Is that what you're looking for?
  6. I built a helper function specifically for this: https://codepen.io/GreenSock/pen/vYMJdjB?editors=0010 Related forums post: I hope that helps!
  7. Hi @codechirag. It's super tough to troubleshoot a live site. There are way too many factors and we can't really tweak things to see what's going on. If you'd like some help, please provide a minimal demo, like a Stackblitz or CodePen. Here's a starter template you can fork: https://stackblitz.com/edit/react-cxv92j Also keep in mind that Split-Type is not a GSAP product, so we can't really support that. Our tool is SplitText. 🙂
  8. Sure, just put this at the end of your timeline: .to(".background-tint", { opacity: 0.5, duration: tl.duration()}, 0) Notice it's duration is the whole duration of the timeline, and it's being inserted at a time of 0, thus it takes up the whole animation. I read that a few times and I'm still totally lost. Sorry - can you please be very specific about what the problem is and how we can reproduce it? What markup did you add exactly? How did it "mess up"?
  9. When an animation renders for the first time, it records the start/end values internally so that it can very quickly interpolate between them during the animation. You've created a scenario where you actually want to CHANGE those values on resize. invalidate() will do exactly that - it flushes any recorded start/end values so that on the next render of that animation, it'll re-calculate those. With that in mind, you can just invalidate the animation and restore its progress: window.addEventListener("resize", () => { let progress = tl.progress(); // remember the progress tl.progress(0).invalidate().progress(progress); // rewind to the beginning, invalidate to flush any recorded start/end values, then restore the progress }); https://codepen.io/GreenSock/pen/BaEdQBy?editors=0110 Is that what you're looking for? You could also consider using a gsap.matchMedia(). There are many ways to accomplish something similar 🙂
  10. That's not an Observer issue - it's just that Apple touchpads and magic mouse keep emitting "wheel" events for a while after you release - it's what creates the momentum effect. So if you flick very strongly, you're firing the animation and then when the animation is done, there are still wheel events getting fired from the strong flick (momentum), thus it triggers another animation because those residual wheel events triggered the Observer's onUp()/onDown(). See the problem? So you could add some logic to sense that condition and work around it, like maybe: https://codepen.io/GreenSock/pen/jORLMLO?editors=0010 To make things easy, I just use ScrollTrigger's "scrollEnd" event handler but you could wire that all up yourself manually if you prefer not to use ScrollTrigger. Does that work better for you?
  11. That sounds like it could simply be a consequence of the fact that most modern browsers handle scrolling on a completely different thread than the main JS thread, thus it renders the content as if it was scrolled (without any ScrollTrigger logic applied) first, and THEN when the JS thread executes, ScrollTrigger does what it must do to pin the element, making it look like it jumps back. Two things you can try (assuming that's the problem you're noticing): 1) Try setting ScrollTrigger.normalizeScroll(true) which forces all the scrolling to occur on the main thread. 2) Use a scroll smoothing library like ScrollSmoother or Lenis which accomplishes a similar thing, unhooking the native scroll and implementing JS-based scrolling instead.
  12. Not if you're doing some kind of routing. The first time the page loads, the window will fire the "load" event after the images load (assuming no lazy loading), but then if you're doing routing in React to go to other "pages" (content) without the browser actually loading an entirely new URL, then the "load" event doesn't fire, thus ScrollTrigger.refresh() isn't automatically called. See what I mean? Again, a minimal demo will go a very long way toward getting you a solid answer. I was totally just guessing here.
  13. Sorry if that was confusing, but let me clarify... You define the start/end values in the vars object when creating a ScrollTrigger, but then that gets parsed into a numeric property value which is what you were looking at in the docs. That property on the ScrollTrigger instance is ALWAYS a number because it's the result of the calculations at that particular viewport size. If you resize the viewport, the number would likely change. But again, that's the result of all the calculations that are based on the start/end values you defined in your vars object. So for example, let's say you did this: let st = ScrollTrigger.create({ trigger: ".trigger", start: "top center" }); Notice the start was set to "top center" which just means "when the top of the trigger element hits the center of the viewport", but then if you check st.start you'll see a number like 523 which simply means that the ScrollTrigger will start when the page scrolls 523px from the top - that is where the top of the trigger hits the center of the viewport. If you then resized the viewport and check st.start, it may be a completely different number, like 418 which means that now that ScrollTrigger will start when the page scrolls 418px from the top because now that is where the top of the trigger hits the center of the viewport. So you were looking at that property in the docs rather than the vars configuration object properties. Here's an excerpt from the ScrollTrigger docs for the vars.start property: Is that what you're looking for?
  14. You can't have nested pinning, but you could probably use position: sticky like this: https://codepen.io/GreenSock/pen/MWRoQoV?editors=0010 Is that what you're looking for?
×
×
  • Create New...