Jump to content
Search Community

Leaderboard

Popular Content

Showing content with the highest reputation since 04/22/2024 in Posts

  1. Indeed without a minimal demo seeing the code in action it is hard to help you debug. That said have you seen my post on how to animate all types of different clip masks? Hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/jOdJGQq
    4 points
  2. Yeah that is an easy fix, check out the video below if you need any help
    3 points
  3. GSAP is highly optimised and will get it's initial values on page load, but because you tween the same element twice they both get the same starting position and because you want the second (ScrollTrigger) animation to wait for the first one to end you have to tell it to that tween some how. Luckily GSAP has you covered with immediateRender: false, if you put that on the second tween everything works as expected. Hope it helps and happy tweening! https://stackblitz.com/edit/stackblitz-starters-cgdvlq?file=components%2FBanner.tsx
    3 points
  4. Welcome to the forum. I'd probably use a yoyo and repeat:1 for the opacity in/out. Also making sure the ease is set to none as this is a scrub:true situation. https://codepen.io/PointC/pen/dyLwoej Hopefully that helps. Happy tweening and welcome aboard.
    3 points
  5. Yep, same issue - you're creating things out of order, thus they refresh in the wrong order. For example, let's say elementA is 100px from the top of the screen, and there's a ScrollTrigger that triggers when that hits the top of the screen ("top top"). So normally, the start would be 100. But what if there's another ScrollTrigger that pins an element above that one for 1000px - that'd push everything down, thus that element should trigger at 1100px instead of 100px. If ScrollTrigger calculates them in the wrong order, it'd set the first one to a start of 100px (because the pinning one hasn't been factored in yet). Here's a helper function that you can call after all of your elements are in place, and it'll order things based on their proximity to the top of the viewport: function verticalSort() { let scroll = window.pageYOffset; ScrollTrigger.getAll().forEach(t => t._sortY = t.trigger ? scroll + t.trigger.getBoundingClientRect().top : t.start + window.innerHeight); ScrollTrigger.sort((a, b) => a._sortY - b._sortY); } https://codepen.io/GreenSock/pen/ZEZPqyd?editors=0010 Better? Of course you could solve everything by explicitly stating the unique refreshPriority for each, but the above function seemed easier and it should work in most cases.
    2 points
  6. I'd also recommend using a unique class as @Rodrigo suggested. You can, however, make it work with the original HTML by using a child combinator to choose only the direct descendants of the header-icons class. gsap.to('.header-icons > div', { Happy tweening.
    2 points
  7. Hi @spotipre welcome to the forum! The angled black part you can do with a clip-path animation, see simple demo below https://codepen.io/mvaneijgen/pen/MWLxyPp And the weird image effect you can probably do with something like Pixi.js. Keep in mind that this question is kinda outside of the scope of these forums, we like to focus on GSAP specific questions, so if you still need help be sure to post a minimal demo focused on an issue with one of the GSAP tools. Hope it helps and happy tweening! https://pixijs.com
    2 points
  8. Are you sure you've updated your pen? It is always best to relink the pen or even fork, so that in the thread we can see the progress of the current version of that time. To me it seems like you've removed the functions from the parameters, this is importent, because it indicates to GSAP that is can recalculate the values, if you leave this out you tell GSAP get the value once and never update it! // From height: gsap.utils.random(10, 100, true), // Is already a function width: gsap.utils.random(0, 100) + "%", // not a fucntion // To height: () => gsap.utils.random(10, 100, true), // Better save and also convert it to a function width: () => gsap.utils.random(0, 100) + "%", // Convert to function Hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/XWQOGpa?editors=0010
    2 points
  9. Oh yes, that's exactly what i was looking for ... wouldn't have guessed i could morphSVG from a class name to another class name. Best library ever! (I promise to learn to use codepen ... it's just firefox obfuscates referrers and these embeds cause all kind of warnings, so i'm somewhat reluctant, but that's my problem to solve.)
    2 points
  10. hi @alexr8 maybe these 2 demos help 1 with draggable and 1 without https://codepen.io/GreenSock/pen/BaQXjWw?editors=0010 https://codepen.io/GreenSock/pen/RwKwLWK
    2 points
  11. Your video is around 15 seconds long, so I've split it up in three sections of each 5 seconds. First of the best thing to do when working with ScrollTrigger is to remove it! This seems counter intuitive, but ScrollTrigger is just animating something on scroll, so just focus on the animation at first and only when you're happy with the animation add ScrollTrigger back in. This way you can focus on one part at a time and it will save a lot of headache when debugging. I've enabled GSDevTools for the animation, so we can first fully focus on the animation and create what we want to happen on scroll. I've modified your HTML and CSS, I've created a .trigger element and have everything stack right on top of each other with CSS (please disable all the JS to see what it looks like) I've taken this logic from my stacking cards post I encourage you to read through it, see below Then on the timeline I've put all the tweens, frist the video tweens to 5 seconds over a duration of 5 seconds, then the video tweens to 10 seconds over a duration of 5 seconds and at the same time the first card animates in from of screen, and them the same for the next card. This is probably not fully correct, but it shows you how you can create a timeline and have things happen at the same time. I've add some ScrollTrigger code but this is commented out, but you can enable it to see what this would do on scroll, but be sure to disable it again when you want to tweak the animation. If you're new to GSAP check out this awesome getting started guide https://gsap.com/resources/get-started/ and check out this awesome tutorial how to work with ScrollTrigger. Hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/bGJOQzq?editors=1010
    2 points
  12. You where almost there! I've move your timeline outside the loop and add the ScrollTrigger logic to the one timeline, then I've add all your tweens to that one timeline and let ScrollTrigger control it. Does that make sense? Hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/qBwLJXX?editors=1010
    2 points
  13. Hi, I think the main issue here is the fact that you're using the same element as the scroller (the document element). ScrollTrigger allows you to define a scroller which is the element where ScrollTrigger will look for the scroll position in order to update any Tween/Timeline you pass to it. From the ScrollTrigger 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. https://gsap.com/docs/v3/Plugins/ScrollTrigger/#config-object Here are a couple of demos that use a similar approach: https://codepen.io/GreenSock/pen/yLRQozy https://codepen.io/GreenSock/pen/OJBvBjB Hopefully this helps. Happy Tweening!
    2 points
  14. Although this didn't feel intuitive to me in this scenario, autoScroll did fix the issue. Thanks a lot!
    2 points
  15. Hi @Sikriti Dakua welcome to the forum! What is the part you're having trouble with? In your example you have different coloured sections which each there own text, but in the example you share all the text is all just stacked right on tof of each other. If that is what you want check out my card stacking tutorial of course swap out the cards for just text, but the logic should be the same. With CSS make all the text stack right on top of each other and then just animate them in and out one by one. Also keep in mind the best thing to do when working with ScrollTrigger is to remove it! This seems counter intuitive, but ScrollTrigger is just animating something on scroll, so just focus on the animation at first and only when you're happy with the animation add ScrollTrigger back in. This way you can focus on one part at a time and it will save a lot of headache when debugging. Hope it helps and happy tweening, but if you still need help be sure to post back here with what you've tried!
    2 points
  16. It looks like your math calculations were off - you were calculating the offset from the current position but you were tweening to absolute numbers rather than relative ones. Is this what you meant to do?: https://codepen.io/GreenSock/pen/XWQQWJK But the problem with that is it's not really responsive. You're animating to specific x/y values but the original top/left absolute positioning is different, so resizing your window will result in different offsets. I think it'd be much cleaner to use a Flip animation instead: https://codepen.io/GreenSock/pen/rNbbNVe?editors=0010 Does that help?
    1 point
  17. Thank you guys! I have a rather long page with 3-4 sections in between which are dynamic and slow. Simply using the .sort() method didn't work But using the verticalSort() helper function you suggested did the trick. I just had to include ScrollTrigger.refresh() after the sorting to make it work properly: function verticalSort() { let scroll = window.scrollY; ScrollTrigger.getAll().forEach(t => t._sortY = t.trigger ? scroll + t.trigger.getBoundingClientRect().top : t.start + window.innerHeight); ScrollTrigger.sort((a, b) => a._sortY - b._sortY); ScrollTrigger.refresh(); }
    1 point
  18. The useGSAP hook has a dependency for at least React 16, but it doesn't use/install React 16: "dependencies": { "gsap": "^3.12.5", "react": ">=16" }, If you already have React 18 installing the @gsap/react package won't change a thing and won't install another version of React. I just tested this on a demo here on my local machine using the latest version of Next without any issues. We only encountered some issues while importing the @gsap/react package from esm.sh, which solves by doing this: import React from "https://esm.sh/react@18.3.1"; import ReactDOM from "https://esm.sh/react-dom@18.3.1"; import gsap from "https://esm.sh/gsap"; import { useGSAP } from "https://esm.sh/@gsap/react?deps=react@18.3.1"; We'll update the dependencies on the hook to be at least version 17 of React. Finally it would be super helpful if you could create a minimal demo that reproduces this error. Happy Tweening!
    1 point
  19. Hi, You can use Stackblitz to create a Nuxt demo and the GSAP Trial package in order to use the bonus plugins on Stackblitz: https://stackblitz.com/ https://www.npmjs.com/package/gsap-trial Here is a simple Nuxt demo: https://stackblitz.com/edit/nuxt-starter-vzsxyp?file=app.vue Hopefully this helps. Happy Tweening!
    1 point
  20. Hi @fraserYT and welcome to the GSAP Forums! You are using an extremely generic selector. I'd strongly recommend you to use a unique class in your elements even if it doesn't have any styles, just for selecting purposes. This seems to work the way you expect: <div class="header-icons"> <div class="menu-item"></div> <div class="menu-item"></div> <div class="menu-item"></div> <div class="menu-item"></div> <div class="menu-item"></div> <div class="menu-item"></div> </div> gsap.to(".header-icons .menu-item", { opacity: 0, y: -80, stagger: 0.1, scrollTrigger: { trigger: ".full-row", start: 0, end: 230, scrub: 0.5, markers: true } }); Here is a fork of your demo: https://codepen.io/GreenSock/pen/oNOVqKm Hopefully this helps. Happy Tweening!
    1 point
  21. hello @mvaneijgen your are a super star, thank your help todayif we meet in the future, beers on me
    1 point
  22. Hi @CRE-ATE welcome to the forum! What for me works best is having the scale always between 0 and 1, where 0 is the minimum and 1 is the max it can have, setting scale beyond that will result in rendering bugs/issues. So in your case make the logo as big as you want it to be and then scale it .to() the value you want it. See demo below. Hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/PogLKwP?editors=0010
    1 point
  23. In some cases, it's adequate to just call ScrollTrigger.sort() after all the ScrollTriggers are created which will set the refresh order according to the "start" value: https://codepen.io/GreenSock/pen/YzMgQrR?editors=1010 Is that what you're looking for?
    1 point
  24. Yeah, that definitely seems like a Firefox rendering bug, totally unrelated to GSAP. My guess is that the renderer needs time to create the raster image for each SVG image. It likely ignores them completely (skips creating the raster) initially because they are display: none. But once it flips to display: block once, that raster image gets created and cached by Firefox, thus it can show it faster next time. Maybe try setting ALL of the images to display: block initially, just for 1 tick maybe so that the browser gets them all rasterized/cached. Rodrigo's suggestion to go with canvas is very good too.
    1 point
  25. Hello @Rodrigoyes I will try to do it I just have to take the time given the work I have at the moment thank you
    1 point
  26. Hi, There are a few issues in your demo. First you're creating a single timeline for all the buttons, that is not going to work the way you intend, create the GSAP Tween/Timeline, inside the loop so each button controls it's own animation. Second, you have the same mask name for all the elements, which means that when one mask is animated it affects all the elements with that mask ID, create a different mask ID for each element. Here is a fork of your demo: https://codepen.io/GreenSock/pen/rNbRxrP Hopefully this helps. Happy Tweening!
    1 point
  27. Well the only thing I can see is that there is no animation at all here: gsap.to(trigger, { scrollTrigger: { trigger: trigger, start: 'top center', y: '-=100px', ease: "power1.inOut", stagger: .2, onEnter: () => { console.log('coucou') } } }) You have a GSAP to() instance but there is no animation whatsoever, just the ScrollTrigger configuration, if you remove that this is what's left: gsap.to(trigger, { }) Nothing, nada, nicht. See the problem? You need to add some property for those elements that can be animated to begin with. Finally you're planning to animate the same element that you're using as a trigger on your ScrollTrigger configuration. Be super careful about that and if possible avoid animating the trigger element because it could lead to unexpected results. Happy Tweening!
    1 point
  28. It's pretty similar in this test. https://codepen.io/GreenSock/pen/PogVJNe
    1 point
  29. Thanks, If others may need I m currently using import gsap from "gsap"; export class LifecycleManager { public ctx: gsap.Context | null; private boundAfterSwapHandler: () => void; private boundPageLoadHandlers: Map<string, () => void>; constructor() { this.ctx = null; this.boundAfterSwapHandler = this.onChangePage.bind(this); this.boundPageLoadHandlers = new Map(); document.addEventListener("astro:after-swap", this.boundAfterSwapHandler); } /** * Initialize the context */ initializeContext(): void { if (this.ctx === null) { this.ctx = gsap.context(() => {}); } } /** * Check if the component with the given ID exist in the DOM * @param id id of the element * @returns boolean */ elementExists(id: string): boolean { if (!id) throw new Error("ID cannot be null"); return document.getElementById(id) !== null; } /** * Execute the callback when the page is loaded and the component is visible * @param id id of the element * @param callback callback function */ onElementLoaded(id: string, callback: (ctx: gsap.Context | null) => void): void { if (!this.boundPageLoadHandlers.has(id)) { const handler = () => this.onPageLoad(id, callback); this.boundPageLoadHandlers.set(id, handler); document.addEventListener("astro:page-load", handler); } } /** * Callback for the page load event * @param id id of the element * @param callback */ onPageLoad(id: string, callback: (ctx: gsap.Context | null) => void): void { if (this.elementExists(id)) { this.initializeContext(); callback(this.ctx); } } /** * Revert the context */ revertContext() { if (this.ctx !== null) { this.ctx.revert(); this.ctx = null; } } /** * When changing page revert the context * and remove the event listeners */ onChangePage(): void { this.revertContext(); } /** * Cleanup all event listeners */ cleanup(): void { this.revertContext(); document.removeEventListener("astro:after-swap", this.boundAfterSwapHandler); this.boundPageLoadHandlers.forEach((handler, id) => { document.removeEventListener("astro:page-load", handler); }); this.boundPageLoadHandlers.clear(); } } export default LifecycleManager; usage <script> import gsap from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; import { SplitText } from "gsap/SplitText"; import { LifecycleManager } from "@/services"; gsap.registerPlugin(ScrollTrigger, SplitText); let manager = new LifecycleManager(); manager.executeWhenVisible("hero", () => { manager.ctx?.add(() => { const childSplit = new SplitText("[data-hero-text-reveal]", { type: "lines", linesClass: "split-child", }); const parentSplit = new SplitText("[data-hero-text-reveal]", { // type: "lines", linesClass: "split-parent", }); gsap.timeline() .set("[data-hero-text-reveal]", { opacity: 1 }) .from(childSplit.lines, { yPercent: 300, skewY: 7, stagger: 0.2, }) .to( "[data-hero-reveal]", { opacity: 1, stagger: 0.1, }, "<=", ); const pathsToAnimate = document.querySelectorAll( '[wb-element="path-to-animate"]', ); pathsToAnimate.forEach((path) => { const finalPath = path.getAttribute("wb-final-path"); gsap.timeline({ scrollTrigger: { trigger: path, start: "top bottom", end: "bottom top", scrub: 1, }, }).to(path, { attr: { d: finalPath || "" }, ease: "none", }); }); }); }); </script>
    1 point
  30. Hi, In your original demo you had both toggleActions and scrub in your ScrollTrigger configuration. It has to be one or the other, but definitely not both, since they pretty much don't work together. From the ScrollTrigger docs: https://gsap.com/docs/v3/Plugins/ScrollTrigger/#config-object scrub Boolean | Number - Links the progress of the animation directly to the scrollbar so it acts like a scrubber. You can apply smoothing so that it takes a little time for the playhead to catch up with the scrollbar's position! It can be any of the following Boolean - scrub: true links the animation's progress directly to the ScrollTrigger's progress. Number - The amount of time (in seconds) that the playhead should take to "catch up", so scrub: 0.5 would cause the animation's playhead to take 0.5 seconds to catch up with the scrollbar's position. It's great for smoothing things out. toggleActions String - Determines how the linked animation is controlled at the 4 distinct toggle places - onEnter, onLeave, onEnterBack, and onLeaveBack, in that order. The default is play none none none. So toggleActions: "play pause resume reset" will play the animation when entering, pause it when leaving, resume it when entering again backwards, and reset (rewind back to the beginning) when scrolling all the way back past the beginning. You can use any of the following keywords for each action: "play", "pause", "resume", "reset", "restart", "complete", "reverse", and "none". I'd assume that Jack picked scrub over toggleActions, since your demo was scrubbing, but most definitely I can't read his mind! 😉 Hopefully this clear things up. Happy Twening!
    1 point
  31. But when the dependency is updated, the entire hook runs again and you have some lingering GSAP instances that are pointing to an element that is not rendered yet because of the useEffect/useLayoutEffect double call React does on Strict Mode. The useGSAP hook will revert only in the initial call of the hook but not when the dependencies are updated, why? Because we wanted to give users the opportunity to put all their logic in the useGSAP hook instead of creating a useGSAP and a useEffect hook, but not every time you need to re-run some logic because of a state/prop change you need to revert and re-create your GSAP instances, enter revertOnUpdate. With that useGSAP will not only run your logic inside the hook on a state/prop update but also revert and re-create your GSAP instances. Hopefully this clear things up. Happy Tweening!
    1 point
  32. Yes this is what I was looking for!!! I never knew about the immediateRender: false! Just one question: you removed toggleActions, but As I scroll back it it moves in reverse, why? Thanks for solving my problem!
    1 point
  33. No, that is why I said: Everything is hard coded right now, because that is the easiest way to demonstrate how the logic works. I have no idea how Svelt works, but I would get the elements as soon as they are ready and grap their heights and then add that to the array.
    1 point
  34. Hi @Sandeep Choudhary welcome to the forum! You just needed to scope the pin: ".right" element eg pin: galleryObj.querySelector(".right"), otherwise it would always gets the first .right element. Hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/ExJGMed?editors=0011
    1 point
  35. Hi @vexkiddy welcome to the forum! Am I missing something? I don't see any GSAP code! Again we would love to see what you can come up with that way we can better help you understand the tools, so please try to get something working then someone here will definitely point you in the right direction. If you're new to GSAP check out this awesome getting started guide https://gsap.com/resources/get-started/ Hope it helps and happy tweening!
    1 point
  36. Thanks, that's helpful. I went with the second suggestion and refactored my scroll effects to use the regular ScrollSmoother body transform. I was also able to use pinning to achieve the "pause" effect.
    1 point
  37. Hi @mukeshKumarSardiwal1997 and welcome to the GSAP Forums! Besides echoing the need for a minimal demo, there are a few things to note about your snippet. When using our useGSAP hook there is no need for manual cleanup of your GSAP/ScrollTrigger instances, the hook does that for you, so there is no need for this: useGSAP(() => { const tl = gsap.timeline.to(element, { scrollTrigger: {}, }); return () => { ScrollTrigger.revert(); }; }); Finally the onRefresh is a callback that works on the config object, but that can't be invoked directly like this: rwd.vars.scrollTrigger.onRefresh() You should be getting an error indicating that onRefresh is not a function. If you want to refresh a specific ScrollTrigger instance just do this: rwd.vars.scrollTrigger.refresh(); https://gsap.com/docs/v3/Plugins/ScrollTrigger/refresh() Hopefully this helps. Happy Tweening!
    1 point
  38. Aha! I forgot about the 'sticky' argument in this.update()
    1 point
  39. Case solved Cause: Incorrect syntax. Change: ScrollTrigger.create({ target: ".services-content-heading-inner", start: "top top", end: "bottom bottom", markers: true }); To: gsap.fromTo('.services-content-heading-inner', { yPercent: 100 }, { yPercent: 0, autoAlpha: 1, duration: 2, ease: easeInOut, scrollTrigger: { trigger: '.services-content-heading-inner', start: "top top", end: "bottom bottom", markers: true } } ); Thank you!
    1 point
  40. I noticed several problems: You had faulty markup (missing closed </div> tags) You were defining a containerAnimation for the getScrollLookup(), but only some of the elements were in the containerAnimation. That is not valid. You were pinning a container element, but you didn't define that in the getScrollLookup() config. Is this more of what you wanted? https://codepen.io/GreenSock/pen/RwOEWYW?editors=0010
    1 point
  41. Hi @Renson Ralph Bitara and welcome to the GSAP Forums! There is a lot of code in your demo and we don't have the time resources to comb through all that and find what the issues could be. After a quick glance I can see some issues in your code though. What is this actually doing? What's the purpose of this? window.addEventListener( "load", function (e) { init(); setInterval(function () { ScrollTrigger.refresh(); }, 100); }, false ); A setInterval will keep executing over and over. That doesn't look right to me, to be refreshing every ScrollTrigger instance every 100 milliseconds. I don't see the use of that particular code. Then you have this: gsap.fromTo( ".services-content-heading-inner", { yPercent: 100 }, { yPercent: 0, autoAlpha: 1, duration: 2, ease: easeInOut } ); ScrollTrigger.create({ target: ".services-content-heading-inner", start: "top top", end: "bottom bottom", markers: true }); You are creating an animation, then you create a ScrollTrigger instance, but what's the objective of that ScrollTrigger? What is actually controlling? For what I can see nothing really. Finally this: ScrollTrigger.create({ start: 0, end: "max", onUpdate: updateValues }); By default this ScrollTrigger instance will work with the window element and scroll position, so that means everytime the user scrolls that function will be called. Again I don't see the use of this. If you want to know if something is in the viewport, why not create a ScrollTrigger instance for that specific element that can tell you whether or not that element is in the viewport? I think you are overcomplicating things quite a bit and you should take a few steps back and go for simpler things first and then start adding more animations and complex stuff to your app. Finally I suggest you to take a look at our getting started guide: https://gsap.com/resources/get-started and a closer look to the ScrollTrigger docs and demos in order to get a better grasp of how ScrollTrigger works: https://gsap.com/docs/v3/Plugins/ScrollTrigger/ Happy Tweening!
    1 point
  42. Why do you have to change the token in dev mode? Surely reading it from the .env file should be adequate? Having to change this every time you want to make a commit is a massive headache. I've tried time and time again to use the gsap token from the env file and keep getting the same 'bad auth' error. I've tried setting it as a plain env variable, I've tried exporting it in the env file, I've tried prefixing it with NPM_CONFIG, nothing works. Nevermind, I didn't realise that you had to store the env variable in bash for it to be replaced in npmrc locally. Today I learned.
    1 point
  43. I complain about using pre-fab code as it's generally too much work to reverse-engineer and tweak but that's what I was doing right here. Came up with a straight CSS/jQuery solution in like 30 minutes versus the hours I was working on the previous code. Plus I can expand with GSAP if need be but works great just like this if anyone else is looking for the same thing (and can add in GSAP) *I'll add to this CodePen if I end up infusing some GSAP though to keep it relevant to the community https://codepen.io/ilrobinson/pen/ExJOvga
    1 point
  44. Thanks for reporting back! Great news that the Lenis team worked fast on this and that everything is working as expected!
    1 point
  45. Thanks for the demo. In the future please add new information to new replies. Editing the first post repeatedly makes it difficult for us and others to follow the conversation. I don't know enough about swiper in react to help you with this, particularly how to reference the Swiper inside the onChange callback. However, this bare-bones example shows how to animate the active slide (change it's scale) and animate something inside it (rotate the number div) Hopefully you can find a way to apply something similar to your project https://codepen.io/snorkltv/pen/WNmzezX?editors=0011
    1 point
  46. 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.
    1 point
  47. run into similar issue using the app directory in NextJS 13. I'm using ScrollTrigger and ScrollSmoother plugin and managed to fix it by moving the gsap.registerPlugin(ScrollTrigger, ScrollSmoother) inside of useEffect/ useIsomorphicLayoutEffect hook. hope this helps
    1 point
  48. Hi @yannick love and welcome to the GreenSock forums! You can try the bonus plugins on your local environment or in Codesandbox and Stackblitz by installing the GSAP Trial package: https://www.npmjs.com/package/gsap-trial Just run: npm install --save gsap-trial If you purchase a Club GreenSock membership, then you can generate a private NPM token in order to safely install and deploy the bonus plugins as mentioned in the docs: https://greensock.com/docs/v3/Installation#npm-club Let us know if you have more questions. Happy Tweeniing!
    1 point
  49. I couldn't help myself - I imagine this may assist others looking to do something similar so I went ahead and created this solution: https://codepen.io/GreenSock/pen/zYRmbEM?editors=0010 The basic concept is to create a simple ScrollTrigger for each box and then use the "start" of each of those to calculate the 0-1-based progress value for snapping on the overall section ScrollTrigger. Does that help?
    1 point
  50. @OSUblake, thank you for your response. At the moment, I set for the trigger end '3000px', but I would like to have this value dynamical because my users will have different number of items there. So I need to calculate the height of the trigger dynamically. Hopefully I express it clearly. Would it be possible to use something like this to get the height of all images (or something else with a clear height) there and use this value as trigger end? let contents = document.querySelectorAll('.image-container') let contentHeight = gsap.getProperty(contents, "height"); Here my .js gsap.registerPlugin(ScrollTrigger); let tl = gsap.timeline({ scrollTrigger: { trigger: ".layer-story-pinned-content", scrub: true, pin: true, start: "top 30", end: '3000px', //endTrigger: '.layer-story-pinned-content', markers: true } }); tl.from( ".layer-story-content-wrapper", { y: 20, autoAlpha: 0, stagger: 0.5 }, 0 ).to( ".layer-story-content-wrapper", { y: 0, autoAlpha: 0, stagger: 0.5 }, 0.4 ); tl.from( ".layer-story-image", { y: 0, autoAlpha: 0, stagger: 0.5 }, 0 ).to( ".layer-story-image", { y: 0, autoAlpha: 1, stagger: 0.5 }, 0.4 ); https://codepen.io/jankout/pen/ZEJOypz
    1 point
×
×
  • Create New...