Jump to content
GreenSock

Search the Community

Showing results for 'overwrite'.

  • 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

  • Learning Center
  • Blog

Categories

  • Products
  • Plugins

Categories

  • Examples
  • Showcase

Categories

  • FAQ

Categories

  • ScrollTrigger Demos

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. I'd probably add a small delay on the "reset" tween and set overwrite to true. Something like this: https://codepen.io/PointC/pen/ZEMjdLj/364a470e414172b8fbd6a7420de056f6 More info about overwrite. Happy tweening.
  2. Hmm.. So I tried the Attribute Plugin using this code, but it doesn't work with my SVG. Actually it doesn't seem to work with the basic div's either. let elements = document.querySelectorAll('.button'); let clickEvent = (e) => { console.log('some event content here...') console.log("----------------" + e.target.id + "----------------------") } elements.forEach((item) => { item.addEventListener("mouseenter", ()=>{ gsap.to(item, {attr: {fill: "#F2653A"}, duration: 1, overwrite: "auto" }); }); item.addEventListener("mouseout", ()=>{ gsap.to(item, {attr: {fill: "red"} ,duration: 1, overwrite: "auto" }); }); item.addEventListener('click', clickEvent) }); });
  3. Hmm.. So I tried the Attribute Plugin using this code, but it doesn't work with my SVG. let elements = document.querySelectorAll('.button'); let clickEvent = (e) => { console.log('some event content here...') console.log("----------------" + e.target.id + "----------------------") } elements.forEach((item) => { item.addEventListener("mouseenter", ()=>{ gsap.to(item, {attr: {fill: "#F2653A"}, duration: 1, overwrite: "auto" }); }); item.addEventListener("mouseout", ()=>{ gsap.to(item, {attr: {fill: "red"} ,duration: 1, overwrite: "auto" }); }); item.addEventListener('click', clickEvent) }); });
  4. 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.
  5. Hi, I'm in this situation and I don't know how to manage the fact that MotionPath animation takes control on the translateX property when reversing the scroll ( go to the very end of the scroll animation, then reverse scrolling back, you will see the circles going to the straight right instead of doing the bending curve as they did in forward mode ). `overwrite:auto` does not seem to help, and `overwrite:true` breaks the animation. TIA.
  6. 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, }, "<" ); };
  7. Hi @Roman S. is you're issue that your elements are not obeying the width you've set? That is because flexbox is trying to 'help', flexbox will automatically distribute the elements over the width you've given it. You can overwrite that using the flex-grow, flex-shrink and flex-basis property or the short hand flex: 0 0 "your width". You're right that this is a CSS issue and we like to focus these forums to just GSAP related questions. Still hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/GRXOvgo?editors=0110
  8. Nice job, @Toso πŸ‘ Minor tweaks: https://codepen.io/GreenSock/pen/KKxXjvW?editors=0010 I'd use backgroundColor rather than background, and I'd set the overwrite to either true or "auto" just in case the user rolls over/out quickly, you don't want to create conflicting animations.
  9. Hi guys! I come humbly in front of you with few drops of hope left, after 5 full days of switching between possible solutions to get a consistent ScrollTrigger behavior on a Gatsby site. Getting directly to you is my last resort, as every google and gsap forum link regarding ScrollTrigger and Gatsby is already visited. πŸ˜’ I cannot get a CodePen reproducing the exact issue so I'll try my best to describe it here. Shortly, the problem seems to be, as I suspect, that the ScrollTrigger does not refresh itself when Javascript pops into the browser on top of the SSR-ed html/css bundle. Here's what i did. I created several projects with different versions for dependencies, but i will stick to the simplest one with all dependencies up to date.It's a gatsby with material-ui plugin added, who's exact structure can be found here: https://github.com/mui-org/material-ui/tree/master/examples/gatsby There are no other plugins added, nor any other configs/plugins changed. I rendered the component that will contain the ScrollTrigger (AboutBlock) in the AboutPage page: about.js const AboutPage = () => { return ( <AboutBlock /> ) } export default AboutPage This is the component where i try to animate some elements on reveal when scrolled into view: aboutBlock.js import gsap from "gsap"; import ScrollTrigger from 'gsap/ScrollTrigger'; import animateReveal from "./gs_reveal"; export default function AboutBlock() { gsap.registerPlugin(ScrollTrigger) const revealRefs = useRef([]) revealRefs.current = [] useLayoutEffect(() => { let scrollTriggers = [] scrollTriggers = animateReveal(revealRefs.current) return () => { scrollTriggers.forEach(t => t.kill(true)) } }, []); const addToRevealRefs = el => { if (el && !revealRefs.current.includes(el)) { revealRefs.current.push(el); } }; return ( <Grid container> <Grid item width={{ xs: '100%', sm: '80%', md: '35%' }} pl={{ xs: 0, md: '2.5%' }} mt={{ xs: 60, sm: 0 }}> <Grid container direction="column" alignItems={{ xs: "flex-start", sm: "flex-end" }}> <Grid item mt={{ xs: 0, md: '10vh' }} id="acum"> <Typography variant="h5" textAlign={{ xs: "left", sm: "right" }} ref={addToRevealRefs} className='gs_reveal_fromRight'> NOW WE ARE IN </Typography> </Grid> <Grid item> <Typography variant="h6" textAlign={{ xs: "left", sm: "right" }} ref={addToRevealRefs} className='gs_reveal_fromRight'> LOCATION </Typography> </Grid> <Grid item mt="10vh" id="hi"> <Typography variant="h5" textAlign={{ xs: "left", sm: "right" }} ref={addToRevealRefs} className='gs_reveal_fromRight'> SAY HI </Typography> </Grid> <Grid item className='toughts'> <Typography variant="h6" textAlign={{ xs: "left", sm: "right" }} ref={addToRevealRefs} className='gs_reveal_fromRight'> TELL US YOUR THOUGHTS </Typography> </Grid> </Grid> </Grid> </Grid> } HTML is longer and crowded, I left a part to get the idea of the structure and styling approach (MUI's sx - emotion). And finally, this is the animateReveal function: gs_reveal.js import ScrollTrigger from 'gsap/ScrollTrigger'; import gsap from 'gsap'; export default function animateReveal(elements) { const triggers = [] elements.forEach(function (elem) { hide(elem) let tr = ScrollTrigger.create({ trigger: elem, id: elem.id, end: 'bottom top', markers: true, onEnter: function () { animateFrom(elem) }, onEnterBack: function () { animateFrom(elem, -1) }, onLeave: function () { hide(elem) } }); triggers.push(tr) }); return triggers; } function animateFrom(elem, direction) { direction = direction || 1; let x = 0, y = direction * 100; if (elem.classList.contains("gs_reveal_fromLeft")) { x = -100; y = 0; } else if (elem.classList.contains("gs_reveal_fromRight")) { x = 100; y = 0; } else if (elem.classList.contains("gs_reveal_fromBelow")) { y = -100 } elem.style.transform = "translate(" + x + "px, " + y + "px)"; elem.style.opacity = "0"; gsap.fromTo(elem, { x: x, y: y, autoAlpha: 0 }, { duration: 1.25, x: 0, y: 0, autoAlpha: 1, ease: "expo", overwrite: "auto", delay: elem.classList.contains("gs_delay") ? 0.3 : 0, }); } function hide(elem) { gsap.set(elem, { autoAlpha: 0 }); } The ScrollTrigger markers are misplaced when page loads, and might move (get more misplaced) on hard reloading page, depending on the current scroll position in the moment of reloading, even though the scroll position is not preserved on reload (always is scrolled on top). - The markers are placed on the correct position on resizing, as expected. I followed gsap official docs on react and react-advanced and tried: grabbing the html elements to animate on scroll inside animateReveal() by let elements = gsap.utils.toArray(".gs_reveal"); Assigning to each element a useRef() and use the .current value for each in animateReveal() grabbing html elements using gsap's selector utility gsap.utils.selector changing to simpler animation on scroll, like just a fade refreshing ScrollTrigger in different moments useLayoutEffect(() => { ScrollTrigger.refresh(true) // or ScrollTrigger.refresh() ... }, []); 6. Lifting ScrollTrigger logic to parent about.js page 7. Assigning scrollTrigger to a timeline triggered by the to-be-reveal element 8. Use useEffect() instead of useLayoutEffect() (recommended anyway for ScrollTrigger) 7. Other who-knows-what unsuccessful twists. I suspected a rehydration error, when the static generated code does not match the client side one. But the only JS that could cause a mismatch is the gsap related one, and it does not seem an SSR issue. I checked if the CSS and HTML elements are being properly SSR-ed, by preventing JS from running in the browser. All looking fine. This is both a SSR issue (gatsby build) and a development issue (no SSR). As i said on point 5, setting a ScrollTrigger.refresh() when component is mounted does not work, but delaying this with a 1-2 seconds in a setTimeout successfully solves the issue useLayoutEffect(() => { setTimeout(() => { ScrollTrigger.refresh(true) }, 2000); }, []); This is hard to be accepted as a solution, since i cannot rely on a fixed value to 'guess' when DOM is properly rendered in the eyes of the ScrollTrigger, not to mention the glitches that might occur. So, the question is 'WHY?', why animating with ScrollTrigger from within useLayoutEffect, which is not triggered on the server anyway and should mark the 'component is successfully mounted' moment, seems to not wait for the DOM being completely painted, even though nothing is generated dynamically! There are quite of threads on this forum regarding gatsby, and none seemed to have a clear cause-outcome-solution. Is this battle lost, should i move on? Do you have any suggestions? Thanks so much for your time reading this, it means so much to me!
  10. Yes you can! Like you do with CSS you can call all your elements at once and then use a stagger (see Stagger docs) to have them animate in one by one. Then when using a smart position parameter we can start the next animation right after the first one is done! Also you can target all transform properties directly with GSAP x, y, rotate, skew, scale ect and if you want to use percentage based values use xPercent and yPercent. I would also recommend keeping all he animation values to GSAP instead of setting something with in CSS that you then need to overwrite with GSAP, that is where .from() is really handy. I've sprinkled a lot of useful comments throughout your pen to explain certain parts, be sure to read through them! Hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/GRXmQqV?editors=0100 Oh and a side note! When working with ScrollTrigger I like to disable it, to really focus on just the animation I find it a lot easier. I've also added a repeat: -1, so be sure to remove those when you're going to enable ScrollTrigger again.
  11. Hello, i have tried the official codepen demo with the horizontalLoop: https://codepen.io/GreenSock/pen/gOvvJee Thanks for this awesome slider. But I run in some troubles with the dragging. I could fix some problems by myself but with 1 problem i have my troubles Scenario: - Open the page and drag much, so the slider its moving. - When it comes nearly to the end (but it has not stopped yet) please press the active button with the white boarders. - It now jumps a lot. Do you know why? Thanks a lot! Other bugs i could solve (but its ugly 😞 Scenario 1: - Open the page and drag just some pixels on the active button (Button number3) and release the mouse. - Then click a few times on the button 3. - Now it jumps some boxes. I tried to fix it in the "toIndex" function before line 150. It works better. vars.overwrite = true; if (index === curIndex) { return; } curIndex = newIndex; gsap.killTweensOf(proxy); return tl.tweenTo(time, vars); Scenario 2: - Drag a lot, so that the slider is moving. - While the slider is moving please press the "wrapper" (the grey lines above or below the boxes) - Now it jumps a loooot. I fixed this with adding a new var isNowDragging (true when the user drags) and change line 182. Seems to work now. if (!isNowDragging) {gsap.set(proxy, {x: startProgress / -ratio});} Thanks a lot for your help.
  12. Hello all, So in this codepen example I use Flip.from to get items into grid slots, and then on another flip to get them back in old parent, but also to transform each item to value I set with gsap.set. This works too, but on 3rd click, when I want to animate items again into grid, the gsap.set doesnt set xPercent value back to 0. I also tried overwrite: true but it didnt work. Is there something Im missing? Thanks
  13. Hi, I've been fiddling with your codepen example for a bit and this seems to do the trick: ScrollTrigger.create({ trigger: ".images", start: "center top", markers: true, onEnter: self => { let state = Flip.getState(images); images.forEach((image, i) => slots[i].appendChild(image)); gsap.set(images, {xPercent: 0, rotation: 0}); Flip.from(state, { duration: 6, overwrite: true, // <- HERE ease: "power1.inOut" }) } }) Since the first ScrollTrigger instance you're creating for the images has once: true, it doesn't really matter if the Flip animation overwrites those. In the tests that I've ran seems to work as expected: https://codepen.io/GreenSock/pen/ZEMeBKR Hopefully this helps. Let us know if you have more questions. Happy Tweening!
  14. That's because you created conflicting animations - you've got your motionPath animation first in the timeline that controls the x/y position, and then you ALSO have another one that's affecting x to go in a completely different direction. So they're both fighting for control. If you do overwrite: "auto" (or true), all that does is basically KILL the overwritten part (so of course you won't see it affecting things after that point at all). You definitely should not be creating conflicting animations like that. The reason it looks different when scrolling forwards vs backwards is because the rendering order inverts in reverse. In other words, when moving the playhead forward, the LATER tween would render last whereas when moving the playhead backwards, the EARLIER tween would render last. That's exactly how it's supposed to work. Possible solutions: Don't overlap the animations. https://codepen.io/GreenSock/pen/dyqNQRR?editors=1010 Use a different (invisible) motionPath that has the shape you want. Basically copy the path you have now, but add that extra part at the top that's curved in the way you want your objects to travel. You can still leave the red stroked path as-is. Everything would look the same visually, but you'd just use one motionPath tween where the path actually has the shape you're going for. You technically could write a bunch of extra JavaScript to force things to render in a particular order no matter which direction the playhead travels, but honestly that seems quite hacky and unintuitive to me. It is doable, though. If you need help with that, we're available for paid custom consulting - just reach out directly to explore those options. I hope that helps!
  15. Hi @Haribo, Yeah I see the issue. It seems that adding overwrite into the onLeave an onLeaveBack scroll tweens seems to fix the problem: onLeave: () => { if (i !== panels.length - 1) { let nextPanelId = `panel-${i + 1}`; gsap.to(window, { overwrite: true, scrollTo: { y: ScrollTrigger.getById(nextPanelId).start + 1, autoKill: false }, }); } }, onLeaveBack: () => { if (i) { let prevPanelId = `panel-${i - 1}`; gsap.to(window, { overwrite: true, scrollTo: { y: ScrollTrigger.getById(prevPanelId).end - 1, }, }); } }, From the DOCS (https://greensock.com/docs/v3/GSAP/Tween/vars) : overwrite 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. Hopefully this helps. Let us know if you have more questions. Happy Tweening!
  16. It looks like you just had your toggleActions wrong: // BAD toggleActions: "play none reverse none" // GOOD toggleActions: "play none none reverse" And this is not a valid start value: // invalid start: "-=200top top" I'm not sure if you meant "top top" or "200 top" or something else. But actually, if I were building this I'd approach it in a very different way: Put the color/backgroundColor into a data-color attribute on any element that I want to have this effect (a space-delimited value like "blue white") Grab all the elements that have that data-color attribute, loop through them and create a ScrollTrigger for each. When it activates, create a new tween that animates to its colors. Here's a demo with my strategy implemented: https://codepen.io/GreenSock/pen/OJoROgY?editors=0010 Benefits: You can easily add as many sections as you want - just slap a data-color value on it in the markup and BOOM, it works. It works more smoothly if you scroll very quickly. With your previous strategy, you had one animation for each section, and you were calling play()/reverse() on them when necessary...but they were controlling the same properties of the same object. Imagine a scenario where the user scrolls quickly, so one animation starts and is midway through when the other animation gets triggered. Now you've got two animations fighting for control of the same properties. Plus you may see a jump because let's just say (to make it simpler) we're animating a number from 0 to 100 in the first one, and 100 to 200 in the second animation. If the first animation is at 50 when the second one starts playing, you'd see it jump from 50 to 100 instantly (and go to 200). With my strategy above, a new tween gets created each time so that it's just taking the value from whatever it currently is to the new value. So everything is perfectly smooth every time. No fighting for control (it has overwrite: "auto"), no overlapping. I hope that helps.
  17. Hi, i'm not exactly sure what effect you are going for. FWIW it seems a bit disorienting to move something down to a y:200 while scrolling up. That aside I would avoid creating 2 timelines initially time that control the same properties of the same thing. To avoid conflicts I would suggest creating these animations fresh when you need them inside your callbacks sort of like: ScrollTrigger.create({ trigger: ".top-page", start: "top-=100 top", end: "top+=200 top", markers: true, onEnter: () => {let tl1 = gsap.timeline({}) .fromTo("header", { y: 0, overwrite: 'auto' },{ duration: 2, y: 200, ease: CustomEase.create("custom", "0.5, 0, 0, 1"), overwrite: 'auto' })}, onLeaveBack: () => {let tl2 = gsap.timeline({}) .to("header", { scale: 1.2, y: 200, }) .set("header", {y: 200,scale: 1,},"hide") .to("header", {opacity:1},"start2") .to(("header"), { y: 0, duration: 1, ease: "power4.out" }, "start2")} }); I would also remove locomotive scroll until you know things are working fine without it. Hopefully this set up will allow you to remove some of redundancy between the 2 animations like tweening and setting y:200 multiple times. If you need more help please try to simplify the animations as much as possible in a fork of the original pen.
  18. I saw a few problems: You're setting the width/height in the same gsap.set() call as the transformOrigin, and in this very rare edge case that's actually a problem because it just so happens that in the for...in loop through the properties, transformOrigin happens BEFORE the width/height. So when it tries to calculate the percentage-based origin offsets, your <rect> literally has no width or height at all, thus it gets positioned in its upper left corner. The solution: set the width/height FIRST. You could just separate those out into their own gsap.set() that you put first. You're creating conflicting animations. If you click again before the first set of animations completely finishes their 4 repeats, you'll be creating new ones that are also fighting with the old ones for control of the same elements. Make sure you kill() the old animations before you create new ones. Or you can just leverage the overwrite feature (overwrite: true here). Just so you know, the smoothOrigin does absolutely nothing in this line: gsap.timeline({ smoothOrigin: true, yoyo: false, repeat: 4 }); Timelines don't have a property like that. Maybe you intended to pass that down as a default for all child tweens?: gsap.timeline({ defaults: {smoothOrigin: true}, yoyo: false, repeat: 4 }); https://codepen.io/GreenSock/pen/NWBaLOd?editors=0010 Does that clear things up?
  19. Hi @aileen-r and welcome to the GreenSock forums! The reason for the different speed is beacuse you're setting the timescale of each animation on the mouse leave event to be 2 and is never reset to 1, that's why is faster after the first mouse over event. If you want to keep the same speed on both events just remove that and make the duration of the animation half the current time: reactions.forEach(reaction => { const action = gsap.to( reaction, { scale: 1.2, margin: '0 30px 0 20px', duration: 0.25, ease: 'power2.inOut', overwrite: 'true', paused: true } ); reaction.addEventListener("mouseenter", function() { action.play(0); }); reaction.addEventListener("mouseleave", function() { action.reverse(); }); }); Now if you still want the leave animation to be faster, then keep the timescale setter on the mouse leave, but add one to the mouse enter as well: reactions.forEach(reaction => { const action = gsap.to( reaction, { scale: 1.2, margin: '0 30px 0 20px', duration: 0.25, ease: 'power2.inOut', overwrite: 'true', paused: true } ); reaction.addEventListener("mouseenter", function() { action.timeScale(1).play(0); }); reaction.addEventListener("mouseleave", function() { action.timeScale(2).reverse(); }); }); You can learn more about timeScale here: https://greensock.com/docs/v3/GSAP/Tween/timeScale() Finally if you want to prevent the bounce effect in the reactions container, that's a bit more tricky since you need to get the current active element check in the array, see if there are elements before and move all those a specific amount of pixels and do the same for the elements after the active one. Finally when leaving the reactions container tween all the reactions back to their original x position. Avoid using margins for this if you can for that scenario. But I must say as a user I would be totally fine with the way things are, just speed up the animation and keep the timescale, no need to change it IMHO. Hopefully this helps. Let us know if you have more questions. Happy Tweening!
  20. Hi, Maybe you should take a look at ScrollTrigger's batch method: https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.batch() Here is a live example: https://codepen.io/GreenSock/pen/NWGPxGZ In the case of your last codepen example it would be as simple as this: gsap.registerPlugin(ScrollTrigger); gsap.set(".grid-i", {y: 50, opacity: 0}); ScrollTrigger.batch(".grid-i", { onEnter: batch => gsap.to(batch, {opacity: 1, y: 0, stagger: 0.15, overwrite: true}), }); Hopefully this helps. Let us know if you have more questions. Happy Tweening!
  21. @GreenSock How do I use this but with a scrolltrigger? I need to animate items per row, but it seems that when I use the row as a trigger it doesn't work. This is what I added to it: ``` rows.forEach((GridItems) => { let tl = gsap.from(GridItems, {opacity: 0, yPercent: 80, stagger: 0.05, duration: 0.7, overwrite: true}); ScrollTrigger.create({ trigger: GridItems, start: 'top 70%', end: 'bottom bottom', markers: true, onEnter: () => tl.play(), onEnterBack: () => tl.restart(), onLeaveBack: () => tl.pause(0), }); });
  22. Hi everyones I got stuck at the rotation so my question is how can i Overwrite the rotation ? ?? please go to the Codepen dont know only show the mobile version ... thanks for your time !
  23. 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!
  24. 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!
  25. 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!
Γ—