Jump to content
Search Community

All Activity

This stream auto-updates

  1. Past hour
  2. Hi, I would always try to keep the animations for each component inside the component. Often is said as a best practice in React that a component should do just one thing, so I'm not really into the approach of having a component handling animations of elements that are not rendered by that component. I have a couple of code bases but those are protected by NDAs so I can't share them. One is this: https://wiredave.com/artificial-intelligence That's GSAP & Next(12), the project manager always talked about moving away to Nuxt for several reasons I won't share here but it seems they're still using Next. Every section in that site, regardless how small and simple it is, is a component and the animation resides inside the component and you can see that there is no lag, FOUC or any other issue with the initial load. There is no real gain in terms of creating a number of GSAP instances rather than just one, unless you create thousands of them at the same time, which rarely is the case. Also is always better to make your files more concise and smaller in order to make maintenance easier down the road. In 3 to 6 months or perhaps a few years down the road, it'll be far easier to decipher what you're doing in a smaller file rather than a large one. Those are my two cents on the subject. Hopefully this helps. Happy Tweening!
  3. Hi, Sorry to hear about the issues, but the demo is working as expected, so definitely is not a GSAP related issue. Most likely something else in your setup (CSS most likely) is interfering with this, so you'll have to look for that. Also keep in mind that the particular demo that was linked is using this stylesheet as well: https://codepen.io/GreenSock/pen/xxmzBrw.css Maybe the styles you're missing are there. Hopefully this helps. Happy Tweening!
  4. Hi, Two things. First, proper cleanup is very important with frameworks, but especially with React. React 18 runs in strict mode locally by default which causes your useEffect() and useLayoutEffect() to get called TWICE. Since GSAP 3.12, we have the useGSAP() hook (the NPM package is here) that simplifies creating and cleaning up animations in React (including Next, Remix, etc). It's a drop-in replacement for useEffect()/useLayoutEffect(). All the GSAP-related objects (animations, ScrollTriggers, etc.) created while the function executes get collected and then reverted when the hook gets torn down. Here is how it works: const container = useRef(); // the root level element of your component (for scoping selector text which is optional) useGSAP(() => { // gsap code here... }, { dependencies: [endX], scope: container }); // config object offers maximum flexibility Or if you prefer, you can use the same method signature as useEffect(): useGSAP(() => { // gsap code here... }, [endX]); // simple dependency Array setup like useEffect() This pattern follows React's best practices. We strongly recommend reading the React guide we've put together at https://gsap.com/resources/React/ Two, you have this on your setup: onUpdate: (self) => { const progress = self.progress; const index = Math.floor(progress * images.length); // HERE setCurrentPrayerIndex(index); gsap.set(`#image-${currentPrayerIndex}`, { rotation: 0, scale: 1, zIndex: prayers.length, }); // Reset rotation, scale, and z-index }, The onUpdate callback of a ScrollTrigger instance is going to fire everytime the scroll position is updated. Do you really want to update the state of your component everytime the user scrolls? On top of that since that state property you're updating is on the useEffect hook and you're not doing proper cleanup, the GSAP Timeline is being created again and again and again, so everytime the user scrolls you have more and more GSAP Timelines and ScrollTrigger instances, which is a memory leak. I would strongly recommend you to not use ScrollTrigger for now, just focus on creating the animation. Once the animation is working the way you intend, then you can add ScrollTrigger back into the mix. Also take a look at the useGSAP hook and the article link I shared in order to bbetter understand how things are wired up when using GSAP in a react app. Happy Tweening!
  5. Today
  6. Hi, This is not actually related to GSAP but just the way browsers work and the inner works ScrollTrigger has to do in order to do it's calculations. ScrollTrigger takes the page back to the top in order to make the calculations and make sure everything is rendered and positioned the way it should, something that is more difficult if the scroll position is not at the top. In your particular case, since you have toggleActions in your setup, that tells ScrollTrigger to play the timeline which hides the large logo and shows the small one. What you could try is to store if the scroll is more than 0 (meaning that is not at the top) in local/session storage. Then when the page is refreshed you check that if it is, you could set the timeline's progress at 1. Maybe the ideas in these threads could help: Hopefully this helps. Happy Tweening!
  7. Asking the following with a concern for performance, rather than code cleanliness or reusability: Is one better off using a single Scrolltrigger, or multiple, when animating elements across different components, but all on the same page? Some context — I'm using useGSAP in React (Next) to animate a timeline with Scrolltrigger that runs the length of a landing page. The elements animated are contained across several components, representing different sections of the page. On one hand, it is obvious to me that a single Scrolltrigger is less overhead than multiple (less initialization etc.). On the other hand, I'm unsure what GSAP does behind the scenes as far as ignoring out of viewport elements and so on. So - if I am using a single Scrolltrigger (less overhead), could I still be incurring more cost, since GSAP is tracking elements I no longer care about? Am I just better off using multiple Scrolltriggers and aggressively scoping? If anyone has any repos or sandboxes demonstrating suggested patterns that'd be much appreciated. (Hopefully higher level/concept questions are okay - and sorry if this is something touched on already - I tried searching for several minutes but couldn't find anything satisfactorily clarifying. Thanks!)
  8. I have tried this but doesn't seem to work for me. the stack doesn't go behind, it just gets off the stack and hides
  9. Cool thanks, I just found this link in another thread and tried it out in Vue. https://stackblitz.com/edit/vitejs-vite-onqhee?file=src%2FApp.vue&terminal=dev It seems to work in stackblitz, but in my project I cant get horizontal scroll to work... all the panels are stacked vertically instead of 'flex' and i can only scroll vertically. The css and the js is all copied identical. I've also checked the gsap and scrolltrigger are both installed correctly. What typically is the issue when the animations don't work? It seems like gsap isn't working
  10. Hey everyone, I love what you can do with GSAP, but I'm a total newbie and struggling with even horizontal scroll. I tried your demo for vue horizontal scroll, but can't seem to get it work in my vue project. Any advice? Thanks!
  11. Thank you so much for your reply, i solved my issue in this post: but i cannot delete this post
  12. Hi, I'm not really clear on what you're trying to do here, but maybe this video by @Carl could help: Happy Tweening!
  13. Hi, Maybe this demo could help: https://stackblitz.com/edit/github-2hpcon-yct8bb?file=src%2Fcomponents%2FLayout.astro It does uses ScrollSmoother, GSAP's smooth scrolling solution, which is a perk of GSAP Club users: https://gsap.com/docs/v3/Plugins/ScrollSmoother/ https://gsap.com/pricing/ Hopefully this helps. Happy Tweening!
  14. Hi, I believe the issue here is that the trackpad keeps dispatching a wheel event even after the user's interaction with the trackpad has ended. This is not a GSAP related issue, but the way trackpads (and apple magic mouse I believe) works. What you can do is create a safeguard, like a boolean that gets toggled when the wheel event is fired and then toggled back when the animation has completed. Something like this: https://codepen.io/GreenSock/pen/NWVKVwx Hopefully this helps. Happy Tweening!
  15. Hi, Maybe a different logic for every element that is not the first, instead of selecting the ScrollTrigger for the current element and using that start point, use the previous ScrollTrigger (if any) end point: const menuLinks = gsap.utils.toArray("header ul li button"); menuLinks.forEach((elem, i) => { elem.addEventListener("click", function () { let target = elem.getAttribute("data-panel"), trigger = ScrollTrigger.getById(target); if (i > 0) { target = menuLinks[i - 1].getAttribute("data-panel"); trigger = ScrollTrigger.getById(target); } gsap.to(window, { duration: 1, scrollTo: i > 0 ? trigger.end : trigger.start, overwrite: true }); }); }); Hopefully this helps. Happy Tweening!
  16. Hi, Also you can borrow some logic from this demo for the flying flair: https://codepen.io/GreenSock/pen/dywBqWJ Hopefully this helps. Happy Tweening!
  17. Hi, I'm not sure what could be the issue here without a minimal demo, clearly something in the styles you're applying is causing this, because the tailwind styles in Jack's demo are working as expected.
  18. Hi, Maybe something like this: ScrollTrigger.create({ trigger: ".parallax-upper-area", start: "top+=20% top", end: "bottom bottom", endTrigger: ".parallax-below-area", pin: ".parallax-upper-area", pinSpacing: false, markers: true }); Or maybe switch the start to this perhaps: ScrollTrigger.create({ trigger: ".parallax-upper-area", start: "top top+=20%", end: "bottom bottom", endTrigger: ".parallax-below-area", pin: ".parallax-upper-area", pinSpacing: false, markers: true }); Also this could be an option: ScrollTrigger.create({ trigger: ".parallax-upper-area", start: "top+=20% top", end: "+=450", pin: ".parallax-upper-area", pinSpacing: false, markers: true }); Unfortunately the description you provide is not completely clear to me, so I'm taking my best guesses here in terms of what you're trying to do. Hopefully this helps Happy Tweening!
  19. hi @mvaneijgen sorry i should have made it live. kindly find the link attached. https://codesandbox.io/p/live/d420f010-2f4f-456a-bac2-95f22efb5f30
  20. Hi @jaeyholic welcome to the forum! Your codesandbox link is not working, maybe you didn't publish it yet? Personally I like to work in Codepen, just plain HTML, CSS and JS, so that I don't have to worry about my preferred library of choice throwing errors and really can focus on the effect I'm going for, but of course to each their own. 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. It is probably not the effect you're going for, but maybe it points you in the right direction. This one works on click, but could also work on scroll, again everything in GSAP starts with an animation and you can then hook it to what ever you like to play that animation. Hope it helps and happy tweening! https://codepen.io/GreenSock/pen/Yzdzxem
  21. I am new to GSAP and I love it so far. I am working on this project but I am facing an issue now. I want to pin a section, then when scrolling, the stacks on images change, set the currentIndex state with the new index, and update the data on the right side of the section. when the current image, leaves the stack, I want it to go to the back of the stack, and the current image comes on top. I have been struggling to finish it and need some help, please. Codesandbox link: https://codesandbox.io/p/devbox/epic-hill-qgf7r5?file=%2Fsrc%2FApp.jsx%3A111%2C73&workspaceId=832ea3ad-fd7e-4423-a361-77ecef5fb412
  22. Hi @xMrCrunchyx welcome to the forum! Did you know GSAP has its own matchMedia() build i which has some nice features when working with GSAP for instance doing some clean up and reinitiating code when breakpoints are met, check it out https://gsap.com/docs/v3/GSAP/gsap.matchMedia() If that doesn't, work we would love to see a minimal demo, so that we can take a deeper look at your code in action. Hope it helps and happy tweening!
  23. I've successfully implemented horizontal scrolling using GSAP, and it's performing admirably. All my elements utilize dynamic values like this: width: max(20px, calc(1.39vw * var(--scale))); font-size: max(16px, calc(1.11vw * var(--scale))); While resizing the window with values still in pixels, everything behaves as expected. However, when the window expands and switches to "vw" units, I encounter an issue where my content gets cut off at the end. This occurs specifically when transitioning from a smaller window size to a larger one in the "vw" range. Any guidance on resolving this issue would be greatly appreciated! Below is the code for my horizontal scrolling functionality: function horizontalScroll() { gsap.registerPlugin(ScrollTrigger); let sections = gsap.utils.toArray(".horizontal-section"); let container = document.querySelector(".horizontal-container"); container.style.width = container.scrollWidth + "px"; if (window.matchMedia("(min-width: 992px)").matches) { gsap.to(sections, { x: () => -(container.scrollWidth - document.documentElement.clientWidth), ease: "none", scrollTrigger: { trigger: ".horizontal-container", pin: true, scrub: 0.6, end: () => "+=" + (document.querySelector(".horizontal-container").offsetWidth - document.documentElement.clientWidth), invalidateOnRefresh: true } }); } }
  24. Yeah just use the SplitText plugin and move the one word to x: -50 and the other x: 50 and they will split. If you still need help please share a minimal demo and we'll be happy to take a look at your setup. Hope it helps and happy tweening!
  25. Hello, @Rodrigo I have made this animation but I'm getting issue with laptop trackpad. Issue is that instead of make one tween in play it let two or more tween to play. Even large scroll on touchpad makes more than 3 tween play at once. This is my live URL and this is my GSAP code. https://blackwolftechnologies.co.za/test/vodamedia const gsapInitialization = () => { console.log("gsapInitialization is done...") gsap.registerPlugin(ScrollTrigger); gsap.config({ easeInOutCubic: function (progress) { return progress < 0.5 ? 4 * progress ** 3 : 1 - Math.pow(-2 * progress + 2, 3) / 2; } }); let sectionEase = "easeInOutCubic"; let slideEase = "power3.easeinOut"; let otherAnimationEase = "easeInOutCubic"; let sectionDuration = 0.7; let slideDuration = 0.6; gsap.registerPlugin(ScrollTrigger); gsap.registerPlugin(ScrollToPlugin); gsap.registerPlugin(Observer); let mastertl = gsap.timeline({ paused: true, defaults: { ease: otherAnimationEase, duration: 0.3, autoAlpha: 0, }, }); gsap.set('.graph_slide_heading', { width: window.innerWidth >= 767 ? 550 : 240, y: 100, autoAlpha: 0, }) mastertl .from('.banner_description', { y: 100, }).addPause() .to(window, { scrollTo: { y: '.horizontal_scroller_module', autoKill: false }, duration: sectionDuration, ease: sectionEase, }) .from('.hs_container_1_text', { xPercent: -100, }).addPause() .to('.hs_inner', { xPercent: -50, autoAlpha: 1, ease: slideEase, delay:0.5, }).addPause() .to(window, { scrollTo: { y: '.one_col_module', autoKill: false }, duration: sectionDuration, ease: sectionEase, }) .from('.one_col_text', { y: 100, }).addPause() .to(window, { scrollTo: { y: '.two_col_module', autoKill: false }, duration: sectionDuration, ease: sectionEase, }) .from('.tc_telco_content', { y: 200, autoAlpha: 0, }) .from('.tc_telco_image', { y: 100, autoAlpha: 0, }, "<").addPause() .to('.tc_telco_content', { y: -100, height: 0, autoAlpha: 0, }) .from('.tc_digital_content', { y: 100, height: 0, autoAlpha: 0, }, "<") .to('.tc_telco_image_container', { autoAlpha: 1, scrollTo: { y: '.tc_telco_image_in_2', autoKill: false, ease: sectionEase, } }, "<") .addPause() .to(window, { scrollTo: { y: '.two_col_module_V2', autoKill: false }, duration: sectionDuration, ease: sectionEase, }) .from('.tcV2_main_slide_heading ', { y: 100, }).addPause() .to('.two_col_module_V2_inner', { xPercent: window.innerWidth >= 767 ? -60 : -100, autoAlpha: 1, ease: slideEase, duration: slideDuration, }).addPause() .to(window, { scrollTo: { y: '.two_col_logo_module', autoKill: false }, duration: sectionDuration, ease: sectionEase, }) .from('.two_col_logo_heading, .two_col_logo_description', { y: 100, }) .from('.two_col_logo_module .two_col_logo_image', { y: 100, }).addPause() .to(window, { scrollTo: { y: '.graph_module', autoKill: false }, duration: sectionDuration, ease: sectionEase, }) .to('.graph_slide_heading', { y: 0, autoAlpha: 1, }).addPause() .to('.graph_slide_heading', { width: window.innerWidth >= 1024 ? 350 : (window.innerWidth >= 767 ? 240 : "100%"), autoAlpha: 1, ease: sectionEase, }) .from(' .graph_module_image', { x: 100, }, "<").addPause() .to(window, { scrollTo: { y: '.logo_slider_module', autoKill: false }, duration: sectionDuration, ease: sectionEase, }) .from('.logo_slider_heading , .logo_slider_description', { y: 100, }) .from(' .logo_slider_module .two_col_logo_container', { y: 100, }) .addPause() .to(window, { scrollTo: { y: '.one_col_module_V2_r', autoKill: false }, duration: sectionDuration, ease: sectionEase, }) .from('.one_col_module_V2_r .one_col_V2_heading', { y: 100, }).addPause() .to(window, { scrollTo: { y: '.contact_us_module', autoKill: false }, duration: sectionDuration, ease: sectionEase, }) .from('.contact_us_heading, .contact_us_description, .contact_us_form_container', { y: 100, }).addPause() // Observer For Timeline Observer.create({ type: "wheel, touch, pointer, touchmove", preventDefault: true, wheelSpeed: -1, tolerance: 100, dragMinimum: window.innerWidth >= 480 ? 100 : 20, onUp: () => { if (!mastertl.isActive() && mastertl.totalProgress() < 1) { mastertl.play(); } }, onDown: () => { if (!mastertl.isActive() && mastertl.totalProgress() <= 1) { mastertl.reverse(); } }, }); // Animation on Arrow Key document.onkeydown = CheckKeyFun; function CheckKeyFun(key) { key.preventDefault(); if (key.keyCode == '38') { // console.log("Up arrow"); if (!mastertl.isActive() && mastertl.totalProgress() <= 1) { mastertl.reverse(); } } else if (key.keyCode == '40') { // console.log("Down arrow"); if (!mastertl.isActive() && mastertl.totalProgress() < 1) { mastertl.play(); } } } // Nav Menu Link To Sections let hamIcon = document.querySelector('#headerModule .hamIcon'); hamIcon.onclick = linkListenerToNav; function linkListenerToNav() { let navTimeout = setTimeout(function () { // Menu Navbar let whatSetUsApartNav = document.querySelector('#menu-1-749d960 .whatSetUsApartMenu .elementor-item-anchor'); let whatDoWeDoNav = document.querySelector('#menu-1-749d960 .whatDoWeDoMenu .elementor-item-anchor '); let whatDoWeOfferNav = document.querySelector('#menu-1-749d960 .whatDoWeOfferMenu .elementor-item-anchor'); let ourClientsNav = document.querySelector('#menu-1-749d960 .ourClientsMenu .elementor-item-anchor'); let socialImpactNav = document.querySelector('#menu-1-749d960 .socialImpactMenu .elementor-item-anchor'); let contactUsNav = document.querySelector('#menu-1-749d960 .contactUsMenu .elementor-item-anchor'); const navMenu = [whatSetUsApartNav, whatDoWeDoNav, whatDoWeOfferNav, ourClientsNav, socialImpactNav, contactUsNav]; navMenu.forEach((menuItem) => { menuItem.addEventListener('click', function (e) { e.preventDefault(); if (menuItem.parentElement.classList.contains("whatSetUsApartMenu")) { // console.log("whatSetUsApart"); mastertl.progress(0.038).play(); } else if (menuItem.parentElement.classList.contains("whatDoWeDoMenu")) { // console.log("whatDoWeDoMenu"); mastertl.progress(0.149).play(); } else if (menuItem.parentElement.classList.contains("whatDoWeOfferMenu")) { // console.log("whatDoWeOfferMenu"); mastertl.progress(0.334).play(); } else if (menuItem.parentElement.classList.contains("ourClientsMenu")) { // console.log("ourClientsMenu"); mastertl.progress(0.752).play(); } else if (menuItem.parentElement.classList.contains("socialImpactMenu")) { // console.log("socialImpactMenu"); mastertl.progress(0.856).play(); } else if (menuItem.parentElement.classList.contains("contactUsMenu")) { // console.log("contactUsMenu"); mastertl.progress(0.93196).play(); } }) }) }, 100) } } window.addEventListener('load', gsapInitialization) // Scroll To Top Function function smoothScrollToTop() { // console.log('smoothscroll'); const rootElement = document.documentElement; rootElement.scrollTo({ top: 0, behavior: "smooth" }); } smoothScrollToTop(); window.addEventListener("load", smoothScrollToTop); window.addEventListener("beforeunload", smoothScrollToTop); document.addEventListener("load", smoothScrollToTop);
  26. Thank you, is there any way to separate two words when hovering?
  1. Load more activity
×
×
  • Create New...