Jump to content
GreenSock

Rodrigo last won the day on September 23

Rodrigo had the most liked content!

Rodrigo

Administrators
  • Posts

    5,047
  • Joined

  • Last visited

  • Days Won

    246

Community Answers

  1. Rodrigo's post in Changing the x transform position of two elements was marked as the answer   
    Hi,
     
    Maybe something like this:

    See the Pen ZEmNRLO by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  2. Rodrigo's post in GSAP ScrollTrigger not working on initial load but works after scrolling through it was marked as the answer   
    Hi,
     
    This is a simpler way to achieve that IMHO:

    See the Pen PoxvEwK by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps
    Happy Tweening!
  3. Rodrigo's post in Start Lottie ScrollTrigger inside timeline was marked as the answer   
    Hi @liflor and welcome to the GreenSock forums!
     
    We'll start from the end 
    The reason for that is that you have two consecutive fromTo instances in the same timeline that affect similar properties on the same element. A fromTo() instance takes the element from one value or state to another. So in this case the second instance takes the element from opacity: 0.5 to 1 and is first rendered after the first one, that's why you see the text there. This solves that problem:
    heroTl.fromTo($gradientTitle,{ scale: 2, opacity:'0', y: '120vh', duration: 2, },{ scale: 2, opacity:'0.5', y: '50vh', duration: 2, },'start'); heroTl.fromTo($gradientTitle,{ scale: 2, opacity:'0.5', y: '50vh', ease: Power3.out, duration: 2, },{ scale: 1, opacity:'1', y: '0', ease: Power3.out, duration: 2, // Tells GSAP to not render this when the code runs immediateRender: false, },2); As for the sequence in the timeline including the Lottie animation, the ScrollTrigger/Lottie helper function is not built with that in mind. This might be a better approach:

    See the Pen xxQNwGQ by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  4. Rodrigo's post in button move animation on hover was marked as the answer   
    Hi,
     
    Maybe something like this:

    See the Pen GRwagLB by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  5. Rodrigo's post in GSAP target not found on a toggle was marked as the answer   
    Hi,
     
    The issue is that you are creating a series of elements and GSAP instances on each click event. So if you click on the parent accordion element the animlist element is a jquery object with elements in it (two in the case of your example). But when you click on one of the child elements there are no elements with the selector you pass to jquery. At this point jquery returns a jquery object with no DOM elements in it, if you check it with some console logs you'll see it:
    $(faqnav).click(function () { let label = $(this); //FAQ header let parent = label.parent(".has-children"); let list = label.siblings(".faqnav__list"); //All the FAQ items let animlist = list.find(".animlist"); console.log("animlist"); console.log(animlist); // parent click -> length: 2 // child click -> length: 0 }); So basically you're passing an jquery object to GSAP that has no DOM elements so GSAP warns you about it
    GSAP target [object Object] not found. You should create a conditional logic check in order to see if there are child elements inside the element you click in order to run or not that particular code.
     
    Hopefully this helps.
    Happy Tweening!
  6. Rodrigo's post in gsap scrollTrigger cotent not working before refershing the page was marked as the answer   
    Hi,
     
    The main issue is here:
    .neo { width: 100%; position: relative; div { transition: all 0.8s !important; margin: 0 auto; } } Every element inside that is using having a CSS Transition applied to it to every style property that is ever changed, which is exactly what GSAP does. Not only using transition all in your CSS (with !important on top of that) is a bad idea in general, but when you use it with GSAP, is even worst. You should never apply CSS transitions to elements that you're animating with GSAP because when GSAP applies a change, the CSS transition will interrupt that and say "NOPE! I won't allow that to happen yet...I'm gonna drag that change out over the course of my duration..." 
     
    Here is a fork of your codepen with that removed:

    See the Pen poQBXrL by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  7. Rodrigo's post in background-attachment fixed on mobile devices was marked as the answer   
    Hi,
     
    This seems to be related to iOS devices as this is working fine on an Android phone:
    https://css-tricks.com/the-fixed-background-attachment-hack/
     
    Here is another alternative:

    See the Pen VaYeoW by callumfindlay (@callumfindlay) on CodePen
     
    You can tween the clip path property of the elements using GSAP if you want.
     
    Hopefully this helps.
    Happy Tweening!
  8. Rodrigo's post in GSAP in React component - Animation can't remember current position was marked as the answer   
    Hi,
     
    This is mostly a JS scope issue. When you change the target element you are creating a new instance of GSAP Context each time:
    useLayoutEffect(() => { let ctx = gsap.context(() => { gsap.to('.slide-marker', { x: currentIndex * 30, duration: 0.5, }); }, component); return () => ctx.revert(); // cleanup! }, [currentIndex]); Is better to create your GSAP Context just once and add a method to it in order to call that method when the currentIndex prop changes:
    useLayoutEffect(() => { ctx.current && ctx.current.doAnimation(currentIndex); }, [currentIndex]); useLayoutEffect(() => { ctx.current = gsap.context((self) => { self.add("doAnimation", (target) => { gsap.to('.slide-marker', { x: target * 30, duration: 0.5, }); }); }, component); return () => ctx.current.revert(); // cleanup! }, []); That seems to work the way you intend:
    https://stackblitz.com/edit/gsap-react-basic-f48716-gqswdm?file=src%2FSlideToggle.js
     
    Take a better look at the GSAP Context docs:
    https://greensock.com/docs/v3/GSAP/gsap.context()
     
    Finally I'd recommend you to check the resources in this page:
     
    Hopefully this helps.
    Happy Tweening!
  9. Rodrigo's post in Multiple sidebar sticky problem with scroll smoother was marked as the answer   
    Hi,
     
    Just add the top and bottom padding to the end point. If you are using different values you can use a conditional check:
    const extraPadding = window.innerWidth > 1024 ? 400 : 200; ScrollTrigger.create({ trigger: ".banner", start: "top top", end: () => "bottom top+=" + (metaElement.clientHeight + extraPadding), pin: metaElement, pinSpacing: false, id: "l", markers: true }); ScrollTrigger.create({ trigger: ".banner", start: "top top", end: "bottom top+=" + (sidebarElement.clientHeight + extraPadding), pin: sidebarElement, pinSpacing: false, id: "r", markers: { indent: 200 } }); Although a better option would be GSAP MatchMedia:
    https://greensock.com/docs/v3/GSAP/gsap.matchMedia()
     
    Hopefully this helps.
    Happy Tweening!
  10. Rodrigo's post in Infinite marquee scroll is not working - GSAP and Vue was marked as the answer   
    Hi @Justusik and welcome to the GreenSock  forums!
     
    In these cases is better to use the Horizontal  Endless Loop helper function:
    https://greensock.com/docs/v3/HelperFunctions#loop
     
    Here is a fork of your codepen:

    See the Pen GRweYYJ by GreenSock (@GreenSock) on CodePen
     
    Here is an example in Vue3 (porting this to Vue2 shouldn't be too complicated):

    See the Pen abpyGQy by bappla (@bappla) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  11. Rodrigo's post in fonts family changing was marked as the answer   
    Hi,
     
    This is what I would do:

    See the Pen PoxLdVg by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  12. Rodrigo's post in ScrollSmoother is not defined was marked as the answer   
    Hi,
     
    You're not importing the ScrollSmoother plugin, so basically you're trying to register something that is not defined anywhere in the scope of that particular file.
    import { gsap } from "gsap"; import { ScrollSmoother } from "gsap/ScrollSmoother"; gsap.registerPlugin(ScrollSmoother); ScrollSmoother.create({ smooth: 2 });  
    You can always check the installation guide on the docs as well in order to see how to proceed in different scenarios, especially the installation helper:
    https://greensock.com/docs/v3/Installation
     
    Hopefully this helps.
    Happy Tweening!
  13. Rodrigo's post in Draggable and inertia - snap to next slide only was marked as the answer   
    Hi @ash_wab and welcome to the GreenSock forums!
     
    This seems to do what you're looking for:

    See the Pen vYQbZYy by GreenSock (@GreenSock) on CodePen
     
    The main idea is to create the snap values array before creating the Draggable instance, update a direction variable depending on the drag direction and finally increase/decrease the current slide index (like in a regular slider) based on some custom logic that you can run in the snap function and then simply return the snap value of that index from the snap values array.
     
    Hopefully this helps and makes sense.
    Happy Tweening!
  14. Rodrigo's post in Creating an SVG in JS, then Animating it. was marked as the answer   
    Hi,
     
    There are two issues in your code. The first one is that when the Timeline is created (regardless if it's paused or not) GSAP will look for those elements in order to handle things internally. When a child instance from a timeline runs it doesn't look for the target element when it runs (it would be extremely bad for performance, so at that point those elements are not there.
     
    The second issue has to do with the selectors you are using:
    let cd = { plays: [ { play_id: "1", startx: "0", endx: "100" }, { play_id: "3", startx: "25", endx: "30" } ] }; let count = 0; cd.plays.forEach((play) => { tl.call(makePlayItem, [count], "<"); tl.from("#p" + count, { drawSVG: "0%", stagger: 0.1, duration: 1 }, "<+1"); tl.set({}, {}, "<+0.5"); count++; }); You are using p+count but the count goes from 0 to 1 and the ids you are using are 1 and 3, so one of those elements never gets selected by GSAP. On top of that those are the IDs of the SVG tags. The DrawSVG Plugin works on the <path> elements not the SVG main tag.
     
    This seems to work the way you intend:
    var tl = gsap.timeline({ defaults: { ease: "none", }, paused: true, }); let cd = { plays: [ { play_id: "1", startx: "0", endx: "100" }, { play_id: "3", startx: "25", endx: "30" } ] }; let count = 0; cd.plays.forEach((play) => { makePlayItem(count); tl.from("#p" + play.play_id + " path", { drawSVG: "0%", duration: 1 }, "<+1"); tl.set({}, {}, "<+0.5"); count++; }); tl.play(); Finally I'd strongly recommend you to check the docs for the DrawSVG Plugin in order to get a better grasp of how it works:
    https://greensock.com/docs/v3/Plugins/DrawSVGPlugin
     
    Hopefully this helps.
    Happy Tweening!
  15. Rodrigo's post in how to pin an element to a specific position was marked as the answer   
    Hi,
     
    I think the best approach is to pin the entire container of the menu, since the dropdown is not a child of of the navbar element.

    See the Pen gOQqowZ by GreenSock (@GreenSock) on CodePen
     
    Another option is to move the dropdown into the navbar and keep only that first ScrollTrigger instance.
     
    Hopefully this helps.
    Happy Tweening!
  16. Rodrigo's post in Looking for some recommendations to kicking things off / cleanup using Nuxt and GSAP page transitions was marked as the answer   
    Hi @bp-lp and welcome to the GreenSock forums!
     
    Thannks for being a Club GreenSock member and supporting GreenSock! 💚
     
    The problem is that you're not waiting for the transition animation to be completed so all your markers are in the same position:

     
    As you can see in this example we're using a watcher in order to run our GSAP code when the transition composable switches the state of the transition complete reactive property to true:
    https://stackblitz.com/edit/nuxt-starter-bthjlg?file=pages%2Fscroll.vue
     
    Whereas you are running your code as soon as the component is mounted which happens as soon as the transition starts.
     
    Finally if you are going to use pinning, even though you are using ScrollSmoother, it would be a good idea to clear the styles of the page wrapper that gets animated, just in case as mentioned in this thread:
     
    Hopefully this helps.
    Happy Tweening!
  17. Rodrigo's post in scrub scroll jumps when elements pins was marked as the answer   
    Hi,
     
    You don't have to pin the horizontal gallery container since it outermost parent <section> is already pinned. That is basically creating the issue:
    const tl = gsap.timeline({ scrollTrigger: { trigger: ".gallery-wrapper", start: "top top", end: gallery_width, pin: true, pinSpacing: 1, scrub: 0.5, invalidateOnRefresh: true } }); Also pinSpacing is either a boolean or a string, so in this case most likely is getting coerced into true:
    !!1 // -> true https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean#boolean_coercion
     
    This seems to work the way you expect:
    const tl = gsap.timeline({ scrollTrigger: { trigger: ".gallery-wrapper", start: "top top", end: gallery_width, scrub: 0.5, invalidateOnRefresh: true } });
    See the Pen ZEmVdEZ by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  18. Rodrigo's post in Flip plugin in React - multiple shapes together was marked as the answer   
    Hi @NordicDefender and welcome to the GreenSock forums!
     
    Thanks for being a Club GreenSock member and supporting GreenSock!
     
    Unfortunately I don't have the time to go through all your code and see what could be the issue. This is the best I can do in terms of coming up with something simple in short time:

    See the Pen bGQzGWx by rhernando (@rhernando) on CodePen
     
    Now I'm 100% sure that there is a dynamic way to achieve that, unfortunately I didn't had the time to look deeply into that, but I'm sure it's there. Given the fact that you have only three items the code itself is quite simple, short and easy to follow, even if it's repetitive (which feels dirty and ugly all over ). Needless to say that if you add more elements this becomes more complicated, hence it would be a good idea to find a more dynamic and robust way to accomplish this.
     
    Another option you could pursue is to re-parent the elements and use Flip.from() instead of Flip.fit().
     
    Hopefully this helps.
    Happy Tweening!
  19. Rodrigo's post in Horizontal Loop with reversed true doesn't work properly after revisiting the page second time (Nuxt js) was marked as the answer   
    Hi @destro014 and welcome to the GreenSock forums!
     
    I believe the issue resides in your CSS more than anything else. I created this simple example on Vue3 and works as expected:
    https://stackblitz.com/edit/vitejs-vite-hyaxkd?file=src%2Fmain.js&terminal=dev
     
    Same setup in Nuxt3:
    https://stackblitz.com/edit/nuxt-starter-9qwh7n
     
    Unfortunately your demo has over 1200 lines of CSS and we don't have the time resources to comb through all that trying to find the problem, I'm afraid you'll have to do that.
     
    Hopefully this helps.
    Happy Tweening!
  20. Rodrigo's post in 2 GSAP Sliders on 1 Page was marked as the answer   
    Hi,
     
    I don't have time to go through your logic and find out what could be the issue but hopefully this example can provide a good starting point:

    See the Pen jOQXYzV by GreenSock (@GreenSock) on CodePen
     
    Another choice would be to use the Horizontal Endless Loop helper function on two different elements:

    See the Pen ZELPxWW by GreenSock (@GreenSock) on CodePen
     
    Now syncing both on the same Draggable instance might be a challenge though. But as I mentioned we don't have the time resources to create custom complex solutions for our users in these free forums.
     
    Hopefully this helps.
    Happy Tweening!
  21. Rodrigo's post in Fake horizontal scoll with long gallery was marked as the answer   
    Ok, sorry for the difficulty in understanding 🙏
     
    This boils down mostly to CSS actually.
     
    I updated the example to use some random width on the second panel (red) in order to set it's width to something bigger than the other panels:

    See the Pen qBQpLRo by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  22. Rodrigo's post in TypeError: The specifier “gsap” was a bare specifier, but was not remapped to anything. Relative module specifiers must start with “./”, “../” or “/” was marked as the answer   
    Hi @Ferrari and welcome to the GreenSock forums!
     
    Thanks for being a Club GreenSock member and supporting GreenSock! 💚
     
    The only reason I can think of is because you are not using a build tool like webpack, vite, parcel, etc. So basically the browser is trying to find a gsap module in a path that doesn't exists.
     
    If you keep having issues please create a minimal demo in Stackblitz that clearly illustrates the problem you're having.
     
    Hopefully this helps.
    Happy Tweening!
  23. Rodrigo's post in Scrolling before animations are done interferes with scrolltrigger was marked as the answer   
    Hi,
     
    Did you tried the code I posted?
     
    Here is a fork of your example with that change in it:

    See the Pen xxQzaaO by GreenSock (@GreenSock) on CodePen
     
    Happy Tweening!
  24. Rodrigo's post in How do I calculate new div height and apply to gsap pin function when screensize changes was marked as the answer   
    Hi @NiklasG and welcome to the GreenSock forums!
     
    There shouldn't be any need for all of that. ScrollTrigger runs all it's calculations and setting start and end points on ever refresh, also in this cases is better to use an endTrigger element rather than ran all those calculations.
     
    Basically the issue here is that you are calculating that value just one time so when the screen size changes that value remains the same. One alternative is to use a function based value:
    const getTravelDistance = () => { let rightDivHeight = document.getElementById("right").clientHeight; let leftDivHeight = document.getElementById("left").clientHeight; return rightDivHeight - leftDivHeight; }; gsap.to("#left", { scrollTrigger: { trigger: "#left", start: "top center", end: () => `+=${getTravelDistance()}`, pin: true, markers: true, pinSpacing: false } }); Another option, as I mentioned, is to use an endTrigger element:

    See the Pen jOQQyQb by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  25. Rodrigo's post in Delay/Stagger not working was marked as the answer   
    Hi,
     
    You are nesting ScrollTrigger instances in a Timeline child animation. That is something that can't work properly:
    https://greensock.com/st-mistakes/#st-in-tl
     
    Here is a fork of your codepen:

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