Rodrigo last won the day on
Rodrigo had the most liked content!
-
Posts
4,148 -
Joined
-
Last visited
-
Days Won
221
Content Type
Profiles
Forums
Store
Blog
Product
Showcase
FAQ
ScrollTrigger Demos
Downloads
Everything posted by Rodrigo
-
Hi, Do you have a minimal demo that shows the issue you're having? This could be just a JS scoping problem and not a GSAP related issue, but without a live editable demo there is not much we can do. Happy Tweening!
- 22 replies
-
- 1
-
-
Hi, Is really hard for us to debug without a minimal demo. The only advice I can offer is to not use the conditions syntax and use two different add() methods in order to effectively revert the animations between screen sizes: let mm = gsap.matchMedia(); mm.add("(min-width: 800px)", () => { // desktop setup code here... }); mm.add("(max-width: 799px)", () => { // mobile setup code here... }); Here is the link to the MatchMedia docs: https://greensock.com/docs/v3/GSAP/gsap.matchMedia() If you keep having issues, please post a minimal simple demo that clearly illustrates the problem. Happy Tweening!
-
Hi @Don Kelwin and welcome to the GreenSock forums. I read your post a few times and is not clear to me what you're trying to achieve. I think your HTML and CSS is a bit convoluted and this could be achieved easier using flexbox and scales. Animating width/height, margin/padding, top/left and any other position property is not very performant and we always recommend animating transforms, like scale, which should be better in this case. I forked your codepen and made the changes I mentioned above. Only the left side buttons are working. Basically the left submit grows the bar and the backLeft button stops the animation and then reverses it after one second: https://codepen.io/GreenSock/pen/RweMxQK I'm not sure that this is what you're after, but hopefully this helps. If you're looking for something else, please be more specific about it, but clear. Use simple words and a short description of what each element should do. Happy Tweening!
-
Can I update the scrollerProxy base on locomotiveScroll?
Rodrigo replied to Pollux Septimus's topic in GSAP
Hi, Unfortunately I have no experience with Locomotive, but as far as I can tell you should be able to set the scroll position of the DOM node used as proxy in the ScrollTrigger configuration. That should be something the people of Locomotive should be able to answer IMHO. Another option could be to use the Scroll Restoration component React Router has: https://reactrouter.com/en/main/components/scroll-restoration Sorry I can't be of more assistance. Hopefully this helps. Happy Tweening! -
Hi, I'm not sure I totally follow what you're trying to do, but maybe try this in your init method: init(){ this.tl.add(this.heroAnimation()) this.tl.add(this.bannerAnimation()) this.tl.call(() => this.cardAnimations()) } By using the add method, you're telling GSAP to call the cardAnimations method when the Timeline is created and not after the previous animations are completed. The call method will execute that function after the previous animations are completed. For different screen sizes you can use GSAP MatchMedia in order to run different types of animations based on the screen height: https://greensock.com/docs/v3/GSAP/gsap.matchMedia() Hopefully this helps. Happy Tweening!
-
Hi @Maria07 and welcome to the GreenSock forums! This boils down to calculating the correct scroll position. In this cases using the offset or the element's position from the top might not always work, since ScrollTrigger adds some space for pinning elements. Is better to use the amount of sections (which normally coincides with the amount of links) and calculate that scroll position based on the start and end points of the ScrollTrigger instance and the index of each link element. const navLinks = gsap.utils.toArray(`${sectionAttribute} [data-point]`); const totalLinks = navLinks.length - 1; navLinks.forEach((link, index) => { link.addEventListener("click", (e) => { e.preventDefault(); if (index === 0) { return gsap.to(window, { scrollTo: { y: tl.scrollTrigger.start, } }); } if (index === totalLinks) { return gsap.to(window, { scrollTo: { y: tl.scrollTrigger.end } }); } gsap.to(window, { scrollTo: { y: tl.scrollTrigger.start + (tl.scrollTrigger.end - tl.scrollTrigger.start) * (index / totalLinks) } }); }); }); Here is a fork of your codepen: https://codepen.io/GreenSock/pen/jOezPLN Hopefully this helps. Happy Tweening!
-
Hi @just and welcome to the GreenSock forums! In this cases is better to just toggle a GSAP animation back and forth instead of creating a new one on each click: https://codepen.io/GreenSock/pen/OJBvPZz Hopefully this helps. Happy Tweening!
- 1 reply
-
- 1
-
-
Hi, This is a bit odd. I just created a React TS app on my local machine and replicated it on Stackblitz without any issues or linting errors/warnings. There are a few on Stackblitz, but with the exact same config files I see nothing in my local environment. I made a production build and ran it on my local server without any issues. https://stackblitz.com/edit/vitejs-vite-phmgws?file=src%2FApp.tsx&terminal=dev The only thing is that you should check your versions of node and npm, since you're using this as a build command: npm create vite@latest app-name --template react-ts Per the Vite docs: # npm 6.x npm create vite@latest my-app --template react-ts # npm 7+, extra double-dash is needed: npm create vite@latest my-app -- --template react-ts If you're have npm 7+ and the corresponding node version, maybe you're instantiating your app with the wrong command. Hopefully this helps. Happy Tweening!
-
Hi, You are using an onComplete callback in order to do the Flip.from method. Is better to use ScrollTrigger's callbacks instead. In this case onEnter and onLeaveBack: onEnter Function - A callback for when the scroll position moves forward past the "start" (typically when the trigger is scrolled into view). It receives one parameter - the ScrollTrigger instance itself which has properties/methods like progress, direction, isActive, and getVelocity(). onEnterBack Function - A callback for when the scroll position moves backward past the "end" (typically when the trigger is scrolled back into view). It receives one parameter - the ScrollTrigger instance itself which has properties/methods like progress, direction, isActive, and getVelocity(). onLeave Function - A callback for when the scroll position moves forward past the "end" (typically when the trigger is scrolled out of view). It receives one parameter - the ScrollTrigger instance itself which has properties/methods like progress, direction, isActive, and getVelocity(). onLeaveBack Function - A callback for when the scroll position moves backward past the "start" (typically when the trigger is scrolled all the way backward past the start). It receives one parameter - the ScrollTrigger instance itself which has properties/methods like progress, direction, isActive, and getVelocity(). Here is a fork of your codepen example: https://codepen.io/GreenSock/pen/MWPQMyo Is worth noticing that in this example I'm wiring the scale animations to the Flip.from() instance, because that actually returns a GSAP Timeline. Hopefully this helps. Happy Tweening!
-
Hi, The reason the toArray method is not working because you have that inside a GSAP Context instance that has a scope defined: let ctx = gsap.context(() => { const darkSections = document.querySelectorAll(".dark-section"); const darkSectionsArr = Array.from(darkSections); let sections = gsap.utils.toArray(".dark-section"); console.log(sections) // <- [] console.log(darkSections) // <- NodeList[...] }, headerRef);// <- this is your scope for GSAP Context So the toArray method is looking for all the elements with the dark-section class inside that scope, not outside. This works the way you intend: // Doesn't take into account the scope now let sections = gsap.utils.toArray(".dark-section"); let ctx = gsap.context(() => { const darkSections = document.querySelectorAll(".dark-section"); const darkSectionsArr = Array.from(darkSections); console.log(sections)// <- [section.dark-section,...] console.log(darkSections)// <- NodeList[...] }, headerRef); Hopefully this clear things up. Happy Tweening!
-
Hi, the issue could be the fact that you’re using a reference in your update method. This seems to work the way you intend tl.to(spinner, { duration: 1, rotate: 360, repeat: 23, onUpdate: () => onCallback(test), }); Hopefully this helps. Happy Tweening!
-
https://react.dev/reference/react/useLayoutEffect This particular example shows how to use a GSAP timeline with a click handler https://stackblitz.com/edit/gsap-react-basic-f48716 This is mostly react related. I recommend you to get a good look at the react page we have and that I linked before and perhaps learn your way around react and how to use event handlers and hooks. https://greensock.com/react Happy Tweening!
-
Hi, I'm not in front of my computer now so there's not a lot I can do from my phone. What I can see is that you're not using the useLayoutEffect hook and you're not using GSAP context neither. I recommend you to check the resources in this page: https://greensock.com/react Also you can see some simple starter templates here where GSAP Context is being used https://stackblitz.com/@GreenSockLearning/collections/gsap-react-starters Finally you should update the versions of both react and GSAP, since the demo is using older ones. Give a try to the approach using GSAP context and the layout effect hook. Most likely this stems from not using the layout effect hook and the DOM not being rendered when your GSAP code runs. Hopefully this helps. Happy Tweening!
-
Hi, Maybe you're lazy loading some images or have some other tool or code that's messing with the layout, causing issues when ScrollTrigger does its calculations. Maybe wait for the next tick in order to know that the DOM has been updated and rendered. I assume that you're 100% sure that your code in that function is running. Also you're animating the trigger element, that's not a good idea in most cases, specially when animating a property that affects it's position on the y axis. Also I don't see the markers boolean there as well. Always use markers when developing and debugging. Without a minimal demo is really hard for us to tell. Please do your best to create a minimal example that illustrates the issue you're having, don't copy your entire project. Happy Tweening!
-
Hi, Just use the callbacks ScrollTrigger has to offer: https://greensock.com/docs/v3/Plugins/ScrollTrigger This seems to work the way you intend: useIsomorphicLayoutEffect(() => { let ctx = gsap.context(() => { const darkSections = document.querySelectorAll(".dark-section"); const darkSectionsArr = Array.from(darkSections); /* let sections = gsap.utils.toArray(".dark-section"); */ const logo = logoRef.current; const t = gsap.to(logo, { color: "#ffffff", paused: true, }); darkSectionsArr.forEach((section) => { ScrollTrigger.create({ trigger: section, markers: true, onEnter: () => t.play(), onEnterBack: () => t.play(), onLeave: () => t.reverse(), onLeaveBack: () => t.reverse(), start: "top 30", end: "bottom 50", }); }); }, headerRef); return () => ctx.revert(); }, []); Hopefully this helps. Happy Tweening!
-
Hi, Sorry for the late response, this fell through the cracks 🙏 There are several issues in your setup. The first one is this: * { transition: all 0.5s ease; } This is a big NO-NO in web development and also when using GSAP. This tells the browser that every element in the DOM has a transition for every property that gets updated. That is going to create problems one way or the other, even if you don't use GSAP. I strongly recommend you against doing that. Then you have some GSAP instances that are creating some animations while at the same time you are changing the same properties of some elements on hover with the CSS. This for example: &:hover { .hoverCard__body { transform: translateY(-75px); .hoverCard__showOnHover { opacity: 1; visibility: visible; display: block; height: auto; transform: translateY(75px); } } } You are changing the height of the element to auto while using GSAP to animate the height of the same element, while having the rule that gives every element in the DOM a transition for every property. Unfortunately we can't debug complex and tangled-up examples like this, we just don't have the time resources for that. I cleaned up your code, removed some CSS that IMO is unnecessary and came up with this: https://codepen.io/GreenSock/pen/gOBoQxM I'm not sure if this is what you're after or not, but as I mentioned I'm having a hard time following what you're trying to achieve here. If this doesn't help, please be as specific as you can about how the animation should work, describe it in simple words and if possible provide a link to an site where this works in the way you intend. Hopefully this helps. Happy Tweening!
-
Hi @fantaz and welcome to the GreenSock forums! The link you're providing is to this thread so that takes us on an infinite loop! I recommend you to fork one of our starter templates in Stackblitz in order to reproduce your issue: https://stackblitz.com/edit/nextjs-5cm4qn Also this could be related to proper cleanup. You should take a look at GSAP Context: https://greensock.com/docs/v3/GSAP/gsap.context() Also take a look at the resources in this page: Hopefully this helps. Happy Tweening!
-
Why the timeline reverse is not putting the H1 back to its original place?
Rodrigo replied to selfspirit's topic in GSAP
Hi @selfspirit and welcome to the GreenSock forums! Yeah, it seems that the calculations are getting a bit off in this case. On top of that animating position properties like margin, top/left, etc., is not very performant. One alternative is to use transform values like X. Another is to use the Flip Plugin: https://codepen.io/GreenSock/pen/NWOXENd Hopefully this helps. Happy Tweening! -
Hi @Tom_S and welcome to the GreenSock forums! This most likely has to do with the fact that you're not properly cleaning up when a specific route gets unmounted. Normally you should use the onMount hook by Svelte and in the return function at the end cleanup your GSAP Context: onMount(() => { const ctx = gsap.context((self) => { }, scopeEl); // <- Scope! return () => ctx.revert(); // <- Cleanup! }); Unfortunately I'm not very familiar with Svelte so I can't tell you much based on the code you posted. That seems like a function that is being used somewhere else in your app, but I couldn't tell. If you keep having issues, please create a minimal demo by forking this starter template we have on Stackblitz: https://stackblitz.com/edit/sveltejs-kit-template-default-unljf6?file=src%2Froutes%2F%2Bpage.svelte Hopefully this helps. Happy Tweening!
-
Hi, I understand, but that is what actually causing the issues in your case. First always use markers when developing or debugging, if you do you would've seen the problem you have before posting the thread here in the forums: In the image you can see that the start point of the second instance is before the end point of the first instance, which will pin an element that is already pinned. That's causing all the problems here. This is the best I can come up with right now: https://codepen.io/GreenSock/pen/LYgeNeJ Unfortunately we don't have the time resources to provide custom solutions to all our users. Maybe there is better and/or simpler way to do this, but hopefully is enough to help with your project. Happy Tweening!
-
Hi, SVG is not something I have a lot of experience with, but my guess is that you're looking for SVG Origin: svgOrigin [Only for SVG elements] Works exactly like transformOrigin but it uses the SVG’s global coordinate space instead of the element’s local coordinate space. This can be very useful if, for example, you want to make a bunch of SVG elements rotate around a common point. You can either define an svgOrigin or a transformOrigin, not both (for obvious reasons). So you can do gsap.to(svgElement, {duration: 1, rotation: 270, svgOrigin: "250 100"}) if you’d like to rotate svgElement as though its origin is at x: 250, y: 100 in the SVG canvas’s global coordinates. Units are not required. It also records the value in a data-svg-origin attribute so that it can be parsed back in. svgOrigin doesn’t accommodate percentage-based values. You can read more about it in the CSS Plugin docs (scroll about the middle of the page) https://greensock.com/docs/v3/GSAP/CorePlugins/CSSPlugin Hopefully this helps. Happy Tweening!
-
Hi, The approach you're following is quite odd IMHO. I don't see the need for this: React.useEffect(() => { preloadImages(); renderCanvas(); window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, []); If you have ScrollTrigger in the mix, it just doesn't make sense to listen for the scroll event. If you want to do stuff based on the scroll event, then you could use the Observer Plugin (also available in ScrollTrigger as ScrollTrigger.observe()) https://greensock.com/docs/v3/Plugins/Observer https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.observe() Also this looks odd as well: React.useEffect(() => { if (!canvasRef.current || images.length < 1) { return; } const img = new Image(100, 100); const context = canvasRef.current.getContext('2d'); let requestId; const render = () => { img.onload = function () { context.drawImage(images[frameIndex], 0, 0); }; requestId = requestAnimationFrame(render); }; render(); return () => cancelAnimationFrame(requestId); }, [frameIndex, images]); Finally you have this for getting the images: function getCurrentFrame(index) { return `assets/frames/process_0${index.toString().padStart(4, '0')}.jpg`; } But there is no assets folder in your example, so there are no images to work with. I strongly recommend you to try to learn more about react and study Blake's codepen in order to try to emulate it as it is right now on React, before start creating and adding your own sequence of images. Unfortunately we don't have the time resources to build that for you right now, but it shouldn't be too complicated. You should forget about ScrollTrigger and just get the sequence working first, then add ScrollTrigger to the mix. Happy Tweening!
-
Hi @Nikhil17 and welcome to the GreenSock forums! Normally we don't provide custom solutions based on requirements list from our users. In your case this was quite simple (simple enough that you should've been able to solve it by investigating a bit ) https://codepen.io/GreenSock/pen/zYmpmGN As I mentioned above we normally don't provide custom solutions so please don't make a habit of posting a list of requirements in order to get a working solution. Also always include a minimal demo in codepen or other sandbox service (like Stackblitz) that shows what you already have. Hopefully this helps. Happy Tweening!
-
Hi, Your content is shifting because of the justify-content property you're giving to your flex element: .header { display: flex; flex-direction: column; justify-content: space-between; /* <- THIS ONE */ min-height: 100vh; padding-top: 7.5em; height: 100%; background: #ffab91; } Also the delay comes from here: Flip.from(state, { absolute: true, // uses position: absolute during the flip to work around flexbox challenges duration: 0.5, stagger: 0.1, ease: "power1.inOut", delay:3 // <- Delay here!! // you can use any other tweening properties here too, like onComplete, onUpdate, delay, etc. }); Maybe you're looking for something like this: https://codepen.io/GreenSock/pen/gOBoKzN Hopefully this helps. Happy Twening!
-
Hi, In order to expand one row at a time you need to wrap your cards accordingly in your HTML or use some logic in order to shift the start position of each card. Something like this: const cards = gsap.utils.toArray(".card"); cards.forEach((card, i) => { gsap.fromTo( card, { height: "20px" }, { height: "300px", scrollTrigger: { trigger: card, start: (self) => "top+=" + (window.innerHeight * Math.floor(i / 2)) + " top", end: "+=100%", scrub: true, ease: "elastic", } } ); }); Here is a working example of that: https://codepen.io/GreenSock/pen/oNapywy As for expanding from the bottom, that requires a bit more work in the setup. Maybe use flex to move everything to the bottom so it looks like the cards are expanding from the bottom. Unfortunately we have limited time resources in these free forums and we can't provide fully working solutions for every user's request. Hopefully this is enough to get you in the right direction. Happy Tweening!