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. The scrub value is just the duration of that tween, so put in whatever value you want. gsap.to(tl, { progress: 1 - self.progress, ease: "power3", overwrite: true, duration: 0.25 });
  2. Hey, I'm new to GSAP and absolutely loving it! I'm currently working on my first commercial Gatsby React site and while experimenting with the useLayoutEffect hook I came across an issue. managed to rectify it and now I was just wondering if I could get a little context. When I started setting up my animations I was nesting each animation into a separate useLayoutEffect hook like so: const h2Ref = useRef(null); const contentRef = useRef(null); useLayoutEffect(() => { const el = h2Ref.current; gsap.set(el, { y: -30, opacity: 0 }); gsap.to(el, { y:0, opacity:1, delay:.25 }); gsap.to(el, { y: -50, opacity: 0, immediateRender: false, overwrite: 'auto', scrollTrigger: { trigger: el, start: "top+=100px center", scrub: .5, } }); }, []) useLayoutEffect(() => { const el2 = contentRef.current; gsap.set(el2, { y: -30, opacity: 0 }); gsap.to(el2, { y:0, opacity:1, delay:.25 }); gsap.to(el2, { y: -30, opacity: 0, immediateRender: false, overwrite: 'auto', scrollTrigger: { trigger: el2, start: "top+=100px center", scrub: .5, } }); }, []) Everything works fine just like this. As an experiment, I had a shift around and dropped several animations into a single useLayoutEffect hook to see if I could clean up my code a little bit. Like this: const h2Ref = useRef(null); const contentRef = useRef(null); useLayoutEffect(() => { const el = h2Ref.current; gsap.set(el, { y: -30, opacity: 0 }); gsap.to(el, { y:0, opacity:1, delay:.25 }); gsap.to(el, { y: -50, opacity: 0, immediateRender: false, overwrite: 'auto', scrollTrigger: { trigger: el, start: "top+=100px center", scrub: .5, } }); const el2 = contentRef.current; gsap.set(el2, { y: -30, opacity: 0 }); gsap.to(el2, { y:0, opacity:1, delay:.25 }); gsap.to(el2, { y: -30, opacity: 0, immediateRender: false, overwrite: 'auto', scrollTrigger: { trigger: el2, start: "top+=100px center", scrub: .5, } }); }, []) When I did that, I was ending up with masses of white space appearing at the bottom of the page whenever I changed to a new route. So really my question is more out of curiosity, why did this happen? Is this something to do with how hooks work or how GSAP works? Just hoping to get a little enlightened Many thanks, and thanks for such an awesome animation tool!
  3. You can't animate "x" and "y" properties on every element to multiple places at the same time You could, however, wrap each element in another <div> and have the pointer parallax animate that one, and the motionPath can animate the child. The way you're handling the parallax pointermove thing is extremely inefficient. On every pointermove event (which can fire over 60 times per second) you're creating a whole new tween for every single element, and you're also calling .getBoundingClientRect() twice. Since you didn't set overwrite: true or overwrite: "auto", it also means you're creating a bunch of conflicting tweens that are fighting with each other for control of the same properties of the same targets. You're also getting the offsetTop and offsetLeft on every element on every pointermove event too which is expensive. You're needlessly duplicating the calculation of speed too (speedX and speedY are identical). You could pre-calculate a lot of the values, store them in a data object along with a tween for each element that you then invalidate() and restart() after updating the x/y destination values, sorta like this: const data = elements.map(el => { return { left: el.offsetLeft, top: el.offsetTop, speed: 100 - el.dataset.size, tween: gsap.to(el, {x: "+=0", y: "+=0", ease: "expo", duration: 2, paused: true}) }; }); const onMouseMove = (event) => { let bounds = wrapper.getBoundingClientRect(), pageX = event.pageX - bounds.width * 0.5, pageY = event.pageY - bounds.height * 0.5; data.forEach(d => { d.tween.vars.x = -((d.left + pageX * d.speed) * 0.005) / 2; d.tween.vars.y = -(d.top + pageY * d.speed) * 0.005; d.tween.invalidate().restart(); }); }; The upcoming release is going to have a very cool feature that'll make this even easier and faster, so stay tuned for that Side note: GSAP has a gsap.utils.random() method that you can tap into instead of making your own. I'm not even sure you need to use MotionPathPlugin - are you just trying to make it go in a circular path? If so, there may be easier algorithms. Like put it in a wrapper <div>, offset the transformOrigin and then rotate it while rotating the inner element in the opposite direction. Just an idea. Have fun!
  4. I don't have much time to dig into this but from a quick glance... You're likely creating a bunch of overlapping/conflicting tweens because you're trying to animate the exact same property of the same object every time you enter or leave a section. So imagine when you go from a red section to an orange section...you leave the red AND enter the orange at the same time, thus it's trying to animate to red AND orange simultaneously. That's a logic issue in your code. You've gotta choose one or the other. My guess is you only need it to happen onEnter and onEnterBack. I'd recommend setting overwrite: true or "auto" on your tweens to prevent conflicts. With the helper function that's doing the smooth scrolling, you can't have the sub-ScrollTriggers also have a scrubbed value other than true due to order-of-operation challenges with the current version. Watch for the next release for some exciting news. https://codepen.io/GreenSock/pen/popoPoN?editors=0010
  5. Are you maybe looking for pinspacing:false Also - If you wanted to go with this type of a solution you'd need to tweak the calculation of the marker placement to be based around the slide container itself rather than the window. Something vaguely like this? This is just a guess so apologies if it doesn't work, I figure most things out by trial and error. But basically you'll want to be adding a little more offset to the start marker on each one. let slides = gsap.utils.toArray(".slide"); slides.forEach((slide, i) => { if (i) { // skip the first one. console.log('maybe?', myslides.offsetWidth / (slides.length - 0) * i) ScrollTrigger.create({ trigger: myslides, markers: true, start: () => `top+=${myslides.offsetWidth / (slides.length - 0) * i} top`, end: "+=1", onEnter: self => gsap.to(".slide", {x: (-100 * i) + "vw", ease: "none", overwrite: true}), onLeaveBack: self => gsap.to(".slide", {x: (-100 * (i - 1)) + "vw", ease: "none", overwrite: true}) }) } });
  6. Hi Cassie, thank you so much for responding. i think what needs to happen it's basically putting each slide in a scrolltrigger and giving it a pin (stays on screen for a second before releasing to the next slide) effect. right now the continuous scroll of the horizontal slider doesnt feel very good. and snapping doesnt either. But i found a post buried here, that i can no longer find that had a solution that was exactly what i needed. and it's the below code. my only problem is i couldnt figure out how to integrate into my page flow like you see in my codepen. because the below code acts as if the horizontal slider is the only main element on the page. let slides = gsap.utils.toArray(".slide"); slides.forEach((slide, i) => { if (i) { // skip the first one. ScrollTrigger.create({ start: () => ScrollTrigger.maxScroll(window) / (slides.length - 0) * i, end: "+=1", onEnter: self => gsap.to(".slide", {x: (-100 * i) + "vw", ease: "none", overwrite: true}), onLeaveBack: self => gsap.to(".slide", {x: (-100 * (i - 1)) + "vw", ease: "none", overwrite: true}) }) } });
  7. Good afternoon, i have a very long page that utilizes scrolltriggers in several modules. one of the modules on my pages has a horizontal scroll with a few slides and within each slide is an animation. everything works pretty well except we have found during beta testing that the user can scroll and very quickly through and past the horizontal "slider" into the regular vertical page. overall the horizontal portion doesnt "feel" great and breaks the user experience. we've tried doing "snap" points- but they snapped in odd ways that didnt feel natural. i've googled this, searched the forums, tried on my own but nothing is working or is overly complex to the point of getting overwhelmed at the complexity of some of these other "snap" solutions. what im wondering is is there a way to add a bit of a "click" feel as each slide finishes. or some sort of anticipation and "pause" after each slide so the user doesnt whip trough the horizontal scroll? i''d be very thankful for any assistance i can get on this, as it's become quite frustrating. const tl2 = gsap.timeline({ scrollTrigger: { trigger: '.module_3_wrapper', start: "center center", end: "center center", pin: '.module_3_wrapper', scrub: 1, pinSpacing: true, } }); let container = document.querySelector('.module_3'); let sections = gsap.utils.toArray(".module_3 .slides"); let scrollTween = gsap.to(sections, { x: () => -(container.scrollWidth - document.querySelector('.module_3_wrapper').clientWidth) + "px", ease: "none", duration: .1, scrollTrigger: { trigger: ".module_3_wrapper", pin: true, start: "center center", scrub: true, invalidateOnRefresh: true, end: `+=${container.offsetWidth}`, } }); I found someone did something like this with a nest scrolltrigger, but i can't figure out how to merge what i have and what this does. but it has the exact effect im looking for. where it nicely locks between slides. let slides = gsap.utils.toArray(".slide"); slides.forEach((slide, i) => { if (i) { // skip the first one. ScrollTrigger.create({ start: () => ScrollTrigger.maxScroll(window) / (slides.length - 0) * i, end: "+=1", onEnter: self => gsap.to(".slide", {x: (-100 * i) + "vw", ease: "none", overwrite: true}), onLeaveBack: self => gsap.to(".slide", {x: (-100 * (i - 1)) + "vw", ease: "none", overwrite: true}) }) } });
  8. Yes, it's generally not a good idea to reuse an animation that might be competing with another animation. The left timeline doesn't know you are changing stuff in the right timeline. Also, I'm not sure what these from statements are for. .from(logoRef.current, { transform: "none" }, "<") It's best to always use GSAP transform properties like x, y, scale, etc instead of transform. If you need to remove one, you can just use a set. .set(logoRef.current, { scale: 1 }, "<") I would suggest reworking your animation into a single animation, kind of like this. A Pen by GreenSock (codepen.io) If some of the stuff isn't easy to control inside a single timeline, you can also make a timeline that does the progress and whatever else you want. gsap.timeline() .to(animation, { overwrite: true, progress: 0.5 }) .to(myLogo, { ... }, 0) Outside of that, the best way to handle competing animations is to just not use them and create your animations on the fly, like in the mouseenter/mouseleave events.
  9. See if this gets you going in the right direction. I just used standalone ScrollTrigger to toggle the nav items. The back ease looks a little bit weird in reverse, so if you wanted a different ease when hiding the items, you should just create a new animation in that if/else. if (self.isActive) { gsap.to(boxes, { overwrite: true, ease: "back.out", // or whatever exit ease you want y: -64, opacity: 0, stagger: { amount: 0.25 } }); } else { gsap.to(boxes, { overwrite: true, ease: "back.out", y: 0, opacity: 1, stagger: { amount: 0.25 } }); } Multiple GSAP Animations in React (codepen.io)
  10. GreenSock

    Unregister Effect

    You don't have to unregister - if you want to replace one, you can just registerEffect() a new effect with the same name and it'll overwrite the previous one.
  11. Hello guys, I am in need of some dire help. I am trying to implement a scrolltrigger effect with snapping exactly like the GSAP codepen demo here, but in React / Next JS. I been working on it for days trying to implement on a website. I also created a mini codesandbox demo with the effect, but as you see, the behavior snapping and scroll is not the same. I was wondering if I could get some assistance. Sandbox link: https://codesandbox.io/s/festive-babycat-b8lh74?file=/pages/_app.js useEffect(() => { let panels = gsap.utils.toArray(".panel"); let scrollTween; function scrollTo(arg) { return { y: arg * innerHeight, autoKill: false }; } function goToSection(i) { scrollTween = gsap.to(window, { scrollTo: () => { scrollTo(i); console.log(i); }, duration: 1, onComplete: () => (scrollTween = null), overwrite: true }); } panels.forEach((panel, i) => { ScrollTrigger.create({ trigger: panel, start: "top bottom", markers: true, onToggle: (self) => self.isActive && !scrollTween && goToSection(i) }); ScrollTrigger.create({ start: 0, end: "max", snap: 1 / (panels.length - 1) }); }); }, []);
  12. I don't quite understand your question here - can you please be more specific? I didn't see anything jerky. You should definitely switch to the more modern GSAP 3 syntax: // OLD TweenMax.to(".bar", 0, {width: "-=3%"}); // NEW gsap.set(".bar", {width: "-=3%"}); If you want to animate things instead of suddenly setting them, you could use a small duration on a gsap.to() call, and make sure to set overwrite: true so that you're not creating conflicting tweens. If you're setting the same value over and over again, you might want to look into using gsap.quickSetter() for performance reasons.
  13. I didn't totally follow your explanation there, @mjray, but my guess is that you were creating conflicting tweens. Did you try simply setting overwrite: true or overwrite: "auto" on your animation? Also, did you know about this method?: https://greensock.com/docs/v3/Plugins/ScrollTrigger/labelToScroll() It's relatively new.
  14. I'm having a very difficult time understanding what you mean. It looks like that ScrollTrigger doesn't have any animation associated with it, so when you self.scroll(...) it won't have an effect on any animation. Did you intend to link an animation to that ScrollTrigger? Currently it's pointless to have toggleActions or scrub (those are mutually exclusive, by the way) on that ScrollTrigger because those only apply if an animation is attached to the ScrollTrigger. It actually looks like you're trying to manually apply a scrub: 0.5 to the "tl" animation in the onUpdate. Why not simply assign that to the ScrollTrigger itself? That'll perform better anyway. You should definitely set overwrite: true if you're gonna keep that manual tween in there. If you still need some help, please provide a minimal demo that clearly illustrates the problem and we'd be happy to answer any GSAP-specific questions.
  15. Welcome to the forums, @Sooova. Would you please provide just a minimal demo that more clearly demonstrates the issue? I'm pretty lost when I look at that demo, especially with all the missing images. You can just use simple colored <div> elements instead maybe. It shouldn't take 100+ lines of code to show the issue. There are a lot of setTimeouts/Promises and delays and stacked up strings of logic - perhaps you could just eliminate any randomization, isolate a single state change of one or two elements, and only focus on that in your demo(?) And please keep in mind that these forums aren't really for general troubleshooting of logic issues, but we're happy to answer any GSAP/Flip questions. A few quick comments: I assume this was a mistake: // BAD onComplete: isComplete(), // <- executes immediately and assigns whatever isComplete returns to the onComplete. // GOOD onComplete: isComplete, And this: // BAD overwrite: "false", // GOOD overwrite: false, You can use gsap.utils.random() instead of your getRandomInt() function.
  16. Hi guys, So, I've done an Horizontal Scroll on Elementor but I'm getting really frustrated with horizontal scroll (anchors) because nothing really works.. Can you please advise what I'm doing wrong? This is the Elementor site. I've tried the bellow code: <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollTrigger.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollToPlugin.min.js"></script> <script>gsap.registerPlugin(ScrollTrigger); let sections = gsap.utils.toArray("section"), nav = gsap.utils.toArray(".menu-item a"), getMaxWidth = () => sections.reduce((val, section) => val + section.offsetWidth, 0), maxWidth = getMaxWidth(), scrollSpeed = 4, snapProgress, lastScrollTween = 0, tl = gsap.timeline(); tl.to(sections, { x: () => window.innerWidth - maxWidth, duration: 1, ease: "none" }); ScrollTrigger.create({ animation: tl, trigger: ".elementor-section-wrap", pin: true, scrub: 1, snap: {snapTo: directionalSnap(tl), duration: 0.5}, end: () => "+=" + maxWidth / scrollSpeed, invalidateOnRefresh: true }); function init() { gsap.set(sections, {x: 0}); maxWidth = getMaxWidth(); let position = 0, distance = maxWidth - window.innerWidth; // add a label for each section to the timeline (for "labelsDirectional" functionality): tl.add("label0", 0); sections.forEach((section, i) => { let progress = position; position += section.offsetWidth / distance; tl.add("label" + (i+1), position); nav[i].onclick = () => { // link clicks should trigger a scroll tween to the appropriate spot snapProgress = progress; // save the current progress so that if we can return it in the directionalSnap() when called right after the scrollTo tween is done (because ScrollTrigger would normally look at the velocity and snap, causing it to overshoot to the next section) lastScrollTween = Date.now(); // for checking in the directionalSnap() if there was a recent scrollTo that finished, in which case we'd skip the snapping (well, return the current snapProgress) gsap.to(window, {scrollTo: maxWidth / scrollSpeed * progress, duration: 1, overwrite: "auto"}); }; }); } init(); ScrollTrigger.addEventListener("refreshInit", init); // on resize, things must be recalculated // a helper function for doing "labelsDirectional" snapping, but we can't use that directly since we're doing some special things with scrollTo tweens, and we need a way to skip the snap if a scrollTo recently finished (otherwise it'll overshoot to the next section) function directionalSnap(timeline) { return (value, st) => { if (Date.now() - lastScrollTween < 1650) { // recently finished doing a tweened scroll (clicked link), so don't do any snapping. return snapProgress; } let a = [], labels = timeline.labels, duration = timeline.duration(), p, i; for (p in labels) { a.push(labels[p] / duration); } a.sort((a, b) => a - b); if (st.direction > 0) { for (i = 0; i < a.length; i++) { if (a[i] >= value) { return a[i]; } } return a.pop(); } else { i = a.length; while (i--) { if (a[i] <= value) { return a[i]; } } } return a[0]; }; }</script> With this CSS (working fine on scroll): @media only screen and (min-width:768px){ .elementor-inner .elementor-section-wrap{ display: inline-flex; } .elementor-section{ width:100vw; } .custom-width{ width: 100px; } .custom-width2{ width: 100vw; } body{ overflow-y: hidden; overscroll-behavior-y: none; } .elementor-inner { width: 100vh; height: 100vw; overflow-x: hidden; overflow-y: scroll; transform: rotate(-90deg) translateX(-100vh); transform-origin: top left; position: absolute; scrollbar-width: none; -ms-overflow-style: none; } .elementor-inner .elementor-section-wrap { transform: rotate(90deg) translateY(-100vh); transform-origin: top left; display: flex; flex-direction: row; width: 600vw; } /*section { width: 100vw; height: 100vh; }*/ ::-webkit-scrollbar { display: none } } @media only screen and (max-width:768px){ .elementor-inner .elementor-section-wrap{ display: block; } body{ overflow-y:auto; } } Thank you
  17. There is no kill method. That's why I was saying that you would need to write that yourself. Maybe something like this. export default class AnimationServicesHomePage { constructor(animationEl) { this.triggers = []; this.DOM = { animationEl: animationEl }; this.DOM.scrollColorElems = [ ...this.DOM.animationEl.querySelectorAll("[data-bgcolor]") ]; if (this.DOM.scrollColorElems) { this.DOM.scrollColorElems.forEach((colorSection, i) => { const prevBg = i === 0 ? "" : this.DOM.scrollColorElems[i - 1].dataset.bgcolor; this.animationBgImgScroll(colorSection, prevBg); }); } /* ScrollTrigger.addEventListener("resize", () => locomotive.update()); ScrollTrigger.refresh(); */ } kill() { this.triggers.forEach((t) => t.kill()); } /* Animation Scroll Bg Color Change Services Apparitions Home */ animationBgImgScroll(colorSection, prevBg) { /* ScrollTrigger.config ({ limitCallbacks: true }) */ const body = document.querySelector("body"); let st1 = ScrollTrigger.create({ trigger: ".services", start: "top 12.5%", end: "bottom 12.5%", markers: true, toggleActions: "play none none none", onEnter: () => body.classList.remove("bg-black"), onLeaveBack: () => body.classList.add("bg-black") }); let st2 = ScrollTrigger.create({ trigger: colorSection, start: "top 50%", end: "bottom 50%", markers: false, invalidateOnRefresh: true, immediateRender: false, preventOverlaps: true, fastScrollEnd: true, onEnter: () => gsap.to("body", { backgroundColor: colorSection.dataset.bgcolor }), onLeaveBack: () => gsap.to("body", { backgroundColor: prevBg, overwrite: "auto" }) }); this.triggers.push(st1, st2); } }
  18. @Septrios we can't effectively troubleshoot live web sites - if you can't provide a minimal demo in CodePen or something like that, you'll probably need to secure paid consulting services. My advice: try to reproduce the issue in the most basic way possible (a few simple <div> elements in a CodePen) and then post that here. I think part of the problem is likely that you're just doing tweens inside a callback which don't get reverted when ScrollTrigger.refresh() is called (like on resize). I'd probably just use a regular tween that has a ScrollTrigger, like this: // OLD ScrollTrigger.create({ trigger: colorSection, scroller:'.js-locomotive', start: "top 50%", end:'bottom 50%', markers:false, toggleActions : "play none none reverse" , onEnter: () => gsap.to("body", { backgroundColor: colorSection.dataset.bgcolor, }), onLeaveBack: () => gsap.to("body", { backgroundColor: prevBg, overwrite: "auto", }), }); // NEW gsap.to("body", { backgroundColor: colorSection.dataset.bgcolor, scrollTrigger: { trigger: colorSection, scroller:'.js-locomotive', start: "top 50%", end:'bottom 50%', toggleActions: "play none none reverse", immediateRender: false, preventOverlaps: true, fastScrollEnd: true } });
  19. Yes, that's exactly it. Thank you Jack. Why is the overwrite:true important in this case?
  20. Maybe preventOverlaps could help you? Alternately maybe looking into overwrite modes? However - as Blake said, if you use one timeline you won't run into these issues. It's by far the easiest solution If you have four sections in the DOM, make sure that your tweens are equally distributed (timing-wise) into four equal parts and then that'll map to the sections!
  21. Hello, I'm a new Gsap's fan in this place . I'm a french Developper, so sorry for my english. I have a problem with GSAP. I have a scrollTrigger.create, where I add and remove a class ('bg-black) depending on the trigger. Also, I change the colors of the background in another scrolltrigger, when scrolling the page. On the first load it works!, but when, I switch to the mobile or switch the page and come back to the first page in desktop(when i m resize the window) , the bg-black class is automatically deleted and the background has the last color of the effect. By debugging, the problem would come from the OnEnter function, but I can't find an answer, thank you for your help I used NUXT, locomotive scroll and GSAP ScrollTrigger.create({ trigger: ".services__content", scroller:'.js-locomotive', start: "top 30%", end:'bottom 30%', markers:true, toggleActions : "play none none reverse" , onEnter: () => body.classList.remove("bg-black") , onLeaveBack: () => body.classList.add("bg-black") }) ScrollTrigger.create({ trigger: colorSection, scroller:'.js-locomotive', start: "top 50%", end:'bottom 50%', markers:false, toggleActions : "play none none reverse" , onEnter: () => gsap.to("body", { backgroundColor: colorSection.dataset.bgcolor, }), onLeaveBack: () => gsap.to("body", { backgroundColor: prevBg, overwrite: "auto", }), });
  22. A few quick notes: Don't use "new" like that. // BAD: let tl = new gsap.timeline({}); // GOOD: let tl = gsap.timeline(); The overwrite value should either be "auto", true, or false - not the string "true". // BAD overwrite: "true" // GOOD overwrite: true I'd strongly recommend moving to the more modern string-based ease syntax: // OLD ease: Power0.easeNone // NEW ease: "none" If you're only adding one tween to the timeline, there's no reason to use a timeline (although it'll work just fine). // LONG let tl = gsap.timeline(); tl.fromTo(...); // SHORT gsap.fromTo(...); You'll have a SIGNIFICANTLY better chance of getting a good answer here if you take the time to create a minimal demo (like a CodePen). Like in your case, I don't really understand the context and I can't see anything being overwritten. I'm left to guess by glancing at a small excerpt of code. If my assumptions are correct, you're trying to call fader() on the ".spaceman" too? Thus you've got an infinitely-repeating x/y tween and you're ALSO trying to have fader() animate it to completely different x/y values simultaneously? That's a logic issue in your code. You could pause() your spaceman animation in that case until the new animation is done and then restart it. There are many ways you could approach this, actually. Here's one: let spaceman = gsap.fromTo('.spaceman', { x: 0, y: 0 } , { x: -2, y: -5, ease: "sine.inOut", duration: 1, repeat: -1, yoyo: true }); function fader(elementName, x, y) { let vars; if (x === 'out') { vars = { x: -150, y: -30, rotation: -15, scaleX: 0.1, scaleY: 0.1, opacity: 0, duration: 2.5, transformOrigin: (y === "left") ? "top left" : "top right", ease: "power4.out" }; } else { vars = { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1, opacity: 1, duration: 1, transformOrigin: (y === "right") ? "top right" : "top left", ease: "power4.out" }; } if (elementName === ".spaceman") { spaceman.pause(); vars.onComplete = () => spaceman.restart(); } return gsap.to(elementName, vars); } If you still need some help, please provide a minimal demo in CodePen or something and we'd be happy to answer any GSAP-specific questions.
  23. Greetings... I have an animation that runs on load which makes my spaceman float up and down. When he gets hidden and returned that animation has been killed. Below are the 2 conflicting animations which both involve x & y. I have looked at overwrites but can't seem to get my head around it. I would like the spaceman animation to run indefinitely so whenever he is visible he is "hovering" var spaceman = new gsap.timeline({ }); spaceman.fromTo('.spaceman', { x: 0, y: 0 } , { x: -2, y: -5, ease: Power0.easeNone, duration: 1, repeat: -1, yoyo: true, overwrite: 'true' }, 2 ); function fader(elementName, x, y) { var tl = new gsap.timeline({}); if (x == 'out') { if (y == 'left') { tl.to(elementName, { x: -150, y: -30, rotation: -15, scaleX: 0.1, scaleY: 0.1, opacity: 0, duration: 2.5, transformOrigin: "top left", ease: "power4.out" }); } else { tl.to(elementName, { x: 150, y: -30, rotation: 15, scaleX: 0.1, scaleY: 0.1, opacity: 0, duration: 2.5, transformOrigin: "top right", ease: "power4.out" }); } } else { if (y == 'right') { tl.to(elementName, { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1, opacity: 1, duration: 1, transformOrigin: "top right", ease: "power4.out", overwrite: 'auto' }); }else { tl.to(elementName, { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1, opacity: 1, duration: 1, transformOrigin: "top left", ease: "power4.out", overwrite: 'auto' }); } } }
  24. The main problem is that you keep creating a new tween every single time there's a mousemove event and also every time there's a mouseenter but you never set an overwrite nor do you kill() the old tween(s). So, for example, you create a repeating backgroundPosition tween the first time the user's mouse enters and then the next time you create a new one but the OLD one is continuing to play and repeat over and over. That tween is affecting the backgroundPosition as well (you're creating a bunch of conflicting tweens). You could just set overwrite: "auto" on your tween(s) but I'd actually recommend simply reusing a single tween instance rather than creating new ones over and over and over again. That'll perform better. https://codepen.io/GreenSock/pen/podNjwp?editors=0010 You had a few typos in there too. Is that CodePen more like what you wanted?
  25. Sure, if you're just staggering them (same animation for all, just offset), you can simply use a "stagger" on a single tween. No need for a timeline. But yes, if you need to animate various things differently, you can absolutely use a timeline that you create in the callback(s). Just make sure you set overwrite: true (or "auto") on the tweens to ensure you don't create conflicts. onEnter: () => { let tl = gsap.timeline({defaults: {overwrite: true}}); tl.to(...).to(...)... } If you're still struggling, please provide a minimal demo and we'd be happy to take a peek. Good luck!
×