Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...

Leaderboard

  1. OSUblake

    OSUblake

    Administrators


    • Points

      17,898

    • Posts

      9,196


  2. GreenSock

    GreenSock

    Administrators


    • Points

      15,455

    • Posts

      18,799


  3. PointC

    PointC

    Moderators


    • Points

      13,377

    • Posts

      4,811


  4. Carl

    Carl

    Moderators


    • Points

      10,446

    • Posts

      9,583


Popular Content

Showing content with the highest reputation since 03/12/2012 in all areas

  1. A GSAP tale: One goofy guy’s odyssey from knowing nothing to knowing just enough to confuse himself. (This is crazy long so feel free to jump to the epic conclusion). Greetings fellow GreenSockers. The end of this week marks the one-year anniversary of my first post on the forum so I thought I’d take the opportunity to share my 12-month story and hopefully encourage others to jump into the conversations around here. Maybe you’ll recognize yourself in some of the things I’ve experienced. My quick history in a nutshell Web design and coding is a second career for me. After 15 years of owning and operating a photography studio and processing lab (back in the film days - yup - I’m old), the digital camera came along and changed that industry, which necessitated a new career for me. I shifted to video production, which led to motion graphics and finally to web design. Our little agency now offers all those services. The web design clients never needed anything fancy so JavaScript took a back seat to HTML & CSS only sites for a number of years. JavaScript & GSAP: false starts and other obligations I first discovered GSAP a few years ago, but only tried it briefly. It looked cool, but with the time obligations of field video work and motion graphics jobs, it wasn’t something I could work into the schedule. Besides that, it was JavaScript – too complicated I thought. I knew JavaScript was the third piece of a good web designer’s skillset along with HTML and CSS, but I always convinced myself that I didn’t have the time and the sites we built didn’t need it. JavaScript Books + Classes = Fail I did make a few attempts at reading some JavaScript books and working through some online tutorials, but it just never ‘stuck’. Maybe the examples were too theoretical and dry or they were the wrong books and classes. I really don’t know, but I abandoned the learning process a number of times. Cut and Paste mentality Why did I really need to learn anyway? You can just Google what you need, cut and paste some code and presto – you’ve got some working JavaScript or jQuery. I only understood a small portion of what I was cutting and pasting, but hey… it worked so the problem was solved. That’s how I operated for quite some time. What’s a loop? What’s an array? What’s an object? Who cares? Wait a minute. This is ridiculous. Last spring, I was remodeling our company website and I had all these grand visions about making things move and behave in certain ways. Googling for code just wasn’t cutting it. I suddenly felt stupid. “This is ridiculous!” I thought. I should be able to learn how to write my own code. Oh yeah, I remembered that GreenSock thing I had looked at a few times and abandoned. That might work. Maybe I could actually learn how to use it this time. I become a forum lurker I started lurking in the shadows of the forum. After reading a lot of posts, I saw people asking many types of questions from simple to crazy complicated (at least to me). Two things I noticed were that every effort was made to find an answer (no matter the difficulty level of the question) and not one post was condescending or snarky. That’s quite rare on the ol’ interwebs, isn’t it? Hmmmm…maybe I’m in the right place. Oh boy… time to ask a question of my own One of the great things about learning GSAP is you’ll also pick up a lot of other JavaScript and/or jQuery along the way. I kept reading and practicing with some simple tweens, but now I had a question. Dare I post? I suppose, like many others, I feared looking like an idiot even though the forum members and moderators seemed quite nice and helpful. I do several dumb things every day so you’d think I’d be used to it by now. Oh well, here goes. My first question had to do with the indexOf() a Draggable snap array. Within 30 minutes, Diaco and Rodrigo had posted great answers and neither one called me stupid! Yay – how cool. I get hooked on GSAP and the forum About that same time, I decided our company should discontinue on-site video production and switch to studio only filming. I got tired of lugging loads of video gear in and out of buildings – it’s quite tiring and as I mentioned earlier – I’m old. This freed up some time and I decided to dedicate that time to learning GSAP and maybe, one day, even helping others. It wasn’t too long and I actually knew the answer to a forum question. I posted some information and wow – a little red indicator lit up on my control panel. Someone liked something I wrote. How fun – I’m hooked. Carl makes direct contact I continued to learn and experiment. I posted a few additional questions of my own, but I tried to answer more than I asked. If someone posted a question for which I had no answer, I tried to look it up in the docs and figure it out. Most of the time I was far too slow and Jack, Carl or one of the mods would already have the answer posted before I was done reading the question, but it was an interesting way to learn. I did sneak in a few good answers, which led to a private message from Carl. He thanked me for participating and helping in the forums. I thought it was pretty cool that a super smart guy like Professor Schooff would take the time to do that for little ol’ me. My decision to dedicate time to the platform and forum was reinforced. http://i.imgur.com/hdaB73Y.jpg Blake and I have a conversation I don’t recall if it was a back and forth in a forum post or a private message conversation, but Blake told me something that, of course is obvious, but it stuck with me and is important for all of us to remember. He mentioned that we all enter this learning process knowing nothing. If someone of Blake’s considerable skill level can be humble enough to remember first starting out in code, there may be hope for me after all. I guess if you think about it, there was a time when the simple concept of a variable was brand new to all of us. We’re not born with these abilities. They’re learned and we’re all at different points on the educational path. Never feel stupid for not knowing something. Moderator Promotion Throughout the last year, I’ve continued to learn and study both GSAP and JavaScript. Some of those books I abandoned in the past even make sense now. I’ve tried to be active in the GS community and answer as many forum questions as possible. If I’ve answered a question of yours, I hope you found it somewhat helpful. I’ve cranked out some fun CodePens and finally started a Twitter account to tweet them out. I am nowhere near an expert with GSAP or JavaScript, but I know so much more than I knew a year ago. Apparently I know enough to be entrusted with a forum promotion to Moderator status. I’m honored to be included on such an amazing team. 12 months down – what’s next? My agency duties are still numerous so I can’t dedicate full time to coding, but it remains something to which I’m committed and thoroughly enjoy. I started this 12-month GSAP journey just wanting the ability to write my own code rather than cutting and pasting the work of others. I’m confident I have achieved that, but I still have days when a simple piece of code just won’t coalesce in my brain and that can be frustrating. I guess we all have those days, right? I make several mistakes every day, but that’s o.k. too. I learn a lot more from my screw-ups than I ever do when it all goes right on the first try. I plan to keep learning and getting better and when I get stuck, I’ll be able to get an answer from this amazing community. I’ll continue to give back to the GS community by answering any questions that are within my abilities to do so. The super mods: Jonathan, Blake, Diaco and Rodrigo Thank you to my fellow moderators. You guys rock and have taught me so much. @Jonathan – if there is a browser bug, quirk or special fix that you are not aware of, I’ve yet to read about it. Your knowledge has helped me fix many pieces of code before they even became a problem. Plus, if I ever have a question of top/left vs. x/y, I know who I’ll ask. @Blake – if I could be half as good at coding as you, I’d be a very happy guy. Your work always teaches and inspires me. I don’t think you’re allowed to ever stop posting on the forum or we may all show up on your doorstep and ask questions. @Diaco – your code is always so concise. I deconstruct some of your pens and am astounded by how much you squeeze out of a few lines. If I made some of your pens from scratch, I’d have 20 variables, 5 loops, 12 tweens and 80 lines of code. You do the same with two variables and 4 lines of code. Amazing stuff. @Rodrigo – when searching the forum, I often land on one of your past posts and learn a lot. Your knowledge is vast and I wish you had more time to post around here. Your ninja skills are incredibly strong. Our superhero leaders @Carl – I’ve participated in several online forums ranging from graphic design to 3D to video production, but the GreenSock forum is the best and a big part of that is you. You not only provide great answers, but you do it in clever ways with just the right amount of humor thrown in here and there. The collection of videos you’ve made is invaluable and should be mandatory viewing for anyone interested in GSAP. I’ve seen you monitoring the forums at all hours of the day and even on weekends. When you get any sleep I’ll never know, but I thank you for your dedication and sharing your knowledge. @Jack – how you had the vision to start GreenSock and write the first version of the animation platform I can only imagine. I’m glad you did because GSAP is such an amazing collection of tools. The friendliness of the community is definitely following your lead. I don’t understand a lot of what you talk about sometimes, but I know enough to be amazed by your brilliance and talent. You call yourself just a guy who geeks out about code, but you’re more than that. You’re a smart and generous innovator who’s created a special brand and place on the web. I think I can safely speak for the community when I say we all appreciate the time and effort you put into helping us make beautiful and high-performance animations. Thank you sir. The epic conclusion. Well… maybe just a regular conclusion. If you didn’t read the whole post, I don’t blame you. It’s ridiculously long and I’m just some guy you don’t know so I’ll wrap it up with this bit of advice. Whether you’re a genius or feel like an idiot, it doesn’t matter. Try to learn one new thing each day and before you know it, a year will have passed and all those little bits will add up to new skills and abilities. If you’ve never posted on the forum, please jump in and participate. The more voices we have around here, the more we all benefit. If you need an answer, please don’t be afraid to ask a question. Believe me, I’m just some goofy guy in front of a computer. If I can learn this stuff, so can you. As I begin my second year in GreenSockLand, I’m looking forward to learning more, seeing everyone’s work and answering as many of your questions as I can. This is an amazing community and I encourage anyone reading this to set up an account and get involved. My best to all of my fellow GreenSockers. See you around the forums. Edit and Update (July 2020): I just made it to five years of hanging around the forum and you can read the continuation of my journey here. motiontricks.com Finally, without further ado, I introduce you to motiontricks.com - Craig (PointC) PS I made a little CodePen to commemorate my one-year forum anniversary. It’s how I felt before and after discovering the power of GSAP. Enjoy.
    50 points
  2. Hey fellow GreenSockers A little over five years ago, I took a chance and posted a question on the GreenSock forum. Nobody called me dumb and that was a HUGE relief! So much so that I wrote an entire GS post about it four years ago. It was a turning point for me and my JavaScript journey. Today, I’m taking another big leap in my life and launching a web animation tutorial site. My reasons for doing so are both personal and professional. This thread is a sequel to my One Year post listed above. Call it My Five Year Journey. Personal reasons My life has been full of twists, turns and milestone events over the past few years. I turned the big 50 and ask myself every day how that’s even possible. The memories of getting my first computer (TRS-80) and learning BASIC in the early 80s are so vivid that they feel like it was only a few years ago. Wasn’t it just yesterday I was programming the PET, VIC-20 and Commodore 64 in high school? Time does fly and I’m not getting any younger. I also celebrated my 30th wedding anniversary. That event itself isn’t a reason to start a new website, but the longer I’m married, the more I realize how lucky I am to have a partner and cheerleader with me when I try new things. She has been a tremendous support in this new endeavor. I wonder how I ever talked her into marrying me all those years ago and how she has put up with me for 30+ years. The other recent personal event that has shaped my decision is the one that is affecting us all right now. Seeing the effect of COVID-19 on the world and how it has robbed too many people of their lives and livelihoods has reminded me that time is precious, and you never know what’s around the corner. As they say, seize the day. Professional reasons After taking the leap and posting that first question on the forum, I was hooked on the GreenSock community. I’ve tried to help as many people as I could in my free time. I love seeing someone have that ‘ah-ha’ moment. This new site is an extension of that desire to help and teach. This will be a difficult challenge. It would be far easier to not do this. As a lifelong introvert, I’m far more comfortable in my dark office typing away on the keyboard so this definitely pushes me out of my comfort zone. It will also be a time management challenge to keep posting new content while taking care of clients and still helping on the forum. I’ll do my best. My final professional reason is that this just seems like the universe is pushing me in this direction. I loved computers and programming in my youth, but my career turned to my other loves of video production and photography. Throughout the last decade there have been many forks in the road, and it seems like every decision has led me here. My life has now come full circle. Fear and self-doubt Despite all the personal and professional reasons listed above, there has still been the nagging self-doubt. Will it be any good? Will anyone read it? Hasn’t this already been written? Maybe others don’t have that little voice in the back of their head, but mine starts yelling at me loudly when I try something big. It’s one thing to post an answer in the forum, but quite another to really put yourself out there with a whole new site. After some sleepless nights, I finally found calm from one realization. If I can help even one person with a problem, teach them something new or spark an idea, it will all be worth it. The rest of the fears don’t matter. Life is just too short to be scared or worried. The website’s focus If you know me from the GS forum, you know I love SVGs and making them move with GSAP. The website will, of course, feature a lot of SVGs and GreenSock will power everything. However, my primary focus will be real world projects. I find that I learn best when I’m building an actual project, so I’ll try to keep that as the focus. I’ll have lots of little tips and quick things too, but projects will be the main thing. Frequent visitors to the forum also know I don’t take it all too seriously and joke around a lot. You’ll be happy to know that several of the tutorials feature terrible jokes and puns at no extra charge. Thanks to the GS gang I’ve said it many times before and I’ll say it again. Thank you to Jack( @GreenSock) for creating the tools, but more importantly, thanks for fostering a terrific online community. Had I not discovered GSAP and started hanging around here, I would not know much about JavaScript and the new site would not exist. Special shout-out to @Carl too. He’s already in the trenches with training and tutorials and has encouraged me the whole way as I was getting this thing launched. All my fellow mods — thanks for the help and comradery over the years. You are all awesome! motiontricks.com Finally, without further ado, I introduce you to motiontricks.com My best to all of you. Thanks for reading. Now, let’s get those pixels movin’! 🚀 -Craig (PointC)
    24 points
  3. You can't animate most flexbox values because they're words, e.g. flex-start, space-around, column-reverse. You can't say, animate to column reverse. The browser has to do the layout. But that's actually a good thing as that's one less thing you have to calculate. To do a flexbox animations, start off by recording the position of your element in it's current state. Now change its flexbox style and let the browser reposition it. Now record the new position of your element. You now know where the element was, and where its supposed to be. Now move your element back to it's old position and animate it to it's new position. This all takes place in between animation frames, so you won't see the jump. This technique will work for every flexbox property. It will actually work for any type of layout that the browser handles, like the new CSS grid. For more information, check out these threads.
    18 points
  4. Welcome to the GreenSock forums! Glad you’re here. It’s a wonderful place to learn and get your questions answered. What topics can I post about here? We love answering questions that are directly related to GreenSock tools. API questions, bug reports, or if you’re wondering why GSAP behaves a certain way - those types of posts are welcome around here. What topics should be avoided? As much as we love solving problems, the following types of questions are beyond the scope of what we generally provide here for free: Logic issues. JavaScript and application logic, CSS setup, and generic troubleshooting that isn’t directly related to GreenSock tools. Third party tools. Frameworks (React, Angular), other JavaScript libraries (LocomotiveScroll, Barba), build tools, etc. We’re happy to help with the GSAP part of things if you strip out as much irrelevant code as possible and provide a minimal demo. “How do I do this cool effect I saw on a trendy website?” Someone here may point you in the right direction but please don't expect a full tutorial on how to create and effect you saw on a slick web site. Where else can I go for help? If your question is primarily about another tool, try looking for a forum or GitHub repository about that tool. If it’s a general programming-related question, try StackOverflow. Want feedback about your working code? We’d be glad to take a peek at GSAP-specific code but for more general topics (like performance or application logic) we’d suggest something like CodeReview. Read first Please read Getting Started with GSAP, common GSAP mistakes (maybe also common ScrollTrigger mistakes), as well as the GSAP docs before asking your question. Often you’ll get your question answered just by doing that! Make a minimal demo This helps provide context and gives us a rough idea of what you’re trying to accomplish. It's WAY better than trying to dig into a live website with lots of other things going on, or looking at a small excerpt of code without much context. Pro tip: It's often easier to create a minimal demo from scratch rather than stripping out irrelevant things from your original project. You will GREATLY increase your chances of getting a prompt answer if you create a minimal demo. After you've posted a demo to our forums, please click the "Fork" button on CodePen before making future changes so that context is not lost for future readers of the forum. Be courteous We try to treat people the way we’d want to be treated around here. Please do the same. Also keep in mind that the people answering your post are doing so for free! Most of our regular contributors gain nothing from helping you except the satisfaction of doing so. Please give them your gratitude and respect. Ask away! We’re eager to help, so make a minimal demo and ask your question! We’ll do our best to answer it promptly. Pay it forward - help someone else The best way to learn is to teach someone. You’d be surprised how much you grow when you try answering some questions here! We are so grateful for the group of volunteers dedicated to helping others in these forums. It’s quite satisfying to come alongside a fellow developer who is struggling and deliver a clever solution to their issue. Become a contributor! You do NOT need to be an expert. Anyone...and we do mean anyone...is welcome here.
    17 points
  5. With over 100,000 posts in the popular GreenSock forums, we've noticed some common mistakes that you'd be wise to avoid. We threw in a few tips as well. Here is a summary of the mistakes: Creating from() logic issues Using fromTo() when from() or to() would work Not setting ALL transforms with GSAP Not using xPercent and yPercent Recreating animations over and over Adding tweens to completed timelines Not using loops Importing things incorrectly Using the old/verbose syntax Creating from() logic issues It's usually smart to use .to() and .from() tweens instead of .fromTo() because they're more dynamic - they pull either the starting or ending values from whatever they happen to CURRENTLY be at the time that tween renders for the first time. It’s one of the tips in the article on animating efficiently. But be careful because that dynamic nature can bite you in a few scenarios. First, keep in mind that .from() tweens go from the provided value to the current value. Take a look at this example: See the Pen Illustrating .from() effects - Part 1 by GreenSock (@GreenSock) on CodePen. Try clicking it one time and letting it play. It works, fading in the element. Now try clicking it multiple times right after each other. The box stops showing up because it uses the current opacity as the end point which, if the animation has not completed, is some value less than 1. The fix for this is simple: use a .fromTo(). Alternatively you could create the animation beforehand and use a control method (we'll talk more about this approach later in this article). See the Pen Illustrating .from() effects - Part 1 by GreenSock (@GreenSock) on CodePen. Second, keep in mind that by default immediateRender is true by default for .from() and .fromTo() tweens because that's typically the most intuitive behavior (if you're animating from a certain value, it should start there right away). But if you create a .from() tween after a .to() tween affecting the same properties of the same object, try to figure out what will happen: const tl = gsap.timeline() tl.to(".box", {x: 100}); tl.from(".box", {x: 100}); You might expect the box to animate x from 0 to 100 and then back to 0. Or maybe you'd expect it to animate from 0 to 100 and then stay at 100. Let’s see what happens: See the Pen Illustrating .from() effects - Part 1 by GreenSock (@GreenSock) on CodePen. The box animates x from 100 to 100 and then back to 0. Why is that? By default .to() tweens wait to render until their playhead actually moves (it's a waste of CPU cycles to render at a time of 0 because nothing will have changed). But since from() has immediateRender: true, x jumps to 100 immediately on the current tick! Then it runs the .to() tween on the next tick (since it’s first in the timeline) and records the current starting value which is 100! So it animates 100 to 100 over 0.5 seconds. Then it runs the .from() tween which has the cached value of 0 as the end value. If you have several timelines affecting the same element, situations like this can be a little tricky to catch. So just be mindful of how things work when using .to() and .from() tweens. They’re very powerful but with power comes responsibility. A simple solution here is to set immediateRender: true on the .to() tween, or immediateRender: false on the .from() tween. The third situation is similar but involves repeatRefresh and repeats. Let’s say you have a situation where you want a looped animation that fades in some text and fades it out. You could create a timeline, use a .from() to fade in the text, then use a .to() to fade it out: const tl = gsap.timeline({repeat:-1}); tl.set(".text", { color: "random([green, gray, orange, pink])" }, 2); tl.from(chars, { opacity: 0 }); tl.to(chars, { opacity: 0 }); This will work just fine! Here’s the same thing but staggered using SplitText to make it look a little nicer: See the Pen Fade in and out text by GreenSock (@GreenSock) on CodePen. But this only randomizes the colors at the start. What if we want new random values each repeat? That’s where repeatRefresh comes in. Let’s add repeatRefresh: true to see what happens: See the Pen Random on Reset (wrong way) by GreenSock (@GreenSock) on CodePen. The animation plays correctly the first time but after that the elements don’t fade in a second time! Why is that? repeatRefresh uses the end values of the animation as the starting values of the next iteration. In this case, the opacity of our text elements are all 0 at the end. So when the animation gets to the .from() the second time around, the opacity animates from a value of 0 to a value of 0 since the tween is relative. What we want to do instead is always animate from a value of 0 to a value of 1 so here the easiest fix is to use a .fromTo(): See the Pen Random on Reset by GreenSock (@GreenSock) on CodePen. Now it does what we want. There are other solutions like using a .set() before the .from() but most often it’s easiest to just use a .fromTo() in cases like this. Using fromTo() when from() or to() would work If you can, it's better for performance, maintainability, and ease to use relative tweens like .from() or .to(). So don't use .fromTo() unless you need to. .fromTo() tweens aren't bad, but should only be used when needed. Not setting ALL transforms with GSAP If you are going to animate an element with GSAP, even the initial transform values (including on SVG elements) should be set with GSAP because it delivers better: Accuracy - The browser always reports computed values in pixels, thus it's impossible for GSAP to discern when you use another unit like % or vw in your CSS rule. Also, computed values are in matrix() or matrix3d() which are inherently ambiguous when it comes to rotation and scale. The matrix for 0, 360, and 720 degrees are identical. A scaleX of -1 results in the same matrix as something with rotation of 180 degrees and scaleY of -1. There are infinite combinations that are identical, but when you set transform-related values with GSAP, everything is saved in a perfectly accurate way. Performance - GSAP caches transform-related values to make things super fast. Parsing all of the components from a computed value is more expensive. If you are worried about a flash of unstyled content, you can handle that by using a technique that hides the element initially and then shows it via JavaScript as this post covers. Or you can set the initial styles with CSS rules and ALSO set them in GSAP. Not using xPercent and yPercent Did you know that you can combine percentage-based translation and other units? This is super useful if, for example, you'd like to align the center of an element with a particular offset, like {xPercent: -50, yPercent: -50, x: 100, y: 300}. We often see people use percent values in the x and y properties which is technically possible but can cause confusion at times. For example, if you set x and y to "-50%" and then later you set xPercent: -50, you'd see it move as if it's at xPercent: -100 because the x and xPercent both have -50%. Whenever you're setting a percentage-based translation, it's typically best to use the xPercent and yPercent properties. // Not recommended x: "50%", y: "50%", // Recommended xPercent: 50, yPercent: 50 Recreating animations over and over Creating your tweens and timelines beforehand has several advantages: Performance - Instead of having to create them right as they’re needed, you can do it ahead of time. Additionally, you need fewer instances of animations. Most of the time you’d never notice, but it’s good practice. Simplified logic - This is especially true when related to user interaction events. Freedom - Want to pause an animation when an event happens? Do it. Want to reverse an animation when the user does something? No problem. This sort of thing is much more difficult to handle when you create animations inside of event callbacks. Most of the time when you create animations beforehand, you will want to keep them paused until they’re needed. Then you can use control methods like .play(), .pause(), .reverse(), .progress(), .seek(), .restart(), and .timeScale() to affect their play state. Here’s a simple example: See the Pen Playing and reversing an animation on hover by GreenSock (@GreenSock) on CodePen. For more information related to creating animations beforehand, you can see the animating efficiently article. One exception to this rule is when you need things to be dynamic, like if the initial values may vary. For example, if you’re animating the height of the bars in a chart between various states and the user may click different buttons quickly, it’d make sense to create the animation each time to ensure they flow from whatever the current state is (even if it's mid-tween) like the demo below. See the Pen Playing and reversing an animation on hover by GreenSock (@GreenSock) on CodePen. Adding tweens to completed timelines A common pattern of mistakes that I’ve seen goes like this: const tl = gsap.timeline() tl.to(myElem, { x: 100 }); myElem.addEventListener("click", () => tl.to(myElem, { x: 300 }) ); Did you catch the mistake? If you add new tweens to a timeline that is already completed, they won’t be called unless you re-run the timeline. Almost always in these situations you should just use control methods for a previously created animation or create a new animation instead (not using an existing timeline) following the guidelines that we covered in the previous section. Not using loops If you want to apply the same effect to multiple elements (sections, cards, buttons, etc.) when a certain event happens to each one, you should almost always use a loop. For example, don’t use a selector like "button" when you want it to affect just one button. For example, if you wanted to fire an effect when each button is clicked: // BAD: immediately animates ALL buttons at once! gsap.effects.explode("button", { direction: "up", duration: 3 }); // GOOD: animation is specific to each button, and only when clicked gsap.utils.toArray("button").forEach(btn => btn.addEventListener("click", () => gsap.effects.explode(btn, { direction: "up", duration: 3 })) }); Inside of this loop, you can use a selector that is scoped to the given element so that you're only getting things INSIDE that element. For example: gsap.utils.toArray(".container").forEach(container => { let info = container.querySelector(".information"), silhouette = container.querySelector(".silhouette .cover"), tl = gsap.timeline({ paused: true }); tl.to(info, { yPercent: 0 }) .to(silhouette, { opacity: 0 }, 0); container.addEventListener("mouseenter", () => tl.play() ); container.addEventListener("mouseleave", () => tl.reverse() ); }); See the Pen Who's That Pokémon? - forEach example demo by GreenSock (@GreenSock) on CodePen. Importing GSAP incorrectly A common issue people face when using GSAP in a module environment is importing GSAP or its plugins incorrectly. Most of the time import errors error can be avoided by thoroughly reading the relevant parts of the installation page. I won't copy all of the details into this post, but be sure to make use of that page if you're facing any sort of import error. It even has a very handy GSAP install helper tool that can generate the correct import code to use in most environments. Using the old/verbose syntax Drop the Lite/Max I regularly see people using the old syntax even though they are loading GSAP 3. Old habits die hard. Even though the old syntax still technically works, the new modern GSAP 3 syntax is sleeker and simpler. Plus the old syntax won't be supported in GSAP 4 (which is far off in the future, but it's still a good idea to write future-friendly code). For example instead of using something that has Lite/Max in it, just use gsap: // old TweenLite.to() TweenMax.from() new TimelineMax() // new gsap.to() gsap.from() gsap.timeline() Use the string form for eases The shorter string form of eases requires less typing and lets you avoid extra import statements in module environments. // old Power2.easeOut Sine.easeInOut // new "power2" // The default is .out "sine.inOut" Duration belongs in the vars parameter Putting the duration inside of the vars parameter does require a bit more typing, but it makes things more readable and intuitive. GSAP’s defaults and effects are very helpful but you can’t make use of them if you’re putting the duration as the second parameter. // old gsap.to(elem, 1, { x: 100 }); // new gsap.to(elem, { duration: 1, x: 100}); // using GSAP’s defaults: const tl = gsap.timeline({ defaults: { duration: 1 } }); tl.to(elem, { x: 100 }); // no duration necessary! tl.to(elem, { y: 100, duration: 3 }); // easily overwrite the default value For a more full listing of changes in GSAP 3, check out the GSAP 3 Migration Guide. Numerical values don’t usually need to be strings For example if you want to set the x transform to 100 pixels, you don’t need to say x: "100px", you can just say x: 100. Simple! The only time when you need to pass numerical values as strings are if you need to change the unit (like x: "10vw") or pass in a complex value (like transformOrigin: "0px 50px"). The target of a tween can be a selector string I often see people do something like this: gsap.to(document.querySelectorAll(".box"), { x: 100 }); Or even with jQuery: gsap.to($(".box"), { x: 100 }); Both of the above will work but could be simplified by passing a selector string in as the target; GSAP will automatically use .querySelectorAll() to get a list of all of the elements that match. So the above can be written simple as gsap.to(".box", { x: 100 }); You could also pass in a complex selector string like ".box, .card" and it will select all boxes and cards. Or use an Array of elements so long as they are of the same type (selector string, variable reference, generic object, etc.). Conclusion So how'd you do? Is your GSAP code clear of these common mistakes? Hopefully you learned a few things. As always, if you need any help, the GreenSock forums are a fantastic resource. We love to help people develop their animation superpowers. If you're looking for another great learning resource, read how to animate efficiently! Now go forth and tween responsibly!
    15 points
  6. Heya! Remember I said I was working on a Svelte project that would be needing some GSAP? Here are some of the barebones examples I made using GSAP and Svelte. onMount: https://svelte.dev/repl/94885eb0f90045da934ed5fd9f7fdb2a?version=3.29.0 Transition directive: https://svelte.dev/repl/1f70e16d637945fa8788fafafb481454?version=3.29.0 In/Out directives: https://svelte.dev/repl/000b2f192c204cd799dbb4f6d70a1c21?version=3.29.0 Action directive: https://svelte.dev/repl/eb2f99e9f3324e25af4eaada0389eed6?version=3.29.0 Animation directive: (TO-DO soon). Hope this helps.
    14 points
  7. Hey fellow GreenSockers, I’ve seen some demos and questions lately with SVGs containing nested groups that are 10 deep and generic class names that aren’t helpful. This makes your job tougher, so I thought I’d share a few tips for better SVG exports from Adobe Illustrator. I’ve created a simple SVG with a background rectangle, some ungrouped squares, a group of circles, a group of lines and one open wavy path. Here’s the artwork with the layer panel in AI. Tip 1: IDs If you have elements that you know you’ll be targeting individually, give them an ID in AI. In this case I’ve given each of the colored squares a name. I’ve also named the wavy open path. Tip 2: Grouping If you have a group of elements that you’ll want to stagger or somehow target as a group, create a group for them. Simply select all of them and pressing Ctrl + G will make a group for you. You can also create a sub-layer and add them to it or create an entirely separate layer. Do whatever works for you. Just get them grouped before export. You can see in my layers panels I have a masterGroup around everything and then nested groups around the straight lines and circles. The elements in those groups do not need an ID as I’ll have no need to target them individually. You can also use nested groups within nested groups. Maybe a character has a group called ‘#face’, but the eyes need to be their own group within the face group. If that’s what you need for control, go for it. Tip 3: Export Settings Choose File –-> Export –-> Export As --> then choose ‘Save as type: SVG’. The directory is unimportant as you won’t actually be saving it. Choose Export at the bottom of that panel and then we’ll get to the important settings. The next screen you’ll see will be for the SVG Options. At this point you could choose OK and the file would be saved, but I find it best to click to ‘Show Code’ instead. That will launch a text editor which will allow you to copy and paste the code into your editor. Make certain the Object IDs is set to Layer Names. If not, the group names and path IDs will not come through to the SVG. The most important setting here is the Styling. If you choose: Internal CSS, you’ll get a bunch of generic class names. The IDs will still come through, but I don’t find generic class names helpful at all. Here’s what you get with that export. <svg xmlns="http://www.w3.org/2000/svg" width="1000" height="500" viewBox="0 0 1000 500"> <defs> <style> .cls-1 { fill: #333; } .cls-2 { fill: #ff0; } .cls-3 { fill: #7ac943; } .cls-4 { fill: #3fa9f5; } .cls-5 { fill: #ff931e; } .cls-6 { fill: none; stroke: #e6e6e6; stroke-miterlimit: 10; stroke-width: 4px; } </style> </defs> <g id="backgroundGroup"> <rect id="backgroundGray" class="cls-1" width="1000" height="500"/> </g> <g id="masterGroup"> <g id="nestedCircles"> <circle class="cls-2" cx="650" cy="150" r="50"/> <circle class="cls-3" cx="650" cy="350" r="50"/> <circle class="cls-4" cx="850" cy="150" r="50"/> <circle class="cls-5" cx="850" cy="350" r="50"/> </g> <rect id="greenBox" class="cls-3" x="100" y="100" width="100" height="100"/> <rect id="blueBox" class="cls-4" x="100" y="300" width="100" height="100"/> <rect id="orangeBox" class="cls-5" x="300" y="100" width="100" height="100"/> <rect id="yellowBox" class="cls-2" x="300" y="300" width="100" height="100"/> <path id="wavyPath" class="cls-6" d="M68,457c45.67-15.25,115.6-33,201-31,84.49,2,104.92,21.37,193,25,108.61,4.48,136.93-22.58,236-28,61.7-3.37,150.91,1.64,262,43"/> <g id="straightLines"> <line class="cls-6" x1="450" y1="100" x2="450" y2="400"/> <line class="cls-6" x1="500" y1="100" x2="500" y2="400"/> <line class="cls-6" x1="550" y1="100" x2="550" y2="400"/> </g> </g> </svg> For styling I prefer to set it to Presentation Attributes. Here’s what you get with that setting. <svg xmlns="http://www.w3.org/2000/svg" width="1000" height="500" viewBox="0 0 1000 500"> <g id="backgroundGroup"> <rect id="backgroundGray" width="1000" height="500" fill="#333"/> </g> <g id="masterGroup"> <g id="nestedCircles"> <circle cx="650" cy="150" r="50" fill="#ff0"/> <circle cx="650" cy="350" r="50" fill="#7ac943"/> <circle cx="850" cy="150" r="50" fill="#3fa9f5"/> <circle cx="850" cy="350" r="50" fill="#ff931e"/> </g> <rect id="greenBox" x="100" y="100" width="100" height="100" fill="#7ac943"/> <rect id="blueBox" x="100" y="300" width="100" height="100" fill="#3fa9f5"/> <rect id="orangeBox" x="300" y="100" width="100" height="100" fill="#ff931e"/> <rect id="yellowBox" x="300" y="300" width="100" height="100" fill="#ff0"/> <path id="wavyPath" d="M68,457c45.67-15.25,115.6-33,201-31,84.49,2,104.92,21.37,193,25,108.61,4.48,136.93-22.58,236-28,61.7-3.37,150.91,1.64,262,43" fill="none" stroke="#e6e6e6" stroke-miterlimit="10" stroke-width="4"/> <g id="straightLines"> <line x1="450" y1="100" x2="450" y2="400" fill="none" stroke="#e6e6e6" stroke-miterlimit="10" stroke-width="4"/> <line x1="500" y1="100" x2="500" y2="400" fill="none" stroke="#e6e6e6" stroke-miterlimit="10" stroke-width="4"/> <line x1="550" y1="100" x2="550" y2="400" fill="none" stroke="#e6e6e6" stroke-miterlimit="10" stroke-width="4"/> </g> </g> </svg> The output is much cleaner and any of those attributes can be easily controlled with CSS or GSAP. This code straight out of AI is ready to animate with no cleanup necessary. You can quickly target those group child elements for whatever you need. It’s the best of both worlds as you can get to each element for a stagger without the need for unique IDs and you can also control them as a collective. The nested circles can be targeted like this: tl.staggerFrom("#nestedCircles circle", 0.5, {attr:{r:0}}, 0.15); Or easily targeted as a group: tl.to("#nestedCircles", 1, {svgOrigin:"750 250", rotation:360}); Bottom line: Better artwork prep will make your GreenSock life easier. Proper names and grouping before you export will make your animation work go faster as you won’t have to fumble with meaningless class names and trying to group things in your code editor. That’s not to say that you can’t tweak a few names or groups – I do that all the time. But the more things you can have exported from AI correctly, the easier your coding and animation work will be. Of course, all this is just my two-cent opinion. Take from it what you will. Hopefully some of it will be helpful. Happy tweening.
    14 points
  8. Oh my turn! my turn!! PS: Sorry couldn't resist
    14 points
  9. Hi there! My name is Sarah, I'm on the Vue core team and do a lot of work with Vue and SVG animation using GSAP. Yep, you're on the right track, refs are the way to target these elements though technically it still works to target an id or class as usual. However, there are some key pieces in here that I want to separate out in case it's helpful to you, because really the sky's the limit! And they play so well together: 1) The way that animation and rendering work, you are *always* going to be touching the DOM in the case of animation, this can't only happen in the virtual DOM (something that people miss about React, too, even when looking at libraries like React-Motion) 2) There's a way to interpolate numbers that then update the DOM by transitioning state, and then there is accessing the DOM directly. You can use Vue and GSAP for both. I rewrote the docs example to use GSAP for our transitioning state example here: https://vuejs.org/v2/guide/transitioning-state.html#Animating-State-with-Watchers, but the way you're working with the DOM nodes and watchers, you may be more interested in this chart I wrote with where I'm spinning up SVG DOM nodes with directives, which is similar to what you're doing. In other words, you can use Vue and GSAP to interpolate number or values, and then apply that to a style binding, OR you can just update the fill in GSAP by targeting the element directly, that will still work. There is even a relative HSL tween that gsap offers if that's your jam 3) You might also want to set things up with a transition component, which offer some javascript hooks for beforeEnter, enter, and leaving states: (I have a bunch of pens that do this but this is probably the simplest Vue Book Content Typer) The nice thing that the transition component offers you is an ability to coordinate one thing entering and another leaving, with transition modes. They're pretty spectacular. You will also be given FLIP under the hood with the transition-group component. 4) You can also plug directly into the mounted lifecycle hook, as you can see here: Vue Weather Notifier Pen. This way you can activate an SVG animation on the component as soon as it's in the DOM. You can also see in this pen I'm changing opacity, using drawSVG, changing color, rotating, you name it- it's all possible on SVG elements and you don't *have* to put them in data. Though there's nothing wrong with transitioning state that way either. I also wrote this article that should help you: https://css-tricks.com/intro-to-vue-5-animations/ And have this open source repo which is a whole workshop just about vue and svg animations: https://github.com/sdras/animating-vue-workshop Please feel free to ask any questions as well. Thanks!
    14 points
  10. Scroll-driven animations re-invented Animate anything on scroll DOM, CSS, SVG, WebGL, Canvas, whatever. Toggle playback state or scrub through animations Entering or leaving a ScrollTrigger area can make an animation play, pause, resume, reverse, restart, or complete...or you can make the scrollbar can act like a scrubber! Pin elements in place Make an element appear immune to scroll changes while the ScrollTrigger is active. This is surprisingly useful for creating slick effects and keeping your animation in view during the scroll. Insane levels of flexibility ScrollTrigger is a control freak's dream when it comes to choreographing animations, but its rich callback system also lets you accomplish things totally unrelated to animation. Directionally smart ScrollTrigger supports vertical and horizontal scrolling, and lets you check if the last scroll movement was forward or backward, and even tracks velocity! Automatic resizing ScrollTrigger elegantly adjusts to viewport size changes. You can even use function-based start/end values to run custom logic or tap into fancy responsive CSS changes. Maximum performance ScrollTrigger uses all kinds of techniques to maximize performance like throttling updates, pre-calculating intersection points to minimize effort during scroll, leveraging transforms, layerizing elements to utilize the GPU, etc. Integrated with GSAP ScrollTrigger is built on GSAP, the battle-tested standard for JavaScript animation that's used on over 10,000,000 sites worldwide including most award-winning ones. Get started with ScrollTrigger Download Documentation Examples Featured ScrollTrigger demos View all demos
    13 points
  11. Hey everyone We’re rolling up on Thanksgiving here in America, so I thought I’d say how thankful I am for this forum. You’re a terrific group of people and one AI. I’m so glad I started participating a few years ago. It’s truly been life changing. As a thank you, I’m gonna drop a couple sliders here for the community. I know there are umpteen ways to make a slider, but this is my take on it. I added multiple control types and linked the nav dots animation to the draggable element for a bit of fun. We often have questions about sliders so hopefully these will be a good jumping-off point for someone. Happy Tweensgiving
    13 points
  12. Are you familiar with CodePen Challenges? In June 2020, GreenSock got to host it! We decided that it'd be fun to have a competition and give away 3 "Shockingly Green" Club GreenSock memberships each week! What is a CodePen Challenge? CodePen is a site where you can create and share small frontend web projects that you've made. You can also start with another person's creation and then modify it to become your own creation (this is called forking). Every month, CodePen hosts 4 weekly challenges with different themes. They host these challenges to help you improve your frontend skills, express yourself, and have some fun! How did this competition work? Every Monday this month, check the CodePen Challenges page for the new theme (you can sign up there for notifications too). Then make something based on that theme! It could be anything. Each week we will provide some different ideas to get you started, but you can create anything so long as it fits the challenge prompt that week. To submit entries to the competition, people tagged @GreenSock on Twitter along with a link to your pen. At the end of the each week, our panel of judges went through and pick their favorite pens that were created that week. The creators of the top 3 pens each week received a one-year "Shockingly Green" Club GreenSock membership on us! Who were the judges? Meet our lovely judges for the GSAP CodePen Challenge Competition (you should follow them!): Aaron Iker Adam Kuhn Annie Liew Cassie Evans Chris Gannon Craig Roblewsky Jhey Tompkins Lisi Linhart Louis Hoebregts Lynn Fisher Olivia Ng Pete Barr Shaun Gorneau Steve Gardner Tom Miller Una Kravets What's this week's challenge? Unfortunately the CodePen Challenge competition is over. But you're free to follow the same challenge prompts to inspire you to create something! We'd still love to see it. You can view all of the challenge prompts on CodePen. The winners Week 1: Sequencing Congratulations to our week one (sequencing) winners: Benoît Wimart, Sicontis, and Cristobal Garcia! Be sure to check out the rest of the submissions. modulofont Sequencing (Mom’s Diner) .cCmsCategoryFeaturedEntry .cBlackContent a { text-decoration: none; } html[dir="ltr"] .ipsGrid_span4:nth-child( 3n+1 ) { margin-left: 2.127659574468085%; } Taika cruising through La Gran Sabana Week 2: Bubbling Congratulations to our week two (bubbling) winners: Louise Flanagan, Oscar Salazar, and Wendy Kong! We had to bring in an extra judge to break ties because the voting was so close so be sure to view all of the submissions as well. Bubbly Bath Bubbles Bunny Breathing Exercise Week 3: Sliding Congratulations to our week three (sliding) winners: Oscar Salazar, Wendy Kong (both are winners two weeks in a row! Very impressive.), and ycw! You can view all of the submissions here. Slash GSAP Penguin Blue Room Week 4: Scrolling Congratulations to our week four (scrolling) winners: supamike, Ismael Martínez, and Shunya! View all of the submissions here. 3D Banners Personal Page Underwater Scrolling Animation Thanks so much to all who participated. We couldn't have ran this competition without you!
    13 points
  13. Welcome! This forum is being provided as a free service to connect talented GSAP animators with those looking to hire them. Please read this entire post before participating. When Posting a Job: Describe the project's technical requirements and provide links to similar examples and/or storyboards (if available). List the start and end dates of the project (or at least a rough timeline). Provide an estimated compensation range. The more detailed you are in describing your needs, the better your odds of success. If you omit the budget, there's a high risk that qualified candidates will assume it isn’t worth their time. Remember that talented GSAP experts are typically in high demand. We encourage candidates to post public replies to show they're interested, but further coordination should be handled privately either through the forum’s private message system or email. It's probably best not to post your email address in a public forum. Once a candidate is found, please update the post to let others know that the job is no longer available. Freelancers Feel free to post your availability in this forum proactively. Include links to your own website, portfolio, CodePen profile, etc. so that people can get a feel for your style and skill level. It’s a great idea (though not necessary) to post a price range for each example as well. Please represent your skills accurately and include proper attribution for work that’s not yours. One of the keys to a successful working relationship is managing expectations (both sides)! Always under-promise and over-deliver. Pricing a project We generally recommend agreeing to an overall project price and timeline ahead of time rather than billing a flat hourly rate. Some developers work twice as fast as others, so an hourly rate isn’t an accurate gauge of overall cost. But for open-ended projects, we understand that hourly rates might be the best fit. Additional notes We are starting this service on a trial basis. Freelancers are NOT employees of GreenSock. Anyone on the Internet can post here. GreenSock is not liable for anything that happens before, after, or during the life of your project. Please don’t contact us for arbitration help. It’s fine if you want to simply report abuse. If we receive complaints about your conduct (employers or developers), you may be banned from posting here. Again, we make no promises to investigate each and every claim or get into "he said, she said" back-and-forth, so it's in your best interest to keep things positive and exceed expectations. Make us proud. GreenSock does not research or endorse any of the parties posting here. Please let us know if you have any suggestions for making this service even better. Happy tweening!
    13 points
  14. React is a hugely popular library choice, and as evidenced by many of the sites in our showcase - React and GSAP can be a powerful combination. However, utilizing GSAP in React requires a different way of thinking than a vanilla JS project. We've written this guide to help you get started using GSAP within a React project. This is not a tutorial, so feel free to dip in and out as you learn. Think of it as a collection of recommended techniques and best practices to use in your projects. Why GSAP? Animating with GSAP gives you unprecedented levels of control and flexibility. You can reach for GSAP to animate everything — from simple DOM transitions to SVG, three.js, canvas or WebGL — your imagination is the limit. More importantly, you can rely on us. We obsess about performance, optimizations and browser compatibility so that you can focus on the fun stuff. We've actively maintained and refined our tools for over a decade and there are no plans to stop. Lastly, if you ever get stuck, our friendly forum community is there to help. Going forward we will assume a basic understanding of GSAP and React. If you're just getting going with React, this tutorial from the React team is a great place to start. Need a GSAP refresher? Take a break and read about tweens and timelines. We’ll be here when you get back. Feeling confident? Skip straight to part 2 - GSAP + React, advanced animation techniques. Quick Links Getting set up Targeting a DOM element for animation Creating our first animation Targeting descendant elements Creating a timeline Controlling when React runs our animation with useEffect Reacting to changes in state Animating on interaction Avoiding flash of unstyled content (FOUC) Cleaning up Online Playgrounds Get started quickly by forking one of these starter templates: CodePen CodeSandbox CodeSandbox + Bonus Plugins Create a new React App If you prefer to work locally, Create React App provides a comfortable setup for experimenting with React and GSAP. To create a project, run: npx create-react-app gsap-app cd gsap-app npm start Once the project is set up we can install GSAP through npm, npm i gsap npm start then import it into our app. import React from "react"; import { gsap } from "gsap"; export default function App() { return ( <div className="app"> <div className="box">Hello</div> </div> ); } More detailed information about getting started with React Additional GSAP installation documentation Targeting elements In order to animate using GSAP we need access to the element in the DOM. Refs provide a way for us to interact with and store references to DOM nodes in a React component. const boxRef = useRef(); return <div className="box" ref={boxRef}>Hello</div>; Read more about refs in the React docs Creating our first animation GSAP updates inline style properties, so it’s important to make sure the DOM has been rendered before trying to animate anything. If we ask GSAP to animate an element that hasn’t been rendered, we’ll get this warning in the console. GSAP target not found. In order to avoid targeting a null element, we can use the useEffect hook. This hook tells React that our component needs to do something after rendering. function App() { // store a reference to the box div const boxRef = useRef(); // wait until DOM has been rendered useEffect(() => { gsap.to(boxRef.current, { rotation: "+=360" }); }); // DOM to render return <div className="box" ref={boxRef}>Hello</div>; } In this example, React will first render the box element to the DOM, then GSAP will rotate the box 360deg. See the Pen React & GSAP Starter Template by GreenSock (@GreenSock) on CodePen. Targeting descendant elements gsap.utils.selector() Creating a ref for each and every element we want to animate can add a lot of noise to our code. We can avoid this by making use of GSAP’s selector utility to easily select descendant elements. const el = useRef(); const q = gsap.utils.selector(el); useEffect(() => { // Target ALL descendants with the class of .box gsap.to(q(".box"), { x: 100 }); }, []); See the Pen gsap.utils.selector() by GreenSock (@GreenSock) on CodePen. Forwarding refs gsap.utils.selector() will target all descendants in the component tree. Within a component based system, you may need more granular control over the elements you're targeting. You can use ref forwarding to get access to specific nested elements. See the Pen Forwarding refs by GreenSock (@GreenSock) on CodePen. Creating and controlling timelines Up until now we've just used refs to store references to DOM elements, but they're not just for elements. Refs exists outside of the render loop - so they can be used to store any value that you would like to persist for the life of a component. If you're coming from class based components, this should be familiar to you as it’s essentially the same as using ‘this’. In order to avoid creating a new timeline on every render, it's important to create the timeline inside an effect and store it in a ref. function App() { const el = useRef(); const q = gsap.utils.selector(el); const tl = useRef(); useEffect(() => { tl.current = gsap.timeline() .to(q(".box"), { rotate: 360 }) .to(q(".circle"), { x: 100 }); }, []); return ( <div className="app" ref={el}> <Box>Box</Box> <Circle>Circle</Circle> </div> ); } This will also allow us to access the timeline in a different effect and toggle the timeline direction. See the Pen React Tutorial 2f by GreenSock (@GreenSock) on CodePen. Controlling when React runs our animation. By default useEffect runs both after the first render and after every update. So every time our component’s state changes, it will cause a re-render, which will run our effect again. We can control when useEffect should run by passing in an array of dependencies. To only run once after the first render, we pass in an empty array. // only runs after first render useEffect(() => { gsap.to(q(".box-1"), { rotation: "+=360" }); }, []); // runs after first render and every time `someProp` changes useEffect(() => { gsap.to(q(".box-2"), { rotation: "+=360" }); }, [someProp]); // runs after every render useEffect(() => { gsap.to(q(".box-3"), { rotation: "+=360" }); }); See the Pen React Tutorial 1b by GreenSock (@GreenSock) on CodePen. Reacting to changes in state Now that we know how to control when an effect fires, we can use this pattern to react to changes in our component. This is especially useful when passing down props. function Box({ children, endX}) { const boxRef = useRef(); // run when `endX` changes useEffect(() => { gsap.to(boxRef.current, { x: endX }); }, [endX]); return ( <div className="box" ref={boxRef}>{children}</div> ); } See the Pen React Tutorial 1c by GreenSock (@GreenSock) on CodePen. Animating on interaction Interaction is one of the most exciting things about animating on the web! In order to hook into user interactions like hover, we can use callbacks. const onEnter = ({ currentTarget }) => { gsap.to(currentTarget, { backgroundColor: "#e77614" }); }; const onLeave = ({ currentTarget }) => { gsap.to(currentTarget, { backgroundColor: "#28a92b" }); }; return ( <div className="box" onMouseEnter={onEnter} onMouseLeave={onLeave}> Hover Me </div> ); See the Pen React Tutorial 1d by GreenSock (@GreenSock) on CodePen. Avoiding flash of unstyled content (FOUC) As useEffect fires after the DOM has been painted, when fading in elements you may notice an undesired flash of unstyled content. In order to avoid the flash, we can replace useEffect with useLayoutEffect. useLayoutEffect functions exactly the same as useEffect, but runs before the DOM has been painted. See the Pen Avoiding FOUC with useLayoutEffect() by GreenSock (@GreenSock) on CodePen. useLayoutEffect is especially useful when you need to make DOM measurements, so we highly recommend it when using our ScrollTrigger and FLIP plugins. More information about useEffect vs useLayoutEffect. Cleaning Up It’s a good idea to return a cleanup function in your effects to kill off any running animations and anything else that could cause a memory leak, like an event listener. This is particularly important if an animation runs for a really long time, makes use of ScrollTrigger, or changes the state in a component. useEffect(() => { const animation1 = gsap.to(".box1", { rotation: "+=360" }); const animation2 = gsap.to(".box2", { scrollTrigger: { ... } }); const onMove = () => { ... }; window.addEventListener("pointermove", onMove); // cleanup function will be called when component is removed return () => { animation1.kill(); animation2.scrollTrigger.kill(); window.removeEventListener("pointermove", onMove); }; }, []); We hope this article was helpful - If you have any feedback please leave us a comment below so we can smooth out the learning curve for future animators! Feeling confident and want to learn more? Check out our follow up article - GSAP + React, advanced animation techniques.
    12 points
  15. I've been getting a bunch of people asking me about how to do a smooth page scroll effect, so here it is. Scrolling is just a transform. If you scroll 100px down, the browser will translate the page -100px up. We can do that with GSAP. TweenLite.set(contentToScroll, { y: -window.pageYOffset }); So how do you prevent the browser from scrolling the content? Position your content in a fixed container, and set the height of the body equal to the height of your content. This will allow the page to scroll, but the fixed container won't move. Now animate the y position of your content based on the scroll position of the page.
    12 points
  16. [updated September 2, 2020] Good news: Google pushed GSAP to their CDN (for use with DoubleClick and AdWords ads). URLs can be found at: https://support.google.com/richmedia/answer/6307288#gs If you get news of other ad networks that have similar news to share, feel free to post here. Enjoy!
    12 points
  17. I know this thread is now over a month old, but I wanted to share a fork of Zach's pen. I made a 6-sided die from the cube. To simplify/clarify, the 3d rotations are moved out of the CSS. Hopefully this demo is useful to someone... https://codepen.io/creativeocean/pen/qBRbNwa
    11 points
  18. Conventional wisdom says that kilobytes have a direct impact on load times and consequently user experience. Too many developers, however, myopically focus on a simplistic (and rather dated) "aggregate total file size" mentality and completely miss the broader goal of improving user experience. This article aims to challenge the old paradigm and explain why "spending" kilobytes on a library like GSAP can be a very smart move. Kilobyte cost factors When you're assessing kilobyte cost in a modern, nuanced way consider these factors: Performance yield Some kilobytes are "cheap" in terms of the initial load but expensive for runtime execution. If our goal is better user experience, this is critical. Would you rather a page that loads 200ms faster with janky animations or one that's super-smooth at runtime but takes a fraction of a second longer to load? Of course there are reasonable limits either way (waiting an extra 30 seconds for a huge file to load would be intolerable even if it made things run buttery smooth), but in most cases we're only talking about fractions of a second difference. For example, GSAP contains "extra" code that automatically GPU-accelerates transforms, applies lag smoothing, avoids layout thrashing, caches important values for super-fast lookups, etc. - would removing those features for the sake of a few milliseconds on initial load (and zero savings once it's cached) be a step forward or backward? Caching When does a 23kb file act like a 0kb file? When it's cached! This is particularly relevant for engaging, animated sites because there are common tasks and code that can be encapsulated and shared. GSAP is a perfect example of a shared resource. An end user only loads it once and then it's completely "free" thereafter...for all pages pointing at that file...on all sites*! *Some browsers may implement domain-specific caching. CDN files loaded from a CDN (Content Delivery Network) are typically "faster" because they're geographically distributed and automatically loaded from the closest server. Plus CDNs have inherent redundancies leading to better reliability. Custom code reduction (kb savings) Loading a library like GSAP may allow you to only write 1kb of custom animation code instead of 5kb of CSS animation code, for example. Plus it has quite a few utility methods that you can tap into for added savings. This can significantly reduce the amount of custom code that must be loaded as your visitors go page-to-page. Non-kilobyte costs If you avoid a tried-and-true library like GSAP, it may feel like you're reducing your costs but don't forget: Development time You could use a minimalistic library or write your own, but how much more time will that take to implement? How much more custom code will it require? How many workarounds will be required to get similar functionality? How many headaches will you run into with cross-browser quirks and inconsistencies that GSAP already solved? GSAP's API has been crafted over a decade to facilitate easy experimentation with minimal code. And when it comes to animation, experimentation is key. Most developers are working against deadlines and it's priceless to have a robust, vetted toolset to rely on. Swagger & confidence Perhaps at the outset your project only has basic animation needs so you choose a basic animation library or write your own custom code for all the animations...but what happens when the client requests something more advanced? Uh oh. Will you port everything to GSAP then? What if you've got hundreds of animations that now need to be dynamically time-scaled or linked to scroll position with smooth scrubbing? How about advanced morphing? If you just use GSAP from the start, you have almost zero risk of running into an "oh no!" moment like that. You can code with confidence that you'll be able to animate pretty much anything with minimal code. What is that kind of developer swagger worth? Documentation, support & training What if you run into trouble? Is excellent documentation available? Is there a community eager to help? Are there training resources for new hires down the road? What's the real long-term impact of your choice? Maintenance The web is littered with abandoned open source projects. What's the track record of the one you're considering? How long has it been actively developed? Or if you're writing all your own animation code from scratch, is it truly maintainable? What's the long-term cost? Are you documenting how everything works? What happens when browsers introduce bugs or new features that impact animations? Other factors to consider Bandwidth is only increasing The impact of a 23kb library is decreasing all the time. It's less than a single image these days. On average, in fact, images account for over 864kb on every web page! And again, GSAP is a one-time load in most cases. It's often cached in which case it costs nothing. GSAP doesn't count against file size budgets on every major ad network They have virtually all recognized GSAP as an industry standard and exempted it from file size calculations. That directly benefits you if your animations are GSAP-based. Conclusion If you adopt the old mindset that's solely focused on the aggregate total file size for each page, it's easy to miscalculate the cost of using a library like GSAP (or any other shared resource). Doing so also pushes developers toward minimalistic less-capable solutions that may end up being far more expensive long-term. We'd encourage a more wholistic, nuanced approach that looks at the overall costs and benefits. Remember the end goals - outstanding user experience, minimal development costs, and long-term viability.
    11 points
  19. @ddi-web-team @Sygol @Yannis Yannakopoulos I whipped together a helper function that should make this quite easy. Check it out in this CodePen: https://codepen.io/GreenSock/pen/823312ec3785be7b25315ec2efd517d8?editors=0010 We may end up adding it as a static method on ScrollTrigger if there's enough interest. What do you think?
    11 points
  20. Hello everyone, This post is going to be one of those a little long and for those more busy and timeless it is about: A person who had a dream and when he reached resolve to thank the people who helped reach that goal. Well let's go then: First, this was my first post on the forum: https://greensock.com/forums/topic/16437-animation-scale-left-to-right/ And on this date I still used Adobe Muse to make a website because I did not know anything about HTML / CSS, but I already wanted to be good, make sites cool, cool and one day I could gain recognition at Awwwards, so if you go see this post will see that mention a site that had just won this recognition. But it was impossible to win not knowing HTML and CSS, so I started to study and learned everything by scouring the internet inside, but something I was sure, to get there I would need to master doing Animations, so every day I needed to understand how it worked the GSAP. I was studying and creating new challenges and whenever I tried to do something and did not find the solution on the Internet, I was obliged to ask in this Forum, and at no time did I leave here without a useful answer, ready for me was very clear, I had found a source for learning and for evolution. So know that this is how I and many people see this forum. So after less than 2 years of many studies and many questions I finally decided to run my dream that was to gain a recognition at Awwwards, and to my surprise I did not only won as a Site of the Day but also the Developer award. A reason for much satisfaction and pride, and I certainly could not without the support, help of this incredible community, who always welcomes and helps everyone who comes here to seek a light for their goal. So thank you to all of you and as a form of gratitude and recognition I made a point of mentioning in the thanksgiving session of my website (http://victor.work) on the page about, because it is also conquest of you. (and also mentioned GSAP FORUM in my hobbies) So through all this I would like to let you know that you provide a very important role for the web community, a tool that we can evaluate as perfect and yet I see you doing the best and working hard to perfect it even more. Guys you are very importants. I'll leave the recognition link here at Awwwards: https://www.awwwards.com/sites/victor-work-folio19 Anyway, this is it: Thank you very much indeed, you guys are awesome.
    11 points
  21. You can do that by determining velocity of mouse or scrolling, then use that velocity to apply skew. So to determine velocity you can use simple easing and take difference between target and easing value. Here is demo showing original effect based on mouse. This one uses a predefined tween, I set the progress of tween based on eased value. The scroll based effect is a lot more simple as you don't need to use any predefined tween,
    11 points
  22. GreenShock /ɡrēn ˌSHäk/ noun: GreenShock psychological condition caused by prolonged exposure to the GreenSock Animation Platform, especially the use of Club GreenSock plugins. "I’m in GreenShock after witnessing Jack Doyle ‘whip up’ a new plugin and casually post it in the forum." synonyms: astonishment, surprise, stupefaction, incredulity, disbelief, speechlessness, awe, wonder, wonderment
    11 points
  23. Here is very basic demo. You can change movement based on element you are animating. You can also use parallax.js which responds to gyroscope on mobile devices.
    11 points
  24. Hello @vibhor4all and welcome to the GreenSock Forum! Like @mikel advised you can check DOM and window. This way you only run your animation when the HTML, SVG, Canvas, and other assets are ready and loaded to be animated. It is best to wait until the DOM is ready then check if the window is loaded. Since both DOM ready and window loaded can fire at different times based on the server wait response and client building the DOM. Also its optional to also only run on the next requestAnimationFrame() to help prevent jank when first loaded. Wait until: DOM ready: Even if the window is loaded before the DOM, the window will fire immediately. window loaded: If the DOM is ready before the window is loaded the window will just fire when it is fully loaded. OPTIONAL - Run code on next render tick. Waits until next requestAnimationFrame() which prevents running code in the middle of render tick Vanilla JS way: // wait until DOM is ready document.addEventListener("DOMContentLoaded", function(event) { // wait until window is loaded - all images, styles-sheets, fonts, links, and other media assets // you could also use addEventListener() instead window.onload = function() { // OPTIONAL - waits til next tick render to run code (prevents running in the middle of render tick) window.requestAnimationFrame(function() { // GSAP custom code goes here }); }; }); Or the jQuery way: // wait until DOM is ready $(document).ready(function(){ // wait until window is loaded - all images, styles-sheets, fonts, links, and other media assets $(window).on("load", function(){ // OPTIONAL - waits til next tick render to run code (prevents running in the middle of render tick) window.requestAnimationFrame(function() { // GSAP custom code goes here }); }); }); But a codepen will be appreciated to help you better Resources: DomContentLoaded() : https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded requestAnimationFrame() : https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame window onload : https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onload Happy Tweening
    11 points
  25. OMG! I was about to get fired, ScrollSmoother saved my life
    10 points
  26. Are you working with React and looking to really advance your GSAP animation skills? You're in the right place. This guide contains advanced techniques and some handy tips from expert animators in our community. This is not a tutorial, so feel free to dip in and out as you learn. Think of it as a collection of recommended techniques and best practices to use in your projects. Why GSAP? Animating with GSAP gives you unprecedented levels of control and flexibility. You can reach for GSAP to animate everything — from simple DOM transitions to SVG, three.js, canvas or WebGL — your imagination is the limit. More importantly, you can rely on us. We obsess about performance, optimizations and browser compatibility so that you can focus on the fun stuff. We've actively maintained and refined our tools for over a decade and there are no plans to stop. Lastly, if you ever get stuck, our friendly forum community is there to help. Going forward we will assume a comfortable understanding of both GSAP and React. If you're starting out we highly recommend reading our foundational article first - First Steps & Handy Techniques.. Quick Links Component Communication Passing down a timeline prop Passing down callback to build a timeline React Context Imperative Communication Creating Reusable Animations registerEffect() Exit Animations Custom Hooks useSelector useArrayRef useStateRef useIsomorphicLayoutEffect Online Playgrounds Get started quickly by forking one of these starter templates: CodePen CodeSandbox CodeSandbox + Bonus Plugins Component Communication In the last article, we covered creating our first animation, and how to create and control timelines within a React component. But there are times where you may need to share a timeline across multiple components or construct animations from elements that exist in different components. In order to achieve this, we need a way to communicate between our components. There are 2 basic approaches to this. a parent component can send down props, e.g. a timeline a parent component can pass down a callback for the child to call, which could add animations to a timeline. Passing down a timeline prop Note that we are using useState instead of useRef with the timeline. This is to ensure the timeline will be available when the child renders for the first time. function Box({ children, timeline, index }) { const el = useRef(); // add 'left 100px' animation to timeline useEffect(() => { timeline.to(el.current, { x: -100 }, index * 0.1); }, [timeline]); return <div className="box" ref={el}>{children}</div>; } function Circle({ children, timeline, index, rotation }) { const el = useRef(); // add 'right 100px, rotate 360deg' animation to timeline useEffect(() => { timeline.to(el.current, { rotate: rotation, x: 100 }, index * 0.1); }, [timeline, rotation]); return <div className="circle" ref={el}>{children}</div>; } function App() { const [tl, setTl] = useState(() => gsap.timeline()); return ( <div className="app"> <Box timeline={tl} index={0}>Box</Box> <Circle timeline={tl} rotation={360} index={1}>Circle</Circle> </div> ); } See the Pen React Tutorial 3a by GreenSock (@GreenSock) on CodePen. Passing down a callback to build a timeline function Box({ children, addAnimation, index }) { const el = useRef(); // return a 'left 100px' tween useEffect(() => { const animation = gsap.to(el.current, { x: -100 }); addAnimation(animation, index); return () => animation.progress(0).kill(); }, [addAnimation, index]); return <div className="box" ref={el}>{children}</div>; } function Circle({ children, addAnimation, index, rotation }) { const el = useRef(); // return a 'right 100px, rotate 360deg' tween useEffect(() => { const animation = gsap.to(el.current, { rotate: rotation, x: 100 }); addAnimation(animation, index); return () => animation.progress(0).kill(); }, [addAnimation, index, rotation]); return <div className="circle" ref={el}>{children}</div>; } function App() { // define a timeline const [tl, setTl] = useState(() => gsap.timeline()); // pass a callback to child elements, this will add animations to the timeline const addAnimation = useCallback((animation, index) => { tl.add(animation, index * 0.1); }, [tl]); return ( <div className="app"> <Box addAnimation={addAnimation} index={0}>Box</Box> <Circle addAnimation={addAnimation} index={1} rotation="360">Circle</Circle> </div> ); } See the Pen Passing down a callback to build a timeline. by GreenSock (@GreenSock) on CodePen. React Context Passing down props or callbacks might not be ideal for every situation. The component you're trying to communicate with may be deeply nested inside other components, or in a completely different tree. For situations like this, you can use React's Context. Whatever value your Context Provider provides will be available to any child component that uses the useContext hook. const SelectedContext = createContext(); function Box({ children, id }) { const el = useRef(); const selected = useContext(SelectedContext); useEffect(() => { gsap.to(el.current, { // animate x by 200 if the box ID matches the selected context value x: selected === id ? 200 : 0 }); }, [selected, id]); return <div className="box" ref={el}>{children}</div>; } function App() { // Any component can read the value passed to the provider, no matter how deeply nested. // In this example, we're passing "2" as the current value. return ( <SelectedContext.Provider value="2"> <Box id="1">Box 1</Box> <Box id="2">Box 2</Box> <Box id="3">Box 3</Box> </SelectedContext.Provider> ); } See the Pen React Tutorial 3c by GreenSock (@GreenSock) on CodePen. Imperative Communication Passing around props or using Context works well in most situations, but using those mechanisms cause re-renders, which could hurt performance if you're constantly changing a value, like something based on the mouse position. To bypass React’s rendering phase, we can use the useImperativeHandle hook, and create an API for our component. const Circle = forwardRef((props, ref) => { const el = useRef(); useImperativeHandle(ref, () => { // return our API return { moveTo(x, y) { gsap.to(el.current, { x, y }); } }; }, []); return <div className="circle" ref={el}></div>; }); Whatever value the imperative hook returns will be forwarded as a ref function App() { const circleRef = useRef(); useEffect(() => { // doesn't trigger a render! circleRef.current.moveTo(300, 100); }, []); return ( <div className="app"> <Circle ref={circleRef} /> </div> ); } See the Pen React Tutorial 3d by GreenSock (@GreenSock) on CodePen. Creating reusable animations Creating reusable animations is a great way to keep your code clean while reducing your app’s file size. The simplest way to do this would be to call a function to create an animation. function fadeIn(target, vars) { return gsap.from(target, { opacity: 0, ...vars }); } function App() { const box = useRef(); useLayoutEffect(() => { const animation = fadeIn(box.current, { x: 100 }); }, []); return <div className="box" ref={box}>Hello</div>; } For a more declarative approach, you can create a component to handle the animation. function FadeIn({ children, vars }) { const el = useRef(); useLayoutEffect(() => { gsap.from(el.current.children, { opacity: 0, ...vars }); }, []); return <span ref={el}>{children}</span>; } function App() { return ( <FadeIn vars={{ x: 100 }}> <div className="box">Box</div> </FadeIn> ); } See the Pen React Reusable 1 by GreenSock (@GreenSock) on CodePen. If you want to use a React Fragment or animate a function component, you should pass in a ref for the target(s). Using gsap.effects GSAP provides a way to create reusable animations with registerEffect() function GsapEffect({ children, targetRef, effect, vars }) { useLayoutEffect(() => { if (gsap.effects[effect]) { gsap.effects[effect](targetRef.current, vars); } }, [effect]); return <>{children}</>; } function App() { const box = useRef(); return ( <GsapEffect targetRef={box} effect="spin"> <Box ref={box}>Hello</Box> </GsapEffect> ); } See the Pen React Reusable 6 by GreenSock (@GreenSock) on CodePen. Exit animations To animate elements that are exiting the DOM, we need to delay when React removes the element. We can do this by changing the component’s state after the animation has completed. function App() { const boxRef = useRef(); const [active, setActive] = useState(true); const remove = () => { gsap.to(boxRef.current, { opacity: 0, onComplete: () => setActive(false) }); }; return ( <div> <button onClick={remove}>Remove</button> { active ? <div ref={boxRef}>Box</div> : null } </div> ); } See the Pen React fade out 1 by GreenSock (@GreenSock) on CodePen. The same approach can be used when rendering elements from an array. function App() { const [items, setItems] = useState([ { id: 0 }, { id: 1 }, { id: 2 } ]); const removeItem = (value) => { setItems(prev => prev.filter(item => item !== value)); } const remove = (item, target) => { gsap.to(target, { opacity: 0, onComplete: () => removeItem(item) }); }; return ( <div> {items.map((item) => ( <div key={item.id} onClick={(e) => remove(item, e.currentTarget)}> Click Me </div> ))} </div> ); } See the Pen React fade out 2 by GreenSock (@GreenSock) on CodePen. However - you may have noticed the layout shift - this is typical of exit animations. The Flip plugin can be used to smooth this out. In this demo, we’re tapping into Flip’s onEnter and onLeave to define our animations. To trigger onLeave, we have to set display: none on the elements we want to animate out. See the Pen React Flip 2 by GreenSock (@GreenSock) on CodePen. Custom Hooks If you find yourself reusing the same logic over and over again, there’s a good chance you can extract that logic into a custom hook. Building your own Hooks lets you extract component logic into reusable functions. Let's take another look at registerEffect() with a custom hook function useGsapEffect(target, effect, vars) { const [animation, setAnimation] = useState(); useLayoutEffect(() => { setAnimation(gsap.effects[effect](target.current, vars)); }, [effect]); return animation; } function App() { const box = useRef(); const animation = useGsapEffect(box, "spin"); return <Box ref={box}>Hello</Box>; } See the Pen React Reusable 7 by GreenSock (@GreenSock) on CodePen. Here are some custom hooks we've written that we think you may find useful: useSelector Memoises GSAP’s selector utility. see demo on codepen function useSelector() { const ref = useRef(); const q = useMemo(() => gsap.utils.selector(ref), [ref]); return [q, ref]; } Usage: function App() { const [q, ref] = useSelector(); useEffect(() => { gsap.to(q(".box"), { x: 200 }); }, []); return ( <div ref={ref}> <div className="box">Hello</div> </div> ); } useArrayRef Adds refs to an array. see demo on codepen function useArrayRef() { const refs = useRef([]); refs.current = []; return [refs, (ref) => ref && refs.current.push(ref)]; } Usage: function App() { const [refs, setRef] = useArrayRef(); useEffect(() => { gsap.to(refs.current, { x: 200 }); }, []); return ( <div> <div className="box" ref={setRef}>Box 1</div> <div className="box" ref={setRef}>Box 2</div> <div className="box" ref={setRef}>Box 3</div> </div> ); } useStateRef This hook helps solve the problem of accessing stale values in your callbacks. It works exactly like useState, but returns a third value, a ref with the current state. see demo on codepen function useStateRef(defaultValue) { const [state, setState] = useState(defaultValue); const ref = useRef(state); const dispatch = useCallback((value) => { ref.current = typeof value === "function" ? value(ref.current) : value; setState(ref.current); }, []); return [state, dispatch, ref]; } Usage: const [count, setCount, countRef] = useStateRef(5); const [gsapCount, setGsapCount] = useState(0); useEffect(() => { gsap.to(box.current, { x: 200, repeat: -1, onRepeat: () => setGsapCount(countRef.current) }); }, []); useIsomorphicLayoutEffect You might see a warning if you use server-side rendering (SSR) with useLayoutEffect. You can get around this by conditionally using useEffect during server rendering. This hook will return useLayoutEffect when the code is running in the browser, and useEffect on the server. caveat: Any "from" state that doesn't match the server-side rendered HTML/CSS content will still suffer from a flash of unstyled content while the JavaScript is being parsed, run and hydrated. read more about useLayoutEffect and server rendering see demo on codepen const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect; Usage: function App() { const box = useRef(); useIsomorphicLayoutEffect(() => { gsap.from(box.current, { opacity: 0 }); }, []); return ( <div> <div className="box" ref={box}>Hello</div> </div> ); } If there is anything you'd like to see included in this article, or if you have any feedback, please leave a comment below so that we can smooth out the learning curve for future animators. Good luck with your React projects and happy tweening!
    10 points
  27. The GreenSock Animation Platform (GSAP) animates anything JavaScript can touch (CSS properties, SVG, React, canvas, generic objects, whatever) and solves countless browser inconsistencies, all with blazing speed (up to 20x faster than jQuery). See why GSAP is used by roughly 11,000,000 sites and many major brands. Hang in there through the learning curve and you'll discover how fun animating with code can be. We promise it's worth your time. Quick links What is GSAP? Loading GSAP Tweening Basics CSSPlugin 2D and 3D transforms Easing Staggers Callbacks Sequencing with Timelines Timeline control Getter / Setter methods Getting Current Values of an Element's Property Club GreenSock We'll cover the most popular features here but keep the GSAP docs handy for all the details. First, let's talk about what GSAP actually does... GSAP is a property manipulator Animation ultimately boils down to changing property values many times per second, making something appear to move, fade, spin, etc. GSAP snags a starting value, an ending value and then interpolates between them 60 times per second. For example, changing the x coordinate of an object from 0 to 1000 over the course of 1 second makes it move quickly to the right. Gradually changing opacity from 1 to 0 makes an element fade out. Your job as an animator is to decide which properties to change, how quickly, and the motion's style (known as easing - we'll get to that later). To be technically accurate, we could have named GSAP the "GreenSock Property Manipulator" (GSPM) but that doesn't have the same ring. DOM, SVG, <canvas>, and beyond GSAP doesn't have a pre-defined list of properties it can handle. It's super flexible, adjusting to almost anything you throw at it. GSAP can animate all of the following: CSS: 2D and 3D transforms, colors, width, opacity, border-radius, margin, and almost every CSS value. SVG attributes: viewBox, width, height, fill, stroke, cx, r, opacity, etc. Plugins like MorphSVG and DrawSVG can be used for advanced effects. Any numeric value For example, an object that gets rendered to an <canvas>. Animate the camera position in a 3D scene or filter values. GSAP is often used with Three.js and Pixi.js. Once you learn the basic syntax you'll be able to use GSAP anywhere that JavaScript runs. This guide will focus on the most popular use case: animating CSS properties of DOM elements. (Note: if you're using React, read this too.) If you're using any of the following frameworks, these articles may help: React Vue Angular What is GSAP Exactly? GSAP is a suite of tools for scripted animation. It includes: The GSAP core - The core of the engine which animates any property of any object. It makes use of tweens and to give you more control over your animations. Extras like time-saving plugins, easing tools, utility methods, and more. Loading GSAP
    10 points
  28. I’ve seen a few questions recently about getting better morphs so I thought I’d share a little tip that may help my fellow AI users. Whether you’ve created your own vectors or downloaded some stock artwork, the scissors tool is a quick way to get better morphs. You can also completely control the start point of your DrawSVG animations. I have an example using a couple heart shapes. This is just an icon from a collection I downloaded. The designer has the first point in the upper right curve of the heart. That’s probably not the best start point for any type of animations, so that needs to be fixed. Step 1 – Cut that path. Grab your scissors tool (it’s in the fly-out menu under the eraser). Line that up with the anchor point at the bottom point of the heart and cut. You’ll now have two anchors at that location. Step 2 – Select the points at the cut location and then join them together. It’s under the Object --> Path –-> Join (or Ctrl+J shortcut.) That is now the new start point of the path. You can now export the SVG. Here’s the difference with DrawSVG. You can see on heart one (as originally designed) the path starts drawing from an unnatural position. In heart two I’ve made that cut at the bottom and the animation feels better and animates the way a heart would naturally be drawn. Here’s the difference with MorphSVG Again, the first heart and star are left as the original designer created them. You can see the morph looks pretty good, but it has a bit of a twist to it. I used the scissors on both heart two and star two with a cut right at the center of the bottom. This morph looks much more natural. The bottom point of the heart splits into the bottom two points of the star and the twisting motion is now gone. There's your hot tip for Valentine's Day. Happy tweening and morphing everyone.
    10 points
  29. Hey everyone Another quick SVG tip. Set your stroke dash length to 0 and your linecap to round. That will get you a nice circle border around your path or a string of circles along an open path. For a complete string of circle shapes along the stroke, set the gap equal to the stroke-width. https://codepen.io/PointC/pen/VXMmZV If you set the gap to less than the stroke-width, you can overlap the circles and create a nice scalloped edge. I personally like around 50-70% of the stroke-width. Throw a gradient on for a nice picture frame. https://codepen.io/PointC/pen/bvvddx With some creative layering and masking you can confine the scalloped edge to the inside or outside of you path. https://codepen.io/PointC/pen/YaaqPQ Using two strokes with different stroke-width and gap sizes, you can turn an ordinary ellipse into a cloud. https://codepen.io/PointC/pen/RMMMKv Morphing shapes with a circle border creates some cool results. https://codepen.io/PointC/pen/rddOqd Since these are circles making up the stroke and not actual elements, we can’t draw them on or make them move individually. Or can we…? Using a mask, we can draw them on and animating the gap size can bring them into position in an interesting manner. https://codepen.io/PointC/pen/wmmmmK It has its limits but can produce some fun results. The main thing to remember is set your dash length to 0 and the linecap to round. After that, experiment with stroke-width and gap size. Happy tweening.
    10 points
  30. Hey GreenSockers, This is my 2,000th post so I wanted to take a minute to commemorate the occasion. It’s so much fun to hang out with all of you. As I’ve said before, this is truly a unique place on the web. The community is so friendly and smart and I learn a ton by reading through different approaches to problems and reverse engineering all the clever answers and demos. Thank you all for sharing your knowledge. A special thanks to @GreenSock and @Carl for putting up with me for 2,000 posts. Shout-out to all the other mods @Jonathan, @OSUblake, @Dipscom, @Sahil, @Rodrigo, @Shaun Gorneau, @Acccent, @Visual-Q, @mikel. You are a terrific group of people (and one A.I.) and I’m inspired by all of you. I hope my little SVG tips & tricks have helped some community members save some time and prevent a few headaches. I’m looking forward to continuing this never-ending journey of learning with the entire GreenSock community. Happy tweening. - Craig
    10 points
  31. Hi and welcome to the GreenSock forums!! A looooooooong time ago I made this for another question in the forums. It uses the draggable tool to move the numbers but you could easily use it to get started with what you need: I made a fork of it and changed a bit to simulate what you need: Hopefully this helps. Happy Tweening!!!
    10 points
  32. Hi dear community! I know you missed new releases with HERO banners. Today I present 3 of them! Please give us feedback if you like them. 1. World Of Tanks — Take Control Animation here 2. World Of Tanks — Video 360° Animation here 3. World Of Warships — Dunkirk Collaboration Animation here Thank you!
    10 points
  33. Not exactly like the example button - a lot less liquidy, but fun nonetheless! https://codepen.io/cassie-codes/pen/15d1e3d339a64bbed746895dff4990b9?editors=0010
    9 points
  34. Hi everyone, as some of you might know I have been working on putting together a series of GreenSock tutorials based on examples from cool award winning websites. Practical GreenSock is now open for signups and you get also a nice launch bonus (40% off Club GreenSock!) from the @greensock team If you have any feedback, questions or suggestions, please let me know. I did run a giveaway on my site that is now closed. I know I should have invited some of the GreenSock fans from the forum to enter but there was so much to do to get the courses live that I forgot. Apologies for that. Let me know "What do you like the most about GreenSock?" in the comments below and I will randomly pick 3 winners of Practical GreenSock. Good luck!
    9 points
  35. Hi Federica, we went through GSAP only smooth scrolling in another forum thread. Here is the final demo. I have also added a scrolltrigger for each box and all markers are aligned correctly even with the smooth scrolling. https://codepen.io/ihatetomatoes/pen/PoZLpbp Please note that smooth scrolling or scrolljacking is not something ScrollTrigger has been build for, but as you can see from the above it is doable. Scroll responsibly
    9 points
  36. By encourage I think he meant "incessantly bugged me for 2 years" Now, that Craig got his blog up, I'll move on to @OSUblake The world needs a GSAP + Pixi hero. Great job, Craig. I'm truly impressed. I can't wait to finish reading all of it. I'm sure motiontricks.com will be a tremendous resource for anyone learning and mastering GSAP. I'll whole-heartedly recommend it. When's the next post going live?
    9 points
  37. I'm so sorry about that - it was just a typo in the docs. It's "className", not "class". toggleClass: {targets: ".c, .a", className: "active"}
    9 points
  38. Hi @Sébastien Gilbert and welcome to the GreenSock Forums. You can tween the same number of values (this is important) via "attr:{}". The following link is an older example of this, but still applies to GSAP 3. https://codepen.io/asistapl/pen/NbQYzP You can also if you prefer use the morpSVG plugin (member benefit) for when you require a differing number of values in your SVG shapes. Here is a thread with an example of that approach. https://greensock.com/forums/topic/21464-multiple-morph-svg/ Do those help you?
    9 points
  39. Wow! I just noticed the GSAP forum cracked 10,000 topics. I just wanted to take a moment to thank Jack for not only creating a fantastic set of animation tools, but also for fostering such a great community. I’ve said it before, and I’ll say it again — this forum really is an oasis in the snarky Interwebs desert. A friendly community with loads of great people and tons of info and demos. Truly one of a kind. A message for any lurkers — try jumping in and asking (or answering) a question. I think you’ll be glad you did. Congratulations Jack. Looking forward to GSAP 3.0 and the next 10,000 topics.
    9 points
  40. Hi, I just want to introduce Compress-Or-Die which is an online compression tool especially created for the creators of banners... so I hope for the most of you. It isn't a tool like tinyjpg or jpegmini that just allows to shrink existing JPGs a little bit. It's the one that creates your (also low quality) images from your original data and really squeezes out the last byte. And allows things like JPGs with transparency and "Selective quality" (as known from Adobe Fireworks) btw... Take a look at it here: http://compress-or-die.com/ In this context these articles could be interesting that explain a lot of the options you can set: http://compress-or-die.com/Understanding-JPG http://compress-or-die.com/Understanding-PNG I am the author of the tool and the article. So if you have questions, wishes or something else, just drop me a line. Thanks, Christoph
    9 points
  41. Hi Tiago, I made a pen simulating the transition of the site you mentioned. But first I think it is interesting to make some observations: 1) When you instantiate the Timeline and nest the Tweens one underneath the other, it is not necessary to put the name of the object every time, you can insert it only once. Like this: let tl = new TimelineMax() .to(...) .to(...) .to(...) // or let tl = new TimelineMax(); tl .to(...) .to(...) .to(...) 2) Since you are animating empty elements, I believe it is easier to animate using scale or xPercent, which will use transform () and have better perfomance than animating Left property 3) When you use Codepen you can insert the libraries directly into the Javascript Session, it becomes easier to manage the libs. Will take that to help you somehow. This pen:
    9 points
  42. Ya there is a lot of code that I am not even sure what is the purpose of that. You are using container's height and width to calculate progress of tweens based on where the cursor is inside the container. Now your container can be a div or window and you need to know how using either affects the implementation. First thing you need is to position your elements where you want them when mouse is at center and from that position eye will translate. You can't use pageX in your actual project because if you scroll it will throw off your calculations. You need to calculate mouse position like I did if your page scrolls. You also need to reset value of rect on resize and scroll event. Figuring out how much the eye should move doesn't need all that calculation, you can just use a number based on radius of your circles.
    9 points
  43. Here's a super rough and quick version that I did. You could probably smooth out some of the paths in Illustrator a bit more even.
    9 points
  44. The secret sauce... Wave === Sine.easeInOut
    9 points
  45. If I understand correctly you could run a loop that tweens every box I suspect at some point the number of elements will impact performance. Hopefully this sparks some ideas. Good luck on your project
    9 points
  46. I got sliiiightly carried away and made this, haha. I don't if it will help because I saw @Rodrigo and @PointC had provided great answers so I didn't bother commenting the code, but feel free to ask if anything is intriguing. PointC, thanks! hehe
    9 points
  47. An even easier way to do this is to make the stagger value negative .staggerFrom(".box", .8, {y:60}, -0.15)
    9 points
  48. I've made a few games using GSAP: Nevergrind - Single-Player RPG Firmament Wars - Realtime Multiplayer Strategy Game I have no regrets using GSAP. It's my favorite tool and as far as I'm concerned it hasn't limited me in any way and I feel very productive with it. I plan to make a 3rd game, a multiplayer co-operative rogue-like follow-up to Nevergrind. Developing games with GSAP is a pure joy. If needed you can even pause the game, as long as you don't use setTimeout or setInterval. As long as every timer and animation is created using GSAP (TweenMax, TimelineMax, TweenMax.delayedCall), you can just do TweenMax.pauseAll() to pause the game (this can be done in Nevergrind by hitting ESC). Since GSAP can tween any object value using any ease, it's simple to Tween using the set method, onUpdate, over time, or whatever kind of animating you need to do. Hope that helps. Discovering GSAP was like finding the holy grail for me because I was seriously using JQuery's .animate before that.
    9 points
  49. So you can imagine, it's Saturday night and there's another deadline looming on Monday. I'm just about to settle in to what I reckon is about 2 hours of work animating "a magical trail randomly jumping around the screen". I got some ideas so just need to crack on. Before I do I just check the "ease-visualizer" and low and behold I find "rough", which I'd forgotten about. Give it a go and that's kinda what I needed, 20 mins later I have finished the job. This keeps happening Jack you have thought of everything and now I don't have any work to do so can enjoy my Saturday evening. So inconsiderate, I mean there's nothing good on TV!! Realised I bought TweenMax 8 years ago, people thought I was mad spending that much money on a tween engine (for Flash). I've used TweenMax in every project I've worked on since buying it and can't imaging developing without it. So just a quick thanks and I'm off to get a beer.
    9 points
  50. There is this big, big tree. Uuuuh, that's high. I always wanted to climb it. Can I? First touch. The peeling is thick, and itchy, but warm and inspiring confidence. I lay my arms around it, starting to rub up. Hmm? Aaha– Okay– That's how– Nice! It's working. That's all I wanted. No need to leave this robust stem. But wait. What's that? There's a branch! And another? I'm curious– The more I climb this tree –body pressed tight onto it– the fear of these little branches slowly fades. I finally, gently step on one. Sometimes they crackle, but never break! My tight grip loosens up; Cheeks stop scratching as I lift my head– Oh boy! So many branches. And look how high I am! Wait what? There's a bird! And anoter one? I start talking to the birds. More birds. I felt like a king just walking the branches. The birds taught me how to jump on them! And soon I'll fly. Soon. I have never experienced anything similar. Such an easy entrance, .. well .. once you accept the word Tween as a thingy describing an animation One can work with GSAP without knowing anything more but .to, .set, and .from. Easy to learn, hard to master. You decide how far you go. When you are part of this special breed of developers/designers, be careful! Because GSAP will suck you in, won't let loose and change the way you see and work the web. That's what I love most. Thank you guys for that. 4 hour research until 1:30am in my freetime, and still burning so much inside that I had to write this. That's how awesome GSAP is.
    9 points
×