Jump to content

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

Search the Community

Showing results for 'overwrite'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


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

Product Groups

  • Club GreenSock
  • TransformManager
  • Supercharge


  • FAQ


  • Examples
  • Showcase


  • Products
  • Plugins


  • Learning Center
  • Blog


  • ScrollTrigger Demos


There are no results to display.

Find results in...

Find results that contain...

Date Created

  • Start


Last Updated

  • Start


Filter by number of...


  • Start



Personal Website



Company Website



  1. At the least you should apply overwrite: true to this tween so that it kills off previous ones. Otherwise you can just adjust the formulas in the ticker to affect the ease: dpkCursorPos.x += (dpkCursorMouse.x - dpkCursorPos.x) * dpkCursorSpeed; dpkCursorPos.y += (dpkCursorMouse.y - dpkCursorPos.y) * dpkCursorSpeed;
  2. Hey Dushyant and welcome to the GreenSock forums. I'm curious: why do you have an animation inside of the mousemove listener and try to set the position in the ticker? They are going to overwrite each other. Are you talking about changing the cursor back to the default if someone hovers an element then scrolls? One way would be to keep track of the scroll position the last time that the mouse moved. Then in the scroll event you check to see if that's over a maximum distance and change it back to the default.
  3. Hi, I have included a CodePen to illustrate my issue. When I am scrolling downward, I have some GSAP code that transforms my elements. Wen I am scrolling upward, the GSAP code transforms them in a different way, and when we reach the top of the window the code transforms the elements in another way. The issue that I am experiencing is that, if I am scrolling fast, or if I touch the bottom and then start to scroll up and down, it *sometimes* causes the elements to jitter. When I inspect the code, it looks like my inline styles that are created by the tweens are fluctuating up and down rapidly, causing the elements to jitter repeatedly. I can usually *but not always* stop it from happening, when I re-scroll in either direction. But it is unpredictable. I am using 'overwrite: true' in most instances to try and compensate for this, in-case it is still reading the values from a previous tween, but it still occurs. Is there something that I can do to completely avoid these values from fluctuating rapidly up and down, and causing my elements to jitter ? Note: I tried using scrollTrigger to do the whole thing and recognize when I am scrolling up or down, but I was unable to figure out a way to handle that.
  4. Hello, I wanted to overwrite the properties of same element on page animated in two different functions. e.g hover function: $(".showcase-item").hover(over, out); function over(){ var hoverAnimation = new TimelineMax(); hoverAnimation.to($(this).find(".showcase-background"), 0.5, {backgroundPosition: '50% 50%',ease: Power1.easeOut}); } function out(){ var hoverAnimation = new TimelineMax(); hoverAnimation.to($(this).find(".showcase-background"), 0.5, {backgroundPosition: '25% 50%',ease: Power1.easeOut}); } click function: $('.showcase-item').on("click", function(){ var showcaseOpen = new TimelineMax(); showcaseOpen.to($(this).parent(), 0.5, {width: '100%',position:'absolute',zIndex:9,ease: Power1.easeOut}) showcaseOpen.to($(this).find(".showcase-background"), 0.5, {scale:1.3,backgroundSize:'contain',backgroundPosition:'0% 50%',ease: Power1.easeOut,'-=0.2'); }); In above code, 'backgroundPosition' has two different values. I want backgroundPosition on hover to be overwritten by one on click.
  5. Hello everyone 🙂 I am quiet new to greensock. Currently I am using ScrollTrigger and the MotionPathPlugin. Here is what I have: https://kwizda.gugler.at/ the tractor is moving on the path perfectly, but as you may see the path isn't moving in the free space given instead its overlapping with the content. On my screen it works perfectly fine, but by changing to another screen it's wrong. Do you have any idea how I could change the path related to the content? Here is my code: gsap.registerPlugin(MotionPathPlugin, ScrollTrigger); gsap.set("#motionSVG", { scale: 0.8, autoAlpha: 1 }); gsap.set("#tractor", {transformOrigin: "50% 50%"}); gsap.to("#motionSVG", { scrollTrigger: { trigger: "#motionPath", start: "top 35%", end: "bottom 35%", scrub: 1, onUpdate: self => { gsap.to("#tractor", { rotation: () => self.direction === 1 ? 0 : -180, overwrite: 'auto', duration: 0.1,}); } }, duration: 10, ease: "none", immediateRender: true, motionPath: { path: "#motionPath", align: "#motionPath", alignOrigin: [0.5, 0.5], autoRotate: 90, } });
  6. 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'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 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!
  7. Hello GSAP community! How's everybody? I would like to know if you could help me. I have two timelines that are triggered by ScrollTrigger when I am within the range of the start attribute. The onEnter and onLeaveBack events of the same ScrollTrigger instance work with timeline.play () and timeline.reverse () respectively, the problem starts when the two timelines are fired and loses the smoothness of the transition. Example: When I move from div.p3 to div.p1 tl2 is interrupted, it is interrupted by tl1 and overwrites everything. I don't quite understand if it could be fixed with invalidate or overwrite. Thank you very much in advance! Here I attach my codepen: https://codepen.io/cpiocova/pen/PoZVEva <body> <div id="box"></div> <div class="p1 pages"></div> <div class="p2 pages"></div> <div class="p3 pages"></div> </body> const box = document.getElementById('box') const tl1 = gsap.timeline({paused: true}) const tl2 = gsap.timeline({paused: true}) tl1.to(box, { duration: 3, x: 350, y: 30, rotation: 45, ease: "expo.inOut" }) tl2.to(box, { duration: 3, x: 20, y: 20, rotation: -125, ease: "expo.inOut" }) ScrollTrigger.create({ trigger: ".p2", start: "0 top", markers: true, onEnter: () => tl1.play(), onLeaveBack: () => tl1.reverse() }) ScrollTrigger.create({ trigger: ".p3", start: "0 top", markers: true, onEnter: () => tl2.play(), onLeaveBack: () => tl2.reverse() }) PD: Excuse my bad English.
  8. I would make a function that creates a new animation. Something like this: export const animIron2 = (model, material, node) => { const tl = gsap.timeline({defaults: {overwrite: "auto"}}); tl.to( model.rotation, { duration: 2, x: 0, y: -2.34, z: -0.05, ease: "expo.inOut", }, 0 ) tl.to( model.position, { duration: 2, x: 3.47, y: -7.1, z: -13.27, ease: "expo.inOut", }, 0 ) } Then call that function when you need it: ScrollTrigger.create({ trigger: ".sp-2", start: "0 top", markers: true, onEnter: animIron2 })
  9. Hey Jose and welcome to the GreenSock forums. There are several ways to handle this sort of thing, the best depends on the effect that you want. If you want it to be smooth (no jumps) no matter what you have a couple of options: Use a single timeline to animate between the various states. Inside of the callbacks you animate the timeline's progress to a certain location. You should probably use overwriting on that tween. It'd look something like this: // helper function function getProgressOfLabel(tl, label) { return tl.labels[label] / tl.totalDuration(); } // in the ScrollTrigger onEnter: () => gsap.to(tl, {progress: getProgressOfLabel(tl, "myLabel"), ease: "none", overwrite: "auto"}) Create tweens when you need to use them (instead of using ones created in the past). That way they can use the current value as the start value. You should use overwriting on that tween. This is probably the method that I'd use. It'd look something like this: onEnter: () => gsap.to(box, { duration: 3, x: 350, y: 30, rotation: 45, ease: "expo.inOut", overwrite: "auto" })
  10. If you use a timeline you would create a timeline with two tweens with some space between (probably using the position parameter of the second tween). The ScrollTrigger's start value would be the start value of your current entry ScrollTrigger. The end would be the end value of your current exit ScrollTrigger. Does that make sense? Alternatively you could use the onEnter and onLeave callbacks to fire entry and exit animations. Just make sure they have overwrite: 'auto' to kill off each other if you do that.
  11. There is a timeline type. No need to do gsap.core.Timeline. (tl: GSAPTimelime, animData: Animation[]) I don't think you should be using Animation as class name. That already exists. https://developer.mozilla.org/en-US/docs/Web/API/Animation If you want to use a class like that, then you should provide default values. class MyAnimation { x: number = 0 y: number = 0 rotation: number = 0 duration: number = 0 constructor(...) {} } But I would recommend just using plain old JavaScript objects. GSAP adds properties to the object, like delay, ease, and overwrite.
  12. Just add on both your #outer_circle tweens overwrite: true after scale, that should take care of it
  13. Hi everyone, Here is what I'm expecting to happen in the Codepen: 1. Click the "Bezier" button to animate the red box along a bezier path 2. While that is playing, click the "Highlight" button. The bezier tween should stop and the red box should animate up to the top left corner of the green box. 3. Click the "Bezier" button again. The red box should then animate back to it's original starting position and then start on the bezier path again. I thought setting overwrite:"all" would help accomplish this, but I can't get the "Highlight" button to work. If you click the "Highlight" button first then it does move the red box to the correct position, but it doesn't work if you click it second. If you click the "Play Vertical" and "Play Horizontal" buttons, then the red box does box in the appropriate direction. Even if you click them in different orders, so the overwrite appears to be working there? Any suggestions?
  14. Hey Phd and welcome to the GreenSock forums. In terms of GSAP, if you want an animation to be replay-able you should save it to a variable. Then you can use control methods on that animation to affect its play state: // gsap, not gasp ;) var slideIn = gsap.fromTo(".text", {xPercent: -100}, {xPercent: 0, duration: 2, ease: “none”, overwrite: “auto”}); // later slideIn.restart(); // simple! However, how you call that method in Adobe Captivate is a question completely unrelated to GSAP. Unfortunately I'm not aware of any regulars here who use Adobe Captivate. I recommend asking that question in Adobe's forums.
  15. I have been trying to get a text rollout animation working in Adobe Captivate. A kind person on the Adobe forums responded with an example making use of GSAP library using the fromTo command, which largely resolves the problem. The animation is dropped into a Captivate slide as a zipped up .html file to animate the text at a certain point on the timeline, only compatible with HTML5 output, which is fine. The problem is that if the slide is replayed, e.g. by restarting the timeline or rewinding and replaying, the fromTo animation does not replay, it only works by refreshing the whole browser page and restarting the player. The question is, how can I get the fromTo to replay correctly if the player timeline is rewound? Gsap code is: gsap.fromTo(“.text”, {xPercent: -100}, {xPercent:0, duration: 2, ease: “none”, overwrite: “auto”});
  16. That's because it will create a new tween every time that the count state updates. Sorry, I don't really use React and this is 100% a React question so I'm probably not the best equipped person to do it If this is all you're doing then you could just use a tween with overwrite: true https://stackblitz.com/edit/react-nempcw With that being said, @OSUblake, @Rodrigo, or @elegantseagulls will probably come by and correct my ignorance. Also FYI there was a recent article made about hooks + GSAP by @Ihatetomatoes that might be useful: https://ihatetomatoes.net/react-and-greensock-tutorial-for-beginners/
  17. Definitely include overwrite: "auto", or overwrite: true, on your tweens. You can set that as a global default if you want: gsap.defaults({overwrite: "auto"});. Besides that nothing sticks out.
  18. Yep, the problem is that you've got competing scrubs (as you know). Also, you're breaking each "section" into individual tweens so if you scroll really fast from section 2 to 3 but due to the delayed scrubbing, the one from section 2 is barely into its progress, but you're also asking #3 to start scrubbing its (separate) tween simultaneously which goes from completely different progress values. I'd suggest just using ONE overall linear tween, and then animate the progress of that tween in an onUpdate of the ScrollTriggers like this: https://codepen.io/GreenSock/pen/pogpYVa?editors=0010 let sections = gsap.utils.toArray(".step"), // do the entire ball tween (across all), linearly ballTween = gsap.fromTo(".ball", {scale: 0}, {scale: sections.length * 2, ease: "none", paused: true}), // we'll tween the playhead of ballTween with this separate tween. This creates the delayed scrub (2 seconds to catch up, or whatever duration you define) tween = gsap.to(ballTween, {duration: 2, ease: "power3", paused: true}), // progress incremenet inc = 1 / sections.length; sections.forEach((step, i) => { ScrollTrigger.create({ trigger: step, start: "bottom bottom", end: "+=1000", pin: true, onUpdate: self => { tween.vars.progress = (i * inc) + self.progress * inc; tween.invalidate().restart(); } }); }); I'm reusing the same "tween" instance over and over and simply altering its vars.progress and then invalidating it solely to improve performance. A simpler (but less performant) option would be to gsap.to(ballTween, { progress: (i * inc) + self.progress * inc, duration: 2, ease: "power3", overwrite: true}) in the onUpdate but that creates a new tween instance each time (somewhat wasteful memory-wise). Now you get a perfectly smooth delayed scrub across everything. 👍 Is that the effect you're after?
  19. Thanks Zach. I used the onUpdate method and tweens per tick with overwrite. I initially used the same values for duration that I had used for the scrub, which should then theoretically take the same amount of time (without a performance drawback and infinite ticks per second). I had to change the values a bit because it got a bit slower after all, i think. But maybe that's just subjective because of the blinking before. https://codepen.io/Skadi2k3/pen/RwrjqWP?editors=0010
  20. Hi guys, I am using ScrollTrigger batch like this: gsap.set(".column", {opacity: .5, y: 20}) var scroll = ScrollTrigger.batch(".column", { batchMax: 6, interval: .3, onEnter: batch => { gsap.to(batch, { opacity: 1, stagger: .3, duration: .5, y: 0, overwrite: true, }); }, onLeaveBack: batch => { gsap.to(batch, { opacity: 0.5, duration: .3, y: 20, overwrite: true }); }, start: "center bottom", end: "center top", }); scroll.getAll().kill(); And I tried to kill it like in example above, but it doesn't work. I am trying to be able to overwrite ScrollTrigger instance that I created - say that this code exists in my base.js file, now I am wondering if there is a way of overwriting all of those animations or simply get rid of them in my project.js file?
  21. .then() function helps in solving my first issue, just that it came with another - tweens with .then callbacks breaks repeat settings for parent timeline. Regarding your question: If someone clicks the left button, do you want both cubes to rotate? Or just one? If just one, are there going to be buttons for every cube? In my case, I do not have buttons, but rather a scroll event when mouse is being hovered on any cube. So for simplicity, let's say, buttons for each cube. What I want is that when user clicks a button (of any cube, or scrolls on any cube in my case) for master timeline keep its' time settings so that when clicking and calling rotate(). rotate(dir = 1, origin) { this.iteration += dir; let delay = origin === "mouse" ? 0 : 2; console.log("rotate", this.iteration % 4, "wall data"); let tl = gsap.timeline(); console.log(this.iteration); tl.to(this.productCube, { rotateY: this.iteration * 90, delay: delay, duration: 2, overwrite: true, }); return tl; } it wouldn't interfere (make any changes in regards to time) with: startRotation() { console.log("start rotation"); let tl = gsap.timeline(); tl.add(this.rotate()) .then(() => this.rotate()) .then(() => this.rotate()) .then(() => this.rotate()); return tl; Any help is appreciated.
  22. I appreciate your help a lot. The full idea of what I want to achieve can be seen at the codepen below, although there is a lot of smelly code not related to GSAP so I do not recommend diving into it. The idea is several cubes or more, where everyone rotates from 0 to 360, or does any animation of any sort by 0.5 delay from the previous cube, and repeats the cycle after all cubes have finished the animation. In addition, the animation must be playable by outside interactions. So I at the moment I have a rotate method (in ProductCube) which rotates the cube by 90 degrees to a given direction: rotate(dir = 1, origin) { this.iteration += dir; let delay = origin === "mouse" ? 0 : 2; console.log("rotate", this.iteration % 4, "wall data"); let tl = gsap.timeline(); console.log(this.iteration); tl.to(this.productCube, { rotateY: this.iteration * 90, delay: delay, duration: 2, overwrite: true, }); return tl; } Furthermore, I have a method to start initial timeline for one single cube, to rotate the cube from 0 to 360 degrees. startRotation() { console.log("start rotation"); let tl = gsap.timeline(); tl.add(this.rotate()) .then(() => this.rotate()) .then(() => this.rotate()) .then(() => this.rotate()); return tl; Lastly, I have another class and method (in ProductShowcase) which starts rotations for all cubes. init() { let tl = gsap.timeline({ repeat: this.repeat, repeatDelay: this.repeatDelay, delay: this.delay, }); tl.addLabel("start") .add(this.cubes[0].startRotation(), "start") .add(this.cubes[1].startRotation(), "start+=0.5") .add(this.cubes[2].startRotation(), "start+=1"); this.animation = tl; } Additionally, I have a function for user interactions which upon scroll rotates any cube additionally. function cubeScroll(target, event) { window.clearTimeout(isScrolling); isScrolling = setTimeout(function () { console.log("Scrolling has stopped.", event.deltaY); console.log(target); if (event.deltaY < 0) { target.rotate(-1, "mouse"); } else if (event.deltaY > 0) { target.rotate(1, "mouse"); } }, 200); } My Issues: The main timeline "init" does not repeat if any child tween has .then() callbacks If I use .add() instead .then(), then all tweens starts from 0, which basically ends up with the last one, from 0 to 360 running instantly rather than by slice, 0-90, 90-180, so on. Will try ".fromTo" in the meantime, by remembering the last degree. any rotate from anywhere else than the main timeline ( in "init" method) breaks the timeline. If you would try to to scroll on the second cube, it would fall out of the chain, and later on, would be the last rotating cube. Will try to have a seperate tween for it. https://codepen.io/affkatron/pen/yLezLGm?editors=0010 Thanks for your ideas in advance.
  23. I don't think it's actually possible to get the behavior you're expecting. Allow me to explain... The "auto" overwriting occurs the first time the tween renders (it looks for other overlapping tweens at that point and kills them). Once a tween (or a portion of a tween) is dead, it's permanent. GSDevTools forces the playhead of the root to the end initially and then back again in order to ensure the accuracy of the duration. For example, a timeline.tweenTo() may be embedded somewhere, and it can only discern its duration once there's a render and it can sense where the playhead is. In other words, if we DON'T force the playhead to the end and back again, the duration may suddenly change once that tweenTo() begins. Plus doing a progress(1).progress(0) allows all those instantiation tasks to run initially, thus you get better performance during the animation. So in your example, the overwrite would happen right away (when the progress(1).progress(0) happens), thus you'd never see the initial y: "-=20" animation because it's dead as a doornail. So it's more of a logic issue than a bug (unless I'm totally missing something). In the next version of GSAP/GSDevTools, I will fix that issue that prevented "auto" overwriting from occurring, but that doesn't solve your example as I explained above. It'll just nuke that first tween right away (which is the proper behavior from what I can tell). I'd generally advise NOT to build animations like that where they overlap. I suppose sometimes it's tough to avoid - it's not like you're breaking a cardinal rule, but as you see here it can create some logic problems in some scenarios. It'd be better to build your sequence properly so that the "y" value goes up with one tween, and then down with another, and don't overlap them. Does that clear things up at all? Sorry about any confusion there. It's quite an edge case. And again, it'd only affect overwrite: "auto" when GSDevTools is run on the root.
  24. Hello guys, I'm trying to use ScrollTrigger.batch with typescript, but I can't set the markers nor the triggers, when I try yo put the markers for instance it says: Argument of type '{ onEnter: (batch: Element[]) => Tween; markers: boolean; }' is not assignable to parameter of type 'ScrollTriggerBatchVars'. Object literal may only specify known properties, and 'markers' does not exist in type 'ScrollTriggerBatchVars'.ts(2345) my code so far: gsap.set(".work", { y: 100 }); ScrollTrigger.batch(".work", { onEnter: (batch) => gsap.to(batch, { opacity: 1, y: 0, stagger: { each: 0.15, grid: [1, 3] }, overwrite: true, }), markers: true, }); am I doing something wrong?
  25. Overwrite: none is not behaving how I imagined it would. In my codepen example I imagined that the second tween would be ignored because the first tween is already animating the element's "width". Instead it seems like the first tween is being overwritten despite overwrite being set to "none". Am I misunderstanding overwrite? Is there a way to accomplish what I want (where the second tween would be ignored because another tween has already 'claimed' the right to animated "width"?) http://codepen.io/anon/pen/BoJMvw Thanks for any help. -Ryan