Jump to content
GreenSock

Leaderboard

Popular Content

Showing content with the highest reputation since 08/28/2022 in all areas

  1. @webflow.be welcome to the forum! Creating a clean SVG is half the work when working with SVGs. I have no idea where your SVG came from, but it was a mess for such a simple file (some programs will do that ). I've cleaned it up a bit, so that it is just the 6 letters in the SVG. You could run your SVGs through SVGGO to help clean it up automatically, but I did it by hand and then loaded it in Figma to modify it visually. What I've coded is giving all the letters a transform on the x axis to the middle of the SVG. This looks like complicated code, but it is just getting the width of the SVG and the X offset of all the letters. If you then do a .from() tween they will animate from that position to their original position. From your slides I think you want only the two letters E's to be visible at on page load, but I'll leave that to you. I would suggest giving all the letters a class to indicate if they need to be visible or not and then add another tween that makes these letters visible, you can play with the position parameter (take a look at the docs) to have all the tween start at the same time. If you are stuck be sure to post back here, but nobody learns from copy and pasting code , so I challenge you to see how far you can come! https://codepen.io/mvaneijgen/pen/yLjMeEJ Veel geluk en succes!
    5 points
  2. Speaking as someone who is also relatively new to GSAP, I really recommend the courses @Carl runs at creativecodingclub.com. Having already gone through many, many hours of the content on there I can tell you there's some really good, clear information on the difference between from, to, and fromTo tweens as well as the "flicker" you mentioned and how to address it.
    5 points
  3. All the animations start at the same time, but the once from the left start at -100 that is 100% to the left of the browser eg they are not visible. So I think you like to stay between 0 ,100 instead of -100, 100. That is not randomly. If you do random they could all come from the same direction. I would build a more elaborate wrap so that you have the control you want. const wrap = gsap.utils.wrap([-100, 100, 70, -20, -50, 70, -20, 50, 0, 40]) you can add as much numbers as you want, just play with these until you find something that works for you. https://codepen.io/mvaneijgen/pen/zYjpPjw
    4 points
  4. If I understand correctly what it is you want to do, transformOrigin will not be helpful here, @amit95 Instead, you might want to use the stagger as an object, so you can define its settings in more detail. I changed the stagger of your closing tween to this e.g. // old stagger: .2 // new stagger: { each: .2, from: 'end' } So, did you mean like this? https://codepen.io/akapowl/pen/gOzxPgx
    4 points
  5. Hi, You can use the Snap Plugin for that: https://greensock.com/docs/v3/GSAP/CorePlugins/SnapPlugin It should be as simple as: gsap.to(myFilter, { size: 80, snap: "size", duration: 5 }); This is a core plugin so you don't need to include any other file, import or register the plugin. Let us know how it works. Happy Tweening!!!
    4 points
  6. Hi Martin! You have multiples ways to do that. First, you can simply add an "onComplete" function to trigger when your SVG is completely draw. .from(".path-1", {drawSVG: 0, onComplete: () => { console.log('Completed'); }}, 0) In an other hand, you can done your scrolltrigger inner a timeline and call your border-color change after like you do now, but like that: main.from(".path-1", {drawSVG: 0}, 0) main.to(".path-1", {stroke: '#ff0000'}); (For the example I change the stroke color of your SVG, but feel free to change it for do your stuff with the .box) Or, in your actual scrolltrigger code, you can use onLeave, onEnterBack function. Best regards! Sam
    4 points
  7. Hey @raana, Your codesandbox sample doesn't have any scroll on the main container, so making this adjustment creates a scroll to test how ScrollTrigger is working: <div style={{ height: "100vh" }}></div> <div className="index-module--container--J02ig"> <!-- REST OF YOUR JSX --> </div> <div style={{ height: "200vh" }}></div> As for running a ScrollTrigger animation (or a part of it) when the page loads, you'll have to tinker with the start position of the ScrollTrigger instance to play part of the animation after the content is loaded. Happy Tweening!!!
    4 points
  8. Hi and welcome to the GreenSock forums. Why not create the particles in the SVG? it doesn't seem to create a performance issue: https://codepen.io/rhernando/pen/ExLPWxJ?editors=0010 Trying to line-up correctly the SVG and the DIV with the particles could become a bit complicated, so I'd try to exhaust every possibility of using just SVG for this. Happy Tweening!!!
    4 points
  9. Hey Andrew, have a look at my solution here: I had some issues with a client's weird Windows/mouse setup, but on other machines it works just fine.
    4 points
  10. Yeah, I think some browsers just don't render transforms on textPath or textSpan elements because they're considered "inline" (same for <span> elements). It's totally unrelated to GSAP. With the newer SVG2 spec, it seems some browsers are shifting to support it. https://lists.w3.org/Archives/Public/www-svg/2016Jan/0010.html In short, I wouldn't recommend doing it if you want 100% browser support. Do what Carl showed. Or wrap it in a <g>. 👍
    4 points
  11. it may be as simple as calling gsap.globalTimeline.progress(1) https://greensock.com/docs/v3/GSAP/gsap.globalTimeline if that doesn't work or causes issues with gameplay try exportRoot() var tl = gsap.exportRoot(); tl.progress(1) https://greensock.com/docs/v3/GSAP/gsap.exportRoot()
    4 points
  12. Hello, You can use the onEnter and onEnterBack callbacks from ScrollTrigger to set/unset the active class on the links elements. Check this codepen to see how it works: https://codepen.io/GreenSock/pen/bGVjLwG Happy Tweening!!!
    4 points
  13. Hi and welcome to the GreenSock forums, In cases like this it really helps to provide a minimal demo as the code you displayed only tells a portion of the story. It's nice to see all the things you've tried, but if you are combining them all at once it's likely some techniques may cancel out others making it very hard for us to know what is causing the issue. Also mixing css animations and gsap is bad practice and can further complicate how your code is being executed. I'm curious why you are using a jQuery each loop on #Dog. An element with an ID should exist only once which means there really shouldn't be anything to loop through. If you have multiple #Dog elements this certainly could be causing a problem. I would strongly suggest getting this to work on a single dog first before you worry about looping and creating multiple animations for multiple sections. to make things easier for you below is a very bare bones demo that shows a single tween being played when the #dogContainer's center passes the center of the viewport for the first time. https://codepen.io/snorkltv/pen/ExEqOVK Feel free to fork the demo and add your html, css, and javascript. The demo already loads GSAP, ScrollTrigger and jQuery. Once you get your dog moving OR we see a minimal demo of what you've tried then we can move forward and tackle individual issues / features.
    4 points
  14. Hi and welcome You don't have a panel class. Your panel is in fact hs-img. Here: https://codepen.io/danielmtd/pen/WNzVJqE
    4 points
  15. Just thought I'd say I've been tracking Carl's svg lessons knowing that I should do them at somepoint, but this first mini project I just got by email looks quality. That is all. (Well except Carl, is there any chance one of your projects involves zooming into svg backgrounds?) I swear he didn't pay me for this 😄, but I feel like this series is morphing into somthing I should do, and I *hate* svgs **Edit: creativecodingclub.com 👍
    3 points
  16. Welcome to the GrenSock forum! There's lots of ways to do that - and depending on what exactly you want to do, one is suited better than another. You will probably best want to look into either timelines or callbacks (everything starting with on... in the Special Properties section of the docs). https://codepen.io/akapowl/pen/KKRXYXo
    3 points
  17. I've disabled one of your ScrollTriggers and the jump seems to have been gone. With this particular ScrollTrigger you're animating the same element that is also the trigger, you almost never wan to do that, because this will endup causing problems when you are not careful. You're also animating the maxWidth with this element, I think you want it to grow to the left and right, right? You can beter use scaleX for that, that is way more performant. I my self like to always start with a timeline in GSAP, this way if I want a second animation to the same ScrollTrigger I can easily do that, but if you start with just a gsap.to() tween you can't. I've restructured your first ScrollTrigger to be a time line and thus if you want to add something else at the same time (like the scaleX of something) you can now do that and use the position parameter to have these start at the same time. https://codepen.io/mvaneijgen/pen/vYjexQg?editors=0010
    3 points
  18. @Geoff Dawes and @___wtem___, Thanks a lot for contributing to this thread 🥳 We really appreciate your help and input! Happy Tweening!!!
    3 points
  19. Hi, It is actually working, we just can't see it The issue is that it starts from the first image that is at the bottom of the stack of images. But lucky for us GSAP has advanced staggers that help you with this: el.addEventListener("mouseover", (e) => { gsap.to(".first", { scale: 0.5, duration: 0.6, stagger: { each: 0.1, from: "end" } }); }); https://codepen.io/GreenSock/pen/gOzxvGQ Happy Tweening!!!
    3 points
  20. While you clear the timeline on that breakpoint (meaning you empty it of all the tweens, timelines, and callbacks it contains), I suppose the timeline instance itself, which has the ScrollTrigger with the pin (!) attached will be present no matter what the viewport size is because you created it outside of any matchMedia call beforehand - so you will probably want to change that. Does that work more like what you intended? https://codepen.io/akapowl/pen/dyezGJO
    3 points
  21. Hi @div138, What worked for me was: 1. renaming the file ScrollSmoother.min.js to ScrollSmoother.min.txt 2. Upload the .txt file to Webflow 3. Then find the URL of the uploaded .txt file - should look something like this <script src="https://uploads-ssl.webflow.com/62e3acd626f7sd0ac59653c2/6we913e507820a453df444d7_ScrollSmoother.min.txt"></script> 4. It will still be able to read the js inside the .txt file. Hope that helps
    3 points
  22. Sorry about the confusion there. It was indeed a regression related to the new revert() functionality (which empowers matchMedia() and context()) that affects when you from() tween non-CSS properties of DOM elements but it should be resolved in the next release which you can preview at https://assets.codepen.io/16327/gsap-latest-beta.min.js Better?
    3 points
  23. Hello, I modified the pen. Hope you find this helpful. https://codepen.io/tripti1410/pen/NWMpqxr?editors=1010 Or as a reference use this remove the zooming part and add opacity 0 to the main image. https://codepen.io/osublake/pen/wWJoQg?editors=1010
    3 points
  24. As you can see in the DevTools GSAP is transforming the `transform: scale(2, 2)` property and you are targeting the `scale:` property directly. This is a bit of a new feature in CSS and targeting it directly has less support by browsers. It is really interesting that we're in a transition phase now with these properties and I'm also interested in what @GreenSock thinks of this. Personally I'm sticking with `transform: scale()` for now, but I do have to admit that targeting the properties directly is much more intuitive. https://codepen.io/mvaneijgen/pen/JjvEQzb
    3 points
  25. I think Safari requires your SVG with the moving elements to have a width and height in the CSS. I popped width: 100%; height: 100%; into inspect and it showed up.
    3 points
  26. Yup, and just to add a bit. GSAP is AMAZING at animating SVG elements. This video breaks it down Taking the storyboard you supplied I very quickly did an animated mockup just to give a rough idea how something like this can come to life with a few lines of code https://codepen.io/snorkltv/pen/NWMdjxd?editors=1111 I did that in about 5 minutes and you could probably learn exactly what all that code means if you spend some time learning the basics of GSAP and SVG. I provide the demo just to give you a little push in the right direction and to show that it isn't necessarily complicated or overwhelming. This lesson may help as well when it comes to understanding the SVG and GSAP workflow This interactive graph by SVG Master @chrisgannon does a great job showing what is possible after investing loads of time honing your craft https://codepen.io/chrisgannon/pen/pbzEYr Be sure to drag the dot around. How cool is that? So yes, pretty much anything you want to animate on an SVG graph is totally possible with GSAP and you don't have to go crazy trying to make it work. If you need help getting started with GSAP I have a free course here and I'm about 17 lessons into my SVG beginner's course. hope this helps!
    3 points
  27. GSAP doesn't "draw" anything. If you make this graph within some design tool and load the SVG in the browser and try to manipulate it with GSAP you'll find it is really easy to do so with GSAP. For instance I see that the green line is not drawn at the first slide, this could easily be done with DrawSVG and that is the power of GSAP, it gives you the tools to animate almost anything.
    3 points
  28. Yep - looks like there's something whacky going on with the new safari update - we're looking into it as a priority. For now if you add normalizeScroll that'll ensure you can scroll again in safari https://codepen.io/GreenSock/pen/mdLOGKN
    3 points
  29. I've added the height of the element to the endTriggers height which makes it that it stops at the end of the section. https://codepen.io/mvaneijgen/pen/oNdYoVE?editors=0010 you can also do this dynamically by getting the hight of the element with JS https://codepen.io/mvaneijgen/pen/BaxQmEE?editors=0010 btw `TimelineMax` is really old syntax from GSAP 2, see the migration guide to update to the new syntax
    3 points
  30. From what I can tell, everything is working exactly as it should. revert() does NOT alter anything in the timeline itself. Think of it like rewinding to the very start and reverting all the properties that were affected by the animation. revert() doesn't flush everything out of the timeline nor does it force the tweens to invalidate() (flush the recorded starting/ending values). It is purely about reverting the values and it also removes it from the parent (sorta like killing it). In your case, however, you specifically called restart() so it shoved it back into its parent. That's unconventional. In general, you should consider a reverted animation to be dead and gone, not to be reused again. Obviously you CAN...but I just advise caution. I just find it easier for people to think in terms of it being gone. I noticed you had repeatRefresh: true but that would do nothing because you didn't have a repeat value on that animation. You misspelled immediateRender It's fine to do x: "100px" but you can shorten it to simply x: 100 since "px" is the default anyway. It depends what you mean by "initial positions". Are you just trying to rewind everything to the start? animation.progress(0) is fine. Or there are about 4 other ways you could do it When a tween renders for the first time, it records the start/end values internally so that it can very quickly interpolate during the course of the tween. It sounds like maybe you want to FLUSH those values out, right? If so, .invalidate() is what you're looking for, yes. Is this what you wanted?: https://codepen.io/GreenSock/pen/rNvLGzB?editors=0010
    3 points
  31. Welcome! It's tough to diagnose without a minimal demo (like a CodePen), but I assume this is what you need: And yes, Carl's resources are fantastic. 👍
    3 points
  32. Right, I see, you've copied my example and tried to adapt it to using SplitText. You are using an outdated syntax and are missing a few little bits. Have a look at the SplitText docs as well. You will see there is already a ton of functionality there. I recommend you also read the get started section in the site here so you can be familiar with the current GSAP syntax. Finally, below is your code refactored to achieve a pleasant animation. The key points there are: Add a class to each split letter, creating a "dictionary" of tweens, storing an "index" reference of the dictionary entry on each letter as a data-attribute and checking to see if the element hovered over has said dictionary reference and if the tween is playing new SplitText(".wtg", {charsClass: "letter"}); const element = document.querySelector('.wtg'); const letters = gsap.utils.toArray(".letter"); const tweens = {}; element.addEventListener('mouseover', onMouseOver); letters.forEach((letter, index) => { tweens[index] = gsap.to(letter, {yPercent: -50, yoyo:true, repeat:1, paused: true}); letter.dataset.tween = index; }) function onMouseOver(event) { const trg = event.target; if(trg.dataset.tween) { tween = tweens[trg.dataset.tween]; if (!gsap.isTweening(trg)) { tween.play(0); } } }
    3 points
  33. May be a another dumb question but is there any particular way to update a paid package? It's as simple as yarn upgrade gsap
    3 points
  34. Hey there! This is applying a transition on *all* properties. So that's going to include any properties being animated with GSAP! This says, whenever anything changes on the element I've applied this to, make that change last 0.4s So when GSAP tries to move the elements, CSS is overriding it. We recommend just using GSAP (we always have, because issues like this arise when you mix CSS and GSAP animations) But of course, you can still use CSS hover effects, you just have to make sure you're not animating the same element and causing conflicts. Here's a simplified demo https://codepen.io/GreenSock/pen/JjvYZqB
    3 points
  35. just for kicks I made a quick test showing a timeline, its child tween, and an independent tween all completing when the globalTimeline gets progress(1). https://codepen.io/snorkltv/pen/ExLjzzp?editors=1111 click the button within 20 seconds or re-run the demo. logs shown in console "child complete" "timeline complete" "independent complete" you can use this as a starter file or create your own codepen or codesandbox minimal demo. the simpler the better.
    3 points
  36. Awesome, yeah that's really helpful thanks! ContainerAnimation is definitely what you're after. Here you go, something like this? https://codepen.io/GreenSock/pen/bGMdJej?editors=0011
    3 points
  37. Ah ok - I see! Well, if you want to pin different elements at different points and incorporate that demo, then you're probably best off creating a timeline for each section. At the moment you have everything positioned absolutely so I'd start by adjusting your HTML and CSS so you have something like this and then you can handle the 'DO MORE' timeline separately and follow the logic in Mikel's pen. https://codepen.io/GreenSock/pen/poVJYRa?editors=1000 Otherwise you could do a rough approximation with staggers - that might work, but you'll have to tweak the timings and layout a little either way! https://codepen.io/GreenSock/pen/vYjOPwg?editors=1010 I also noticed you're using some old syntax so you may want to have a little look at this article!
    3 points
  38. start here. https://mgearon.com/css/css-background-clip-text/ here is a stripped down demo i had showing the text shrink https://codepen.io/snorkltv/pen/NWMqzGW google "css clip mask text" for more. not really sure how to handle video. you may have to use canvas.
    3 points
  39. OMG! YOU @Rodrigo are a LEGEND!!!!!! It's works! 🥳
    3 points
  40. Hello Anna, welcome to the GSAP forum! In JS, instead of the line that sets the random image from lorem picsum, you could create an array with all your image-urls and then adjust that image-setting line to target the element with the respective index, like so maybe: // instead of this.. gsap.set('.gridBlock', {backgroundImage: i => `url(https://picsum.photos/${size}/${size}?random=${i})`}); //... you could do this for your pre-stored images const imageArray = [ 'url(https://picsum.photos/id/231/400/300)', 'url(https://picsum.photos/id/232/400/300)', 'url(https://picsum.photos/id/233/400/300)', 'url(https://picsum.photos/id/234/1600/1200)', 'url(https://picsum.photos/id/235/400/300)', 'url(https://picsum.photos/id/236/400/300)', 'url(https://picsum.photos/id/237/400/300)', 'url(https://picsum.photos/id/238/400/300)', 'url(https://picsum.photos/id/239/400/300)' ] gsap.set('.gridBlock', {backgroundImage: i => imageArray[i] }); Then you'll probably also have to change the bigImg url to e.g. the url of your largest image, so the 'pre-loading' type of functionality of that pen will still work out as intended. https://codepen.io/akapowl/pen/oNdXpOE Or, since after all, all that line does is set a background-image to the respective div-element, you could just do it manually via CSS instead. .gridLayer:nth-child(1) .gridBlock { background-image: url(https://your.url/image1.jpg) } .gridLayer:nth-child(2) .gridBlock { background-image: url(https://your.url/image2.jpg) } ... https://codepen.io/akapowl/pen/VwxLybz
    3 points
  41. Hi and welcome to the GreenSock forums!! I believe you are on the right track with your approach. Just a few pointers. No need to add an onComplete or onUpdate callback in a timeline instance that is going to trigger a new GSAP instance, just replace the onComplete with another .to(), .from() or .fromTo() instance (depending on what you intend to do) after the instance, and replace the onUpdate with, again, a .to(), .from() or .fromTo() instance using the less than sign "<" as the position parameter and give it the same duration. I'm not sure if this code does what you're after: TL_items .to(".item-description-2", { opacity: 1, }) .to(".item-description-2", { autoAlpha: 0 }) .to(".item-2", { x: "23vw", //slide in from left - out of view into view }) .to(".item-1", { x: "55vw", // slide to the right of screen - but not out of view ease: "power2.out", }) .to(".item-description-1", { autoAlpha: 1 // fade in description when centre stage }) .to(".item-2", { x: "0vw", // slide to centre }) .to(".item-description-2", { autoAlpha: 1 // fade in description when centre stage }) .to(".item-1", { x: "0vw", // slide to the right of screen ease: "power2.out", }) .to(".item-description-1", { autoAlpha: 0 // fade out description when not centre stage }, "<") .to(".item-2", { x: "-43vw", // slide to centre }) .to(".item-description-2", { autoAlpha: 0 // fade out description when not centre stage }) .to(".item-3", { x: "-55vw", // slide in from out of view ease: "power2.out", }) .to(".item-description-3", { autoAlpha: 1 // fade in description when centre stage }) .to(".item-2", { x: "-75vw", // slide in from out of view ease: "power2.out" }) .to(".item-3", { x: "-75vw", // slide in from out of view ease: "power2.out", }) .to(".item-description-3", { autoAlpha: 1 // fade in description when centre stage }) .to(".item-3", { x: "-175vw", // slide in from out of view ease: "power2.out", }) .to(".item-description-3", { autoAlpha: 0 // fade out description when not centre stage }, "<-=0.25"); But as you can see is far simpler to follow than the usage of onComplete and onUpdate. Finally take a look at the docs for the GSAP Timeline's position parameter: And take a look at the documentation regarding easing as well, to ensure that you're using the correct syntax: https://greensock.com/docs/v3/Eases Happy Tweening!!!
    3 points
  42. thanks for the video. I don't have any windows / android devices. In the demo below I'm rotating the <text> element. Does that give more consistent results? https://codepen.io/snorkltv/pen/oNdgJVd @GreenSock may be able to shed more light on this, but please understand the company and support staff may be observing holiday hours today
    3 points
  43. Welcome to the GSAP forum! Since your .container__content has position: fixed anyway there really isn't much use pinning it with ScrollTrigger - since it is already fixed - and I think this is also where your problems originate. The only thing in your scenario that would need to be pinned is your .container__bg, which also makes sense to be used as the trigger element for the text going the other direction. If you need mulitple animations to be triggered at the same time and/or scrubbed along the exact same distance like you would here then, best just use a timeline instead of setting up multiple ScrollTriggers, and use the position parameter to tell GSAP that they should both start right away. https://codepen.io/akapowl/pen/MWGWezY
    3 points
  44. That's because you forgot to define the targets. Remember, when you just feed in a state object, it'll use the targets that were captured in that state by default but in your example, those elements were completely removed from the DOM and there are entirely new ones that got rendered, hence the need to tell the Flip "use these new targets and search the state object for the IDs that match..." // BAD Flip.from(state, { duration: 1 }); // GOOD Flip.from(state, { targets: ".box", // <-- BINGO duration: 1 }); Does that clear things up?
    3 points
  45. thanks for the demo. option 1: instead of using a stagger use a loop to create the animations and add them to the timeline. inside your loop run a condition that checks if you're on the last iteration. if yes, don't add that animation to the timeline. option 2: use a function based value for the autoAlpha property in the stagger. with this technique you can run a condition on each target to see if it is the last or not. based on that condition you can return a custom value. here is a demo for option 2 https://codepen.io/snorkltv/pen/rNvBQYV
    3 points
  46. Here's a video to clear it all up in case anyone's struggling! Happy tweening pals.
    3 points
  47. Ok, sure - so it's probably best to think in terms of state rather than animation to start with. Your boxes are either active or not active - if you work out that logic then you can base your animation off that. Maybe something like... https://codepen.io/GreenSock/pen/bGvXJed?editors=0011
    3 points
  48. Everything inside ' ' or " " is called a string but when you change these to backticks ` ` it's transformed to a template literal that it's still a string but it gives you the option to add variables inside it and supports multiline strings. It's just sugar syntax to make the code more readable. For short: `top ${property}` can be easily replaced to 'top ' + property or "top " + property You can read more about template literals here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals If the trigger location is set top it may not find that css variable ( check for typos ). Try to log it in your website and see if it outputs something. https://codepen.io/danielmtd/pen/oNqKoWo
    3 points
  49. Hey I refactored that top code - thank you for that suggestion - yes, if I remove the refresh, the issue comes back. Thank you so much for your help, this project is due in a few days so I was started to get quite upset about the whole thing. So great to end the day with a win, really appreciate it
    3 points
  50. The new gsap.context() in GSAP 3.11 totally solves this issue - it offers two key benefits: Collects all GSAP animations and ScrollTriggers that are created within the supplied function so that you can easily revert() or kill() ALL of them at once. No need to keep track of a bunch of variables, Arrays, etc. This is particularly useful in React modules or anywhere you need to be able to "clean up" by reverting elements to their original state. [optionally] Scopes all selector text to a particular Element or Ref. This can help simplify your code quite a bit and avoid needing to create lots of Refs in React/Angular. Any GSAP-related selector text inside the supplied function will only apply to descendants of the Element/Ref. Let's say you've got a big block of GSAP code that's creating a bunch of different animations and you need to be able to revert() them all... let ctx = gsap.context(() => { gsap.to(...); gsap.from(...); gsap.timeline().to(...).to(...); ... }); // then later... ctx.revert(); // BOOM! Every GSAP animation created in that function gets reverted! https://codepen.io/GreenSock/pen/xxWRjyq Docs: https://greensock.com/docs/v3/GSAP/gsap.context()
    3 points
×