Jump to content
Search Community

control animation speed with scrollTrigger scrub? versus duration?

jeanettable test
Moderator Tag

Go to solution Solved by GreenSock,

Recommended Posts

Hello Gracious Teachers and Friends!

 

I'm struggling to discover clearly in the docs what is considered best practice to control animation tweens execution while placing the timeline containing those tweens on a scrub with scrollTrigger. In my attached minimal demo, I have been playing with duration properties (bringing them up quite high 🤨 with minimal change), and also leveraging the position property to add space between tweens.

It is also mentioned that scroll time = distance in this different forum post . Use of an empty tween at the end of the timeline is something else I tried so that the animation wouldn't get cut off before all three text sections animate their fades into and out of view....which appears to be working in my case to not cut off the last bit of animation. ** If I take that empty tween away, the animation I thought I had on 100% to end cuts off the animation right where it's at when the time (aka distance) runs out. ** I'm just wondering what is considered most effective, or "best practice." And I'd love a little guidance for the "aha" moment that will aid my understanding and guide me toward the best way to achieve a more readable speed of something like these text samples for a typical user scroll speed. 

Much appreciated. :)

See the Pen OJgGeeJ by jeanettable (@jeanettable) on CodePen

Link to comment
Share on other sites

  • Solution

There's an explanation in the docs about this.

 

I find it easiest to visualize it like this: turn markers on for your ScrollTrigger. Now look at where the "start" and “end” values are - it must squish/stretch the timeline to fit inbetween there perfectly. So let's say your ScrollTrigger's end is 500px below the start and you've got 5 seconds worth of tweens in your timeline - if you just change the durations of the tweens to be 100 times what they were before (SUPER long), it doesn't matter because it still has to move the playhead from the start to the end within 500px. 

 

See what I mean? 

 

So if you want it to last longer, all you need to do is push your "end" further down on the page. Right now, you've got end: "+=100%" which is basically the height of the viewport. Try something like this: end: "+=5000"

  • Like 8
Link to comment
Share on other sites

  • 1 year later...
On 10/3/2021 at 9:30 AM, GreenSock said:

There's an explanation in the docs about this.

 

I find it easiest to visualize it like this: turn markers on for your ScrollTrigger. Now look at where the "start" and “end” values are - it must squish/stretch the timeline to fit inbetween there perfectly. So let's say your ScrollTrigger's end is 500px below the start and you've got 5 seconds worth of tweens in your timeline - if you just change the durations of the tweens to be 100 times what they were before (SUPER long), it doesn't matter because it still has to move the playhead from the start to the end within 500px. 

 

See what I mean? 

 

So if you want it to last longer, all you need to do is push your "end" further down on the page. Right now, you've got end: "+=100%" which is basically the height of the viewport. Try something like this: end: "+=5000"

Woudn't this create a lot of space if I'm pinning an element and pinSpacing is true,  how to avoid pinSpacing in this case ?

if I make pinSpacing false the component scroll is overlapping with its below elements, need your help on this. Thanks @GreenSock

Link to comment
Share on other sites

@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;

 

 

Link to comment
Share on other sites

It's pretty tough to troubleshoot without a minimal demo - the issue could be caused by CSS, markup, a third party library, your browser, an external script that's totally unrelated to GSAP, etc. Would you please provide a very simple CodePen or CodeSandbox that demonstrates the issue? 

 

Please don't include your whole project. Just some colored <div> elements and the GSAP code is best (avoid frameworks if possible). See if you can recreate the issue with as few dependancies as possible. If not, incrementally add code bit by bit until it breaks. Usually people solve their own issues during this process! If not, then at least we have a reduced test case which greatly increases your chances of getting a relevant answer.

 

Here's a starter CodePen that loads all the plugins. Just click "fork" at the bottom right and make your minimal demo

See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen

 

If you're using something like React/Next/Vue/Nuxt or some other framework, you may find StackBlitz easier to use. We have a series of collections with different templates for you to get started on these different frameworks: React/Next/Vue/Nuxt.

 

Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions. 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...