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,409 results

  1. At first glance the rabbit hole did not seem that deep, I might be wrong when I apply it across my entire application (I already notice that I should replace the setTimeouts with a delay for instance). But in short, this is how I approached it. I have made a file that operates as a wrapper for gsap, it imports an external file that manages the state of the animations (a Pinia datastore in my case). Which has a boolean property called "showAnimations" to determine wether animations will be played or not. /services/gsap-wrapper.ts import gsap from "gsap" import appStore from "@/stores/app" const gsapWrapper = {...gsap} gsapWrapper.to = ( target: gsap.TweenTarget, durationOrVars: number | gsap.TweenVars, vars?: gsap.TweenVars ) => { let options = {} as gsap.TweenVars if (typeof durationOrVars === "number") { options.duration = durationOrVars } else { vars = durationOrVars } options = { ...options, ...vars, } as gsap.TweenVars // Pinia datastore const app = appStore() // Overwrite duration & delay when animations are not allowed if (!app.showAnimations) { options.duration = 0 options.delay = 0 options.ease = "none" if (typeof options.stagger == "number") { options.stagger = 0 } else if (typeof options.stagger === "object" && options.stagger !== null) { options.stagger.each = 0 } } return gsap.to(target, options) } gsapWrapper.fromTo = ( target: gsap.TweenTarget, durationOrFromVars: number | gsap.TweenVars, fromOrToVars: gsap.TweenVars, toVars?: gsap.TweenVars ) => { let options = {} as gsap.TweenVars let fromVars = fromOrToVars if (typeof durationOrFromVars === "number") { options.duration = durationOrFromVars fromVars = fromOrToVars } else { toVars = fromOrToVars fromVars = durationOrFromVars } options = { ...options, ...toVars, } as gsap.TweenVars // Pinia datastore const app = appStore() // Overwrite duration & delay when animations are not allowed if (!app.showAnimations) { options.duration = 0 options.delay = 0 options.ease = "none" if (typeof options.stagger == "number") { options.stagger = 0 } else if (typeof options.stagger === "object" && options.stagger !== null) { options.stagger.each = 0 } } return gsap.fromTo(target, { ...fromVars, }, options) } export default gsapWrapper In the other files where I normally include gsap via import gsap from "gsap", I now simply import it as followed: import gsap from "/services/gsap-wrapper" This approach allows me to enable/disable all gsap animations from 1 single location which seem to have the following up- and downsides. Upsides I have on boolean variable that I can modify to disable ALL animations throughout my application The code is relatively simple, and can be easily adjusted and expanded It uses the default gsap library, so unless breaking changes occur in the gsap.to method. Everything will remain working with future gsap updates Downsides It is applicable to ALL gsap.to methods. As a workaround you could import both the gsap-wrapper and gsap into a file, but that could easily become a slippery slope It can be quite a hassle to figure out how the wrapper function should be written to respect the original gsap method and its types
  2. I noticed a problem with the Firefox browser. I have a looping marquee made with the seamless loop helper function and the Observer plugin on my website, it works great on every browser except Firefox. The marquee loops and it can be controlled with the scroll wheel with the help of the Observer plugin. I have hover event listeners to stop the marquee when I'm hovering on it. When the marquee stops I can scroll normally, when I hover out and the marquee resumes, the scrolling goes back to extremely slow again. This only happens on Mozilla Firefox, works great on the other browsers. Here's the code I'm using for the marquee gsap.registerPlugin(Observer); document.addEventListener("DOMContentLoaded", () => { const projectsList = document.querySelector(".horizontal_projects-wrap"); projectsList.addEventListener('pointerenter', pauseLoop); projectsList.addEventListener('pointerleave', playLoop); const names = document.querySelectorAll(".horizontal_project-title") let hovered = false; function pauseLoop () { tl.pause(); loopObserver.disable(); hovered = true; } function playLoop () { tl.play(); loopObserver.enable(); hovered = false; } const tl = horizontalLoop(names, { repeat: -1, }); const loopObserver = Observer.create({ type: 'wheel', onChangeY(self) { let factor = 2; if (self.deltaY < 0) { factor *= -1.4; } else { factor *= 1.4; } gsap.to(tl, { timeScale: factor * 2, duration: .15, }) gsap.to(tl, { timeScale: factor / 2, duration: .15, onComplete: () => { if (factor<0) { gsap.to(tl, { timeScale: 1, duration: 0.1, }) } } }, "+=.1"); } }); }); /* This helper function makes a group of elements animate along the x-axis in a seamless, responsive loop. Features: - Uses xPercent so that even if the widths change (like if the window gets resized), it should still work in most cases. - When each item animates to the left or right enough, it will loop back to the other side - Optionally pass in a config object with values like "speed" (default: 1, which travels at roughly 100 pixels per second), paused (boolean), repeat, reversed, and paddingRight. - The returned timeline will have the following methods added to it: - next() - animates to the next element using a timeline.tweenTo() which it returns. You can pass in a vars object to control duration, easing, etc. - previous() - animates to the previous element using a timeline.tweenTo() which it returns. You can pass in a vars object to control duration, easing, etc. - toIndex() - pass in a zero-based index value of the element that it should animate to, and optionally pass in a vars object to control duration, easing, etc. Always goes in the shortest direction - current() - returns the current index (if an animation is in-progress, it reflects the final index) - times - an Array of the times on the timeline where each element hits the "starting" spot. There's also a label added accordingly, so "label1" is when the 2nd element reaches the start. */ 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; }
  3. I'm not sure what you mean by "properly" - from what I can tell, it's doing everything exactly properly. Are you trying to find all the tweens that affect a particular target and kill them? If so, you can use gsap.killTweensOf(). If you want to just find the tweens of a particular target, you can use gsap.getTweensOf(). overwrite: "auto" runs the first time the tween renders, and it finds ONLY the in-progress tweens that are affecting the same individual properties of the same target, and kills those (just the individual properties that overlap). If you set overwrite: true, it'll find all of the tweens of the same target(s) regardless of what properties overlap, and kill them immediately. So with the above tools, you should be able to accomplish pretty much anything you need.
  4. Hi Rodrigo, I did some experiments after reading through your response. The animation goes back to normal after the window is resized. However, we can't just ask the visitors to resize the window to see the effect, right? And, I am unsure what you mean by "the order things are called". Assuming I am right, I moved the About section above all other animations. However, the problem still occurs. Then, I try to comment out the command lines one by one. I noticed that as long as the "homePlanet" animation is not calling. Everything will work just fine, as you showed me in your reply. So, I started asking myself about my looping rotation and its speed. Please see my codes below. planet .to(".dot-line", { repeat: -1, rotation: "+=360", duration: 100, ease: "none", transformOrigin: "center center" }) .to(".planet", { repeat: -1, rotation: "+=360", ease: "none", svgOrigin: "431.92 431.92", duration: 30, overwrite: "auto" }, 0) .to(".planet-ab", { repeat: -1, rotation: "+=360", ease: "none", svgOrigin: "566.76 566.76", duration: 60, overwrite: "auto" }, 0) I am using duration to control its speed. I wonder if it could be the duration that caused the issue. This looping feature involved 2 sections, which you can see in the below codepen link. https://codepen.io/danclp/pen/KKEarwe The rotation works as a continuing animation, even after it has been scroll-triggered away in the first section. You can still see the rotation animation available in the second section (the sliding text section). Did I code correctly, or does it have another way of calling when we want it to animate continuously? Also, should I use duration or something else when I want to slow down the rotation speed? Can you give me some advice? Thank you.
  5. ho sorry , oki after many test i just starting found correct solutions: `overwrite: 'auto'` => ` overwrite: true,` https://codepen.io/djmisterjon/pen/BabpgPx?editors=0011 i will need make more deep test to see if this broke behaviors in my app !? but seem promising, de delay animation seem override thanks
  6. 120Tracking Prevention blocked access to storage for <URL>. require.js:168 Uncaught Error: Mismatched anonymous define() module: function(e){"use strict";function _inheritsLoose(t,e){t.prototype=Object.create(e.prototype),(t.prototype.constructor=t).__proto__=e}function _assertThisInitialized(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function n(t){return"string"==typeof t}function o(t){return"function"==typeof t}function p(t){return"number"==typeof t}function q(t){return void 0===t}function r(t){return"object"==typeof t}function s(t){return!1!==t}function t(){return"undefined"!=typeof window}function u(t){return o(t)||n(t)}function K(t){return(l=pt(t,at))&&ie}function L(t,e){return console.warn("Invalid property",t,"set to",e,"Missing plugin? gsap.registerPlugin()")}function M(t,e){return!e&&console.warn(t)}function N(t,e){return t&&(at[t]=e)&&l&&(l[t]=e)||at}function O(){return 0}function Y(t){var e,i,n=t[0];if(r(n)||o(n)||(t=[t]),!(e=(n._gsap||{}).harness)){for(i=dt.length;i--&&!dt[i].targetTest(n););e=dt[i]}for(i=t.length;i--;)t[i]&&(t[i]._gsap||(t[i]._gsap=new Ft(t[i],e)))||t.splice(i,1);return t}function Z(t){return t._gsap||Y(yt(t))[0]._gsap}function $(t,e){var r=t[e];return o(r)?t[e]():q(r)&&t.getAttribute(e)||r}function _(t,e){return(t=t.split(",")).forEach(e)||t}function aa(t){return Math.round(1e5*t)/1e5||0}function ba(t,e){for(var r=e.length,i=0;t.indexOf(e[i])<0&&++i<r;);return i<r}function ca(t,e,r){var i,n=p(t[1]),a=(n?2:1)+(e<2?0:1),o=t[a];if(n&&(o.duration=t[1]),o.parent=r,e){for(i=o;r&&!("immediateRender"in i);)i=r.vars.defaults||{},r=s(r.vars.inherit)&&r.parent;o.immediateRender=s(i.immediateRender),e<2?o.runBackwards=1:o.startAt=t[a-1]}return o}function da(){var t,e,r=ot.length,i=ot.slice(0);for(ut={},t=ot.length=0;t<r;t++)(e=i[t])&&e._lazy&&(e.render(e._lazy[0],e._lazy[1],!0)._lazy=0)}function ea(t,e,r,i){ot.length&&da(),t.render(e,r,i),ot.length&&da()}function fa(t){var e=parseFloat(t);return(e||0===e)&&(t+"").match(nt).length<2?e:t}function ga(t){return t}function ha(t,e){for(var r in e)r in t||(t[r]=e[r]);return t}function ia(t,e){for(var r in e)r in t||"duration"===r||"ease"===r||(t[r]=e[r])}function ka(t,e){for(var i in e)t[i]=r(e[i])?ka(t[i]||(t[i]={}),e[i]):e[i];return t}function la(t,e){var r,i={};for(r in t)r in e||(i[r]=t[r]);return i}function ma(t){var e=t.parent||F,r=t.keyframes?ia:ha;if(s(t.inherit))for(;e;)r(t,e.vars.defaults),e=e.parent||e._dp;return t}function pa(t,e,r,i){void 0===r&&(r="_first"),void 0===i&&(i="_last");var n=e._prev,a=e._next;n?n._next=a:t[r]===e&&(t[r]=a),a?a._prev=n:t[i]===e&&(t[i]=n),e._next=e._prev=e.parent=null}function qa(t,e){!t.parent||e&&!t.parent.autoRemoveChildren||t.parent.remove(t),t._act=0}function ra(t){for(var e=t;e;)e._dirty=1,e=e.parent;return t}function ua(t){return t._repeat?_t(t._tTime,t=t.duration()+t._rDelay)*t:0}function wa(t,e){return(t-e._start)*e._ts+(0<=e._ts?0:e._dirty?e.totalDuration():e._tDur)}function xa(t){return t._end=aa(t._start+(t._tDur/Math.abs(t._ts||t._rts||B)||0))}function ya(t,e){var r;if((e._time||e._initted&&!e._dur)&&(r=wa(t.rawTime(),e),(!e._dur||gt(0,e.totalDuration(),r)-e._tTime>B)&&e.render(r,!0)),ra(t)._dp&&t._initted&&t._time>=t._dur&&t._ts){if(t._dur<t.duration())for(r=t;r._dp;)0<=r.rawTime()&&r.totalTime(r._tTime),r=r._dp;t._zTime=-B}}function za(t,e,r,i){return e.parent&&qa(e),e._start=aa(r+e._delay),e._end=aa(e._start+(e.totalDuration()/Math.abs(e.timeScale())||0)),function _addLinkedListItem(t,e,r,i,n){void 0===r&&(r="_first"),void 0===i&&(i="_last");var a,s=t[i];if(n)for(a=e[n];s&&s[n]>a;)s=s._prev;s?(e._next=s._next,s._next=e):(e._next=t[r],t[r]=e),e._next?e._next._prev=e:t[i]=e,e._prev=s,e.parent=e._dp=t}(t,e,"_first","_last",t._sort?"_start":0),t._recent=e,i||ya(t,e),t}function Aa(t,e){return(at.ScrollTrigger||L("scrollTrigger",e))&&at.ScrollTrigger.create(e,t)}function Ba(t,e,r,i){return qt(t,e),t._initted?!r&&t._pt&&(t._dur&&!1!==t.vars.lazy||!t._dur&&t.vars.lazy)&&d!==Mt.frame?(ot.push(t),t._lazy=[e,i],1):void 0:1}function Ea(t,e,r){var i=t._repeat,n=aa(e)||0;return t._dur=n,t._tDur=i?i<0?1e10:aa(n*(i+1)+t._rDelay*i):n,t._time>n&&(t._time=n,t._tTime=Math.min(t._tTime,t._tDur)),r||ra(t.parent),t.parent&&xa(t),t}function Fa(t){return t instanceof Bt?ra(t):Ea(t,t._dur)}function Ha(t,e){var r,i,a=t.labels,s=t._recent||mt,o=t.duration()>=E?s.endTime(!1):t._dur;return n(e)&&(isNaN(e)||e in a)?"<"===(r=e.charAt(0))||">"===r?("<"===r?s._start:s.endTime(0<=s._repeat))+(parseFloat(e.substr(1))||0):(r=e.indexOf("="))<0?(e in a||(a[e]=o),a[e]):(i=+(e.charAt(r-1)+e.substr(r+1)),1<r?Ha(t,e.substr(0,r-1))+i:o+i):null==e?o:+e}function Ia(t,e){return t||0===t?e(t):e}function Ka(t){return(t+"").substr((parseFloat(t)+"").length)}function Na(t,e){return t&&r(t)&&"length"in t&&(!e&&!t.length||t.length-1 in t&&r(t[0]))&&!t.nodeType&&t!==i}function Qa(t){return t.sort(function(){return.5-Math.random()})}function Ra(t){if(o(t))return t;var p=r(t)?t:{each:t},_=zt(p.ease),m=p.from||0,g=parseFloat(p.base)||0,v={},e=0<m&&m<1,y=isNaN(https://requirejs.org/docs/errors.html#mismatch at makeError (require.js:168:17) at intakeDefines (require.js:1254:36) at Object.localRequire [as require] (require.js:1446:21) at requirejs (require.js:1797:24) at custom.js:32:1 makeError @ require.js:168 intakeDefines @ require.js:1254 localRequire @ require.js:1446 requirejs @ require.js:1797 (anonymous) @ custom.js:32 testrahul.js:1 hiiiiiiiiiiiiiiiiiiiiiiiii testrahul.js:42 Service Worker registered with scope: https://totalfood.greenhonchos.in/ totalfood.greenhonchos.in/:1100 [Intervention] Images loaded lazily and replaced with placeholders. Load events are deferred. See https://go.microsoft.com/fwlink/?linkid=2048113 customtest.js:34 gsap test[object Object] customtest.js:35 {"Back":{},"Bounce":{},"CSSPlugin":{"name":"css","aliases":{"autoAlpha":"opacity,visibility","scale":"scaleX,scaleY","alpha":"opacity","transform":"x,y,z,scale,scaleX,scaleY,xPercent,yPercent,rotation,rotationX,rotationY,skewX,skewY","translateX":"x","translateY":"y","translateZ":"z","rotate":"rotation","rotationZ":"rotation","rotateZ":"rotation","rotateX":"rotationX","rotateY":"rotationY"},"core":{}},"Circ":{},"Cubic":{},"Elastic":{},"Expo":{},"Linear":{},"Power0":{},"Power1":{},"Power2":{},"Power3":{},"Power4":{},"Quad":{},"Quart":{},"Quint":{},"Sine":{},"SteppedEase":{},"Strong":{},"default":{"utils":{},"effects":{},"ticker":{"time":0.537,"frame":5,"_listeners":[null]},"plugins":{},"globalTimeline":{"vars":{"sortChildren":false,"defaults":{"duration":0.5,"overwrite":false,"delay":0},"autoRemoveChildren":true,"id":"root","smoothChildTiming":true},"_delay":0,"_repeat":0,"_ts":1,"_dur":0,"_tDur":0,"labels":{},"smoothChildTiming":true,"autoRemoveChildren":true,"_sort":false,"_dirty":0,"_zTime":0.006,"_tTime":0.537,"_time":0.537,"_act":false,"_initted":1},"core":{},"version":"3.3.1"},"gsap":{"utils":{},"effects":{},"ticker":{"time":0.537,"frame":5,"_listeners":[null]},"plugins":{},"globalTimeline":{"vars":{"sortChildren":false,"defaults":{"duration":0.5,"overwrite":false,"delay":0},"autoRemoveChildren":true,"id":"root","smoothChildTiming":true},"_delay":0,"_repeat":0,"_ts":1,"_dur":0,"_tDur":0,"labels":{},"smoothChildTiming":true,"autoRemoveChildren":true,"_sort":false,"_dirty":0,"_zTime":0.006,"_tTime":0.537,"_time":0.537,"_act":false,"_initted":1},"core":{},"version":"3.3.1"}} customtest.js:36 Uncaught TypeError: gsap.to is not a function at customtest.js:36:14 at Object.execCb (require.js:1696:33) at Module.check (require.js:883:51) at Module.<anonymous> (require.js:1139:34) at require.js:134:23 at require.js:1189:21 at each (require.js:59:31) at Module.emit (require.js:1188:17) at Module.check (require.js:938:30) at Module.enable (require.js:1176:22) (anonymous) @ customtest.js:36 execCb @ require.js:1696 check @ require.js:883 (anonymous) @ require.js:1139 (anonymous) @ require.js:134 (anonymous) @ require.js:1189 each @ require.js:59 emit @ require.js:1188 check @ require.js:938 enable @ require.js:1176 init @ require.js:788 (anonymous) @ require.js:982 (anonymous) @ require.js:134 (anonymous) @ require.js:1189 each @ require.js:59 emit @ require.js:1188 check @ require.js:938 enable @ require.js:1176 init @ require.js:788 (anonymous) @ require.js:1014 (anonymous) @ require.js:134 runCallbacks @ domReady.js:24 callReady @ domReady.js:35 pageLoaded @ domReady.js:50 setTimeout (async) (anonymous) @ domReady.js:94 execCb @ require.js:1696 check @ require.js:883 enable @ require.js:1176 init @ require.js:788 callGetModule @ require.js:1203 completeLoad @ require.js:1590 onScriptLoad @ require.js:1717 load (async) req.load @ require.js:1942 load @ require.js:1685 load @ require.js:834 fetch @ require.js:824 check @ require.js:856 enable @ require.js:1176 enable @ require.js:1557 callPlugin @ require.js:1098 fetch @ require.js:824 check @ require.js:856 enable @ require.js:1176 enable @ require.js:1557 (anonymous) @ require.js:1161 (anonymous) @ require.js:134 each @ require.js:59 enable @ require.js:1113 init @ require.js:788 (anonymous) @ require.js:1460 setTimeout (async) req.nextTick @ require.js:1815 localRequire @ require.js:1449 requirejs @ require.js:1797 (anonymous) @ customtest.js:29 current_location_modal.js:11 custom-checkout location/index/index/ current_location_modal.js:21 test modal compat.js:43 Fallback to JQueryUI Compat activated. Your store is missing a dependency for a jQueryUI widget. Identifying and addressing the dependency will drastically improve the performance of your site. (anonymous) @ compat.js:43 execCb @ require.js:1696 check @ require.js:883 (anonymous) @ require.js:1139 (anonymous) @ require.js:134 (anonymous) @ require.js:1189 each @ require.js:59 emit @ require.js:1188 check @ require.js:938 (anonymous) @ require.js:1139 (anonymous) @ require.js:134 (anonymous) @ require.js:1189 each @ require.js:59 emit @ require.js:1188 check @ require.js:938 enable @ require.js:1176 init @ require.js:788 (anonymous) @ require.js:1014 (anonymous) @ require.js:134 (anonymous) @ mixins.js:129 execCb @ require.js:1696 check @ require.js:883 (anonymous) @ require.js:1139 (anonymous) @ require.js:134 (anonymous) @ require.js:1189 each @ require.js:59 emit @ require.js:1188 check @ require.js:938 (anonymous) @ require.js:1139 (anonymous) @ require.js:134 (anonymous) @ require.js:1189 each @ require.js:59 emit @ require.js:1188 check @ require.js:938 enable @ require.js:1176 init @ require.js:788 (anonymous) @ require.js:1014 (anonymous) @ require.js:134 (anonymous) @ mixins.js:129 execCb @ require.js:1696 check @ require.js:883 (anonymous) @ require.js:1139 (anonymous) @ require.js:134 (anonymous) @ require.js:1189 each @ require.js:59 emit @ require.js:1188 check @ require.js:938 (anonymous) @ require.js:1139 (anonymous) @ require.js:134 (anonymous) @ require.js:1189 each @ require.js:59 emit @ require.js:1188 check @ require.js:938 enable @ require.js:1176 init @ require.js:788 (anonymous) @ require.js:1014 (anonymous) @ require.js:134 (anonymous) @ mixins.js:129 execCb @ require.js:1696 check @ require.js:883 (anonymous) @ require.js:1139 (anonymous) @ require.js:134 (anonymous) @ require.js:1189 each @ require.js:59 emit @ require.js:1188 check @ require.js:938 enable @ require.js:1176 init @ require.js:788 callGetModule @ require.js:1203 completeLoad @ require.js:1590 onScriptLoad @ require.js:1717 load (async) req.load @ require.js:1942 load @ require.js:1685 load @ require.js:834 fetch @ require.js:824 check @ require.js:856 enable @ require.js:1176 enable @ require.js:1557 (anonymous) @ require.js:1161 (anonymous) @ require.js:134 each @ require.js:59 enable @ require.js:1113 init @ require.js:788 (anonymous) @ require.js:1460 setTimeout (async) req.nextTick @ require.js:1815 localRequire @ require.js:1449 load @ mixins.js:128 (anonymous) @ require.js:1095 (anonymous) @ require.js:134 on @ require.js:517 callPlugin @ require.js:955 fetch @ require.js:824 check @ require.js:856 enable @ require.js:1176 enable @ require.js:1557 (anonymous) @ require.js:1161 (anonymous) @ require.js:134 each @ require.js:59 enable @ require.js:1113 init @ require.js:788 callGetModule @ require.js:1203 completeLoad @ require.js:1590 onScriptLoad @ require.js:1717 load (async) req.load @ require.js:1942 load @ require.js:1685 load @ require.js:834 fetch @ require.js:824 check @ require.js:856 enable @ require.js:1176 enable @ require.js:1557 (anonymous) @ require.js:1161 (anonymous) @ require.js:134 each @ require.js:59 enable @ require.js:1113 init @ require.js:788 (anonymous) @ require.js:1460 setTimeout (async) req.nextTick @ require.js:1815 localRequire @ require.js:1449 load @ mixins.js:128 (anonymous) @ require.js:1095 (anonymous) @ require.js:134 on @ require.js:517 callPlugin @ require.js:955 fetch @ require.js:824 check @ require.js:856 enable @ require.js:1176 enable @ require.js:1557 (anonymous) @ require.js:1161 (anonymous) @ require.js:134 each @ require.js:59 enable @ require.js:1113 init @ require.js:788 callGetModule @ require.js:1203 completeLoad @ require.js:1590 onScriptLoad @ require.js:1717 load (async) req.load @ require.js:1942 load @ require.js:1685 load @ require.js:834 fetch @ require.js:824 check @ require.js:856 enable @ require.js:1176 enable @ require.js:1557 (anonymous) @ require.js:1161 (anonymous) @ require.js:134 each @ require.js:59 enable @ require.js:1113 init @ require.js:788 callGetModule @ require.js:1203 completeLoad @ require.js:1590 onScriptLoad @ require.js:1717 load (async) req.load @ require.js:1942 load @ require.js:1685 load @ require.js:834 fetch @ require.js:824 check @ require.js:856 enable @ require.js:1176 enable @ require.js:1557 (anonymous) @ require.js:1161 (anonymous) @ require.js:134 each @ require.js:59 enable @ require.js:1113 init @ require.js:788 (anonymous) @ require.js:1460 setTimeout (async) req.nextTick @ require.js:1815 localRequire @ require.js:1449 requirejs @ require.js:1797 (anonymous) @ (index):418
  7. I've tested on my Mac and I don't see what you mean, sorry. Your code seems quite inefficient to me. This is a bit better, although it could be further optimized: https://codepen.io/GreenSock/pen/xxeOjLZ?editors=1010 Make sure you overwrite previous tweens so you're not continually creating new conflicting ones that are fighting for the same property. And a modifier is better than an onUpdate for what you're doing. Are you saying that when you scroll all the way to the bottom of the page, you want your x animation to suddenly stop? Does it work the way you want if you REMOVE Lenis? That's not a GreenSock product, so we can't really support that. I think the whole point of Lenis is that it'll smooth the scroll so that it doesn't suddenly stop, so I wonder if what you're asking is more of a Lenis question, not a GSAP one(?)
  8. Hi, Thank you again for clarifying on the issues in the implementation of logic. The solution works well in the CodePen, but I observed a strange issue with Pinned container in my actual project. Unfortunately this does not happen in CodePen and I don't know how can I explain it well enough for you to understand. But let me try. Whenever I am scrolling with container pinned, and like 1 or 2 of the 4 cards have already animated (to the top), if I refresh the page at that very point, and when the page reloads, it doesn't seem to start from that particular point - say for example, when container gets pinned and all the cards animate to the top with stagger, and then I scroll further to animate first card to the top, then I refresh the page, it logs card's index "0 enter" but the card will be still there. And when I scroll further, the next card starts animating with the first card still there. To investigate on this issue I commented out all the code keeping only the pinned trigger, initial set method for cards and the main ScrollTrigger for staggered animation of cards like below mentioned code. To my surprise, this didn't work as well - it works fine when I have not scrolled to the pinned section and reload, but when I try to reload the page after scrolling into the pinned section the trigger markers jump to some unimaginable point(usually at the very top of the page), not at all at the same point before reload. And the cards animation stops there because the it will never hit the trigger. Upon carefully observing this, I saw a strange jumping behavior of scrollbar thumb whenever page reloads, it goes up once and then come to the original position or vice versa sometimes. In CodePen it always stayed at the top on refresh, although I don't have any specific code to scroll to the top on reload, but this is how it is. To check it further, I commented-out the pinned container ScrollTrigger and the reloaded the page - to my surprise, this time the scroll thumb was not jumping up and down at all, it stayed there no matter whatever the scroll position is. So, pinning the container is causing the issue here. I hope I made myself clear about the issue I am facing here, unfortunately I am not able to show this very awkward behavior with pinned sections. And I do not have any clue on how do I resolve this. Please help. ScrollTrigger.create({ id: "pinned", trigger: '.pinned', start: 'top top', pin: true, end: "+=" + pinDistance, }); gsap.set(cards, { y: 1000, rotate: (index) => -angle * index, zIndex: (index) => cards.length - index, }); ScrollTrigger.create({ trigger: '.cards_wrap', start: 'top top', end: 'bottom bottom', // markers: true, onEnter() { console.log("enter"); gsap.to('.card', { y: 0, duration: 1, delay: 0.5, stagger: { amount: 0.5 }, overwrite: true, }); }, onLeaveBack() { console.log("leave back"); gsap.to('.card', { y: 1000, duration: 1, stagger: { amount: 0.5, }, overwrite: true }); } });
  9. I noticed several problems: It's extremely inefficient code, performance-wise. Every single time the user scrolls at all, you're creating new tweens on the same elements, over and over and over again, without even overwriting (so they'd be fighting for control). At the very least, I'd recommend setting overwrite: "auto" or overwrite: true, but honestly I think I'd re-engineer the entire approach so you're not constantly doing that on every scroll. It's much more efficient to animate to scale: 0.9 or scale: 1 instead of transform: "scale(0.9)" or transform: "scale(1)". And instead of constantly creating new tweens, if your goal is to just go back and forth between those two values, why not just create a single tween instance and then play() or reverse() it? You created a "timeline" variable and you only put a set() call in it, so it literally has no duration at all. Well, it's 0 seconds. And then you're restarting that but I assume you're asking us how you could smoothly go back to that initial value, right? If so, just create a tween that goes to that value. You're not doing any cleanup of your Lenis stuff. Beware that React calls hooks TWICE in strict mode. So be careful - you might accidentally be creating redundant Lenis stuff. That's not a GreenSock product, so we can't really support it here. It's very difficult to offer advice when we don't have a minimal demo. If you'd like more help, please make sure you create a minimal demo that clearly illustrates the issue. That'll GREATLY increase your chances of getting a good answer. Here's a starter template with Next.js that you can fork: https://stackblitz.com/edit/nextjs-5cm4qn
  10. Hi @Federico2811 welcome to the forum! The issue here is your CSS position fixed and probably also bootstrap which adds scroll-behavior: smooth; which you'll need to overwrite with scroll-behavior: auto !important; (they either put it on the body or the html or everything I don't know anymore) Next you're overwriting the default scroll of the browser, you need to be a really skilled web developer and 100% know what you're doing if you want to take that control away from the browser and roll you're own! I've been doing this for over 10 years now and I've never needed to overwrite the scroll in that way. Here is your demo with the overflow and position properties set back to normal and now ScrollTrigger works like a charm. If I was you I would restructure your layout a bit and pin the element that contains all your elements instead of creating position: fixed; elements you can even pin the body like so pin: "body", but better is to create an element, something like #pinMe an use that as the pin. As you've found you can indeed set a different scroller in ScrollTrigger, but there was to much code in your minimal demo to figure out how that would work, my advise first do it the 'normal; way, by having the browser handle the scrolling, before you do your custom scroll and again you really need to know what you're doing if you want to go that route. Hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/ExMjqvV?editors=1010
  11. Welcome to the forum! In that video you attached, it very much looks like you have CSS transitions applied on elements that are affected by ScrollTrigger. Themes like Elementor often apply something like transition: all .3s to lots of elements - those will interfere with GSAP, so you'll have to make sure to overwrite them in your custom CSS. On top of that I would also make sure to overwrite the scroll-behaviour to auto because if I recall correctly, Elementor will by default set it to smooth, which can also interfere with your scroll related JS at some point. I hope this will help already. If it doesn't, unfortunatelly we won't be able to help without a minimal demo clearly demonstrating your issue. Good luck.
  12. Hello, I wanted to ask - is it possible to run the from() animation on an element after the to() animation has worked on it? Here's an example, first I run the to() animation: let hideSearchTl = gsap.timeline({ defaults: { ease: 'cubic-1', duration: 0.2, overwrite: true, }, }), elements = $('selector'); hideSearchTl.to(elements, { width: 0, autoAlpha: 0, padding: 0, }); Then, when performing certain actions, I want to return the element with a from() animation: hideSearchTl.from(elements, { width: 0, autoAlpha: 0, padding: 0, }); Using reverse() is not entirely suitable (or I don’t know how to use it) because it “reverses” the easy property. I need easy the same as in to() animation. As far as I understand the complexity in the filled style attribute, I just can’t come up with a solution.
  13. Hi, I am building a slider based on this example https://codepen.io/andrei-savu/pen/BaPqzvX It works when it's alone on a page, https://yaojuilan.art/gsap While it isn't working when there is something else https://yaojuilan.art/system_of_conductors/field-walk#kinmen (the slider works sometime. it is unstable. ) I tried logging out the observer onChange, the event does trigger, but the items just would not do the horizontal transition. I am wondering if observer has some sort of limitation, or maybe observer listener is interfering with something? Sorry i did not create a codepen, because this component does works standalone. Here is the slider component export default async function Page() { const data= await getPageContent() return ( <div id='intro' className='relative h-auto w-full overflow-x-hidden'> <div className='h-[50vh] w-full'> some content </div> <Slider items={data?.carousel_img?.images} /> <div className='h-[200vh] w-full bg-red-100'> some content </div> </div> ) } export default function Slider({ items, section }) { useGSAP(() => { let loop = horizontalLoop(`.carousel-${section} li`, { repeat: -1 }) let slow = gsap.to(loop, { timeScale: 0, duration: 0.5 }) loop?.timeScale(0) Observer.create({ target: `.carousel-${section}`, type: 'pointer,touch,wheel', wheelSpeed: -1, preventDefault: true, onChange: (self) => { loop.timeScale(Math.abs(self.deltaX) > Math.abs(self.deltaY) ? -self.deltaX : -self.deltaY) // whichever direction is bigger slow.invalidate().restart() // now decelerate }, }) }) return ( <div className='absolute bottom-12 w-full cursor-grab overflow-hidden'> <ul className={`carousel-${section} carousel flex flex-nowrap pl-0`}> {items?.map((item, i) => ( <li key={i}> <Image alt={'collective of images'} src={item} width={150} height={150} sizes='100vw' className='pointer-events-none touch-none select-none ' /> </li> ))} </ul> </div> ) } function horizontalLoop(items, config) { items = gsap.utils.toArray(items) if (!items.length) return 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 }
  14. 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 !
  15. Very thanks, moreover I found that my code has a transition property from default css, I needed to overwrite it
  16. Here are some of the problems I noticed: You were adding a new "mouseleave" event handler on EVERY "mousemove" event, so when the mouse left the button, there were probably thousands of those firing, all trying to tween the same properties of the same element. Massively wasteful. You weren't applying any overwrite logic, so you were creating a bunch of overlapping tweens, all controlling the same stuff. I'd recommend using gsap.quickTo() for the best performance on things where you're constantly interrupting and trying to go to new destinations. You were using pageX/pageY instead of clientX/clientY for measurements, thus after scrolling the calculations would be incorrect. You were only applying the magnetic affect to one .btn instead of all of them. Just loop through them accordingly. You were using an onscroll listener, but you might want to consider using ScrollTrigger instead because it simplifies things. Maybe this will help: https://codepen.io/GreenSock/pen/QWooxbG?editors=0010
  17. Hi @isaac19197 welcome to the forum! It is hard to debug your setup from just a code snippet (also because this is just 1/3 of the setup, CSS and HTML is really important, to get a proper inside of what is going on). It can be fairly difficult to target the same element with different tweens and have them fight for control. There is a few things you can try, set immediateRender: false, to the later tween or overwrite: true. You can also do an onComplete call back on your first tween and only create the ScrollTrigger instance if the original animation has finished playing. These are just some things I can say on top of my head . If you still need help please create a minimal demo, so that we can take a look at your code in action. Side note I see you've found the .to() and .fromTo() tweens, but have you also seen .from()? For instance you can rewrite your frist tween like so, which will do the same as your .fromTo() tween .from(mainText, { opacity: 0, // Will animate from to browser default 1 scale: 0.5, // will animate from to browser default 1 duration: 1 }) Hope it helps and happy tweening! And here a Codepen demo you can just fork which loads all the GSAP plugins https://codepen.io/GreenSock/pen/aYYOdN
  18. Yeah, to avoid that your HTML/CSS needs some basic structure first, then figure a way to animate said structure. Sometimes is necessary to overwrite something set in the CSS files in order to make something work as expected. Finally in over 12 years of doing web development I've never heard of a single person who told me that ran into an user that had JS disabled on the browser. Normal users don't do that, so more than an irrational fear is an unfounded one IMHO. Happy Tweening!
  19. 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; }
  20. I noticed several problems: You're altering the raw attribute values for the <line> elements which fundamentally changes their bounding box and consequently their transform origin calculations. I think it'd be much cleaner to either animate the attributes or the transforms, not both. You could even translate them to <path> elements and use morphSVG (well, if you're a Club GSAP member). You're setting duration and overwrite on a timeline object, but that's not a thing. Did you mean to set {defaults: { duration: .6, overwrite: "auto"}} You created conflicting tweens (wastefully). One tween in the timeline animates ALL the hand rotations, and then you also have another tween for each one of the hands animating them to a different rotation. Same goes for opacity. svgOrigin is not something you animate. It's almost NEVER what people want to do, like if they set .to(".hand", {rotation: 360, svgOrigin: "100 100"}) they just want it to rotate around that spot (so set the svgOrigin immediately) rather than slowly over time moving svgOrigin to that spot. If you really need to animate that (and again, almost nobody ever actually needs to do that), you could use a proxy object and apply it in an onUpdate. You had 3 values in the svgOrigin, like "100 100 90" but that's not valid. SVGs can only be 2D (so 2 values, not 3). I'd probably approach it more like this: https://codepen.io/GreenSock/pen/WNPdbjB I hope that helps.
  21. I've implemented a horizontal scrolling feature using GSAP. However, when I click on a link in the nav, it does not link me to the exact location of each section. Here's the website I've made: https://southfield-center.webflow.io/ Here's the GSAP code I used: <script src="https://unpkg.co/gsap@3/dist/gsap.min.js"></script> <script src="https://unpkg.com/gsap@3/dist/ScrollTrigger.min.js"></script> <script src="https://unpkg.com/gsap@3/dist/ScrollToPlugin.min.js"></script> <script> gsap.registerPlugin(ScrollTrigger); function getScrollLookup(targets, { start, pinnedContainer, containerAnimation }) { let triggers = gsap.utils.toArray(targets).map((el) => ScrollTrigger.create({ trigger: el, start: start || "top top", pinnedContainer: pinnedContainer, refreshPriority: -10, containerAnimation: containerAnimation, }) ); return (target) => { let t = gsap.utils.toArray(target)[0]; let i = triggers.length; while (i-- && triggers[i].trigger !== t) {} if (i < 0) { return console.warn("target not found", target); } return containerAnimation ? st.start + (triggers[i].start / containerAnimation.duration()) * (st.end - st.start) : triggers[i].start; }; } // Function to initialize the scroll animation function initScrollAnimation() { let sections = gsap.utils.toArray(".section"), navLinks = document.querySelectorAll(".gsap-code"), nav = document.querySelectorAll(".nav"), getMaxWidth = () => { let width = 0; sections.forEach((section) => { const rect = section.getBoundingClientRect(); width += rect.width; console.log(`Section ${section.id} width: ${rect.width}`); }); return width; }, maxWidth = getMaxWidth(), scrollSpeed = 16, snapProgress, lastScrollTween = Date.now(), curIndex = 0, tl = gsap.timeline(); tl.to(sections, { x: () => window.innerWidth - maxWidth, duration: 1, ease: "none", }); ScrollTrigger.create({ animation: tl, trigger: ".scrollable-div", pin: true, scrub: 1, invalidateOnRefresh: true, }); function init() { gsap.set(sections, { x: 0 }); maxWidth = getMaxWidth(); let position = 0, distance = maxWidth - window.innerWidth; tl.add("label0", 0); sections.forEach((section, i) => { let progress = position; const rect = section.getBoundingClientRect(); position += rect.width / distance; tl.add("label" + (i + 1), position); if (i < navLinks.length) { navLinks[i].onclick = () => { snapProgress = progress; lastScrollTween = Date.now(); curIndex = i; gsap.to(window, { scrollTo: maxWidth / scrollSpeed * progress, duration: 1, overwrite: "auto" }); }; } }); } init(); ScrollTrigger.addEventListener("refreshInit", init); ScrollTrigger.create({ trigger: ".section_about", start: "top top", onToggle: (self) => { if (self.isActive) { gsap.set(nav, { display: "flex" }); } else { gsap.set(nav, { display: "none" }); } }, }); let getPosition = getScrollLookup(".section", { start: "center center", containerAnimation: tl, }); navLinks.forEach((link) => { link.onclick = (e) => { e.preventDefault(); let target = e.target.getAttribute("href"); gsap.to(window, { scrollTo: getPosition(target), duration: 1, overwrite: "auto" }); }; }); } if (window.innerWidth >= 992) { initScrollAnimation(); } </script>
  22. @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
  23. Have you ever been in a situation with GSAP where you needed a higher level of control over conflicting tweens? If you’re just creating linear, self-playing animations like banner ads, chances are the default overwrite mode of false will work just fine for you. However, in cases where you are creating tweens dynamically based on user interaction or random events you may need finer control over how conflicts are resolved. Overwriting refers to how GSAP handles conflicts between multiple tweens on the same properties of the same targets at the same time. The video below explains GSAP’s overwrite modes and provides visual examples of how they work. Want to master GSAP? Enroll in CreativeCodingClub.com and unlock 5 premium GreenSock courses with over 90 lessons. New lessons like this one are added weekly to keep your learning fresh. GSAP’s 3 Overwrite Modes false (default): No overwriting occurs and multiple tweens can try to animate the same properties of the same target at the same time. One way to think of it is that the tweens remain "fighting each other" until one ends. true: Any existing tweens that are animating the same target (regardless of which properties are being animated) will be killed immediately. "auto": Only the conflicting parts of an existing tween will be killed. If tween1 animates the x and rotation properties of a target and then tween2 starts animating only the x property of the same targets and overwrite: "auto" is set on the second tween, then the rotation part of tween1 will remain but the x part of it will be killed. Setting Overwrite Modes // Set overwrite on a tween gsap.to(".line", { x: 200, overwrite: true }); // Set overwrite globally for all tweens gsap.defaults({ overwrite: true }); // Set overwrite for all tweens in a timeline const tl = gsap.timeline({ defaults: { overwrite: true } }); Below is the demo used in the video. Open it in a new tab to experiment with the different overwrite modes See the Pen overwrite demo by SnorklTV(@snorkltv) on CodePen. Hopefully this article helps you better understand how much control GSAP gives you. Overwrite modes are one of those features that you may not need that often, but when you do, they can save you hours of trouble writing your own solution. For more tips like this and loads of deep-dive videos designed to help you quickly master GSAP, check out CreativeCodingClub.com. You’re going to love it.
  24. juste a self note, this will make tl more hard to manage: example: so i need to alway think to override complexe tl. example here the pivot not work because the last crush the first ! am not sure i understand what happen underhood ! It's a shame not to have an understanding to just overwrite the delays and keep the classic behavior on auto.
  25. we can play animations when we click on the Nav "Slides 1 2 3..." and i want it to start as Slides[0] index array element that is Slide A as already Played or Finished animation, and then we can click on Nav slides to play the animation the issue im having is, i want when i click on Slide 2 3 4 or 5 it should Overwrite gsap.set property Slides[0] by GSAPSlideTL or in other words Slides[0] is not working when click animation to play GSAPSlideTL thank you
×
×
  • Create New...