Jump to content
Search Community

Rodrigo last won the day on April 28

Rodrigo had the most liked content!

Rodrigo

Administrators
  • Posts

    6,674
  • Joined

  • Last visited

  • Days Won

    287

Community Answers

  1. Rodrigo's post in Switch Array of SVG Component was marked as the answer   
    Hi,
     
    I'm not really clear on what you're trying to do here, but maybe this video by @Carl could help:
     
    Happy Tweening!
  2. Rodrigo's post in Invalid property morphSVG set to #end Missing plugin? was marked as the answer   
    Hi,
     
    This is related to a funky way Astro is handling SSR with React rather than a GSAP related problem. The solution seems to be import the plugin from the dist folder as a default import and not a named import:
    import gsap from 'gsap-trial'; import MorphSVGPlugin from 'gsap-trial/dist/MorphSVGPlugin'; import { useGSAP } from '@gsap/react'; import { useRef } from 'react'; if (typeof window !== 'undefined') { gsap.registerPlugin(useGSAP, MorphSVGPlugin); } export const MorphTest = () => { const btnRef = useRef<HTMLDivElement>(null); const { contextSafe } = useGSAP(() => { console.log(MorphSVGPlugin); },{ scope: btnRef }); if (!contextSafe) return; const onClick = contextSafe(() => { gsap.to('#start', { morphSVG: '#end', }); }); return (/* JSX Here */); }; Here is a fork of your demo:
    https://stackblitz.com/edit/github-txz3pq-tycrjg?file=src%2Fcomponents%2FMorphTest.tsx
     
    Hopefully this helps.
    Happy Tweening!
  3. Rodrigo's post in ScrollTrigger Jumps on Horizontal Scroll was marked as the answer   
    Hi,
     
    You seem to be using Lenis, you have a business license, why not use ScrollSmoother?
     
    The issue here seems to be that something is getting cached and interfering with ScrollTrigger calculations, that's why a hard refresh fixes the issue.
     
    Maybe wrap all your code in a load event in order to be sure that everything is loaded:
    window.addEventListener("load", () => { // GSAP code here }); Unfortunately without a minimal demo there is not much we can do. If possible try to create a demo that recreates the problem so we can have a better look.
     
    Sorry I can't be of more assitance.
    Happy Tweening!
  4. Rodrigo's post in Animating concurrent scrollTrigger elements was marked as the answer   
    Hi,
     
    This would be my approach:

    See the Pen vYMqvNr by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  5. Rodrigo's post in move text to top one after one by scrolltrigger was marked as the answer   
    Hi,
     
    Just create a loop for the cards, add a couple of to() instances to the timeline and using the position parameter create an overlap with the previous card:

    See the Pen WNWBaKz by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  6. Rodrigo's post in Good way to register GSAP Plugins in Next.JS App router, and how many many times we can do it? was marked as the answer   
    Hi,
     
    The ideal way would be to register the plugins is to do it in the outmost layout file, as shown in this demo:
    https://stackblitz.com/edit/stackblitz-starters-cxedmc?file=app%2Flayout.tsx
     
    Is worth mentioning though that there is absolutely no issue if a plugin is registered more than once, so you won't run into any issues if you do that.
     
    Hopefully this helps.
    Happy Tweening!
  7. Rodrigo's post in Animating a RadixUI Dialog component with GSAP in React was marked as the answer   
    Hi,
     
    Yeah the issue is not related to GSAP but simply the way these frameworks/libraries actually work. When you toggle the setOpen state, that tells radix to render the modal component, but it doesn't mean that the DOM has been updated.
     
    When you create this:
    useGSAP( () => { tlRef.current = gsap.timeline({ paused: true, defaults: { ease: 'power1.inOut' }, }); tlRef.current .to('.modal', { autoAlpha: 1, duration: 0.7 }) .to('.overlay', { autoAlpha: 1, duration: 0.5 }, '<') .to( '.menu-item', { autoAlpha: 1, stagger: 0.1, duration: 1, }, '>' ) .reverse(); }, { scope: containerRef, } ); That runs when the component first mounts and the modal is not mounted so all those selectors come back null, so while the GSAP Timeline has been created, no DOM element will be animated. In fact if you remove all your GSAP code and leave just this:
    const [isOpen, setIsOpen] = useState(false); const [isMounted, setIsMounted] = useState(false); const containerRef = useRef<HTMLDivElement | null>(null); const toggle = () => { setIsOpen(!isOpen); }; useEffect(() => { setIsMounted(true); }, []); And inspect the DOM there is nothing being added to it, so updating the isOpen state is not causing any effect in the DOM, the modal is not even being rendered, so you should first check that the modal is being rendered in the DOM before it can be animated with GSAP.
     
    Happy Tweening!
  8. Rodrigo's post in Toggle class when element is within viewport and has a variable height was marked as the answer   
    Hi @MDesigns and welcome to the GSAP Forums!
     
    You're looking for ScrollTrigger's refresh method:
    https://gsap.com/docs/v3/Plugins/ScrollTrigger/static.refresh()
     
    Something like this:
    $('.post-list-footer a').click(function(e) { e.preventDefault(); $('.post').show(); $(this).hide(); // After adding the new elements refresh the ScrollTrigger instances on the page ScrollTrigger.refresh(); }); That will tell ScrollTrigger to run all the calculations again, updating the start and end points accordingly. Here is a fork of your demo:

    See the Pen rNbEyGw by GreenSock (@GreenSock) on CodePen
     
    Here is a demo that emulates an API callback using ScrollTrigger's batch method:
    https://gsap.com/docs/v3/Plugins/ScrollTrigger/static.batch()
     

    See the Pen YzOzjbL by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  9. Rodrigo's post in Question about horizontal scroll section was marked as the answer   
    Hey Sam,
     
    I'm on my phone now so no chance at looking at the site.
     
    On a quick glance at the snippet you posted, I see that in your horizontal tween you're using the default easing function which is power1.out, that will make the motion start fast and end slow. When mimicking horizontal scroll always use ease none (see the ease visualizer on our learning center).
     
    Give that a try and let us know how it goes 
    Happy Tweening!
  10. Rodrigo's post in Controlling the drag position of an element that's already controlled via another element's scroll position was marked as the answer   
    Hi,
     
    Well I couldn't resist to create a simple demo of this, super fun!:

    See the Pen BaEMOrd by GreenSock (@GreenSock) on CodePen
     
    The magic numbers you see there are because:
    The width of the wrapper is 80% the screen width. The wrapper for the box has a 10 px padding on the left/right The box element has a fixed width of 75px  
    Hopefully this helps.
    Happy Tweening!
  11. Rodrigo's post in Sticky slider with snap scroll was marked as the answer   
    Hi @milecoder and welcome to the GSAP Forums!
     
    That can be done with the Observer Plugin:
    https://gsap.com/docs/v3/Plugins/Observer/
     
    If you check that particular site, in that section they hide the custom scrollbar, if you hover on it you'll see the scrollbar again and you can actually scroll past that section without the swipe effect.
     
    What can be used is a combination of ScrollTrigger and Observer as shown in this demo:

    See the Pen ExEOeJQ by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  12. Rodrigo's post in ScrollSmoother over iframe was marked as the answer   
    Hi,
     
    Honestly I couldn't tell you but you can try ScrollSmoother and every other GSAP Bonus plugin forking this codepen:

    See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen
     
    Also you can try all the bonus plugins in your local development environment by installing the GSAP Trial package:
    https://www.npmjs.com/package/gsap-trial
     
    Hopefully this helps.
    Happy Tweening!
  13. Rodrigo's post in Is there a better way to fade in text blocks based on the timeline progress? was marked as the answer   
    I doubt you'll run into performance problems with this TBH, since you have a rather small collection of elements.
     
    IMHO though this seems simpler to understand, follow and maintain:
    const blockElements = gsap.utils.toArray(".block"); const block1 = blocks.querySelector(".block-1"); const block2 = blocks.querySelector(".block-2"); const block3 = blocks.querySelector(".block-3"); const blockSettings = [ { element: block1, position: 30 }, { element: block2, position: 50 }, { element: block3, position: 60 } ]; blockSettings.forEach((b, i) => { const block = blockElements[i]; const otherBlocks = blockElements.filter((block, j) => i !== j); tl.add(() => { gsap.to(block, { opacity: 1, duration: 1, scale: 1 }); gsap.to(otherBlocks, { opacity: 0, duration: 1, scale: 1.2 }); }, b.position); }); You don't have to resort to that conditional block and anything that results in simpler and shorter code, is going to make more sense if you have to look at it in 6 months.
     
    Here is a fork of your demo:

    See the Pen oNORmKL by GreenSock (@GreenSock) on CodePen
     
    Is worth mentioning that using the add() to add an anonymous function is the same as using call():
    const tl = gsap.timeline(); tl.add(() => {}, position); // Exactly the same tl.call(() => {}, [/*parameters*/], position); Hopefully this helps.
    Happy Tweening!
  14. Rodrigo's post in Animating TranslateY noticing flickering in React was marked as the answer   
    That is mostly because GSAP handles all the transforms using the 3D transform matrix:
    https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function
    https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix3d
     
    While setting a single transform using CSS does just that, applies a single transform. When you do that and then animate the same property with GSAP, GSAP takes that value applied by CSS and uses it's own method for transforms. That is why we recommend doing what you tried and worked, use GSAP to  set all the initial transforms that will be animated with GSAP, to avoid that extra step when the animation first runs. Also sometimes is a good idea to use the advice from the FOUC article to prevent annoying flashes before the JS runs.
     
    Happy Tweening!
  15. Rodrigo's post in nuxt cleanup and scrolling trigger was marked as the answer   
    Cleanup is not needed when refreshing the page, that's a whole new load of everything in it. If you want to keep the scroll position you can try with scroll restoration, using ScrollTrigger's clearScrollMemory method:
    https://gsap.com/docs/v3/Plugins/ScrollTrigger/static.clearScrollMemory()
     
    Also you can find out more here:
    https://stackoverflow.com/questions/73049943/scroll-behaviour-not-working-in-nuxt3-application
    https://github.com/nuxt/nuxt/issues/22487#issuecomment-1867422709
     
    Hopefully this helps.
    Happy Tweening!
  16. Rodrigo's post in divide a site into two equal parts and have different scroll speeds was marked as the answer   
    Hi,
     
    Basically your ScrollTrigger import is wrong:
     
    // Wrong import scrolltrigger from "https://esm.sh/scrolltrigger"; // Right import ScrollTrigger from "https://esm.sh/gsap/ScrollTrigger"; ScrollTrigger  is part of the GSAP package, not an individual separate package and is PascalCased, you had it in lower case.
     
    Hopefully this helps.
    Happy Tweening!
  17. Rodrigo's post in Re-using timeline with dynamic fill property was marked as the answer   
    Hi @Vilas and welcome to the GSAP Forums!
     
    You're using the invalidate method AFTER restarting the timeline, it has to be BEFORE:
    const runAnimation = (currentColorName) => { currentColor = currentColorName; tl.invalidate(); tl.restart(); };  
    Another option is to use the call method:
    https://gsap.com/docs/v3/GSAP/Timeline/call()
     
    const tweenFill = () => { gsap.to(circles, { stagger: { each: 0.05 }, ease: "none", fill: function () { return `#${currentColor}`; } }); }; tl.call(tweenFill); tl.to( circles, { stagger: { each: 0.05, repeat: 1, yoyo: true }, scale: 1.05, ease: "sine.inOut", transformOrigin: "center center" }, "<" ); Here is a fork of your codepen:

    See the Pen bGJxEJd by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps
    Happy Tweening!
  18. Rodrigo's post in Awaiting for timelines to revert() was marked as the answer   
    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!
  19. Rodrigo's post in Mixing ScrollTrigger with Lenis in a Nuxt project was marked as the answer   
    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!
  20. Rodrigo's post in SVG path animation triggerd by scrolling with different sections was marked as the answer   
    Hi,
     
    Not really TBH. What you're trying to achieve is not the simplest thing to do and adding stuff through a CMS only brings more complexity to it since you need a 100% dynamic solution for this.
     
    As I mentioned before the issue resides in the start and end points of each ScrollTrigger, having different sections for the SVG only adds an extra wrinkle to this.
     
    Here are a couple of demos that use different approaches to this:

    See the Pen zYrPrgd by creativeocean (@creativeocean) on CodePen
     

    See the Pen jOryjNX by oliviale (@oliviale) on CodePen
     
    Finally this mostly boils down to your layout more than anything else. I forked your demo and added different indents and ids to each ScrollTrigger instance and you can see in section 2 your SVG is waaaaay too tall, it goes beyond the final spacing element. The mask and path for that section also is the same height but the actual drawing is smaller, that's why that section's draw animation finishes before the end point of the ScrollTrigger instance is reached:

    The light blue rectangle is one of the SVG tags for section 2, but the path finishes quite before that, that's why you're getting those pauses between sections.

    See the Pen QWoYQQQ by GreenSock (@GreenSock) on CodePen
     
    You can see that the end point for scroller 3 is way after the animation already ended
     
    Again this boils down to HTML/CSS/SVG and not a GSAP related issue and is beyond the scope of the help we can provide in these free forums. You have to find a way to make your SVG to dynamically adapt to the dimensions of the content and the screen.
     
    Good luck with your project!
    Happy Tweening!
  21. Rodrigo's post in Invalid scope on dynamically rendered elements with scrolltriggers when switching routes in Next js was marked as the answer   
    Yeah the issue could be that the fact that the boolean on your state is updated that doesn't necessarily means that the elements are rendered yet, especially when you run that ScrollTrigger.refresh() method. Any particular reason for that? I don't really see any reason for having that code in that component. Removing that single line seems to fix the issue.
     
    As far as I can tell there is no real need to have that refresh call there, since when that component is unmounted the useGSAP hook will revert everything inside of it, so there shouldn't be any reason to globally refresh ScrollTrigger, unless there are other ScrollTrigger instances in your parent component, but still 
    if you need it you can add the revertOnUpdate option to the useGSAP hook to revert everything:
    useGSAP( () => { if (feedLoaded) { ScrollTrigger.refresh(); // rest of your code } }, { scope: curatorContainer, revertOnUpdate: true, dependencies: [feedLoaded], } ); Hopefully this helps.
    Happy Tweening!
     
  22. Rodrigo's post in I encountered some issues with ScrollTrigger again. was marked as the answer   
    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:

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

    See the Pen OJBvBjB by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  23. Rodrigo's post in How to animate a storyline with multiple stacked texts? was marked as the answer   
    Hi,
     
    In this case the Observer Plugin might be a better fit actually:
    https://gsap.com/docs/v3/Plugins/Observer/
     

    See the Pen XWzRraJ by GreenSock (@GreenSock) on CodePen
     
    Here is a demo that mixes ScrollTrigger with Observer:

    See the Pen ExEOeJQ by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  24. Rodrigo's post in Scroll, zoom and pin into SVG logo was marked as the answer   
    Hi,
     
    Mainly the issue is that when using invalidateOnRefresh with ScrollTrigger your values need to be function based. This is what was happening, invalidateOnRefresh was flushing the starting values of the scale tween, but nothing more. The final value was always the same.
     
    This seems to fix the problem:
    let logoToScale = () => (window.innerWidth / logo.getBBox().width) * 5; const timelineHeader = gsap.timeline({ scrollTrigger: { id: "ZOOM", trigger: "div.landing", scrub: true, start: "top top", end: "+=100% 0", pin: true, markers: true, invalidateOnRefresh: true } }); timelineHeader.to(logo, { duration: 1.5, ease: "none", scale: () => logoToScale() }); Here is a fork of your demo:

    See the Pen WNWgaqZ by GreenSock (@GreenSock) on CodePen
     
    Hopefully this helps.
    Happy Tweening!
  25. Rodrigo's post in ssr:warn Please gsap.registerPlugin(CustomEase) when using CustomEase with Nuxt 3 was marked as the answer   
    Hi @m__shum and welcome to the GSAP Forums!
     
    Sorry to hear about the issues. I created a new Nuxt3 app here in my local machine and this is working without any issues:
    import gsap from "gsap"; import { CustomEase } from "gsap/CustomEase"; import { onMounted } from "vue"; if (typeof window !== "undefined") { gsap.registerPlugin(CustomEase); } const myEase = CustomEase.create('myEase', 'M0,0 C0.29,0 0.311,0.268 0.35,0.502 0.423,0.951 0.756,0.979 1,1 '); onMounted(() => { gsap.to("h1", { x:200, y: 200, ease: "myEase", duration: 2, }); }); I would recommend you to use the onMounted hook in your setup.
     
    We have this starter template on stackblitz that you can use as a reference:
    https://stackblitz.com/edit/nuxt-starter-aih1uf
     
    Hopefully this helps.
    Happy Tweening!
×
×
  • Create New...