Jump to content

GreenSock last won the day on September 22

GreenSock had the most liked content!


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by GreenSock

  1. Scaling just stretches things. And border-radius is a tricky thing to set directly like that when there are different values for the different axis since it's a complex property (8-in-1). In this case, it's better to set it directly in the onUpdate rather than going through GSAP: https://codepen.io/GreenSock/pen/xxmPWqa?editors=1010 Honestly, I doubt you'd notice any real-world performance difference if you just animate width instead of trying to calculate and update the border-radius on every single tick. It's simpler to just turn off the scale: true option.
  2. Very sorry about that, @stijlmassi and @grizhlie, but Lenis is a completely different type of solution. Both ScrollSmoother and Lenis have pros and cons to their approaches. Our original goal was to leverage native scroll technology (no scrolljacking, just let the user drag the scrollbar wherever they want but have the content smoothly "catch up"). This means that EVERY way of scrolling gets smoothed (drag the scrollbar, press the arrow or spacebar keys, etc.) whereas I think Lenis is more about intercepting mouse wheel events, preventing them, and basically creating a tween of sorts that updates the scrollTop/scrollLeft value. But it won't smooth if you scroll in other ways, as mentioned earlier. And of course ScrollSmoother has a bunch of extra features like lag and speed effects, etc. I'm not criticizing Lenis at all - if it suits your needs, fantastic. Use it. Works great with GSAP/ScrollTrigger. But the fundamental nature of HOW things get scrolled is completely and radically different in ScrollSmoother. It's simply not possible, as far as I know, to completely solve the issues you mentioned while at the same time smoothing all of those inputs across the board and avoid scrolljacking. In a future major release, we very well may opt for a totally different approach but for now it's not really feasible (as far as I know) to "fix" what you mentioned because Safari is just absolutely terrible with various scroll-related bugs. We've spent many hundreds of hours trying to come up with the silver bullet workaround and the response we got from the Safari team was basically "nope, it's impossible". We'll definitely continue to look for ways to improve things in the coming months. If anyone has specific suggestions, we're all ears.
  3. Thanks for seeking clarification, @Jack_8123. We always appreciate folks who are diligent about honoring the licensing terms. Our entire business model is built on the honor system and trust. It's totally fine if your payment gateway takes a fee during checkout for products that [themselves] don't use GreenSock technology. The usage you described is covered under the standard "no charge" license because the furniture obviously doesn't use GSAP and your web site isn't charging any fees to access certain parts or features of the site (right?). Enjoy! 💚
  4. Yeah, Flip uses x/y transforms to do its magic, but you had a "mousemove" handler that was simultaneously trying to control the same properties, animating them to completely different positions. You created conflicting tweens. Make sense?
  5. The only time you need to use the "targets" property is when you're trying to animate (Flip) a set of targets that is different than the one in the getState() object. By default, it'll just use the same targets that had their state captured in the Flip.getState() call. So if it matches that, there's really no need to explicitly define a "targets" property. Make sense?
  6. I definitely wouldn't do that. I think it'd be helpful if you tried wrapping your head around how browsers render things and the performance ramifications. Think through how many pixels the browser is forced to re-calculate on each tick. GSAP itself can rip through stuff SUPER fast, but in 99.9% of the cases, the slowdown is due to graphics rendering in the browser. GSAP might take up 0.5% of the resources and the rest might be eaten up by layout and graphics rendering. The key is to make it cheaper on the browser to do all those tasks. Transforms are far, far cheaper for the browser than if you're changing the top/left/width/height of the elements because those properties cause layout reflow (expensive). As I said earlier, if you're scaling things up too much, some browsers will pixelate so the solution is to make the native dimensions bigger and adjust your scale values accordingly (I already described this technique in my last post). You're asking the browser to fabricate a LOT of pixels on every tick the way you're doing it right now. I'm not surprised Safari is slowing down. Again, it's totally unrelated to GSAP. Performance is a very deep topic, but here are some general tips: Try setting will-change: transform on the CSS of your moving elements (I know in your case this caused pixelization, but if you employ the last technique I mentioned, it'd likely resolve that). Make sure you're animating transforms (like x, y) instead of layout-affecting properties like top/left. Definitely avoid using CSS filters or things like blend modes. Those are crazy expensive for browsers to render. Be very careful about using loading="lazy" on images because it forces the browser to load, process, rasterize and render images WHILE you're scrolling which is not good for performance. Make sure you're not doing things on scroll that'd actually change/animate the size of the page itself (like animating the height property of an element in the document flow) Minimize the area of change. Imagine drawing a rectangle around the total area that pixels change on each tick - the bigger that rectangle, the harder it is on the browser to render. Again, this has nothing to do with GSAP - it's purely about graphics rendering in the browser. So be strategic about how you build your animations and try to keep the areas of change as small as you can. If you're animating individual parts of SVG graphics, that can be expensive for the browser to render. SVGs have to fabricate every pixel dynamically using math. If it's a static SVG that you're just moving around (the whole thing), that's fine - the browser can rasterize it and just shove those pixels around...but if the guts of an SVG is changing, that's a very different story. I'd recommend strategically disabling certain effects/animations and then reload it on your laptop and just see what difference it makes (if any). Ultimately there's no silver bullet, like "enable this one property and magically make a super complex, graphics-heavy site run perfectly smoothly even on 8 year old phones" I hope this helps! 💚
  7. That's because you've got the default ease on the animation of "power1.out", so when you snap to perfect 1/3rd increments, it's not linear. For example, halfway through the tween, the actual movement of the element might be more like 85% because the easing smooths out at the end. Set it to ease: "none" to make sure the mapping is linear. I assume you meant to do this?: https://codepen.io/GreenSock/pen/VwqMrVv?editors=0110
  8. Hi @PapaDeBeau. Are you talking about with ScrollSmoother in particular? Or a non-ScrollSmoother-controlled page? It'd definitely increase your chances of getting a solid answer quickly if you provide a super minimal demo showing just a basic idea of what you want to do (even if it's not functional). And are you trying to navigate to an anchor onclick or when the page loads? ScrollSmoother has a very easy way to animate to a particular element: https://greensock.com/docs/v3/Plugins/ScrollSmoother/scrollTo() And if want to do that onload, @Cassie already had that in her demo. You could do: window.addEventListener("load", () => { let urlHash = window.location.href.split("#")[1], scrollElem = document.querySelector("#" + urlHash); if (scrollElem) { // if you've got a ScrollSmoother instance... smoother.scrollTo(scrollElem); // otherwise... gsap.to(window, { scrollTo: scrollElem }); // don't forget to load/register ScrollToPlugin } }); Does that help?
  9. I noticed several problems: You've got a 3rd party library that's applying a CSS animation that's interfering. Specifically, the animate-fade-down class. You're using a setTimeout() for some reason (typically it's better to use gsap.delayedCall()) and you didn't do proper cleanup of that timeout id. Remember that React calls the useEffect()/useLayoutEffect() TWICE in strict mode, so you're creating duplicate calls that are creating duplicate animations. You weren't adding the Flip animation to the context. Remember that it'll only record animations that are created DURING that gsap.context()'s function invocation, but you're delaying them for 2 seconds, so they're not happening during that invocation. Just use the .add() method to add them. You're making DOM changes that affect more than just the .flip-container element. You should include the other element(s) in your Flip animation and getState() too. https://codesandbox.io/p/sandbox/sweet-water-h898lt?file=/src/pages/Home/index.jsx:9,33 I hope that helps.
  10. You don't need that gsap.context() wrapper because gsap.matchMedia() IS essentially a specialized gsap.context(): https://codesandbox.io/s/keen-cartwright-dqqvz4?file=/src/App.js Better? Also, did you try updating to the latest version of GSAP? I noticed you were using 3.11.x
  11. I'm not a React guy, but it if you console.log(gsapApp.current), you'll see that it's undefined. So that's the problem - you're trying to define the scope as something that's undefined. The scope should either be an Element or a Ref whose .current property is an Element. That isn' the case in your demo.
  12. I'm sure there's a reasonable explanation and there's something in your project that's causing the issue, but without a minimal demo that clearly illustrates the problem, we can't effectively diagnose what's going on. Are you using React or any other 3rd party framework? Are you absolutely positive you're not double-creating things?
  13. There are fundamental logic flaws in the way you're engineering things (if I'm understanding your goal correctly). When you unpause that first tween, it renders at its end state because the parent timeline's playhead is PAST where that tween ends. Since you pause() the timeline, there's no reason for that 2nd tween to render again at that point because it already rendered there and the playhead hasn't moved. I'm curious why you're building it that way. If you think about how those tweens are laid out in the timeline, you'd expect x to jump to 200 and then just stay there (the second tween animates x from 200 to 200, meaning it would look like it's doing nothing). That isn't happening because you're short-circuiting things by pausing the first tween, getting the second one to render and lock in its starting/ending values in a way that's abnormal (ignoring the effects of the first tween), and then circling back and unpausing the first tween after the playhead has already passed its end position. Very very odd in my view. I suspect there's a much cleaner way of accomplishing what you're after that doesn't involve short-circuiting things in odd ways. I mean technically you can force it to render the way you want like this: // OLD pausedFromTweensToggle(false); timeline.pause(); // NEW pausedFromTweensToggle(false); let time = timeline.time(); // record the current time timeline.progress(0).time(time).pause(); // rewind, then jump back to the current time to force everything to render at that state https://codepen.io/GreenSock/pen/yLGoGdY?editors=1010
  14. A few ideas: Delete the .cache folder in node_modules. https://stackoverflow.com/questions/40742538/clearing-webpack-cache Run npm cache clean --force in terminal Delete you package-lock.json file Maybe even delete your whole local project and download it again from github and try all over again(?)
  15. @1N54N3 I'm not seeing any unexpected behavior. It's important that you understand how tweens work... The very first time a tween renders, it records the start and end values internally so that it can very quickly interpolate between them. There are two issues I see in your setup: You're setting overwrite: true on your 2nd tween which will IMMEDIATELY find any tweens of that same target and kill them. So that wipes out your "moveFrom" tween. You initially paused your timeline, so none of the "to" tweens inside of that will render right away. Then, when you click "play", you're pausing the "moveFrom" tween, thus it never had a chance to render even once and record internally the start/end states. So of course your "moveTo" tween runs from the current value (0). All exactly as expected. Then later, if/when you unpause that "moveFrom" tween, it'll record the start/end values at that point. Since it's a "to" tween, it just uses the CURRENT value as the "from". At the point it renders for the very first time then, you've probably got x at 200 from the other tween. Does that clear things up? You're welcome to use .fromTo() tweens if you need total control of both ends (start/end). Or you can force a render of the tweens in the timeline by doing something like timeline.progress(1).progress(0) before pausing anything internally.
  16. Yeah, that's pretty odd. Again, it's not GSAP-related. You could try wrapping that <div> in a container <div> and animate that container instead. At this point it's a matter of trying to force Chrome to render it correctly. 🤷‍♂️
  17. Yeah, this definitely sounds like some kind of caching issue in your build tool(?) I'd try doing everything you can to clear out any caching you've got (not browser cache - more like your bundler, NPM, etc.)
  18. That makes me a bit nervous, @Aitor. I don't think that's actually a solution. It sure sounds like maybe you accidentally created multiple/conflicting tweens/ScrollTriggers on the same element(s)? Super hard to tell without a minimal demo. Or maybe what you're running into is the refresh() that happens on mobile when the screen resizes due to the address bar showing/hiding. I wonder if ignoring that would help, like: ScrollTrigger.config({ ignoreMobileResize: true }); 🤷‍♂️
  19. I can't reproduce that either, but it's definitely unrelated to GSAP. Have you tried adding will-change: transform in your CSS? Or you can also try adding force3D: false to your tween. I'm curious if either of those solve it for you.
  20. You mean like this?: https://codepen.io/GreenSock/pen/dywzYrO ScrollTrigger.create({ start: 1, // as soon as the user scrolls down even 1 pixel, trigger onEnter: () => gsap.to(".main-tool-bar", {top: 0}), once: true }); By the way, I noticed you had a CSS transition on the element you were animating with GSAP. You definitely shouldn't do that. It'll perform much, much better if you just let GSAP handle it. Otherwise, the CSS animation constantly interferes and tries to restart gradually animating the value that GSAP just tried to set.
  21. That definitely sounds like custom logic stuff (beyond the scope of free help we can provide here), but here are some comments: Browser graphics rendering will definitely perform better if you animate transforms instead of width/height/top/left. So if I were you, I'd animate x/y and scale only. And when you animate the highlighted scale bigger, you'd need to move all the elements to the left/right to make room for that growth. It might work best to just think of the entire thing like one timeline with sequenced animations (almost like it goes through the succession of the first one being selected, then the second one, then the third one, etc.) and just embed the animations accordingly into a single timeline. Pause that animation and then all you do is animate the playhead to do your highlighting based on the user's interaction. Like if they click to go to the 2nd element, perhaps that's at a time of 2.5 seconds on the timeline, so you animate the playhead there. You can literally animate the playhead like any other object, like gsap.to(timeline, { time: 2.5, duration: 1 }) Good luck! If you get stuck, feel free to post a minimal demo that clearly illustrates the issue with as little code as possible, and we can answer GSAP-specific questions. If you need custom logic help, you can contact us for paid options or post in the Jobs & Freelance forum. 👍
  22. I can't think of any demos at the moment, but since you'd be constantly updating the destination scrollLeft property on every wheel/touch event, instead of creating a new tween instance each time (gsap.to(...)), I'd strongly recommend using a gsap.quickTo() because it simplifies things and also is more performant. 👍
  23. In case my previous explanation didn't make it clear enough (we typed our responses at the same time )... It's not "muddled" - it's protected. If we didn't put those there, your element could suddenly jump when the GSAP animation ends if you've got CSS rules somewhere that affect the element. See what I mean? If you really need to remove those, you could use clearProps. But I'm curious: is there some real-world symptom you're wrestling with related to these inline styles?
  24. Yes, that's completely normal. The reason it must do that is because modern browsers introduced individual transform components which can interfere with "normal" ones. For example: /* standard */ transform: rotate(45deg); /* newer alternate */ rotate: 45deg; For maximum compatibility and performance, GSAP always uses "transform" (only). But imagine what would happen if you had CSS like this: .box { rotate: 45deg; } And then you do this: gsap.to(".box", { rotation: 90 }); Which would result in the inline style like this: <div class="box" style="transform: rotate(90deg)"></div> Great, but now it has a "transform" inline, AND a CSS rule that says rotate: 45deg. DOH! What's the browser supposed to do? Combine/Add them together (135deg)? Completely ignore one of them even though they're different CSS properties? Browsers are notorious for making those decisions differently, so for example maybe Chrome would have the transform override the rotate, and Firefox may make the rotate override the transform. And maybe Safari would combine them. So we add those inline styles to ensure complete uniformity and compatibility. Does that clear things up?