Jump to content
Search Community

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

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

Found 1,407 results

  1. @GreenSock Thanks for the detailed explanation. Definitely makes sense. I do have an few additional question if you don't mind. onToggle: (self) => { // skip the animation if it's the last one and we're scrolling foward, or if it's the first one and we're scrolling backwards if (self.isActive || !((isLast && self.direction === 1) || (isFirst && self.direction === -1))) { gsap.to(sItems[i], { opacity: self.isActive ? 1 : 0, overwrite: true, delay: self.isActive ? 0.5 : 0 }); } }, This is a simple crossfade, if it becomes more complex would you recommend wrapping everything into a timeline and then trigger it here? In my real project the animation targets more than just the parent element. Would there be a benefit to creating a animation or would you just essentially create it here? And finally, I updated the original example to have an animation to more closely resemble the animation I intend to use (using SplitText). In the snippet below you are setting the opacity to two different states, what if I need three? Ideally the split header would enter from bottom, rest at mid, then exit top (see example). gsap.to(sItems[i], { opacity: self.isActive ? 1 : 0, overwrite: true, delay: self.isActive ? 0.5 : 0 }); I tried to make a simple animation here but this only shows the out portion? if (self.isActive || !((isLast && self.direction === 1) || (isFirst && self.direction === -1))) { gsap.to(splitHeaders[i].lines, {opacity: self.isActive ? 1 : 0, y: self.isActive ? '0%' : '-100%'}); } //Trying to convert this st.to(outHeader.lines, { duration: 1, y: "-100%", skewX: "8deg", skewY: "0deg", opacity: 0, stagger: 0.1, ease: "power4.inOut" }); https://codepen.io/samso-studios/pen/MWLeazg
  2. I had some comments in the code to make it clear. The general concept is to fire off a fresh animation whenever a section becomes active or inactive (onToggle). So a single ScrollTrigger for each with an onToggle. That way, you're just using trigger points to initiate individual animations when necessary. Your previous technique was embedding very specific crossfades between only the neighboring sections. So you baked in "section 1" fading out with "section 2" fading in, etc. So it was all tied together. If you entered section 4, it'd have to play that very specific animation where a fully-opaque section 3 would fade out, then section 4 would fade in. No bueno. It's a logic/engineering thing. But the effect you asked for was more dynamic, where each individual section needed to handle itself on its own when it became active/inactive (not tying it together directly with the neighboring animation). Basically my approach made things very dynamic, so if you scroll from section 1 to section 4, it'd start fading out section 1 onLeave, and as you fly past section 2, that'd start as well but you'd hit its end so quickly that the "out" tween would overwrite the "in" one and basically you'd never see it because the opacity might be 0.07 and then go to 0. Same for section 3. And then by the time you got to section 4, it'd fire off its "in" animation with that 0.5-second delay, so the user would end up seeing section 1 fade out and section 4 fade in. I hope that clears things up. Also note that gsap.utils.toArray() might be useful in your code. And you can do standalone ScrollTriggers (like in my demo) - you don't always have to embed them in timelines/tweens.
  3. Ah, okay - just set overwrite: true on the staggered tween. Is that what you're looking for? https://stackblitz.com/edit/react-4vxqpg?file=src%2FAnimations.jsx
  4. Yep. That's exactly what I'm trying to do. I originally thought that gsap might have gotten the new values after I set the transform manually, I don't care how I set it (through gsap or not) I just wanted it set and not forgotten. Which yours looks like it does perfectly! So gsap.set and tl.set is the fix? gsap.set(".layer-1", {x: 200}); tl.set( '.layer-1', {x: 200,overwrite: true}, "layer-1"); Thanks!
  5. Hi, Based on your demo I assume that you don't want to use the timer functionality and your setup doesn't use the Inertia plugin. In that case this boils down to the logic that is being run when the draggable proxy is released: let snapProgressDirectional = (value, direction) => { let snapped = snapProgress(value); if (direction < 0 && value - snapped > threshold) { return snapped + progressPerItem; } else if (direction > 0 && snapped - value > threshold) { return snapped - progressPerItem; } return snapped; }; draggable = new Draggable(document.createElement("div"), { // use a proxy element trigger: ".slides-container", onPress() { gsap.killTweensOf(animation); this.startProgress = animation.progress(); }, onDrag() { let change = (draggable.startX - draggable.x) / totalWidth; animation.progress(draggable.startProgress + change); }, onRelease() { gsap.to(animation, { progress: snapProgressDirectional(animation.progress(), (this.deltaX > 0 ? 1 : -1)), duration: slideDuration, overwrite: true }) } }); I created a fork of the original codepen from the GSAP collection: https://codepen.io/GreenSock/pen/eYbwobg Hopefully this helps. Happy Tweening!
  6. Yes, that's correct - gsap.quickTo() is a highly-optimized option that skips various features and conveniences in order to get maximum speed. Staggering is one of the things omitted. You might want to consider using Observer to get the event debouncing and be sure to set overwrite: "auto", and also set position: fixed for your elements if you're using .clientX/Y, otherwise it'll break when you scroll the page: https://codepen.io/GreenSock/pen/NWemEVQ
  7. Hi @hanjames welcome to the forum! I had to remove your Tailwind classes, because I don't know how to overwrite those when flipping. But you can just do your javascript logic of setting your main image to the position in the column, I've used the following flip demo from the docs https://greensock.com/docs/v3/Plugins/Flip/ https://codepen.io/GreenSock/pen/OJNYjmz?editors=0010 And added that to your timeline at a point that seems logical. It still needs some tweaking, but I think you can take it from here. https://codepen.io/mvaneijgen/pen/ZEVjgPB?editors=0010 As a side note, instead of y: '0%', you can do yPercent: 0. Hope it helps and happy tweening!
  8. You could wrap your rotatingText in another element and animate that element on scroll, then with the ScrollTrigger onEnter and onLeave callbacks pause the initial tween and play it again. It is a bit hard to give advies when there is no minimal demo in which we can poke around, so this is the best I can do for now. The issue you're facing is because two tweens animate the same element and the same property, so you could also look in to overwrite: true on the second tween or instead of a fixed pixel value make it dynamic with `+=${360 * 5}`, but having two distinct elements is the best way to go in my opinion. Hope it helps and happy tweening!
  9. @1N54N3 I'm not seeing any unexpected behavior. It's important that you understand how tweens work... The very first time a tween renders, it records the start and end values internally so that it can very quickly interpolate between them. There are two issues I see in your setup: You're setting overwrite: true on your 2nd tween which will IMMEDIATELY find any tweens of that same target and kill them. So that wipes out your "moveFrom" tween. You initially paused your timeline, so none of the "to" tweens inside of that will render right away. Then, when you click "play", you're pausing the "moveFrom" tween, thus it never had a chance to render even once and record internally the start/end states. So of course your "moveTo" tween runs from the current value (0). All exactly as expected. Then later, if/when you unpause that "moveFrom" tween, it'll record the start/end values at that point. Since it's a "to" tween, it just uses the CURRENT value as the "from". At the point it renders for the very first time then, you've probably got x at 200 from the other tween. Does that clear things up? You're welcome to use .fromTo() tweens if you need total control of both ends (start/end). Or you can force a render of the tweens in the timeline by doing something like timeline.progress(1).progress(0) before pausing anything internally.
  10. I found the solution in other topic gsap.utils.toArray(".cb-tagreel-row2").forEach((line, i) => { const speed = 1; // (in pixels per second) const links = line.querySelectorAll(".cb-tagreel-item2"), tl = horizontalLoop(links, { speed: speed, repeat: -1 }); links.forEach((link) => { link.addEventListener("mouseenter", () => gsap.to(tl, { timeScale: 0, overwrite: true }) ); link.addEventListener("mouseleave", () => gsap.to(tl, { timeScale: 1, overwrite: true }) ); }); }); function horizontalLoop(items, config) { items = gsap.utils.toArray(items); config = config || {}; let tl = gsap.timeline({ repeat: config.repeat, paused: config.paused, defaults: { ease: "none" }, onReverseComplete: () => tl.totalTime(tl.rawTime() + tl.duration() * 100) }), length = items.length, startX = items[0].offsetLeft, times = [], widths = [], xPercents = [], curIndex = 0, pixelsPerSecond = (config.speed || 1) * 100, snap = config.snap === false ? (v) => v : gsap.utils.snap(config.snap || 1), // some browsers shift by a pixel to accommodate flex layouts, so for example if width is 20% the first element's width might be 242px, and the next 243px, alternating back and forth. So we snap to 5 percentage points to make things look more natural totalWidth, curX, distanceToStart, distanceToLoop, item, i; gsap.set(items, { // convert "x" to "xPercent" to make things responsive, and populate the widths/xPercents Arrays to make lookups faster. xPercent: (i, el) => { let w = (widths[i] = parseFloat(gsap.getProperty(el, "width", "px"))); xPercents[i] = snap( (parseFloat(gsap.getProperty(el, "x", "px")) / w) * 100 + gsap.getProperty(el, "xPercent") ); return xPercents[i]; } }); gsap.set(items, { x: 0 }); totalWidth = items[length - 1].offsetLeft + (xPercents[length - 1] / 100) * widths[length - 1] - startX + items[length - 1].offsetWidth * gsap.getProperty(items[length - 1], "scaleX") + (parseFloat(config.paddingRight) || 0); for (i = 0; i < length; i++) { item = items[i]; curX = (xPercents[i] / 100) * widths[i]; distanceToStart = item.offsetLeft + curX - startX; distanceToLoop = distanceToStart + widths[i] * gsap.getProperty(item, "scaleX"); tl.to( item, { xPercent: snap(((curX - distanceToLoop) / widths[i]) * 100), duration: distanceToLoop / pixelsPerSecond }, 0 ) .fromTo( item, { xPercent: snap( ((curX - distanceToLoop + totalWidth) / widths[i]) * 100 ) }, { xPercent: xPercents[i], duration: (curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond, immediateRender: false }, distanceToLoop / pixelsPerSecond ) .add("label" + i, distanceToStart / pixelsPerSecond); times[i] = distanceToStart / pixelsPerSecond; } function toIndex(index, vars) { vars = vars || {}; Math.abs(index - curIndex) > length / 2 && (index += index > curIndex ? -length : length); // always go in the shortest direction let newIndex = gsap.utils.wrap(0, length, index), time = times[newIndex]; if (time > tl.time() !== index > curIndex) { // if we're wrapping the timeline's playhead, make the proper adjustments vars.modifiers = { time: gsap.utils.wrap(0, tl.duration()) }; time += tl.duration() * (index > curIndex ? 1 : -1); } curIndex = newIndex; vars.overwrite = true; return tl.tweenTo(time, vars); } tl.next = (vars) => toIndex(curIndex + 1, vars); tl.previous = (vars) => toIndex(curIndex - 1, vars); tl.current = () => curIndex; tl.toIndex = (index, vars) => toIndex(index, vars); tl.times = times; tl.progress(1, true).progress(0, true); // pre-render for performance if (config.reversed) { tl.vars.onReverseComplete(); tl.reverse(); } return tl; }
  11. You can set overwrite: true, in your tween, so that it will overwrite current tweens already playing. https://codepen.io/mvaneijgen/pen/gOZWbJb?editors=0010 I don't know what you mean with the following
  12. Hi @Tony Geek I would then create all the tweens in the callbacks them self. .fromTo() tween are great for this, because then we can make sure the animations always start from the placed we want. You could of course create a function with a tween in there and call that function each time in the callbacks, but this also works. I've set overwrite: true, just as a precaution for when tweens would overlap. Hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/ZEVpRXY?editors=0011
  13. Hi everyone, I would like to recreate the animation you can see on CodePen. I'm a beginner about gsap so I need your help. My code is on vue.js and and is as follows: <template> <div class="scrollDist"></div> <div class="main"> <svg width="100%" height="100%" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> <mask id="m"> <g class="medi"> <rect fill="#fff" width="100%" height="100vh" y="850" /> <image y="15%" href="../assets/img/big-cloud.svg" width="1900"/> </g> </mask> <image class="sky" href="../assets/img/sky.jpg" width="1900" /> <image class="piccoli" href="../assets/img/piccoli.svg" width="1000" x="40%" /> <image class="small-cloud" href="../assets/img/small-cloud.svg" x="1%" y="17%" width="20%" /> <image class="background" href="../assets/img/background.png" width="1900" /> <image class="medi" href="../assets/img/medi.svg" width="900" x="20%" /> <image class="grandi" href="../assets/img/grandi.svg" width="1000" x="35%" /> <text fill="#fff" x="35%" y="50%">EXPLORE</text> <image class="arrow" x="47%" y="52%" href="../assets/img/arrow-down.svg" width="30" /> <g mask="url(#m)"> <rect fill="#fff" width="100%" height="100%" /> <text x="35%" y="50%" fill="#162a43">FURTHER</text> </g> <rect ref="arrowBtn" width="30" height="100" opacity="0" x="47%" y="52%" style="cursor:pointer"/> </svg> </div> </template> <script setup> import { gsap } from "gsap"; import ScrollToPlugin from "gsap/ScrollToPlugin"; import { onMounted, ref } from 'vue'; gsap.registerPlugin(ScrollToPlugin); gsap.set('.main', {position:'fixed', background:'#fff', width:'100%', height:'100vh', top:0, left:'50%', x:'-50%'}) gsap.set('.scrollDist', {width:'100%', height:'100vh'}) gsap.timeline({scrollTrigger:{trigger:'.scrollDist', start:'top top', end:'bottom bottom', scrub:1}}) .fromTo('.sky', {y:0},{y:-200}, 0) .fromTo('.medi', {y:100},{y:-1000}, 0) .fromTo('.small-cloud', {y:-150},{y:-500}, 0) .fromTo('.piccoli', {y:-10},{y:-100}, 0) .fromTo('.background', {y:-50},{y:-600}, 0) const arrowBtn = ref(null); onMounted(() => { arrowBtn.value.addEventListener('mouseenter', (e) => { gsap.to('.arrow', {y:10, duration:0.8, ease:'back.inOut(3)', overwrite:'auto'}); }); arrowBtn.value.addEventListener('mouseleave', (e) => { gsap.to('.arrow', {y:0, duration:0.5, ease:'power3.out', overwrite:'auto'}); }); arrowBtn.value.addEventListener('click', (e) => { gsap.to(window, {scrollTo:innerHeight, duration:1.5, ease:'power1.inOut'}); }); }); </script> <style> body, html { width: 100%; height: 100vh; background: #ddd; font-size: 99px; text-align: center; } div { position: absolute; } </style> Can anyone help me? Thanks in advance. C.
  14. Sorry for not providing a codepen. I think it is not possible in this case. I would like to ask if can be think of a way to detect the problem by looking at the page, which is this: https://nmiai.e451.net/ The problem is the following. I have several elements with the class "fade". I watch them with an intersection observer that fires a gsap.to() function when they enter the viewport and another gsap.set() function when they exit the viewport. const fades = document.querySelectorAll('.fade'); if (fades) { fades.forEach(function (fade) { fadeOut(fade); }); } // omitting intersection observer for simplicity function loadFades(entries) { entries.forEach((entry) => { if (entry.isIntersecting) { fadeIn(entry.target); } else { fadeOut(entry.target); } }); } function fadeIn(fade) { gsap.to(fade, { y: '0', opacity: '1', duration: '2', overwrite: true, ease: 'power4.out', }); } function fadeOut(fade) { gsap.set(fade, { y: '50px', opacity: '0', overwrite: true, }); } This is the entire code in context: https://github.com/aitormendez/nmiai-website/blob/main/site/web/app/themes/sage/resources/scripts/animateProject.js This works in all cases except for the work page. On this page the duration of the gsap.to() is multiplied. I haven't been able to figure out why. In this video you can see a comparison of how it works on the front page and on the work page. The first case has a correct duration, the second case does not. Why? Any idea will be welcome.
  15. Hey Cassie Thanks for your swift response, per usual. I'm doing great, thanks for asking. As I said, the actual code is a lot more abstract, since the fade-in animations are set in a completely different script, which is loaded on page load. The animations are set through data-attributes on the elements. Much like a scroll animations library like Animate On Scroll. I can't just overwrite or reset the animations, since I don't really know what the animations _are_. I'll have to experiment, and see if I can work the swopScroller function into the animations library. I'll report back.
  16. Heya! So the best approach here is likely just using tweens. Tweens are more dynamic and ideal for stuff like this. They'll take whatever the property value at that particular point in time is, no matter what it is, and tween to the property value you've specified. https://codepen.io/GreenSock/pen/LYXoKGX?editors=0110 Timelines are great for control, but it can get fiddly if you're animating the same elements in multiple timelines. Sometimes using overwrite:auto and immediateRender:false can help get the behaviour you're after, there's also an invalidate() method that you can call on a timeline that flushes out stored starting values, that can also be helpful too. https://codepen.io/GreenSock/pen/OJggZgK But yeah, I'd likely go for tweens for anything more dynamic and event driven! Hope this helps ☺️
  17. Welcome to the GreenSock forum @blueblueblueblue For ScrollTrigger to get new values after invalidating the old you will need to use function based values for what you're tweening on, or else the invalidation on refresh won't do much for you in the first place. x: () => -1 * width, // instead of x: -1 * width, Secondly, you could try changing the ScrollTrigger event that you overwrite your width variable on, from "refreshInit" to "revert". That does seem to work better for me then. https://codepen.io/akapowl/pen/JjevVGG Personally, I don't actually see the need for an extra function to call on resize when you have only a few values that need re-evalution anyway, so I would actually ommit that function altogether in your case and just get the values on the tween itself directly; then you also wouldn't have to worry about any events anymore. I would also suggest moving away from getBoundingClientRect().width for this, because you technically only add one extra step for the browser to get to the value you need (and getBoundinClientRect() values might not always return what you think they do in other scenarios); when you can instead use something like element.scrollWidth instead. I hope that will help get you on the right track. https://codepen.io/akapowl/pen/vYQjMyZ
  18. Because in my case, I want when end scrollTrigger animation of box1, box2 must be next to child2 but currently it is overwrite each other.
  19. Hello there, Marko, welcome to the GSAP forum. Does the codepen show the same issue for you - because for me it doesn't. I'm not familiar with Elementor at all, but your video very much looks like there are conflicting CSS transitions applied to the element that is being changed inline by ScrollTrigger; so when ScrollTrigger changes e.g. the position to/from fixed on the pinned element, it will transition when the inline styles get applied. I'd suggest digging through your CSS and looking for transitions that are being applied by Elementor - and if they might affect any element that is being targeted by GSAP / ScrollTrigger in any way, remove them / overwrite them so they don't have an effect on that element any more. I hope that will help resolve the issue for you.
  20. For the slide I had used a snippet of code of a codepen demo with scrolltrigger and scrollTo: let sections = gsap.utils.toArray(".scroller-sections"), scrollTween; function goToSection(i) { scrollTween = gsap.to(window, { scrollTo: {y: i * window.innerHeight, autoKill: false}, duration: 1, ease: "expo.out", onComplete: () => { scrollTween = null }, overwrite: true }); } sections.forEach((section, i) => { ScrollTrigger.create({ trigger: section, start: "top bottom-=1", end: "bottom top+=1", onToggle: self => self.isActive && !scrollTween && goToSection(i) }); }); the problems are for the animations that are different for each slide and the elements (inside svg) if you see here https://punctum.studio/preview/sitaricerca/ are positioned with transform or matrix and y or x doesn't work well.
  21. What do I mean by the title is something done like this... but this is different because it doesn't have a scrollbar because it relies in scrollObserver...so I don't understand how can I make work the scrollTrigger alongside inside the scrollObserver. https://codesandbox.io/s/nervous-resonance-xpjvdf?file=/src/OshiNoko.jsx You can check in my code inside...which what I am trying to do is that I'm trying to spread the scale:2 in the text that is closing in the middle so it looks cool...and then once it pass by the middle it will slowly scale:1 or lower the scale...The scale should be dependent if it's closing in the middle of the item...but it doesn't plus it calls many times the markers which kinda sucks and also I don't know why when I'm trying to onUp or onDown it seems the text a bit laggy when transition? what I am missing here? This is the codes. const gotoSection = (index, isScrollingDown) => { let target = isScrollingDown ? swipePanels[currentIndex] : swipePanels[index]; let currentYPercent = gsap.getProperty(".list-of-items", "yPercent"); gsap.to(target, { scale: isScrollingDown ? 2 : 1, // duration:1.25, ease: "power2.inOut", scrollTrigger: { trigger: target, scrub: 1, start: "top center", end: "bottom center", markers: true } }); gsap.to(".list-of-items", { yPercent: limitYPercent(currentYPercent, isScrollingDown ? +1 : -1), duration: 0, // overwrite:true, ease: "none" }); currentIndex = index; }; // ScrollTrigger.create({ // trigger:'.wrapper', // scrub:true, // start: "top center", // end: "bottom center", // markers:true, // onEnter:() => { // let target = swipePanels[currentIndex]; // gsap.to(target,{ // scale:2, // }) // }, // onLeave:() => { // let target = swipePanels[currentIndex]; // gsap.to(target,{ // scale:1, // }) // } // }) instanceObserver = ScrollTrigger.observe({ target: ".wrapper", wheelSpeed: -1, onUp: () => { gotoSection(currentIndex + 1, true); }, onDown: () => { gotoSection(currentIndex - 1, false); }, tolerance: 10, preventDefault: true, allowClicks: true });
  22. @GreenSock Thanks, I just use your code and it works. I guess I should use fromTo tween and also overwrite property, because I also have hover animation. Thanks for your help!
  23. Are you saying that the CodeSandbox demo works fine, but it only breaks when you try it in a different project that you can't show us? A few ideas: Make sure you don't have any CSS transitions or CSS animations applied to the element that you're animating with GSAP. Those could be conflicting. If the user might click multiple times quickly, I'd strongly recommend setting something like overwrite: "auto" or overwrite: true on your first tween to make sure any in-progress tweens of that same element are killed to avoid conflicts. You could probably simplify your code a bit into a single tween that has a repeat/yoyo on it: gsap.fromTo(e.currentTarget, {scale: 1}, {scale: 0.75, duration: 0.25, yoyo: true, repeat: 1, overwrite: true}); There are other ways too. https://codepen.io/GreenSock/pen/BaGjRar?editors=0010 If you still need some help, please make sure you provide a minimal demo that clearly illustrates the issue. We'd be happy to take a look at any GSAP-specific questions you may have.
  24. It seems like you're trying to overwrite what ScrollTrigger is already animating. This will not play nice if a user first scrolls then clicks and then goes back to scrolling again. You almost never want to overwrite tweens you're already created, you can only do this if you're a 100% sure of what you're doing. Here is an example from https://greensock.com/st-demos/ using the scrollTo plugin, with this plugin it allows you to scroll to certain parts of your page and thus ScrollTrigger will just animate things like it would also do if a user scrolls, so no need to create multiple animations that do the same thing. You can do this like the demo is showing, or you can use labels in your timeline to navigate to check out https://greensock.com/docs/v3/Plugins/ScrollTrigger/labelToScroll() https://codepen.io/GreenSock/pen/bGexQpq You can add a empty tween to your timeline to have it do nothing x amount of seconds, with something like this, but this will not work in your current setup, because you have 0 duration tweens which all start at the same time. .add(() => {}, "+=5"); // Add pause of 5 seconds If you want 0 duration tweens just use a .set() function or better change the easing of a normal animation ease: "steps(1)" this will make the transition instant, so it will have the effect you're after, but you keep all the control of the timeline. https://greensock.com/docs/v3/Eases
  25. I assume you meant to do something like this?: var items = gsap.utils.toArray(".gallery-item__inner"), cursor = document.querySelector(".me"), xTo = gsap.quickTo(cursor, "x", {duration: 0.3, ease: "power3"}), yTo = gsap.quickTo(cursor, "y", {duration: 0.3, ease: "power3"}); gsap.set(cursor, {xPercent: -50, yPercent: -50, autoAlpha: 1, scale: 0, pointerEvents: "none"}); window.addEventListener("mousemove", (e) => { xTo(e.pageX); yTo(e.pageY); }); items.forEach((item) => { item.addEventListener("mouseenter", () => { gsap.to(cursor, {scale: 1, duration: 0.2, overwrite: "auto"}); }); item.addEventListener("mouseleave", () => { gsap.to(cursor, {scale: 0, duration: 0.01, overwrite: "auto"}); }); }); https://jsfiddle.net/t6byepfa/
×
×
  • Create New...