Jump to content

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


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. Hi, This should work: const roll1 = roll(".rollingText", {duration: 10}), roll2 = roll(".rollingText02", {duration: 10}, true), scroll = ScrollTrigger.create({ onUpdate(self) { if (self.direction !== direction) { direction *= -1; roll1.timeScale(direction * 3); roll2.timeScale(direction * 3); gsap.to([roll1, roll2], {timeScale: direction, overwrite: true, duration: 1}); } } }); Happy Tweening!
  2. The live example you have and the demo you provided don't use either Draggable or the Inertia Plugin, so you can set the draggable option to false: let carousel = buildCarousel(items, { radiusX: 250, radiusY: 210, activeAngle: -90, draggable: false, onClick(element, self) { self.to(element, {duration: 1, ease: "power1.inOut"}, "short"); }, onActivate(element, self) { element.classList.add("active"); }, onDeactivate(element, self) { element.classList.remove("active"); }, // when a drag or animation starts (via the Carousel's to()/next()/previous() methods) onStart(element, self) { gsap.to(descriptions[items.indexOf(element)], {autoAlpha: 0, duration: 0.25, overwrite: "auto"}); }, onStop(element, self) { gsap.to(descriptions[items.indexOf(element)], {autoAlpha: 1, overwrite: "auto"}); } }); If you want to use the example with the red circles you can just offset the start and endpoints by minus 25%: gsap.set(items, { motionPath: { path: circlePath, align: circlePath, alignOrigin: [0.5, 0.5], start: -0.25, end: i => (i / items.length) - 0.25, }, scale: 0.9 }); The rest of the code should remain the same. Yet another option with the latter example (red dots) is to set the start point of the path to the top of the circle. Check this article by @PointC https://www.motiontricks.com/cut-your-path-start-points-in-adobe-illustrator/ Hopefully this helps. Happy Tweening!
  3. Hey, folks! My team over at The DataFace has this nifty Svelte action powered by GSAP that we've been using for the past few projects. It blends a few approaches that we've seen in the forums. I thought we'd share the wealth with a few key examples in this repl. We have a more complex version that handles timeline positioning that I can share once it's refined. import { gsap } from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger' gsap.registerPlugin(ScrollTrigger); export default (node, { type, children, scrollTrigger, ...args }) => { let targets = children ? node.children : node; let timelineArgs = scrollTrigger ? { scrollTrigger: { trigger: node, start: 'top center', ...scrollTrigger } } : {}; let timeline = gsap.timeline(timelineArgs)[type](targets, { ease: 'power2.out', overwrite: true, ...args }); return { update(params) { timeline.duration(params.duration); }, destroy() { timeline.killTweensOf(targets); } } };
  4. Hi, The issue is not really about overwritting, that's a completely different situation. Basically what's happening here is that you have different event handlers battling for control to play/reverse the same GSAP instance, nothing more. A simple boolean and some conditional logic seems to solve the issue, in order to prevent ScrollTrigger's update callback from controlling the instance: https://codepen.io/GreenSock/pen/Yzvdpog Here you can read more about overwrite: https://greensock.com/docs/v3/GSAP/Tween/vars Let us know if you have more questions. Happy Tweening!
  5. Hi Everyone! I have a timeline that plays and reverses based on scroll direction. I also use a mouse enter/leave function to trigger/control the same timeline. When using ScrollSmoother the direction overrides the mouse enter/leave functions (the timeline won't play until the scroll is at rest, even when I trigger mouse enter/leave events). My question: Can I overwrite the scroll control to prioritize the "mouse enter/leave" functions? Thanks, as always.
  6. Hi @Fabian W and welcome to the GreenSock forums! First thanks for being a Club GreenSock member and supporting GSAP! 🥳 What you are looking for is the invalidateOnRefresh configuration option in the ScrollTrigger configuration object: Boolean - If true, the animation associated with the ScrollTrigger will have its invalidate() method called whenever a refresh() occurs (typically on resize). This flushes out any internally-recorded starting values. https://greensock.com/docs/v3/GSAP/Tween/invalidate() This seems to work the way you intend: let t1 = gsap.to(c1, { scrollTrigger: { scrub: true, start: () => 0, end: () => 'max', markers: true, invalidateOnRefresh: true,// <- HERE }, y: () => document.body.clientHeight - c1.clientHeight, ease: 'none', overwrite: 'auto' }); let t2 = gsap.to(c2, { scrollTrigger: { scrub: true, start: () => 0, end: () => 'max', markers: true, invalidateOnRefresh: true,// <- HERE }, y: () => document.body.clientHeight - c2.clientHeight, ease: 'none', overwrite: 'auto' }); Hopefully this helps. If you have more questions let us know. Happy Tweening!
  7. I'm not entirely sure how you want it to work, but it may be as simple as: ScrollTrigger.create({ trigger: el, start: 'top 50%', end: (self) => '+=' + el.offsetHeight, onToggle: (self) => { if (self.isActive) { gsap.to('body', { backgroundColor: color || 'transparent', duration: 0.6, overwrite: 'auto', }); } }, }); The way it was set up in Rodrigo's demo made the ScrollTriggers overlap which would cause the tweens to fight with each other during the overlaps.
  8. Hi @eliphino and welcome to the GreenSock forums! First, thank you for being a Club GreenSock member and supporting GreenSock! 🥳 I think this approach works better, since you are also adding the event listener to the window object on every loop: window.addEventListener("mousemove", e => { gsap.to(targets, { duration: 0.35, x: e.pageX, y: e.pageY, ease: "none", overwrite: "auto", stagger: 0.035, }); }); Also I'd recommend you to use less elements, since adding a bunch of them tends to look a bit off, but I'll leave that to your better judgement and the needs of your project. Let us know if you have more questions. Happy Tweening!
  9. If you want to overwrite the default scroll behavior of the browser you'll need to have a clear goal with it and know what you're doing. If you do not have this or you are new to coding I would not recommend doing this. ScrollTrigger taps in the to default scroll behavior. If you have some other element you want to use as the scroll container you can define a scroller (see the docs https://greensock.com/docs/v3/Plugins/ScrollTrigger) String | Element - By default, the scroller is the viewport itself, but if you'd like to add a ScrollTrigger to a scrollable <div>, for example, just define that as the scroller. You can use selector text like "#elementID" or the element itself. If you instead just want to watch for the scroll event you can also use the Observer plugin https://greensock.com/docs/v3/Plugins/Observer Instead of showing the issue you're having can you maybe explain what your goal is? If we know what it is you want to do it will be easier to help you with an appropriate solution.
  10. Hi @Rodrigo, Thank you for your detailed answer! All clear. I finally managed to do it but without using the snap functionality, cause I needed to scroll up and down. The solution was based on another example found on the forum by @ZachSaucier (the codepen : https://codepen.io/GreenSock/pen/NWxNEwY , and the thread: Here is the (a) solution : let panels = gsap.utils.toArray('.block-scroll'), scrollTween; function goToSection(i) { scrollTween = gsap.to(window, { scrollTo: {y: i * innerHeight, autoKill: false}, duration: 1, ease: Power3. easeOut, onComplete: () => scrollTween = null, overwrite: true }); } panels.forEach((panel, i) => { ScrollTrigger.create({ //markers: true, trigger: panel, start: 'top 75%', end: 'top 25%', onEnter: self => { self.isActive && !scrollTween && goToSection(i+1); console.log(panel); }, onEnterBack: self => { self.isActive && !scrollTween && goToSection(i); } }); }); Anyway, thanks for your quick answer.
  11. @Rodrigo - I truly appreciate your detailed explanation. Everything you said makes sense and speaks to the core of the issue that I was facing. I was not aware of the overwrite property, so that was super helpful as well. I believe I'll be able to come up with a good solution based on your feedback. Thanks again for your time and knowledge!!
  12. Hi, The issue with overwrites is basically generated when one or more GSAP instances affect the same property (blur filter in this case), on the same element at the same time. Right now you are creating two different animations for each element before even running one of them. On top of that you are not correctly reversing all the animations, for example you move from heading-2 to heading-3. When you enter heading-2 the heading-1 element gets affected by one animation, when you move to heading-3, one heading-1 animation is reversed but as soon as you enter heading-3 another one starts while the other is still reversing. You have two different animations affecting the same property on the same element. On top of that overwrite won't help you in this case, you can test it by using this configuration in your methods: function animation_blur(elem) { const theAnimation = gsap.timeline(); gsap.set(elem, { filter: 'blur(0px)' }); theAnimation.to(elem, { filter: 'blur(5PX)', ease: 'none', duration: 0.5, overwrite: true, }); return theAnimation } function animation_blur2(elem) { const theAnimation = gsap.timeline(); gsap.set(elem, { filter: 'blur(0px)' }); theAnimation.to(elem, { filter: 'blur(20PX)', ease: 'none', duration: 0.5, overwrite: true, }); return theAnimation } You'll notice that this definitely doesn't work the way you want. Here is what overwrite does: If true, all tweens of the same targets will be killed immediately regardless of what properties they affect. If "auto", when the tween renders for the first time it hunt down any conflicts in active animations (animating the same properties of the same targets) and kill only those parts of the other tweens. Non-conflicting parts remain intact. If false, no overwriting strategies will be employed. Default: false. Since your animations affect just one property everything will be flushed out and only the animations created by the animation_blur2 method will remain and work, that's why I think the best approach is the one I suggested, as that takes the element from it's current state to the state you want (no blur, low blur or high blur). If you need to use reverse, that means that you are using an event handler for doing that, so why using a method that creates a new GSAP instance is not an option? If you want to keep the current approach you have, you have to look into reversing everything and then playing the instances you want, but you already ran into some logic issues with your code. Based on the Codepen example you gave us I provided a solution for the issue I saw there which should be scalable into a larger setup without too much problems. If you keep having issues, let us know. Happy Tweening!
  13. Hey @Rodrigo - thanks for your response! I appreciate the new approach that you suggested, but I am looking for a solution that still uses .reverse() on mouseleave. (My original codepen is kind of a boiled down example of something more complicated that I'm working on). You mentioned that I'm running into "overwrite issues" - do you think that this is the core issue that I'm facing in my original codepen? Could you possibly expand on overwrite issues? Is there any documentation on overwrite issues? Any ways to combat overwrite issues from occurring? Thanks again!
  14. Hi, Your setup is a bit convoluted IMHO and you are clearly running into overwrite issues. I think this approach is better and a bit more flexible: https://codepen.io/GreenSock/pen/oNyGLgv Granted, due to the fact that you are using two different blur animations in different situations makes it a bit difficult to find a flexible and dynamic solution, but at least for three elements this works. Let us know if you have more questions. Happy Tweening!
  15. Ha!, well this is not the case, by defining an extra ScrollTrigger object within a tween you'll define a second ScrollTrigger that has nothing to do with your timeline and will just overwrite what you'll try to do within the ScrollTrigger in your timeline. So don't do that! Removing the ScrollTrigger in your tween will fix your issue. https://codepen.io/mvaneijgen/pen/zYadQYP?editors=0010
  16. Your overall timeline has a scrub: true, this makes it animate on the users scroll position, but you overwrite this scrub (TIL you can overwrite ScrollTrigger properties within a tween!? Edit: No you can't!) within the frame animation and set it to 0.5, this makes it lag behind 0.5 seconds, which will result in it still playing when the next animation is already in view. You could do a few things to resolve this: Set the scrub the same for all animations on the timeline. Have a delay of 0.5 on the next animation either with the position parameter or a delay: 0.5 on the tween Hope it helps and happy tweening!
  17. Hi, OK, thanks for that information, I can see the confusion now. There is no issue at all here, everything is working as expected. The difference between desktop and a touch device are these event handlers: container.addEventListener("mouseenter", () => { reversedOnPause = tl.timeScale() < 0; isOver = true; gsap.to(tl, {timeScale: 0, duration: 1, overwrite: true}); container.classList.add("paused"); }); container.addEventListener("mouseleave", () => { isOver = false; gsap.to(tl, {timeScale: reversedOnPause ? -1 : 1, duration: 1, overwrite: true}); container.classList.remove("paused"); }); So when there is a touch start event in a device it acts as a mouse enter, but the touch end doesn't act like a mouse leave, you actually have to touch elsewhere, outside the boundaries of the container element, to trigger the mouse leave. If you remove those event listeners or add a different logic for touch events it should work as expected. Happy Tweening!
  18. Hi, Scrolltrigger version 3.11.3 (and probably older versions too) save the history.scrollRestoration value at the beginning and it seems it's not possibile to overwrite that value later: _scrollRestoration = _win.history.scrollRestoration || "auto"; Then the stored value is applied again every clearScrollMemory call: _isString(scrollRestoration) && (_win.history.scrollRestoration = _scrollRestoration = scrollRestoration); Even setting history.scrollRestoration to manual at the beginning of my script, due to Webpack bundle, the Scrolltrigger code is extecuted before mine. In my case I need to set the scrollRestoration to manual because I use Barba.js Is there a way to do it? Am I missing something?
  19. Hi @dhdbtkd welcome to the forum! By default ScrollTrigger selects the the body (or HTML) as the scroll element, eg the element that normally scrolls. If you want to overwrite that, you'll have to define what element is the scroller in your case scroller: ".myScroller", for it to work. (I gave your element a class of myScroller) String | Element - By default, the scroller is the viewport itself, but if you'd like to add a ScrollTrigger to a scrollable <div>, for example, just define that as the scroller. You can use selector text like "#elementID" or the element itself. Read more on the docs https://greensock.com/docs/v3/Plugins/ScrollTrigger https://codepen.io/mvaneijgen/pen/JjZEyVo Personally I wouldn't overwrite the normal browser behavior if you don't have a clear use case for it. In your case you can just set the header and footer to position: fixed; and have the browser behave like it normally does, but that is just my opinion. Hope it helps and happy tweening!
  20. If you want it to happen for each of your images, then set the ScrollTrigger up in the forEach loop over the images. Adjust its start so it is the same as the start for the ScrollTrigger that is scrubbing the image-height plus half a window's height. Set your colors-array up, so that it also contains the initial color as the first value and then target the colors like this in your callbacks. // pseudo-code... const colors = [firstPanelColor, secondPanelColor, thirdPanelColor, fourthPanelColor ] onEnter: () => { gsap.to("body", { duration: 0.5, backgroundColor: colors[i+1], overwrite: 'auto' }); } onLeaveBack: () => { gsap.to("body", { duration: 0.5, backgroundColor: colors[i], overwrite: 'auto' }); } https://codepen.io/akapowl/pen/rNKORBb
  21. it seems I didn’t quite understand you, or I didn’t explain it well, I know how to change the background when the first panel reaches 50%, but how to change the background of the next ones so that each panel has its own color, I tried to do this, but the panel changes color only 1 time per black const colors = ['#F5EBFF','#EEF8FF', '#000000'] ScrollTrigger.create({ trigger: "section.black", scroller: ".scroller", start: () => "top -" + (window.innerHeight * 0.5), onEnter: () => { console.log('color', colors[i]) gsap.to("body", { duration: 1, backgroundColor: colors[i], overwrite: 'auto' }); }, onLeaveBack: () => { gsap.to("body", { duration: 1, backgroundColor: i === 0 ? '#ffffff' : colors[i-1], overwrite: 'auto' }); }, invalidateOnRefresh: true })
  22. @Isla that is correct, bootstrap will apply a lot of CSS to your layout. You either have to overwrite that or write your own logic for this particular block of content. It's really important how you build your layout if you want to animate it and with bootstrap this is not something you get great control over, because it will imply that you want everything underneath each other on mobile.
  23. Definitely. If you don't kill() that animation, it will keep running. So every time there's a resize event, it'll create a whole new infinitely-repeating tween and every one of them will be fighting for control of the same properties of the same targets. You don't notice it because basically the "last one wins". So you may have 100 animations all running and tweaking the same property, but the last one created is the last one that runs, thus the final render looks correct. You just have a bunch of unnecessary tweens doing unnecessary work. You could set overwrite: true or overwrite: "auto" if you prefer, but I think it's cleaner/faster to just kill() the old tween before you create the new one. Yep. Here's a technique I use: // reusable function that handles setting it all up for you... function callAfterResize(func, delay) { let dc = gsap.delayedCall(delay || 0.2, func).pause(), handler = () => dc.restart(true); window.addEventListener("resize", handler); return handler; // in case you want to window.removeEventListener() later } Usage: callAfterResize(loop); By default, it'll wait until 0.2 seconds elapses with no "resize" events before calling the function, but you can customize it, like if you want it to wait 0.5 seconds instead: callAfterResize(loop, 0.5); Done. ✅ Have fun!
  24. Hi all. I have been tasked my by company to revamp our site. We have designs and a concept for a single-page site that makes use of animations tied to scroll progress. GSAP and Scrolltrigger has been amazing for this so far. At this point I have the full animation orchestrated from the top to the bottom of the page. Scrolling at a reasonable speed results in the desired effect. However scrolling too quickly or jumping to certain points on the page results in elements ending up in places where they shouldn't be. The animation is quite a complex one when all put together. It involves the same elements being animated multiple times, as they move around the page while scrolling. I've divided the single-page into various sections, and have a separate timeline that handles each section. I'm unable to share a full codepen as I'm not allowed to share certain information such as our assets, but I have included code below that I hope adequately shows my approach. I've tried various solutions suggested already on this forum, including: setting "immediateRender" and "overwrite", using only fromTo's, relative vs absolute values. I think that my mistake lies in my approach to the task, I believe I'm not employing the optimal practices in order to complete a complex animation of this nature. useEffect(() => { gsap.registerPlugin(ScrollTrigger); planetFloat(); landingPhase(); discoverPhase(); discussPhase(); decidePhase(); }, []); export const landingPhase = () => { gsap .timeline({ scrollTrigger: { trigger: ".scroll-trigger", start: "10% bottom", end: "+=2000", scrub: 0.25, }, }) // Move landing text off screen .to(".landing-text", { opacity: "-=1", x: "+=300", }) // Bring greatness text onto screen .fromTo( ".greatness-text", { autoAlpha: 0, x: -300 }, { autoAlpha: 1, x: 0, }, ">-50%" ) // Scale up discover system .fromTo( ".discover-system", { opacity: 0, scale: 0 }, { opacity: 1, scale: 1, }, // ">-60%" "<" ) // Telescope ledge rises into view .fromTo( ".telescope", { y: 350 }, { y: 0, }, // ">-60%" "<" ) // Greatness text descends below telescope ledge .to( ".greatness-text", { opacity: "-=1", y: "+=550", }, ">100%" ) // Journey text descends into view .fromTo( ".journey-text", { y: -550, autoAlpha: 0 }, { y: 0, autoAlpha: 1, }, ">-70%" ) // Beginning of system rearrange --> .to( "#moon-container", { x: "-=50", y: "-=100", scale: "-=0.7", overwrite: true }, ">100%" ) .to( "#galaxy-swirl-container", { x: "-=400", y: "+=50", rotate: 7, scale: "+=0.4", overwrite: true }, "<" ) .fromTo("#sun-container", { scale: 0 }, { scale: 0.3 }, "<") .to( "#ringed-planet-container", { x: "-=500", y: "+=100", overwrite: true }, "<" ) .fromTo("#red-planet-container", { scale: 0 }, { scale: 1 }, "<") .fromTo("#darkBlue-planet-container", { scale: 0 }, { scale: 1 }, "<") .to( "#lightBlue-planet-container", { x: "-=160", y: "+=240", scale: "+=0.5", overwrite: true }, "<" ) .to( "#dark-planet-container", { x: "+=50", y: "-=150", scale: "-=0.5", overwrite: true }, "<" ) .to( "#turquoise-planet-container", { x: "-=260", y: "+=60", scale: "+=1.5", overwrite: true }, "<" ) // <-- Ending of system rearrange // Telescope ledge zooms out of view .to( ".telescope", { y: "+=500", x: "-=800", }, "<" ) // Journey text zooms out of view .fromTo( ".journey-text", { y: 0, x: 0, }, { y: 500, x: -800, }, "<" ); }; export const discoverPhase = () => { gsap .timeline({ scrollTrigger: { trigger: ".scroll-trigger", start: "25% bottom", end: "+=2000", scrub: 0.25, }, }) // Phase 1 text moves in from the right .fromTo(".phase1-text", { x: 1500 }, { x: 1200 }, "") // Discover text fades in .fromTo( ".discover-text", { autoAlpha: 0, scale: 2.5 }, { autoAlpha: 1, scale: 2.5 }, "<" ) // Phase 1 text moves over the screen .to(".phase1-text", { x: "-=135%" }, ">100%") // Beginning of system rearrange --> .to( "#galaxy-swirl-container", { rotate: -15, x: "+=300", scale: "-=0.4", overwrite: true }, ">-50%" ) .to( "#sun-container", { x: "+=250", y: "+=25", scale: "-=0.05", overwrite: true }, "<" ) .to("#moon-container", { x: "+=250", overwrite: true }, "<") .to( "#lightBlue-planet-container", { x: "+=200", y: "-=50", scale: "-=0.5", overwrite: true }, "<" ) .to( "#dark-planet-container", { x: "+=200", y: "+=25", scale: "-=0.1", overwrite: true }, "<" ) .to( "#turquoise-planet-container", { x: "+=200", y: "-=75", scale: "-=0.5", overwrite: true, }, "<" ) .to( "#red-planet-container", { x: "+=400", y: "+=50", overwrite: true }, "<" ) .to( "#darkBlue-planet-container", { x: "+=400", y: "+=50", overwrite: true }, "<" ) .to( "#ringed-planet-container", { x: "+=450", scale: "-=0.2", overwrite: true }, "<" ) // <-- Ending of system rearrange // Discover text moves away with system .to( ".discover-text", { rotate: -25, x: "+=450", scale: "-=0.6", opacity: "-=1" }, "<" ) // Curiosity header text slides in .fromTo( ".curiosity-header-text", { x: -700, }, { x: 0 }, "<" ) // Curiosity paragraph 1 text slides in .fromTo( ".curiosity-paragraph1-text", { x: -700, }, { x: 0 }, ">-70%" ) // Curiosity paragraph 2 text slides in .fromTo( ".curiosity-paragraph2-text", { x: -700, }, { x: 0 }, ">-70%" ) // Beginning of system rearrange --> .to( "#lightBlue-planet-container", { x: "-=500", y: "+=500", scale: "+=15", overwrite: true, }, ">200%" ) .to( "#turquoise-planet-container", { x: "-=825", y: "+=30", scale: "+=1.5", overwrite: true, }, "<" ) .to( "#ringed-planet-container", { y: "-=50", x: "-=50", scale: "+=1", overwrite: true, }, "<" ) .to( "#red-planet-container", { x: "-=1500", opacity: "-=1", overwrite: true, }, "<" ) .to( "#darkBlue-planet-container", { x: "-=1500", opacity: "-=1", overwrite: true, }, "<" ) .to( "#dark-planet-container", { x: "-=900", y: "-=150", scale: "+=0.5", overwrite: true, }, "<" ) .to( "#moon-container", { y: "-=0", x: "-=200", scale: "+=0.5", overwrite: true, }, "<" ) .to( "#galaxy-swirl-container", { x: "-=1500", opacity: "-=1", scale: "+=10", overwrite: true, }, "<" ) .to( "#sun-container", { opacity: "-=1", x: "-=1500", y: "-=200", scale: "+=2", overwrite: true, }, "<" ) // <-- Ending of system rearrange // Curiosity header text moves off screen .to( ".curiosity-header-text", { x: "-=700", }, "<" ) // Curiosity paragraph 1 text moves off screen .to( ".curiosity-paragraph1-text", { x: "-=700", }, "<" ) // Curiosity paragraph 2 text moves off screen .to( ".curiosity-paragraph2-text", { x: "-=700", }, "<" ) // Phase 1 text moves off screen .to( ".phase1-text", { x: "-=1000", }, "<" ) // Discuss text fades up and in .fromTo( ".discuss-text", { autoAlpha: 0, scale: 0, y: 500, }, { autoAlpha: 1, scale: 2.5, y: 0, }, ">-50%" ) // Phase 2 texts slides on screen .fromTo( ".phase2-text", { x: -1700, }, { x: -800, }, "<" ); };
  25. I've been tinkering with it a bit, but I don't want to judge wether this is a bug or not. One thing I found is that if you do not set box-sizing: border-box inline (as in 1.: deactivate it via dev-tools or 2.: alternatively overwrite/clear it in a refresh callback and refresh the smoother instance) on the pin-spacer of the first ScrollTrigger it appears to work as intended by @thei. Maybe this can serve as a workaround for now and if this atually is a bug, help find the root of the problem. Works for me in both, the OPs codepen and @Cassie simplified demo. https://codepen.io/akapowl/pen/rNvJXbd https://codepen.io/akapowl/pen/xxjWxRV