Jump to content

Rodrigo last won the day on June 1

Rodrigo had the most liked content!


  • Posts

  • Joined

  • Last visited

  • Days Won


Community Answers

  1. Rodrigo's post in Problem with gsap.context() and revert was marked as the answer   
    Yeah for some reason codesandbox is being weird, it wouldn't be the first time 🤷‍♂️
    Instead of finding a way to make the sandbox link work I ported the example to Stackblitz:
    https://stackblitz.com/edit/stackblitz-starters-91fcze?description=A create-react-app project based on react and react-dom&file=src%2FApp.js&title=React Starter
    I recommend you that for future questions just use Stackblitz, far more stable and less troubles than in codesandbox.
    Happy Tweening!
  2. Rodrigo's post in GOT PROBLEM WITH GSAP SCROLLTRIGGER !! was marked as the answer   
    This is a far more complicated logic issue. The problem here is that at certain points the Y position of the rec is the same while the progress of the timeline keeps increasing as you scroll. This generates odd values for this:
    gsap.ticker.add(() => gsap.to(section_2_container, { x: 0, y: -( gsap.getProperty(rec, "y") - ((window.innerHeight - rec.clientHeight) * section_2.progress()) ) }) ); I tried different approaches for this, taking into account the Y position of the element in order to not move the container, but all of them resulted in space at the bottom of the element, which is the initial problem you had (I remember the other thread you created about this).
    I think the best course of action is a different approach for this:

    See the Pen xxyoLRz by GreenSock (@GreenSock) on CodePen
    You can also explore the custom ease helper function by switching the ease option in the config object by changing it to this:
    // immediateRender: true, ease: pathEase(path),  
    This might not be exactly what you need, but solving the issue you have in your current setup is a custom logic work that's beyond the scope of what we can do in these free forums. Unfortunately we don't have the time resources to provide that kind of custom work for our users. You can contact us for a consulting work or post in the Jobs & Freelance forums if you want.
    Hopefully this helps.
    Happy Tweening!
  3. Rodrigo's post in conflicting tweens was marked as the answer   
    Your problem is here:
    gsap.set(gsap.utils.toArray(entry, name, desc, details), { clearProps: true }); If you check the docs for the toArray method you'll see that the second parameter it's a scope element or selector:
    targets : [Object | String | NodeList | Array] - The target(s) that you want wrapped in a flattened Array (it can be selector text, objects, NodeList, jQuery objects, etc.) scope : [Element | Ref] (optional) - The Element (or React ref) to which the selector text scope should be limited, like calling .querySelectorAll([selector-text]) on this Element rather than the document. In other words, it will only return descendant Elements of the scope Element, like jQuery.find(). This is only helpful when targets is selector text. So basically you're telling GSAP, create an array with the entry element and use the name element as scope, the other two (desc and details) are just ignored, because the method is expecting two parameters.
    There are two solutions:
    Pass an array with the elements to the method: gsap.set(gsap.utils.toArray([entry, name, desc, details]), { clearProps: true }); Don't use the toArray method. Those elements are already DOM nodes so you can wrap them in an array and be done with it: gsap.set([entry, name, desc, details], { clearProps: true }); Hopefully this helps.
    Happy Tweening!
  4. Rodrigo's post in gsap animation not working after fetch function was marked as the answer   
    This is just how you should run your effect hooks in React when getting async data or doing async operations. You already have a your data in a hook so that's a good start. Just make your tag list a dependency in the layout effect and it works:
    const { tagsList } = useFetchProducts(); useLayoutEffect(() => { if(tagsList.length === 0) return; let ctx = gsap.context(() => { gsap.set(".text", { xPercent: 50, autoAlpha: 0 }); gsap.to(".text", { xPercent: 0, duration: 1, stagger: 0.2, autoAlpha: 1 }); }, HeroRef); // <- scopes all selector text to the root element return () => ctx.revert(); }, [tagsList]); Hopefully this helps.
    Happy Tweening!
  5. Rodrigo's post in Gsap react target got undefined or not found was marked as the answer   
    This particular example shows how to use a GSAP timeline with a click handler
    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.
    Happy Tweening!
  6. Rodrigo's post in Show text block was marked as the answer   
    I just updated the codepen in order to add a time constant that would make the elements stay longer:

    See the Pen abRRJxY by GreenSock (@GreenSock) on CodePen
    Basically this is about the position parameter. I suggest that you read about it and see how it works in order to get a better grasp and understand what's happening in the code, but basically is increasing the amount of time between the opacity animations.
    Hopefully this helps.
    Happy Tweening!
  7. Rodrigo's post in What is the simplest way to deploy to Vercel when I'm using Club Greensock? was marked as the answer   
    Be sure to have something like this in your .npmrc file:
    always-auth=true @gsap:registry=https://npm.greensock.com //npm.greensock.com/:_authToken=${NPM_TOKEN} This repo was deployed less than two weeks ago to vercel without any issues:
    Here is the live page (not a lot, just a proof of concept of a successful deployment and CI/CD pipeline):
    If you inspect the console you'll find this line there:
    Hopefully this helps.
    Happy Tweening!
  8. Rodrigo's post in Hi i how can i move to next section without create more spacing ? was marked as the answer   
    This is the closest I can get to what you need:

    See the Pen ExdJyBe by GreenSock (@GreenSock) on CodePen
    There's still a bit of space at the bottom but I don't know how to remove that.
    Hopefully this helps.
    Happy Tweening!
  9. Rodrigo's post in GSAP Timeline not playing Nuxt.js was marked as the answer   
    Hi @CptRobby and welcome to the GreenSock forums!
    This seems to be related to some stuff Vue does to refs that is a bit longer to explain here. But is definitely not a GSAP issue.
    If possible don't store your GSAP timeline in a ref, since that particular element becomes reactive as well, so if nothing in your app depends on that ref being updated, there is no actual need to store the GSAP Timeline in a ref, just create a variable and update that variable inside the GSAP Context instance:
    const block = ref(); const button = ref(); let tl; let ctx; onMounted(() => { ctx = gsap.context(() => { tl = gsap.timeline(); tl.to(button.value, { opacity: 1, duration: 1, }); }, block.value); }); Finally is not a good idea to make paused: true a default in your Timeline configuration, since every single instance you add will be paused and you'd have to change that as you create them. Is better to just make the timeline paused:
    let ctx; let tl; onMounted(() => { ctx = gsap.context(() => { tl = gsap.timeline({ paused: true, }); tl.to(el, { /*...*/ }); // Later in your code or in a method tl.play(); }, scope); });  
    Hopefully this helps.
    Happy Tweening!
  10. Rodrigo's post in Revealing w/ stagger chars GSAP Scrolltrigger was marked as the answer   
    The issue was here:
    const scroller = gsap.to(this.intro, { x: () => window.innerWidth - this.intro.clientWidth - introBounds.left * 2, scrollTrigger: { trigger: "body", start: "top top", end: "bottom-=200 bottom", scrub: true, invalidateOnRefresh: true } }); This is your scroller animation and the horizontal animation has the default easing which is power1.out, so that will slow down the animation at the end, but it won't slow down the scrolling, so it appears to be some space as you scroll down and the text moves to the left. That's just the easing function. When using ScrollTrigger to create some sort of horizontal animation it's always a good idea to start with no easing function (ease: "none") and then try a specific one if you need/want it.
    This seems to work the way you expect:
    const scroller = gsap.to(this.intro, { x: () => window.innerWidth - this.intro.clientWidth - introBounds.left * 2, ease: "none", scrollTrigger: { trigger: "body", start: "top top", end: "bottom-=200 bottom", scrub: true, invalidateOnRefresh: true } }); Finally there is no need to run all the extra code in order to determinate whether or not a character is in the screen, ScrollTrigger will animate that for you if they are on the screen. So this:
    this.introObj.chars.forEach((letter) => { gsap.to(letter, { y: 0, autoAlpha: 1, scrollTrigger: { trigger: letter, start: "right right", containerAnimation: scroller, invalidateOnRefresh: true, toggleActions: "play none none reverse", markers: true } }); }); Has the same effect as this:
    lettersToAnimate.forEach((letter) => { gsap.to(letter, { y: 0, autoAlpha: 1, scrollTrigger: { trigger: letter, start: "right right", containerAnimation: scroller, invalidateOnRefresh: true, toggleActions: "play none none reverse", markers: true } }); }); Hopefully this helps.
    Happy Tweening!
  11. Rodrigo's post in Move an image horizontally (from the start or middle window to the end ) was marked as the answer   
    I'm not sure I understand correctly what you're trying to do, but maybe is something like this:

    See the Pen Poyejgq by GreenSock (@GreenSock) on CodePen
    This is mostly about the proper layout and HTML markup. Also is worth noticing that you were using very old versions of GSAP and ScrollTrigger, is better to always use the latest ones.
    Hopefully this helps.
    Happy Tweening!
  12. Rodrigo's post in lock scrolltrigger in timeline and enable via onclick multiple times was marked as the answer   
    This might not be the easiest of things. One option is to add/remove an event listener to the document.body element, that prevents the default for the scroll event and the touch ones:
    But having a scroll bar and the content not moving should be misleading and probably bad UX.
    Another option is to set the document.body overflow to hidden until the conditions you set (be explicit about those to the users, otherwise this is also terrible UX) are met.
    Here is a fork of your codepen that somehow works:

    See the Pen WNamKNv by GreenSock (@GreenSock) on CodePen
    Hopefully this helps.
    Happy Tweening!
  13. Rodrigo's post in use a vue3 Options API was marked as the answer   
    Once again this is a Vue related issue, not a GSAP one.
    You have to watch for the selected category on your menu items and not animate all of them in every single one. Is too much redundancy and possible a performance issue. You have to learn about Vue, in this case watchers and reactivity:
    I forked your example and made the changes in it:
    Hopefully this helps.
    Happy Tweening!
  14. Rodrigo's post in Snow effect with random repositions on loop was marked as the answer   
    Hi @AmbrosiaDevelopments and welcome to the GreenSock Forums!
    I'm not an expert in particle animations and normally they're not the simplest thing to achieve, but for what I can see what you need is just some delay between replays.
    In your first two examples adding a repeatDelay option to the stagger config seems to work:
    stagger: { each: 0.05, repeat: -1, repeatDelay: 5, // amount of seconds before it repeats } In your last example maybe this:
    onComplete: () => gsap.delayedCall(5, () => setCx(dot, delay)) Also you can learn from the masters themselves (@Carl and  @OSUblake)

    See the Pen BjNZYP by osublake (@osublake) on CodePen
    Hopefully this helps.
    Happy Tweening!
  15. Rodrigo's post in Is there any way to purchase SmoothScroller? was marked as the answer   
    We don't have single products purchase, sorry. What you can do is buy the Shockingly Green subscription and not select to auto-renew your subscription and it will expire one year after your purchase. During that year you get access to all the bonus tools and it's updates. After that you'll be able to keep using the files you downloaded as we don't include any phone-home scripts in our tools, so your site will keep working as long as you have the files there. You just won't get access to the latest updates of the bonus stuff.
    Hopefully this clear things up. Let us know if you have any doubts.
    Happy Tweening!
  16. Rodrigo's post in ScrollTrigger pin breaking on using react-transition-group page transition in Next js was marked as the answer   
    Hi @CuteAppi and welcome to the GreenSock forums!
    The reason for this is because of two things:
    When the ScrollTrigger instance is created in the scroll page, the transition is not yet completed, so ScrollTrigger does it's calculations when the element is still at the left of the sreen. You are using pinning in ScrollTrigger. The transition animation uses transform (Scale and X) and pinning uses position fixed. When an ancestor of a fixed element has a transform applied to it it breaks the way it behaves:
    https://stackoverflow.com/questions/15194313/transform3d-not-working-with-position-fixed-children The solution is to wait for the transition to be completed (as seen in the layers page) and clear the styles of the container that is animated in the page transition.
    Here is a fork of your example that is working as expected:
    Hopefully this helps.
    Happy Tweening!
  17. Rodrigo's post in Side menu to navigate through timelines was marked as the answer   
    Just in case here are a few examples:

    See the Pen BaRqeGb by GreenSock (@GreenSock) on CodePen

    See the Pen ZEXYrJR by GreenSock (@GreenSock) on CodePen

    See the Pen jOezPLN by GreenSock (@GreenSock) on CodePen
    Happy Tweening!
  18. Rodrigo's post in Translate the pinned element after pinning "ends" was marked as the answer   
    Hi @2Pacalypse- and welcome to the GreenSock forums!
    I don't have time right now to create a custom example from scratch for this. I know my way around React but I don't know enough about styled components to get it working the way I intend. Here is my idea:
    Instead of using a regular animation I'd use the Flip plugin to reparent the circle using conditional rendering, this would require an extra wrapper for the circle at and use the onLeave and onEnterBack callbacks to trigger that animation. Also an extra wrapper means that you don't have to pin the circle (actually I think that's the main cause of your issues right now), but you can pin the wrapper and animate the circle a lot easier with Flip. Here is a super simple example using re-parenting to create the animation:

    See the Pen MWyGoxZ by GreenSock (@GreenSock) on CodePen
    Hopefully this is enough to get you started.
    Happy Tweening!
  19. Rodrigo's post in The case of the missing pinned Lottie animation... was marked as the answer   
    I can't test on Safari, but maybe the problem is here:
    LottieScrollTrigger({ target: "#map", path: "https://assets1.lottiefiles.com/packages/lf20_q7yxm6pp.json", speed: "medium", pin: ".left-side-column", pinnedContainer: ".left-side-column", start: "top 20%", end: "+=2000", scrub: 1, pinSpacing: true, markers: false }); Why are you setting the pinned container to be the same element you are pinning in that particular ScrollTrigger instance? That makes no sense to me honestly. The other ScrollTrigger instance is not pinning that element, nor any other ScrollTrigger instance for that matter.
    Finally if you want two different ScrollTrigger instances to end at the same time you can use the previous method in a function based value in the lottie ScrollTrigger instance:
    LottieScrollTrigger({ target: "#map", path: "https://assets1.lottiefiles.com/packages/lf20_q7yxm6pp.json", speed: "medium", pin: ".left-side-column", start: "top 20%", end: (self) => self.previous().end, scrub: 1, markers: {indent: 300}, id: "lottie" }); Here is a fork of your example with these changes in it:

    See the Pen xxyyoeO by GreenSock (@GreenSock) on CodePen
    Finally when you're pinning an element in a ScrollTrigger instance there is no need to add this:
    pinSpacing: true, Since that's the default.
    Hopefully this helps.
    Happy Tweening!
  20. Rodrigo's post in ScrollTrigger refresh on resize? was marked as the answer   
    This is basically related to the units you're passing to GSAP. So right now you're passing a number 0, so GSAP says: "OK, you want me to tween the width of this element to 0 pixels" and GSAP, being an extremely good library, does exactly what you're asking. The problem is that you're basing your entire setup in percentage-based values. For that you have to be specific so GSAP knows you're intentions. Regardless of all the hard work putted into GSAP, the library still can't read minds .
    This seems to work the way you intend:
    walltl .to(".left-crunch", { width: "0%" }) .to(".right-crunch", { width: "0%" }, 0); Hopefully this helps.
    Happy Tweening!
  21. Rodrigo's post in Pinned element not pinning to top of pin spacer was marked as the answer   
    Hi @Lb1594 and welcome to the GreenSock forums!
    You are officially another victim of the double call in React's effect hooks (useEffect and useLayoutEffect) as explained here:
    When using React GSAP Context is your best friend:
    Basically you have to create your ScrollTrigger inside a Context instance:
    useEffect(() => { const ctx = gsap.context(() => { gsap.to(elementRef.current, { scrollTrigger: { trigger: elementRef.current, start: "top top", end: "+=200vh", pin: true, pinSpacing: false, markers: true, } }); }); return () => ctx.revert(); }, []); Finally I'd recommend you to check the resources in this page:
    Hopefully this helps.
    Happy Tweening!
  22. Rodrigo's post in Routing transition jump after fetching was marked as the answer   
    This actually is not GSAP related, but stems from the configuration you have for your transitions and the timeout property in the Transition component.
    You have this in the Transition component:
    <Transition key={location.pathname} timeout={500} // <- Timeout of just 500ms or 0.5 seconds nodeRef={nodeRef} onEnter={() => { const node = nodeRef.current; toggleCompleted(false); gsap.set(node, { autoAlpha: 0, scale: 0.8, xPercent: -100 }); gsap .timeline({ paused: true, onComplete: () => toggleCompleted(true), }) .to(node, { autoAlpha: 1, xPercent: 0, duration: 0.25 }) .to(node, { scale: 1, duration: 3 }) .play(); }} onExit={() => { const node = nodeRef.current; gsap .timeline({ paused: true }) .to(node, { scale: 0.8, duration: 3 }) .to(node, { xPercent: 100, autoAlpha: 0, duration: 3 }) .play(); }} > <div ref={nodeRef}>{children}</div> </Transition> But the animation in has a duration of 3 seconds and the out animation six seconds!. The timeout option tells Transition Group when the DOM should be ready to be updated, hence those jumps. If you change the timeout value to 6500 it works.
    A word of advice, as a user I would really, really, REALLY hate if the developers would have me waiting over nine(!) seconds between one page and the other I would close the site never go back. IMHO that's really bad UX. Just my two cents on the subject.
    Hopefully this helps.
    Happy Tweening!
  23. Rodrigo's post in problem in applying ScrollSmoother in React (whole site divided into components) was marked as the answer   
    Hi @aashabul and welcome to the GreenSock forums!
    Here is a simple example for using ScrollSmoother with React Router:
    Hopefully this helps.
    Happy Tweening!
  24. Rodrigo's post in Contact us form IDEAS PLSSS was marked as the answer   
    Hi @SylvesterM and welcome to the GreenSock forums!
    Definitely it can be animated, but there are a few possibilities. Of the top of my mind I don't remember any particular thread or codepen example regarding this, maybe another user does.
    You can start by checking this:
    https://codepen.io/tag/form animation
    Then create your own example and if you get stuck in the process we can help you with any GSAP related issue. Just remember to include a minimal demo and check the forums guidelines.
    Happy Tweening!
  25. Rodrigo's post in Gsap one animation start and pin the section animation continue scrollTrigger was marked as the answer   
    The problem you have here is that your two ScrollTrigger instances are overlapping, that means that you have conflicting GSAP Timelines affecting the same properties on the same elements. 
    It might be better to create a ScrollTrigger instance that just pins the container and another that scrubs the animation. You can use the one that pins so set the same end point in the one that triggers the animation:
    const tl = gsap .timeline({ scrollTrigger: { trigger: ".second", start: "top center", end: (self) => { return self.previous().end; }, scrub: true, markers: true } }) .to(".box1", { xPercent: 50 }) .to( ".box2", { xPercent: -50 }, "<" ); Here is a fork of your demo:

    See the Pen ZEqMrjm by GreenSock (@GreenSock) on CodePen
    Hopefully this helps.
    Happy Tweening!