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

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. Hi @latteouka. Thanks for sharing. I don't have time to dig through all that code but I wanted to make sure I pointed out that this is not true: There are no such limits. But you shouldn't create multiple simultaneous tweens that are all trying to control the same property of the same element because obviously the same value can't go in a bunch of different directions at the same time. You might want to consider overwrite: "auto" which only overwrites individual overlapping properties rather than entire tweens (which is what overwrite: true does). If you've got any GSAP-specific questions that you'd like answered, feel free to post them here.
  2. Really like the idea because I don't need to install any other dependencies. Also the logic of the intro/outro animation can be clear thanks to GSAP. I tried to do some page transitions with Next.js and three.js using this technique. What I want to achieve is to combine both html and threejs element in intro/outro animations. Demo After I finished the demo, I wrap the context into a tiny package for my own reuse. @chundev/gtranz I remove the setTimeline, background, setBackground in the context because I didn't use them at all and that also make sure context does not trigger re-render because of state change. The context itself is very simple you can just grab the code from src folder if you need it. I want to share the biggest problem I encountered. As I wrote in the Github readme, if I tweened something that is already be set in the outro. (I need instant scroll animation of the images which are also the outro elements) That will break the transition later because as I researched, one element can only have one tween at a time. (I could barely find information about this topic and struggled for a while) So I set the default to overwrite:true (default is false, in the original post, it only do the simplest css intro/outro so no problems) and arrange the order of animation setup by myself. What I did was: 1. use a state to determine the setup order of intro/outro. (if you overwrite some tweens that are used in the outro.) 2. use custom event to re-setup outro whenever you want (mostly after the animation that tweened the same element, with onComplete callback) I don't really know if it's good practice or not. But I did solve my problem and make nice transition by doing so. Just want to share my experience. I really love this community and learn so much things here. Thank you!
  3. Hey @Rodrigo, Thanks for the recommendations here! I have implemented them and everything is much smoother. My message above was about creating a lerp type of effect fpr the cards using the velocityY property - that's what that this chunk is trying to do using onUp or onDown: const posSetter = gsap.quickSetter(cards, "x", "%"); const clamp = gsap.utils.clamp(-20, 20); const lerp = [8, 16, 24]; const proxy = { x: 0 }; Observer.create({ target: cardItems, type: "wheel,touch,pointer", onUp: (self) => { let lapsedProgress; if (lapsedProgress === 1) return; lapsedProgress = scrollTl.progress() - 0.075; progressTo(lapsedProgress); const x = clamp((self.velocityY / -300) * lerp[Math.floor(Math.random() * lerp.length)]); if (Math.abs(x) > Math.abs(proxy.x)) { proxy.x = x; gsap.to(proxy, { x: 0, duration: 0.8, ease: "none", overwrite: true, onUpdate: () => posSetter(proxy.x) }); } }, }) I guess this is a better example of what i'm trying to do, but wanted to use the velocityY property: https://codepen.io/GreenSock/pen/wvMeNee?editors=0010 Do you think this is doable or should I go down the route of the above example? Here is the updated Codepen for reference: https://codepen.io/jackkemm/pen/RwearyE?editors=0011 EDIT: One thing I noticed too, on mobile/touch devices, the scroll is in the opposite direction. I have tried adding -1 to wheelSpeed and scrollSpeedfor touch devices but the scroll is still in the opposite direction. Is there a way to change this? Thanks, Jack
  4. I'll also have to read up on the overwrite: true. I hadn't come across that in my Googling, either.
  5. Yep, sorta like this: https://codepen.io/GreenSock/pen/oNaxdje?editors=1010 Better? And the reason the killTweensOf() helped is because you were creating a TON of conflicting tweens all trying to control the same properties of the same element. You could have solved it equally well by setting overwrite: true. None of that is necessary if you use the gsap.quickTo() technique.
  6. @GreenSock I would like to re-open this topic once more. On the same example, try to scroll using laptop trackpad, as using mouse it seems to be working fine. And try to do long, short scrolls. The scrollbar then goes to the end of next section, but automatically scrolls back to to top section. overwrite or autoKill seems not helping
  7. It looks like you're creating a ton of conflicting tweens that are fighting with each other. Set overwrite: true on your tween to have it immediately kill all other tweens of the same target. And I'm not sure why you're using two different ScrollTriggers for each element - why not just use one? https://stackblitz.com/edit/vue-fchh5m?file=src%2FApp.vue
  8. @Cassie @GreenSock Thanks for the reply, however I am using 2 timelines with same pin value, as I need to implement the following scenarios 1. I need to scale out the image or video from starting to its final value - Timeline 1 with same pin value. - It's working perfectly ( imageTimelineAnimation in the below code) 2. The second timeline is for snap scrolling the other images / Videos while the component is pinned. - Timeline 2 - This also works. (snapScrollAnimation in the below code) however the pinning is working and animation also plays smooth, but it's leaving large space at the bottom for desktop, tablet, mobile. I am adding margin bottom to the main container to adjust the bottom spacing. but while doing snap scrolling until I reach the last element it never appears on the screen, I have given fixed height for the container as well but not helping. I want to make the next element of the container to be maintaining the exact bottom spacing which I want to but struggling to achieve that. Need your suggestion if you know anything I'm missing. The elements I'm making animations are inside a grid container - FYI I understand that it'll be tough to understand to provide any suggestions based on the explanation on this, but whatever I know I have posted here to seek help on this. I would like to tell you that it's a really great package, you guys are Rockstars. Keep rocking. This is my code for your reference, it's huge but it gives you overall picture of what I'm trying to do ( Starting Point InitializeAnimation ) import gsap from 'gsap'; import { ScrollTrigger } from 'gsap/dist/ScrollTrigger'; export function getScrollY() { return window.pageYOffset != null ? window.pageYOffset : document.documentElement.scrollTop != null ? document.documentElement.scrollTop : document.body.scrollTop; } export function isLandscape() { return window?.matchMedia('(orientation: landscape)')?.matches; } export function detectTabletOrientation() { return isLandscape() && window.innerWidth < 1180 ? '10% 65%' : isLandscape() && window.innerWidth >= 1180 && window.innerWidth < 1400 ? '10% 80%' : '20% 50%'; } let currentCount = 0; // Text Area - START export const slidePrevNextText = (current, next) => { const currentText = gsap.fromTo( current, { autoAlpha: 1, duration: 1, overwrite: 'auto', paused: true, x: 0, }, { autoAlpha: 0, duration: 1, overwrite: 'auto', paused: true, x: '-200px', } ); const nextText = gsap.fromTo( next, { autoAlpha: 0, duration: 1, overwrite: 'auto', paused: true, x: 0, }, { autoAlpha: 1, duration: 1, overwrite: 'auto', paused: true, x: 0, } ); currentText.play('<'); nextText.play('>'); return [currentText, nextText]; }; export const slidePrevNextTextReverse = (current, next) => { const currentText = gsap.fromTo( current, { autoAlpha: 1, duration: 1, overwrite: 'auto', paused: true, x: 0, }, { autoAlpha: 0, duration: 1, overwrite: 'auto', paused: true, x: 0, } ); const nextText = gsap.fromTo( next, { autoAlpha: 0, duration: 1, overwrite: 'auto', paused: true, x: '-200px', }, { autoAlpha: 1, duration: 1, overwrite: 'auto', paused: true, x: 0, } ); currentText.play('<'); nextText.play('>'); return [currentText, nextText]; }; // Text Area - END // Initial Move out animation for Device asset and Optional Element const mainContainerTween = (id, isTablet, isMobile) => gsap.fromTo( `div#device-${id} .device-outline-border`, { duration: 2, opacity: 1, overwrite: 'auto', paused: true, stagger: 0.1, visibility: 'visible', x: 0, y: 0, yPercent: 0, }, { duration: 2, opacity: 1, overwrite: 'auto', paused: true, stagger: 0.1, visibility: 'visible', x: isTablet ? -135 : -225, y: !isTablet && !isMobile ? -50 : 0, yPercent: !isTablet ? -4 : 0, } ); const childContainerTween = (id, isTablet) => gsap.fromTo( `div#device-${id} div.child-container`, { bottom: '0', duration: 2, left: isTablet ? '9%' : '14%', opacity: 0, overwrite: 'auto', paused: true, position: 'relative', right: '0', stagger: 0.1, top: '-35%', visibility: 'hidden', x: 0, y: !isTablet ? -150 : 0, }, { bottom: '0', duration: 2, opacity: 1, overwrite: 'auto', paused: true, position: 'relative', right: '0', stagger: 0.1, visibility: 'visible', x: isTablet && window.innerWidth < 1024 ? 350 : isTablet && window.innerWidth >= 1024 ? 420 : 520, y: !isTablet ? -125 : -36, } ); const progressButtonTween = (id) => gsap.fromTo( `.progress-container--${id}`, { opacity: 0, overwrite: 'auto', paused: true, visibility: 'hidden', }, { opacity: 1, overwrite: 'auto', paused: true, visibility: 'visible', } ); const progressButtonPositionSet = (id, buttonStyles?) => gsap.set(`.progress-container--${id}`, { ...buttonStyles, }); const progressElementPosition = (id, styles) => gsap.set(`.progress-container--${id}`, { ...styles, }); const fullScreenTween = (id, isTablet?) => gsap.fromTo( `div#device-${id} .full-screen`, { duration: 0.6, opacity: 0, overflowY: isTablet ? 'hidden' : 'auto', visibility: 'hidden', }, { duration: 0.6, opacity: 1, overflowY: 'auto', visibility: 'visible', } ); const firstImageGradientTween = (id) => gsap.fromTo( `div#device-${id} div.asset-overlay`, { duration: 0.6, opacity: 1, paused: true, visibility: 'visible', }, { duration: 0.6, opacity: 0, paused: true, visibility: 'hidden', } ); export const scrollWindowToTween = (value, seconds?) => gsap.to(window, { duration: seconds ? seconds : 2.25, overwrite: 'auto', paused: true, scrollTo: { y: value, }, }); const firstTextAreaTween = (id, isMobile?, isTablet?) => gsap.fromTo( `.tarea--${id}:first-child`, { paused: true, y: 0, }, { paused: true, y: isMobile ? -10 : 0, } ); export const initialImageAnimation = (id, isTablet, isMobile) => { const dCards = gsap?.utils?.toArray(`div.asset--${id} div.asset-component`); const sCards = gsap?.utils?.toArray(`div.optional--${id}`); const [, snapTrigger] = ScrollTrigger.getAll(); return scrollWindowToTween(snapTrigger.start, 2.5) .play() .eventCallback('onStart', () => { firstImageGradientTween(id).play('<'); firstTextAreaTween(id, isMobile, isTablet).play('<'); gsap.to(`div#device-${id} div.drop-shadow`, { opacity: 1, transition: 'opacity 1s, visibility 1s', visibility: 'visible', }); }) .eventCallback('onComplete', () => { if (!isMobile) { if (secondaryCards.length > 0 && window.innerHeight > 719) { mainContainerTween(id, isTablet, isMobile).play('-=2.5'); childContainerTween(id, isTablet) .play('-=2.5') .eventCallback('onStart', () => { if (isTablet && window.innerWidth > 600 && window.innerWidth < 1024) { gsap.to(`div#device-${id} div.child-container`, { inset: window.innerWidth < 820 ? `-20% 0px 0px 2%` : `-20% 0px 0px 7%`, }); } }); } if (dCards.length > 1) { progressButtonTween(id).play('>'); } if (dCards.length >= 1) { fullScreenTween(id, isTablet).play('>'); } } }); }; export const reverseInitialImageAnimation = (id, isTablet, isMobile) => { const dCards = gsap?.utils?.toArray(`div.asset--${id} div.asset-component`); const sCards = gsap?.utils?.toArray(`div.optional--${id}`); const [imageTrigger] = ScrollTrigger.getAll(); return scrollWindowToTween(imageTrigger.start - 50, 2.5) .play() .eventCallback('onStart', () => { firstImageGradientTween(id).reverse('<'); firstTextAreaTween(id).reverse('<'); if (!isMobile) { if (sCards.length > 0) { mainContainerTween(id, isTablet, isMobile).reverse('-=1.5'); childContainerTween(id, isTablet).reverse('-=1.5'); gsap.to(`div#device-${id} div.drop-shadow`, { opacity: 0, transition: 'opacity 1s, visibility 1s', visibility: 'hidden', }); } if (dCards.length > 1) { progressButtonTween(id).reverse(0); } if (dCards.length >= 1) { fullScreenTween(id, isTablet).reverse(0); } } }); }; async function finishOnFastLeave( { isActive, progress, getVelocity, animation, direction }: ScrollTrigger, current: number, id: any ) { const dCards = gsap?.utils?.toArray(`div.parent-container div.asset--${id}`); const sCards = gsap?.utils?.toArray(`div.child-container div.optional--${id}`); const textElements = gsap?.utils?.toArray(`.tarea--${id}`); const progressValue = +progress.toPrecision(2) * 100; const length = dCards.length - 1; const index = Math.round(+(+(progressValue / 100).toPrecision(1) * length).toPrecision(1)); const currentCard: any = dCards[current]; const currentSecondaryCard: any = sCards[current]; const targetCard: any = dCards[index]; const targetSecondaryCard: any = sCards[index]; if (!isActive && Math.abs(getVelocity()) > 1000) { await animation.progress(progress === 1 ? 1 : 0).pause(); slideTween(targetCard, targetSecondaryCard) .play() .eventCallback('onStart', () => { slidePrevNextText(textElements[current], textElements[index]); const currentElements: any = textElements.filter((ele, i) => i !== index); gsap.set([...currentElements], { autoAlpha: 0, }); }) .eventCallback('onComplete', () => { slideTween(currentCard, currentSecondaryCard).reverse(); }); } } // first card Animation here export const firstImageAnimation = (id, setInViewport, isTablet, isMobile, theme) => { const dCards = gsap?.utils?.toArray(`div.asset--${id} div.asset-component`); imageTimelineAnimation = gsap.timeline({ ease: 'Power3.easeOut', paused: true, reversed: true, scrollTrigger: { end: (self) => !isTablet && !isMobile ? self.next().start - 10 : isMobile ? self.next().start : self.next().start - 50, fastScrollEnd: true, invalidateOnRefresh: true, onEnter: () => { setInViewport(true); }, onEnterBack: ({ isActive, animation }) => { if (isActive) { animation.scrollTrigger.vars.scrub = 2; reverseInitialImageAnimation(id, isTablet, isMobile); setInViewport(false); } }, onLeave: () => { if (dCards.length === 1) { setInViewport(false); } }, onLeaveBack: () => { firstImageGradientTween(id).reverse(); }, onToggle: async ({ isActive, getVelocity, direction, animation, progress }) => { if (!isActive && currentCount > 0 && direction === -1 && getVelocity() < 0) { await animation.progress(progress === 1 ? 1 : 0).pause(); gsap.set([`.asset--${id}:first-child`, `.optional--${id}:first-child`], { opacity: 1, visibility: 'visible', yPercent: 0, }); gsap.set([`.asset--${id}:not(:first-child)`, `.optional--${id}:not(:first-child)`], { opacity: 0, visibility: 'hidden', yPercent: 100, }); } }, pin: `.container--${id} div.ui-demo-container--${id}`, scrub: 2, start: () => (isMobile ? '5% 50%' : isTablet ? detectTabletOrientation() : '20% 55%'), trigger: `div.asset-container--${id} div.asset-${id}-0`, // markers: {startColor: 'blue', endColor: 'black'}, }, }); imageTimelineAnimation .fromTo( `div#device-${id} .transparent-border`, { duration: 0.5, opacity: 0.95, outline: 'none', }, { duration: 0.5, onStart: async (self) => { await initialImageAnimation(id, isTablet, isMobile); }, opacity: 1, outline: !isMobile && !isTablet ? '4px solid' : isMobile ? '1.72px solid' : '2px solid', } ) return imageTimelineAnimation; }; export const slideTween = (nextCard, nextSecondaryCard?) => gsap.fromTo( [nextCard, nextSecondaryCard], { autoAlpha: 0, duration: 1.25, paused: true, stagger: 0.1, yPercent: 100, }, { autoAlpha: 1, duration: 1.25, paused: true, stagger: 0.1, yPercent: 0, } ); export const onStartTweens = (currentIndex, nextIndex, textElements) => { slidePrevNextText(textElements[currentIndex], textElements[nextIndex]); const currentElements: any = textElements.filter((ele, i) => i !== currentIndex); gsap.set([...currentElements], { autoAlpha: 0, }); }; function checkIfAnyOverlap(rect1: any, rect2: any) { return !( rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom ); } export const checkForElementOverlap = (id) => { const element = document ?.querySelector(`section#${id} div.ui-demo-container--${id}`) ?.getBoundingClientRect(); const nextSiblingElement = document.querySelector(`section#${id}`)?.nextElementSibling?.getBoundingClientRect(); const mainElement = document.querySelector(`main`).getBoundingClientRect(); if ( (!!nextSiblingElement && checkIfAnyOverlap(element, nextSiblingElement)) || (!!mainElement && checkIfAnyOverlap(element, mainElement)) ) { return !!nextSiblingElement ? nextSiblingElement?.top - element?.bottom : mainElement?.bottom - element?.bottom; } else { return false; } }; export const handleBottomSpacing = (id, isTablet, isMobile) => { const element = document ?.querySelector(`section#${id} div.ui-demo-container--${id}`) ?.getBoundingClientRect(); const childContainer = document?.querySelector(`section#${id} div.child-container`)?.getBoundingClientRect(); const value = element?.bottom > childContainer?.bottom ? Math.round(element?.bottom - childContainer?.bottom) : Math.round(childContainer?.bottom - element?.bottom); if (!isMobile && !isTablet) { gsap.set(`section#${id}`, { marginBottom: element?.bottom > childContainer?.bottom ? (value > 0 ? 96 - value : 96 + value) : 96, }); } else if (!isMobile && isTablet) { gsap.set(`section#${id}`, { marginBottom: element?.bottom > childContainer?.bottom ? (value > 0 ? 64 - value : 64 + value) : 64, }); } }; export const goToCard = (progress: number, direction: number, index: number, currenIndex: number, nextCount: number, id: string) => { const dCards = gsap?.utils?.toArray(`div.parent-container div.asset--${id}`); const sCards = gsap?.utils?.toArray(`div.child-container div.optional--${id}`); const textElements = gsap?.utils?.toArray(`.tarea--${id}`); const currentCard: any = dCards[currenIndex]; const currentSecondaryCard: any = sCards[currenIndex]; const nextCard: any = dCards[nextCount]; const nextSecondaryCard: any = sCards[nextCount]; const targetCard: any = dCards[index]; const targetSecondaryCard: any = sCards[index]; if (index === currenIndex && direction === 1) { slideTween(nextCard, nextSecondaryCard) .play() .eventCallback('onStart', () => onStartTweens(index, nextCount, textElements)) .eventCallback('onComplete', () => { slideTween(currentCard, currentSecondaryCard).reverse(); }); } else if (index === currenIndex && direction === -1) { slideTween(currentCard, currentSecondaryCard).reverse(-0.5); slideTween(nextCard, nextSecondaryCard) .play('-=0.5') .eventCallback('onStart', () => onStartTweens(index, nextCount, textElements)); } else if (index > currenIndex) { slideTween(targetCard, targetSecondaryCard) .play() .eventCallback('onStart', () => onStartTweens(currenIndex, index, textElements)) .eventCallback('onComplete', () => { slideTween(currentCard, currentSecondaryCard).reverse(); }); } else if (index < currenIndex) { slideTween(targetCard, targetSecondaryCard) .play() .eventCallback('onStart', () => { const currentElements: any = textElements.filter((ele, i) => i !== currenIndex); gsap.set([...currentElements], { autoAlpha: 0, }); slidePrevNextTextReverse(textElements[currentCount], textElements[index]); }) .eventCallback('onComplete', () => { slideTween(currentCard, currentSecondaryCard).reverse(); }); } }; export const snapTimeline = (id, stateMethods) => { const { setActive, setInViewport, isTablet, isMobile } = stateMethods; const dCards = gsap?.utils?.toArray(`div.parent-container div.asset--${id}`); const sCards = gsap?.utils?.toArray(`div.child-container div.optional--${id}`); const textElements = gsap?.utils?.toArray(`.tarea--${id}`); if (dCards.length > 1) { const getEnd = () => { return isMobile ? 'bottom' : isTablet ? 'bottom top' : '+=5000'; }; snapScrollAnimation = gsap.timeline({ ease: 'Power3.easeOut', reversed: true, scrollTrigger: { end: () => getEnd(), endTrigger: `.ui-demo-container--${id} div.snap-last`, fastScrollEnd: true, invalidateOnRefresh: true, onEnterBack: () => { currentCount = dCards.length - 1; setActive(currentCount); setInViewport(true); }, onLeave: (self) => { currentCount = dCards.length - 1; setActive(currentCount); }, onLeaveBack: () => { currentCount = 0; setActive(0); setInViewport(true); }, onToggle: (self) => { finishOnFastLeave(self, dCards.length - 1, id); }, pin: `.container--${id} .ui-demo-container--${id}`, preventOverlaps: true, scrub: 2, // markers: true, snap: { duration: 1, ease: 'none', onComplete: ({ progress, direction }) => { const progressValue = +progress.toPrecision(2) * 100; const length = dCards.length - 1; const index = Math.round(+(+(progressValue / 100).toPrecision(1) * length).toPrecision(1)); currentCount = index; handleBottomSpacing(id, isMobile, isTablet); }, onStart: ({ progress, direction }) => { const progressValue = +progress.toPrecision(2) * 100; const length = dCards.length - 1; const index = Math.round(+(+(progressValue / 100).toPrecision(1) * length).toPrecision(1)); const nextCount = currentCount + 1 < dCards.length && direction === 1 ? currentCount + 1 : currentCount - 1 > 0 ? currentCount - 1 : 0; if (index > currentCount) { setActive(index); } else if (index < currentCount) { setActive(index); } else { setActive(nextCount); } goToCard(progress, direction, index, currentCount, nextCount, id); }, snapTo: 1 / (dCards?.length - 1), }, start: () => (isMobile ? 'top 9%' : isTablet ? 'top 4.5%' : 'top 5%'), trigger: `.ui-demo-container--${id} div.snap-first`, }, }); } return snapScrollAnimation; }; // tslint:disable-next-line: no-big-function export const initializeAnimation = async (id, stateMethods) => { const dCards = gsap?.utils?.toArray(`div.asset--${id} div.asset-component`); const secondaryCards = gsap?.utils?.toArray(`div.optional--${id}`); const { setInViewport, isTablet, isMobile, theme } = stateMethods; firstImageAnimation(id, setInViewport, isTablet, isMobile, theme); snapTimeline(id, stateMethods); const matchMediaRef: gsap.MatchMedia = gsap?.matchMedia(); const desktopTabletSet = () => { gsap.set(`.asset--${id}:first-child`, { opacity: 1, visibility: 'visible', yPercent: 0, }); gsap.set(`.asset--${id}:not(:first-child)`, { opacity: 0, visibility: 'hidden', yPercent: 100, }); gsap.set(`div#device-${id} div.asset-overlay`, { visibility: 'visible', opacity: 1 }); dCards.forEach((assetCard: HTMLDivElement, i) => { const secondaryCard: any = secondaryCards[i]; if (i === 0) { gsap.set(`div#device-${id} .outline-border`, { background: 'transparent', scale: isTablet ? 2 : 1.5, }); gsap.set(`div#device-${id} .transparent-border.${theme}`, { background: 'transparent', borderColor: 'transparent', borderRadius: '0px', }); gsap.set(`.tarea--${id}:first-child`, { opacity: 1, visibility: 'visible', x: 0, y: 0, }); gsap.set(secondaryCard, { opacity: 1, visibility: 'visible', yPercent: 0, }); } else { gsap.set(secondaryCard, { opacity: 0, visibility: 'hidden', yPercent: 100, }); } }); if (sCards.length === 0) { mainContainerTween(id, isTablet, isMobile).kill(); progressButtonTween(id).kill(); } if (dCards.length === 1) { progressButtonTween(id).kill(); } else if (dCards.length === 0) { fullScreenTween(id).kill(); progressButtonTween(id).kill(); } }; const mobileSet = () => { gsap.set(`.asset--${id}:first-child`, { opacity: 1, visibility: 'visible', yPercent: 0, }); gsap.set(`.asset--${id}:not(:first-child)`, { opacity: 0, visibility: 'hidden', yPercent: 100, }); gsap.set(`div#device-${id} div.asset-overlay`, { visibility: 'visible', opacity: 1 }); gsap.set( [`div#device-${id} div.child-container`, `div#device-${id} .full-screen`, `.progress-container--${id}`], { display: 'none' } ); childContainerTween(id, isTablet).kill(); fullScreenTween(id, isTablet).kill(); progressButtonTween(id).kill(); mainContainerTween(id, isTablet, isMobile).revert(); gsap.set(`div#device-${id} .outline-border`, { background: 'transparent', scale: 2, }); gsap.set(`div#device-${id} .transparent-border.${theme}`, { background: 'transparent', borderColor: 'transparent', borderRadius: '0px', }); gsap.set(`.tarea--${id}:first-child`, { opacity: 1, visibility: 'visible', x: 0, y: 0, }); }; matchMediaRef .add( [ '(min-width: 960px)', '(min-width: 1440px)', '(min-width: 1920px)', '(min-width: 768px) and (max-width: 1023px)', '(min-width: 768px) and (max-width: 1023px) and (orientation: landscape)', '(min-width: 1024px) and (max-width: 1180px) and (orientation: landscape)', ], () => desktopTabletSet() ) .add( [ '(min-width: 320px) and (max-width: 719px)', '(min-width: 320px) and (max-width: 719px) and (orientation: landscape)', '(max-height: 719px) and (orientation: landscape)', ], () => mobileSet() ); }; export let snapScrollAnimation: gsap.core.Timeline; export let imageTimelineAnimation: gsap.core.Timeline;
  9. I'd probably add a small delay on the "reset" tween and set overwrite to true. Something like this: https://codepen.io/PointC/pen/ZEMjdLj/364a470e414172b8fbd6a7420de056f6 More info about overwrite. Happy tweening.
  10. Hi @Roman S. is you're issue that your elements are not obeying the width you've set? That is because flexbox is trying to 'help', flexbox will automatically distribute the elements over the width you've given it. You can overwrite that using the flex-grow, flex-shrink and flex-basis property or the short hand flex: 0 0 "your width". You're right that this is a CSS issue and we like to focus these forums to just GSAP related questions. Still hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/GRXOvgo?editors=0110
  11. Hmm.. So I tried the Attribute Plugin using this code, but it doesn't work with my SVG. Actually it doesn't seem to work with the basic div's either. let elements = document.querySelectorAll('.button'); let clickEvent = (e) => { console.log('some event content here...') console.log("----------------" + e.target.id + "----------------------") } elements.forEach((item) => { item.addEventListener("mouseenter", ()=>{ gsap.to(item, {attr: {fill: "#F2653A"}, duration: 1, overwrite: "auto" }); }); item.addEventListener("mouseout", ()=>{ gsap.to(item, {attr: {fill: "red"} ,duration: 1, overwrite: "auto" }); }); item.addEventListener('click', clickEvent) }); });
  12. Hmm.. So I tried the Attribute Plugin using this code, but it doesn't work with my SVG. let elements = document.querySelectorAll('.button'); let clickEvent = (e) => { console.log('some event content here...') console.log("----------------" + e.target.id + "----------------------") } elements.forEach((item) => { item.addEventListener("mouseenter", ()=>{ gsap.to(item, {attr: {fill: "#F2653A"}, duration: 1, overwrite: "auto" }); }); item.addEventListener("mouseout", ()=>{ gsap.to(item, {attr: {fill: "red"} ,duration: 1, overwrite: "auto" }); }); item.addEventListener('click', clickEvent) }); });
  13. Nice job, @Toso 👍 Minor tweaks: https://codepen.io/GreenSock/pen/KKxXjvW?editors=0010 I'd use backgroundColor rather than background, and I'd set the overwrite to either true or "auto" just in case the user rolls over/out quickly, you don't want to create conflicting animations.
  14. Yes you can! Like you do with CSS you can call all your elements at once and then use a stagger (see Stagger docs) to have them animate in one by one. Then when using a smart position parameter we can start the next animation right after the first one is done! Also you can target all transform properties directly with GSAP x, y, rotate, skew, scale ect and if you want to use percentage based values use xPercent and yPercent. I would also recommend keeping all he animation values to GSAP instead of setting something with in CSS that you then need to overwrite with GSAP, that is where .from() is really handy. I've sprinkled a lot of useful comments throughout your pen to explain certain parts, be sure to read through them! Hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/GRXmQqV?editors=0100 Oh and a side note! When working with ScrollTrigger I like to disable it, to really focus on just the animation I find it a lot easier. I've also added a repeat: -1, so be sure to remove those when you're going to enable ScrollTrigger again.
  15. Hello all, So in this codepen example I use Flip.from to get items into grid slots, and then on another flip to get them back in old parent, but also to transform each item to value I set with gsap.set. This works too, but on 3rd click, when I want to animate items again into grid, the gsap.set doesnt set xPercent value back to 0. I also tried overwrite: true but it didnt work. Is there something Im missing? Thanks
  16. Hi, I've been fiddling with your codepen example for a bit and this seems to do the trick: ScrollTrigger.create({ trigger: ".images", start: "center top", markers: true, onEnter: self => { let state = Flip.getState(images); images.forEach((image, i) => slots[i].appendChild(image)); gsap.set(images, {xPercent: 0, rotation: 0}); Flip.from(state, { duration: 6, overwrite: true, // <- HERE ease: "power1.inOut" }) } }) Since the first ScrollTrigger instance you're creating for the images has once: true, it doesn't really matter if the Flip animation overwrites those. In the tests that I've ran seems to work as expected: https://codepen.io/GreenSock/pen/ZEMeBKR Hopefully this helps. Let us know if you have more questions. Happy Tweening!
  17. That's because you created conflicting animations - you've got your motionPath animation first in the timeline that controls the x/y position, and then you ALSO have another one that's affecting x to go in a completely different direction. So they're both fighting for control. If you do overwrite: "auto" (or true), all that does is basically KILL the overwritten part (so of course you won't see it affecting things after that point at all). You definitely should not be creating conflicting animations like that. The reason it looks different when scrolling forwards vs backwards is because the rendering order inverts in reverse. In other words, when moving the playhead forward, the LATER tween would render last whereas when moving the playhead backwards, the EARLIER tween would render last. That's exactly how it's supposed to work. Possible solutions: Don't overlap the animations. https://codepen.io/GreenSock/pen/dyqNQRR?editors=1010 Use a different (invisible) motionPath that has the shape you want. Basically copy the path you have now, but add that extra part at the top that's curved in the way you want your objects to travel. You can still leave the red stroked path as-is. Everything would look the same visually, but you'd just use one motionPath tween where the path actually has the shape you're going for. You technically could write a bunch of extra JavaScript to force things to render in a particular order no matter which direction the playhead travels, but honestly that seems quite hacky and unintuitive to me. It is doable, though. If you need help with that, we're available for paid custom consulting - just reach out directly to explore those options. I hope that helps!
  18. Hi, I'm in this situation and I don't know how to manage the fact that MotionPath animation takes control on the translateX property when reversing the scroll ( go to the very end of the scroll animation, then reverse scrolling back, you will see the circles going to the straight right instead of doing the bending curve as they did in forward mode ). `overwrite:auto` does not seem to help, and `overwrite:true` breaks the animation. TIA.
  19. It looks like you just had your toggleActions wrong: // BAD toggleActions: "play none reverse none" // GOOD toggleActions: "play none none reverse" And this is not a valid start value: // invalid start: "-=200top top" I'm not sure if you meant "top top" or "200 top" or something else. But actually, if I were building this I'd approach it in a very different way: Put the color/backgroundColor into a data-color attribute on any element that I want to have this effect (a space-delimited value like "blue white") Grab all the elements that have that data-color attribute, loop through them and create a ScrollTrigger for each. When it activates, create a new tween that animates to its colors. Here's a demo with my strategy implemented: https://codepen.io/GreenSock/pen/OJoROgY?editors=0010 Benefits: You can easily add as many sections as you want - just slap a data-color value on it in the markup and BOOM, it works. It works more smoothly if you scroll very quickly. With your previous strategy, you had one animation for each section, and you were calling play()/reverse() on them when necessary...but they were controlling the same properties of the same object. Imagine a scenario where the user scrolls quickly, so one animation starts and is midway through when the other animation gets triggered. Now you've got two animations fighting for control of the same properties. Plus you may see a jump because let's just say (to make it simpler) we're animating a number from 0 to 100 in the first one, and 100 to 200 in the second animation. If the first animation is at 50 when the second one starts playing, you'd see it jump from 50 to 100 instantly (and go to 200). With my strategy above, a new tween gets created each time so that it's just taking the value from whatever it currently is to the new value. So everything is perfectly smooth every time. No fighting for control (it has overwrite: "auto"), no overlapping. I hope that helps.
  20. Hello, i have tried the official codepen demo with the horizontalLoop: https://codepen.io/GreenSock/pen/gOvvJee Thanks for this awesome slider. But I run in some troubles with the dragging. I could fix some problems by myself but with 1 problem i have my troubles Scenario: - Open the page and drag much, so the slider its moving. - When it comes nearly to the end (but it has not stopped yet) please press the active button with the white boarders. - It now jumps a lot. Do you know why? Thanks a lot! Other bugs i could solve (but its ugly 😞 Scenario 1: - Open the page and drag just some pixels on the active button (Button number3) and release the mouse. - Then click a few times on the button 3. - Now it jumps some boxes. I tried to fix it in the "toIndex" function before line 150. It works better. vars.overwrite = true; if (index === curIndex) { return; } curIndex = newIndex; gsap.killTweensOf(proxy); return tl.tweenTo(time, vars); Scenario 2: - Drag a lot, so that the slider is moving. - While the slider is moving please press the "wrapper" (the grey lines above or below the boxes) - Now it jumps a loooot. I fixed this with adding a new var isNowDragging (true when the user drags) and change line 182. Seems to work now. if (!isNowDragging) {gsap.set(proxy, {x: startProgress / -ratio});} Thanks a lot for your help.
  21. Hi, Maybe you should take a look at ScrollTrigger's batch method: https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.batch() Here is a live example: https://codepen.io/GreenSock/pen/NWGPxGZ In the case of your last codepen example it would be as simple as this: gsap.registerPlugin(ScrollTrigger); gsap.set(".grid-i", {y: 50, opacity: 0}); ScrollTrigger.batch(".grid-i", { onEnter: batch => gsap.to(batch, {opacity: 1, y: 0, stagger: 0.15, overwrite: true}), }); Hopefully this helps. Let us know if you have more questions. Happy Tweening!
  22. @GreenSock How do I use this but with a scrolltrigger? I need to animate items per row, but it seems that when I use the row as a trigger it doesn't work. This is what I added to it: ``` rows.forEach((GridItems) => { let tl = gsap.from(GridItems, {opacity: 0, yPercent: 80, stagger: 0.05, duration: 0.7, overwrite: true}); ScrollTrigger.create({ trigger: GridItems, start: 'top 70%', end: 'bottom bottom', markers: true, onEnter: () => tl.play(), onEnterBack: () => tl.restart(), onLeaveBack: () => tl.pause(0), }); });
  23. Hello @amitr95 I think the problems you are having might just be related to the general processing of the code's logic you run inside your function, and not really to GSAP measuring the height incorrectly. Here is an approach, that is a bit different on the logic side of things, which works fine for me with regard to the height. I also added overwrite: 'auto' to the tweens, so GSAP can sort out conflicting tweens that might be created along the way. [Note: this approach is not meant to be 100% bullet-proof. It is mainly to show, that the height gets tweened to the proper value.] https://codepen.io/akapowl/pen/VwBqJmj Edit: Since getting the logic right for something like this can become a bit tricky, here's another example of your setup, using an approach by OSUBlake - which works a lot better. Hope that will help. https://codepen.io/akapowl/pen/BaPvXQM Based on this demo. https://codepen.io/osublake/pen/JYQqZr
  24. I'm not completely sure what you're asking. But I think your problem is that you have one element that is controlled by two ScrollTriggers and they will fight for control if the first one is not yet done and the other one is starting, so you either have to make sure the other one is done when the next one starts or make it one big ScrollTrigger that just triggers over the whole duration (this seems like the easiest solution) https://codepen.io/mvaneijgen/pen/GRBPbgr?editors=1010 You could also look in to the overwrite property https://greensock.com/docs/v3/GSAP/Tween/vars If true, all tweens of the same targets will be killed immediately regardless of what properties they affect. If "auto", when the tween renders for the first time it hunt down any conflicts in active animations (animating the same properties of the same targets) and kill only those parts of the other tweens. Non-conflicting parts remain intact. If false, no overwriting strategies will be employed. Default: false.
  25. Well, as with everything, the devil is in the detail, which is why it is very hard to give general recommendations for a more complex scenario like yours. Since you are concerned about things not working when reloading the page when it's scrolled down, you might want to reconsider the general approach of how you implement the change of the backgroundColor, too, because the way you are doing it in the demos you posted, things will not work as you might intend in that case. One logical problem is the following: You are changing the playstate of pre-built timelines with.to() tweens in callbacks of ScrollTriggers, when the page is loaded at the very bottom, ScrollTrigger will make sure that those callbacks get called. So now you have multiple tweens being called quickly one after the other, which are all tweening on the same property of the same element, so you are creating conflicting tweens. When you scroll back up then, the .to() tween is supposed to be reversed, but it will probably reverse back to the color that it was at the time when that tween was being created - which very likely is not the color you'd expect but some value of a color in between all those colors. Creating your tweens upfront can be quite the tricky scenario to begin with, when you are going to tween on the same property of the same element with multiple different instances. So one way you could prevent all those logical hurdles, would be to create the tweens in the callbacks directly instead of pre-building them. Then you could either use .fromTo() tweens to make sure you always tween from one specific color to another specific color, when the callback runs, or .to() tweens with overwrite set to 'auto' to prevent conflicts I mentioned above. In this pen with the lottie-scrolltriggers handling the pinning themselves, things seem to work fine even if I create those ScrollTriggers before all the lottie-scrolltriggers, but your mileage may vary. https://codepen.io/akapowl/pen/gOjKLqy
×