Jump to content
GreenSock

Search the Community

Showing results for tags 'gsap3'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • GreenSock Forums
    • GSAP
    • Banner Animation
    • Jobs & Freelance
  • Flash / ActionScript Archive
    • GSAP (Flash)
    • Loading (Flash)
    • TransformManager (Flash)

Product Groups

  • Club GreenSock
  • TransformManager
  • Supercharge

Categories

There are no results to display.


Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Personal Website


Twitter


CodePen


Company Website


Location


Interests

  1. Hey guys So i am making a project with gsap3 kind of like the apple airpod website I have like 500 + images and on scroll these images are being rendered in the canvas. I want to animate some text which will depend on the frame count the sequence is - frame ==0 animate in some text frame>0 animate out the previous text frame>10 again animate in some text frame>200 animate out the previous text so it goes... can some one tell me how can i do this in a efficient way. Thanks
  2. Hello all. I know using calc in JS is not recommended. But as long as it is not in the not supported category, I'd call these bugs. Click the toggle button twice and now the h1 has top: 4.75px instead of calc(1vh). I don't know if GSAP is trying to optimize something, but even if it is it should set 1vh, not 4.75px. https://codepen.io/taylankasap/pen/ZEWMLbB It's jumping to some huge values. https://codepen.io/taylankasap/pen/YzqONVR It is changing values (see devtools) even when from and to are same. https://codepen.io/taylankasap/pen/MWyqJdO It would be good if I could let CSS calculate things for me but with these issues I don't think it's possible. I guess I'll not use calc, just wanted to let you know of these issues.
  3. Hi! I try to change animation with (window.matchMedia()).matches How can i get tween from timeline and replace (or edit) it? I read about .remove() method, but how can i add on removed place other tween and how can i add label to tween. for example: tl .addLabel('start') .to('.box-1', {x:100}, "start") // <--- how to change this or how to .remove() this and place other tween on this place .to('.box-2', {x:100}, "start")
  4. Hi, I'm looking for help regarding scroll trigger and items positioned fixed within a pinned section. I'm having an issue where I have a modal that needs to stay in window view once it's open, but it looks like it's being positioned relative to its pinned parent and I'm able to continue scrolling as normal. Hoping someone would be able to help me out!
  5. Hi Devs, I don't know what's wrong in my code , the animations are super slow in firefox and sometimes in chrome as well. I have two issues Translating animations are super slow in firefox and sometimes in chrome Text animations are flickering on scroll I use SVG as react components Can u guys please help me improve my code. Im using NextJs and GSAP3. Thanks. let timeline = gsap.timeline({ delay: tableAndAbove ? 0.5 : 0, scrollTrigger: !tableAndAbove && { trigger: "#sellersLandingMobileContainer", start: "30% 20%%", }, }); if (tableAndAbove) { timeline.from("#sellersLandingMobile", { duration: 1, scale: 0.8, autoAlpha: 0, rotation: 0.01, }); timeline.from( "#sellersLandingMobile", { duration: 1, translateX: "20%", ease: "expo.out", rotation: 0.01, }, "-=0.6" ); } timeline.to( "#sellersLandingHeroText .hide-text", { duration: 0.8, ease: "expo.out", translateY: 0, delay: 0, autoAlpha: 1, rotation: 0.01, }, "-=0.9" ); timeline.from( "#sellersLandingCTA", { duration: 0.5, ease: "expo.out", scale: 0.5, autoAlpha: 0, rotation: 0.01, }, "-=0.5" ); document.querySelectorAll("#sellersLandingStoreLink").forEach((el) => { timeline.from( el, { duration: 0.5, ease: "expo.out", translateY: 20, autoAlpha: 0, rotation: 0.01, }, "-=0.3" ); }); const images = [ "#sell24By7Img", "#chatBroadcastInvoiceImg", "#lightningfastpaymentsImg", ]; const sections = [ "#sell24By7TextContainer", "#chatBroadcastInvoiceTextContainer", "#lightningfastpaymentsTextContainer", ]; useScroll(); useEffect(() => { gsap.to("#punchGrowthHeading .hide-text", { scrollTrigger: { trigger: "#punchGrowthHeading", start: "top 80%", }, duration: 1, ease: "expo.out", translateY: 0, rotation: 0.01, }); images.forEach((el, index) => { gsap.from(el, { scrollTrigger: { trigger: el, start: "30% 80%", }, duration: 1, ease: "expo.out", autoAlpha: 0, transform: `translate3d(${index === 1 ? 100 : -100}px, 0, 0)`, perspective: 1000, rotation: 0.01, force3D: true, }); }); sections.forEach((el) => { gsap.to(`${el} .hide-text`, { scrollTrigger: { trigger: el, start: "30% 80%", }, duration: 1, ease: "expo.out", translateY: 0, rotation: 0.01, }); gsap.from(`${el} p`, { scrollTrigger: { trigger: `${el} p`, start: "30% 80%", }, duration: 1, ease: "expo.out", autoAlpha: 0, }); });
  6. Hello devs , i'm trying to implement smooth scroll and scrollTrigger pinning on same view port. As the smooth scroll works by disabling scroll and translating -Y , pinned div also translates instead of pinning. Reference : https://codepen.io/wooooosky/pen/LQNZgv Can anyone give me a solution , would be helpful. Thanks in advance.
  7. Hi ! I have a problem for tweening my camera . I create a codepen with the minimum of code just to reproduce my issue and I annotate all my code (sorry for my English I'm french by the way ^^ ) I also put a lot of console.log() for debugging purpose . the question is at line 75-122 the start point is my camera.postion line 23 : camera.position.z = 30; and my tween001 line 75 : var tween001 = gsap.to(camera.position,{ delay:2,duration:5,z:60,onUpdate:function(){ camera.updateProjectionMatrix(); console.log("play"); },onComplete:function(){ console.log("complete"); },ease:"elastic" }); so the tween is about to move my camera from the Z = 30 to Z = 60 its work perfectly but ... When the user move the camera(line 90: when the user move/over/click on the 3d its fire and eventlistener that pause "tween001.pause()" ) I want the tween001 use the "actual" camera.postion and not when the camera.postion used when the tween 001 get fire . Cause when the tween001 is played again or it resume from a pause the start point used is the default one x=0 y=0 z=30 . An idle function play the tween001 again at line 109 window.setInterval(checkTime, 1000);// every 1 second lauch checktime function checkTime() { //idleCounter get 1 every second and at 5 second coz timeout is 5 checktime relauch the tween001 if (idlecounter < timeout) { idlecounter++; //console.log("++ "); } else if (idlecounter == timeout) { tween001.play(); console.log('timeout'); } } Any help will be welcome
  8. There is a problem with gsap ScrollTrigger issues when try to achive horizontal scroll effect on those section and then end of ehis section going to next section. But the problem is when i added pin:true the specific section it's scroll but not pinned on that moment also the next section is moving up before finish the horizontal scroll finished. what i want to achieve https://drive.google.com/file/d/1SpJS5NxL0yK2hs1Ou7G3LSQ3gkvdhcWL/view And What i am facing problem with scrollTrigger when pin:true https://drive.google.com/file/d/1rHEMFfC8JB6GGOEH6MAa8t2jsvdBSXi4/view Here Is my code for Horizontal Scroll with ScrollTrigger let container: any = document.documentElement.querySelector( '.brand-showcase' ); let tl = gsap .timeline({ scrollTrigger: { pin: true, scrub: 1, trigger: container, end: container.scrollWidth - document.documentElement.clientWidth, }, defaults: { ease: 'none', duration: 1 }, }) .to( '.panel-section', { x: -(container.scrollWidth - document.documentElement.clientWidth), }, 0 ) .to( '.panel-item', { opacity: 1, scale: 1, duration: 0.6, stagger: { amount: 0.8, }, }, 0 ); Here Is The HTML Structure for every scroll-item <div class = 'brand-showcase'> <div class="brand-strategy-showcase-container"> <div class="panel-section"> <div class="panel-item"> <div class="showcase-content"> <div class="bss-title">Brand Research & Strategy 1</div> <div class="bss-content"> Spending quality time with our clients in order to uncover what your brand really stands for is by far the most important step. After taking an objective look at your industry and key audiences, we will articulate your purpose, proposition, and personality. From there, we will be able to create experiences that will connect your brand with your customers. </div> <ul class="bss-list"> <li>Market & Landscape Research</li> <li>Market & Landscape Research</li> <li>Market & Landscape Research</li> <li>Market & Landscape Research</li> </ul> <a href="#" class="btn co-btn"> view Project <div class="icon"> <img src="@/assets/img/next_icon.svg" alt="next" /> </div> </a> </div> <div class="showcase-sticky-img"> <img class="item-img" src="@/assets/img/brand-showcase-sticky-img.jpg" alt="Brand Image" /> </div> </div> </div> </div> </div> Hope you understand my issues. Looking for the help from the team gsap or any other coder with gsap master. Thanks in advance
  9. As you can see in my codepen code there is a image and I want to fixed its position center in the section. When scrolling down it will follow the scroll. When the following section comes up there will be a parallax effect. That means image will stick at the bottom of that section and following sections going up over the image. Here is a simple example. Like the form on that website, I want my image but in the center of viewport. If you don't understand please let me know.
  10. I want to create something like function with parrameters to generate template for timeline Example: let tl = gsap.timeline({paused: true, defaults: {duration: 0.2}}) /** opt format: opt = { prop: "", // x, y from: "", // value "+=10".. to: ""// value "0" } */ function tlgenerator(element, opt){ let tl = gsap.timeline(); tl.fromTo(element, {opt.prop: opt.from, autoAlpha: 0}, {opt.prop: opt.to, autoAlpha: 1}) return tl } tl.addLabel("start") .add(tlgenerator(element1, {prop: "y", from: "-=10", to: "0"}), "start") .add(tlgenerator(element2, {prop: "x", from: "+=10", to: "0"}), "start") .... It is not working example I'm not sure that this question need codepan demo?
  11. Recently, I created gatsby project and I wanted to implement show animation to a card component. The problem comes when my 'react-intersection-observer' detects when a card appears on a screen. Then gsap gives me warning with content: 'Invalid property autoAlpha set to 0 Missing plugin? gsap.registerPlugin()' instead of animating my card component. I've already read many topics about this issue. I've tried to use 'gsap.registerPlugin()' function or to put 'CSSPlugin' to 'const plugins' but they don't solve the issue. I see the same issue when I use properties like: 'opacity' instead of 'autoAlpha'. I hope you'll point what is an issue here! There is code of my card component: export default function Card({ number, title, text, fixed, ...props }) { const [ref, inView] = useInView({ threshold: 0.2, triggerOnce: true }) function show() { gsap.registerPlugin(CSSPlugin) const tl = gsap.timeline() tl.set(ref, { autoAlpha: 0 }).to(ref, { duration: 1, autoAlpha: 1 }) } useEffect(() => { if (!inView) return show() }, [inView]) return ( <StyledCard ref={ref} {...props}> <ImageWithMask as={Img} fixed={fixed} brightValue={0.5} /> <StyledContent> <StyledSmall>{number}</StyledSmall> <Heading style={{ textAlign: "right" }}>{title}</Heading> <Paragraph className="paragraph" color={paragraphColor.grey}> {text} </Paragraph> </StyledContent> </StyledCard> ) }
  12. Hi i want to make exact animation for testimonial section from this website (https://appinventiv.com/) at the end you will find testimonial section Please provide complete step by step tutorial i was noob to GSAP please help me
  13. I've got a bunch of elements I'm doing a stagger animation on. I'd like to set different properties (say scale/position) for each of these elements based on index of stagger. Is there a straightforward way of doing this with a single gsap call? The current solution I'm thinking of involves looping through the elements to get index and setting the properties and delay as per this with individual gsap calls in the loop. Any ideas are appreciated, I didn't make a codepen cause I felt like the description explained it well enough.
  14. altaircena

    Draggable

    Hi, I've got some Qs, I wanna create a draggable slider in react like in "http://robinmastromarino.com" and as I was checking the forum, I got confused about the algorithm and also, as I added and tried some of code instances, it didn't work. I use gsap module itself, not react-gsap. plz help
  15. I'm trying to create a write on text animation that changes with each repeat of the timeline, but even though I have repeatRefresh set to true, (which should invalidate the tweens) it only repeats the same text over and over. I'm using a function in the "text" property of .vars that returns a random item from an array of strings. Am I missing something, and is it possible to achieve the effect I'm trying to with this method?
  16. With over 120,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 CSS transitions and GSAP on the same properties 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. If you're animating dynamically to a new position that's updated very frequently, you might want to consider the gsap.quickTo() method. 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&#39;s That Pok&eacute;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 CSS transitions and GSAP on the same properties You should definitely avoid having CSS transitions applied to elements that you're animating with GSAP. That's terrible for performance because the browser would constantly be interrupting things. For example, let's say you animate width to 500px from 100px. On every single tick (requestAnimationFrame), GSAP would set the interpolated value but the CSS transition would basically say "NOPE! I won't let you do that yet...I'm gonna transition to that new value over the course of ____ seconds..." and it'd start interpolating. But on the very next tick, GSAP would set a new value and CSS transitions would interrupt and start over again, going to that new value. Over and over and over. That would not only add a bunch of stress to the browser, but it'd slow things down regarding the overall timing of the animation. For example, if the GSAP tween has a duration of 1 second and the CSS transition is also set to 1 second, that means it'd stop moving after TWO seconds! 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!
  17. Hi everyone, I'm really newbie with gsap and I'm more than sure that I did some awful mistakes. Sorry in Advance if this was already asked / the answer is in documentation but I really couldn't find it and I managed to spend 8h trying to fix this ( deleting and remade-ing ) . So for short I found some really great examples and this one caught my eye: This one more precisely: https://codepen.io/osublake/pen/YrXdGZ -- I started to analyse it and I tried initially to migrate from gsap 2 to gsap 3 but unfortunately I managed to fail miserably. Afterwards I tried to recreate it from scratch to understand how it works where I failed but still ... I managed to get stuck. The main problem: I don't understand why in the demo this line: var animation = new TimelineMax({ repeat: -1, paused: true }) .add(baseTl.tweenFromTo(1, 2)) mainly starts the timeline in a great position and in my situation: _.animation = gsap.timeline({repeat: -1, paused: true}).add(_.timeline.tweenFromTo(1, 2)); it just stays in place. I also tried to reproduce Blake's example in localhost and it does the same thing ( after changing everything to gsap.timeline and gsap.to ). I'm thinking that I miss something or it's a bad thing on putting the timeline in 'this' object. In the end I just want to properly select the center object/objects and increase the scale . And I'm trying to implement a progressive scaling on each item like: 0.6-0.8-1-0.8-0.6
  18. Hi there! I have a question about how timelines are managed in GSAP 3. While a timeline's animation is running, in the js console I seem to be able to use: gsap.globalTimeline.restart(); If the animation has finished it ignores the restart completely. I can only get it to restart if call it while it's running. The project is a game, this is a particular scene, where I will need to restart the timeline and set a different player (between 1 and 4). Also as we're looking to use VUE.js as a single page application I expect will need a master timeline per scene. It's a bit complicated and a client/work related so I can't post it on codepen. If I can get this working and convince the team to use it then definitely interested in becoming a green sock member. There's nothing as powerful as GSAP for timeline management so definitely need to get this working. It's also worth mentioning during the script I can log the variables for the timelines I've created (tl) when the script runs, but not after it's finished running. Please ignore primarily what the animations are doing - as they're working well (it's a responsive scene of a player jumping over a bar then crying when they lose lol). It's mostly just being able to reset / rewind etc the main timeline and each other individual ones. As I can't seem to get either to work. $(document).ready(function () { var pCurrentPlayerNumber = 1; var currentplayer = ".player" + pCurrentPlayerNumber; var currentplayerwrapper = ".player" + pCurrentPlayerNumber + "-wrapper"; console.log(currentplayer); console.log(currentplayerwrapper); var tlSetStage = gsap.timeline(); tlSetStage.set(currentplayer, {className: "+=visible"}) .set(currentplayerwrapper, {className: "+=centercenter"}) .set(".currentplayername", {className: "+=p" + pCurrentPlayerNumber + "-bg"}) .set(currentplayerwrapper, {transform: "translateZ(200px)"}) .set(".highjump-set.fg", {transform: "translateZ(400px)"}) .set(".highjump-set", {className: "+=centercenter"}) .set(".highjump-set", {xPercent: 300}); var tl = gsap.timeline(); tl.set(currentplayerwrapper, {xPercent: -300, yPercent:-50}) .set(".highjump-set", {xPercent: 300}) .set(currentplayer, {className: "+=stancePlayerRunFast"}) .to(currentplayerwrapper, {xPercent: "+=200", yPercent:-50, duration: 1, delay:1}) .to(".highjump-set", {xPercent: "-=280", yPercent:-50, duration: 1, delay:0},1) .set(currentplayer, {className: "-=stancePlayerRunFast"}) .set(currentplayer, {className: "+=stancePlayerJump"}) .to(currentplayerwrapper, {xPercent: "+=50", rotationY:-180, yPercent:-50, duration: 0.5}) .to(".highjump-set", {xPercent: "-=10", yPercent:-50, duration: 1, delay:0},2) .set(currentplayer, {className: "+=aniPlayerPaused"}) .to(currentplayerwrapper, {xPercent: "+=10", rotationY:-180, yPercent: -80, rotationZ: 50, ease: "power4.Out", duration: 0.5}) .to(".highjump-set", {xPercent: "-=20", yPercent:-50, duration: 1, delay:0},3) .to(".highjump-pole-hoz", {xPercent: "+=70", yPercent:"+=330", duration: 0.5, delay:0},3) .to(".highjump-pole-hoz", {yPercent:"-=190", duration: 0.5, delay:0},3.5) .to(".highjump-pole-hoz", {xPercent: "+=20", yPercent:"+=220", duration: 0.5, delay:0},4) .to(currentplayerwrapper, {xPercent: "+=20", rotationY:-180, yPercent: -20, rotationZ: 100, ease: "power4.Out", duration: 0.5},4) .to(".highjump-set", {xPercent: "-=20", yPercent:-50, duration: 1, delay:0},4) .to(currentplayerwrapper, {xPercent: "+=20", rotationY:-180, duration: 2}) .set(currentplayer, {className: "-=stancePlayerJump"}) .to(currentplayerwrapper, {xPercent: "+=20", rotationY:-180, rotationZ: 0, duration: 0.5}) .set(currentplayer, {className: "-=aniPlayerPaused"}) .set(currentplayer, {className: "+=stancePlayerCry"}) .to(currentplayerwrapper, {rotationY:-180, rotationZ: 0, duration: 2}); console.log(tl); }); If I try to restart them using the below command I get a not defined error. Should I be doing each timeline as a function? tl.restart(); or tlSetStage.restart(); Ideally if I can at least just get the master timeline to reset at this stage it would be a win. Being able to reset individual timelines would also be great. Any help very much appreciated!
  19. Hi there! I'm trying to make this horizontal section to "stick" or "snap" the next or prev slide based on the scroll wheel event, but i'm unable to do so. The main goal is, no matter how long the scroll event lasts, it should simple move/scroll to the next or prev slide. Am taking the wrong approach for that (using scrollTrigger and end())? https://codepen.io/jimmyadaro/pen/jOWaZZV I've tried copying this Codepen since it achieves what i'm looking for, but had no success with that. https://codepen.io/mikeK/pen/eoyrWK?editors=0010
  20. Steps to reproduce: Open Codepen Link, it will probably look sort of fine embedded, but it'll be obvious if you resize the screen so the boxes form a 2x2 pattern. Click a box. Goal: To have the boxes animate into the middle from their current position in a nice smooth curve (inwards). Issue: Top left box behaves completely as expected, the rest do not. Details: I'm using MotionPath to animate the boxes into the middle in a curved fashion. According to my math the coordinates should be fine, but the animations are erratic. I'm not entire sure what's going on. If i were to hazzard a guess it would be that the coordinates are correct, but the "handles" in the bezier curve are off?.
  21. Hi there! I´m using the brand new Scroll Trigger plugin, it´s amazing! But i´m having a problem using it with Smooth scroll: i have a link that scroll the page to some point, but after this scroll the Scroll Trigger markers move and the animation that should be triggered doesn´t start. If not scrolled, the script works as it should. Here is the example with markers: https://byhumans.works/area/cliente/roalca/ The bottom blue section have a countdown ( gsap timeline ) that is triggered once with Scroll Trigger. Click on buttons after "Nuestros Productos" title and you will see how the blue section with numbers below lost the trigger start point. I have to do something else after i smooth scroll the page? if i use other script to scroll the page same thing happens. This happens in all browsers, in pc, ipad and smartphone. Thanks My js: // scroll on click category var prodCatBtn = util.$$('.prod-cat-link'); // scroll util.on(prodCatBtn, 'click', function(){ gsap.to(window, { duration: 0.35, delay: .35, scrollTo: { y: ".switcher-prod", offsetY: 140 }, ease: "power2.inOut" }); }); // top boxes animation var counter1 = { var: 1950 }; var counter2 = { var: 0 }; var counter3 = { var: 0 }; var count1 = util.$(".number-1"); var count2 = util.$(".number-2"); var count3 = util.$(".number-3"); count1.innerHTML = counter1.var; count2.innerHTML = counter2.var; count3.innerHTML = counter3.var; gsap.registerPlugin(ScrollTrigger); // counter animation var tl = gsap.timeline({ repeat: false, ease: "none" }); tl.to(counter1, { var: 2004, duration: 3, onUpdate: function () { count1.innerHTML = Math.ceil(counter1.var); }, }) .to(counter2, { var: 16, duration: 3, onUpdate: function () { count2.innerHTML = Math.ceil(counter2.var); }, }, "-=2") .to(counter3, { var: 160, duration: 3, onUpdate: function () { count3.innerHTML = Math.ceil(counter3.var); }, }, "-=2"); ScrollTrigger.create({ trigger: ".counter-wrap", animation: tl, toggleActions: "play pause resume pause", start: "top bottom", markers: true, });
  22. Hello Everyone, I am trying to animate the text using the new scrollTrigger Plugin, there is a glitch when the start point reaches the scroller-start, why is this happening? I am unable to figure it out. Please help me to fix this glitch issue. Thanks.
  23. I'm having a problem and i'm unsure as to whether it's either with Barba or Gsap ScrollTrigger itself I have no clue . So in my website , when I go from the homepage to the about page everything works as normal except the horizontal scroll part that I have put in (Facts Section) , thing is I do this very same action on mobile and it works perfectly sometimes and then other times it does the same as it does with the Desktop Version , so it's either my code and the way I have implemented the horizontal scroll but thing is when I go directly to the page as in not through the homepage and just initiate all the functions in about.js independently , everything including the horizontal scroll works as desired and perfectly , so I don't know which is causing the problem , could ye have a look maybe ?? So here is my homepage.js (Barba Init code) //Variable Declarations and Function Definitions let viewBox = "" heading_Pos = [0, 0] displayState = "" hamburger_display_button = Array.from($('.mobile_nav_sticky'))[0] opened_nav_buttons = document.querySelector('.options') logo = $(".Actual_Logo_Svg") // Morphing Circles and ellipses to paths to be able to morph them and checking the viewbox for device size MorphSVGPlugin.convertToPath("ellipse"); shapes = Array.from($('.Logo_In_Shapes path')) const homeInit = () => { viewBox = "", heading_Pos = [0, 0], displayState = "" hamburger_display_button = Array.from($('.mobile_nav_sticky'))[0] opened_nav_buttons = document.querySelector('.options') logo = $(".Actual_Logo_Svg"); // Morphing Circles and ellipses to paths to be able to morph them and checking the viewbox for device size MorphSVGPlugin.convertToPath("ellipse"); shapes = Array.from($('.Logo_In_Shapes path')) } const logo_tl_func = () => { let logo_tl = gsap.timeline({ onComplete: moveLogo, }) // Morphing into the Logo logo_tl.from(shapes, 1, { y: -600, autoAlpha: 0, ease: "bounce", stagger: 0.15 }) logo_tl.to(shapes, 1, { fill: '#F0C368', stagger: 0.05 }) let firstAnimation = gsap.to('.shapes', { duration: 2, morphSVG: ".Logo_Proper_Background" }); let secondAnimation = gsap.to('.textShape', { duration: 2, fill: '#1D373F', morphSVG: ".Logo_Proper_Text" }); logo_tl.add([firstAnimation, secondAnimation]) } const changeViewBox = media_query => { media_query.matches ? viewBox = "-150 -180 2495 890" : viewBox = "-150 -350 3574 880" media_query.matches ? heading_Pos = [-511, -15] : heading_Pos = [-1540, 40]; media_query.matches ? displayState = "none" : displayState = "block" } const moveLogo = () => { gsap.to(logo, { attr: { viewBox: viewBox }, duration: 3 }) fadeInHeadingAndLinks(); } const fadeInHeadingAndLinks = () => { gsap.to('.nav_links', { display: displayState, scale: 1, duration: 3 }) gsap.to('.logo_heading', { display: "block", x: heading_Pos[0], y: heading_Pos[1], // scale:1, duration: 3 }) gsap.to('.mobile_nav_sticky', { display: "block", scale: 1, duration: 5 }, "+=.7") } const pageTransition = () => { var tl = gsap.timeline(); tl.set('.loading_container img', { scale: 0.3 }) tl.to('.loading_container', { duration: 1.2, width: "100%", left: "0%", ease: "circ.out", }) .to('.loading_container img', { scale: 0.6, duration: 1 }, "-=1.2") .to('.loading_container', { duration: 1.2, width: "0%", right: "0%", ease: "circ.out", }) .to('.loading_container img', { scale: 0.3, duration: 1.2 }, "-=1.3") } // Helper Functions const delay = (ms) => { return new Promise(resolve => setTimeout(resolve, ms)); } // Initialization Methods $(document).ready(() => { window.matchMedia("(max-width: 600px)").matches ? logo.attr('viewBox', '-350 -700 1274 1680') : logo.attr('viewBox', '-680 -380 2074 1080') var viewbox = window.matchMedia("(max-width: 600px)") changeViewBox(viewbox) }) hamburger_display_button.onclick = () => { opened_nav_buttons.classList.toggle('open') } barba.init({ sync: true, transitions: [{ name: 'transition-base', preventRunning: true, timeout: 5000, async leave() { const done = this.async(); pageTransition(); await delay(1000); done(); }, async enter() { window.scrollTo(0, 0); }, }], views: [ { namespace: 'home', afterEnter() { homeInit() window.matchMedia("(max-width: 600px)").matches ? logo.attr('viewBox', '-350 -700 1274 1680') : logo.attr('viewBox', '-680 -380 2074 1080') let viewbox = window.matchMedia("(max-width: 600px)") changeViewBox(viewbox) logo_tl_func(); hamburger_display_button.onclick = () => { opened_nav_buttons.classList.toggle('open') } }, }, { namespace: 'about', afterEnter() { aboutInit() face_tl_func() scroll_p_tl_func() scroll_skills_tl_func() scroll_facts_tl_func() }, } ], }); // //Global Hooks // barba.hooks.leave(() => { // const done = this.async(); // pageTransition(); // await delay(1000); // done(); // }) // barba.hooks.enter(() => { // window.scrollTo(0, 0); // }) and here's my about.js // Variable Declarations and Function Definitions let factsContainer_sm = document.querySelector(".factsContainer_sm") const aboutInit =() => { factsContainer_sm = document.querySelector(".factsContainer_sm") let head = document.getElementsByTagName('head')[0], link = document.createElement('link') link.rel = 'stylesheet' link.href= "../../Resources/CSS/about.css" head.appendChild(link); } const face_tl_func = () => { let face_tl = gsap.timeline(), paths = document.querySelectorAll('.My_Face path'), filledYellowElements = ['.Main_Hair_Part', '.Eyeball_2', '.Eyeball_1', '.Nostril_1', '.Nostril_2', '.Tongue_Part'], filledNavyElements = ['.Pupil_2', '.Pupil_1']; face_tl.set(filledNavyElements, { fill: 'unset' }), face_tl.set(filledYellowElements, { fill: 'unset' }), face_tl.fromTo(paths, { drawSVG: "0%" }, { duration: 1, drawSVG: "100% ", stagger: 0.15 }) let firstAnimation = gsap.to(filledYellowElements, { duration: 2, ease: "slow", fill: '#F0C368' }, "-=.7"), secondAnimation = gsap.to(filledNavyElements, { duration: 2, ease: "bounce", fill: '#1D373F' }, "-=.7") face_tl.add([firstAnimation, secondAnimation]) } const scroll_p_tl_func = () => { let scroll_tl = gsap.timeline({ scrollTrigger: { trigger: '.content', start: "top center", end: "+=1000", markers: true, scrub: true // pin: true } }) scroll_tl.to('.first', { transform: "rotateX(50deg) rotateZ(331deg) translateX(42px)", duration: .5, }), scroll_tl.to('.flag', { scale: 1 }, '-=.1'), scroll_tl.addLabel("first_down") scroll_tl.to('.second', { transform: "rotateX(50deg) rotateZ(331deg) translateX(42px)", duration: 2, }, "first_down-=.1") scroll_tl.addLabel("second_down") scroll_tl.to('.third', { transform: "rotateX(50deg) rotateZ(331deg) translateX(42px)", duration: 2, }, "second_down-=.01") } const scroll_skills_tl_func = () => { let scroll_tl = gsap.timeline({ scrollTrigger: { trigger: '.skillsContainer', start: "top center", markers: true, } }), barWidth = "", bars = [...document.querySelectorAll('.bar')] bars.map(bar => { barWidth = bar.dataset.width; let barAnimation = gsap.to(bar, { width: barWidth, }), percentageAniamtion = gsap.to('.percentage', { scale: 1, }) scroll_tl.add([barAnimation, percentageAniamtion]); }) } const scroll_facts_tl_func = () => { let scroll_tl = gsap.timeline({ scrollTrigger: { trigger: '.factsContainer', start: "top center", // pin: true, scrub: true, end: "+=300", markers: true, } }), facts = [...document.querySelectorAll('.fact')] scroll_tl.to('.factsContainer h2', { scale: 1.5, duration: 1, ease: "slow" }) scroll_tl.to(facts, { xPercent: -85 * (facts.length - 1), scrollTrigger: { trigger: ".factsContainer_sm", start: "center center", pin: true, // pinSpacing:false, markers: true, scrub: 1, snap: 1 / (facts.length - 1), // base vertical scrolling on how wide the container is so it feels more natural. end: () => `+=${factsContainer_sm.offsetWidth}` } }); } // //Initialization Methods aboutInit() face_tl_func() scroll_p_tl_func() scroll_skills_tl_func() scroll_facts_tl_func() Here's the website homepage - https://adamoceallaigh.netlify.app/ Here's the about page - https://adamoceallaigh.netlify.app/about.html Appreciate all the help ye can give , if ye can , can ye check both mobile and desktop versions. 🤙 Cheers Adam
  24. Hi there, TL;DR How to prevent the gsap animations to be aborted in react because of a rerender/prop change How to use dynamic props/state inside a gsap tween without beeing interrupted I'm building a spinng wheel with dynamic start- and end-points. You guys already helped me a lot with this: Now I need to implement this into an acutal react application. The biggest problem is, that I use dynamic Properties inside my gsap tweens to calculate e.g. the stop position or when to stop animation. React rerenders my component and aborts the whole animation as soon as a property changes. Of course react should do that - but how to I keep my animation running? What my code should do: start spinning by clicking the "Start Spinning" Button Wheel is spinning infinite Stop wheel by clicking the "Stop Spinning" Button Wheel at least the minimum amount (5) and then stops at the set position What my code actually does: start spinning by clicking the "Start Spinning" Button Wheel is spinning infinite Clicking "Stop Spinning" does not work -> triggers in my local invironment a rerender and aborts the animation in codepen it flickers and then nothing happens (the stop position is never passed into the tween) ... In the codepen it actually does not rerender but the updated prop won't be passed into the tween. const loopAnim = gsap.to(circleRef.current, { rotation: "+=360", ease: "none", duration: 0.5, onComplete: () => { // The props won't update in here... if (loopIteration.current >= fullSpins && typeof stopAt === "number") { stopAnim.play(); } else { loopIteration.current++; loopAnim.play(0); }, paused: true });
  25. How can I change the transform to matrix I find it difficult to drag in the slider when creating the tilt effect as well as some delay in changing the slide and I think this will fix it just a belief I use gsap.to https://codesandbox.io/s/broken-currying-05h9k
×