Jump to content
Search Community

flowen

Members
  • Posts

    87
  • Joined

  • Last visited

Posts posted by flowen

  1. so i've been playing around with your code.

    And I'm still confused how to optimise the scrolltrigger for multiple sections.

     

    So I have multiple sections on my page and I want to use each section as a trigger for the elements in that section (right now the headings which I have split with splittingjs). 

    Wouldn't I still need to create multiple scrollTrigger instances so I have a different trigger element (section) for the animations within that? I'm not quite sure I understand how to optimise this. 

    In your code you refer to section as the trigger, which I suppose also means that you create multiple timelines in the loop that returns section (sections.foreach(section => ())). If you meant the whole array (sections), I tried that and it won't trigger anything. 

     

    Something else I noticed is that animating all the characters that are split is bad for performance. So I choose to use CSS, with a class, instead.

    Saw in the video I should probably use the onEnter hook, as I don't think I can use toggleClass to just fire it once, right?

     

  2. @mikel didn't know that was possible! Interesting way to approach, though I don't understand the creation of the path (yet). Although for now I've seemed to have fixed it by making the svg responsive. 

     

    The reason why my svg wasn't responsive is that React was removing the 'viewbox' attribute. It was supposed to be 'viewBox'. Took me half a day to find as there was no error ?

     

    also thanks @ZachSaucier !

  3. Another motion path issue, this time with a codepen :)

     

    So I have this fartpillow animating in from the right (outside of the screen) triggered by an intersection observer.


    On smaller screens the fartpillow jumps out of the screen and I can't seem to get the motion path resize correctly. The final implementation is in React, but I'm using pretty much the exact same code from this prototype.

     

    One of the challenges is that I want the animation to start outside of the container as well, but I somehow (not sure how) fixed this.

    Just thinking ahead that this might be another challenge if the path fits to size within the container.

     

     

     

    See the Pen VwYpvoq?editors=0010 by GreenSock (@GreenSock) on CodePen

  4. Sorry I can't share the actual code, but I have a deploy you can see live here

     

    When the motion path animation starts, "YES" suddenly changes position to the far right. 

     

    What are some things I could look at to make sure this doesn't happen?

     

    The svg including the motion path is styled fixed with a 100% width and height

    The parents of the element Yes has absolute positioning and is rotated, perhaps there's an issue there?

     

    I know this is far from perfect to help me debug, but right now I can't offer more.

  5.   /**
       * setup Gsap animation
       */
      useEffect(() => {
        if (
          !refWrapperLarge.current ||
          !refWrapperSmall.current ||
          !refWrapperBorder.current ||
          !refText.current ||
          !refRectLargeRight.current
        )
          return
    
          // animation code
      }, [
        refWrapperLarge.current,
        refWrapperSmall.current,
        refWrapperBorder.current,
        refText.current,
        refRectLargeRight.current,
      ])

     

    This month I've been coding a lot in React hooks (in Gatsby env) with GSAP. 

     

    But I keep coming across the above (anti-)pattern. I wondered if perhaps someone had a better solution or idea how this could be done. 

     

    So if you're not familiair with the useEffect hook, it's a piece of code that keeps re-running when for examples values (or state) changes. 

    Which can be super-useful in apps. 

     

    But in order to animate elements with GSAP, I kept coming back to this pattern.  I first need to check if all refs exists (they're primarily defined with the useRef() hook). 

    On the first run they do not, since the component is still being rendered.

    In the dependency array I add the refs as well, so it will re-run, until all DOM elements exists.

     

    Only then can I start animating the components. 

     

    @Rodrigo you have any idea/suggestion?

  6. https://greensock.com/docs/v3/GSAP/gsap.to()

     

    There's no mention of the available options for the advanced stagger options. Instead there's a broken link to a codepen, which I think should be this one?

     

    I feel like the docs are not completely updated yet? Just wanna help out here and there, not sure if the forum is the best way to do this.

     

    edit: I created a link in the post, but instead it auto-formatted it to normal text? 

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

  7. 3 hours ago, ZachSaucier said:

    Hey IntouchGroup and welcome to the forums.

     

    In GSAP 3, eases are super simple: A linear/no ease is just ease: "none" (or ease: "linear", both work)!

     

    Thanks for the reduced demo

    ah! I had a similar issue. I looked in the docs and there it told me to get a 'linear.easeNone' or 'power0.easeNone' but neither of those worked. 

     

    as well as in the ease visualiser if you click power0 

  8. I have a different problem now.. I'll keep it in this topic as the topic is still correct.

     

    - I have multiple paused timelines, that I add to a master timeline.

    - I pause them, otherwise they're being playing during initialisation.. right?

    - I start playing the master timeline once all state is set, but nothing happens. I think because the child timelines are still paused... could this be?

     

    Due to the nature of useEffect effects, I think I'm supposed to set them up like this: 

    - Check if the timeline exists (first time this fails, so we return)

    - timeline is being set so we rerun the effect 

    - add them with a setter

     

     

     

     

    const Intro = () => {
      const [tlIntroMaster, setTlIntroMaster] = useState(null)
      const [tlIntro, setTlIntro] = useState(null)
      const [tlLoop, setTlLoop] = useState(null)
    
      useEffect(() => {
        setTlIntro(
          gsap
            .timeline({ defaults: { duration: 0.2, repeat: 0 } })
            ...
        )
    
        setTlLoop(
          // it's important this one repeats
          gsap
            .timeline({ defaults: { duration: 0.25 }, repeat: -1, paused: true })
            ...
        )
      }, [])
    
      // here I add them to setTlIntroMaster
      useEffect(() => {
        if (!tlLoop || !tlIntro) return
    
        setTlIntroMaster(
          gsap
            .timeline()
            .add(tlIntro)
            .add(tlLoop)
        )
      }, [tlLoop, tlIntro])
    
      // this use effect reruns when the tlIntroMaster has a timeline
      // we play it.. but it won't play. 
      // the children are still in a paused state and I can't seem to run them
      useEffect(() => {
        if (!tlIntroMaster) return
        // I log to see if something is there - yes
        console.log(tlIntroMaster)
        tlIntroMaster.play()
      }, [tlIntroMaster])
    
      return (
        <>
          ...
        </>
      )
    }

     

     

  9. 27 minutes ago, ZachSaucier said:

    GSAP 3 is no longer in beta! It's been soft-released with the full release coming in a few hours. Yes, I highly recommend GSAP 3 as it's great!

     

    I had just kill initially but there was a visual glitch. AFAIK .kill() doesn't actually immediately stop tweens or timelines. It just frees it to be garbage collected. So there could be some time between when you call .kill() and it being garbage collected, in which case the animation could continue partially. You probably just need a .pause().kill() and can drop the .seek(0).

    Oh, wow, what a timing! I'll have to upgrade of course :) Thanks for mentioning and thanks for the explanation on the chain!

     

     

     

    • Like 2
  10. Right now I unfortunately don't have a codebox/pen with my latest try at it, but hopefully the example will help a bit until I upload the full code. 

     

    https://codesandbox.io/s/smoosh-violet-fk6un (this example is pure js, no react)

     

    So I have:

    - a Master timeline. 

    - smaller timelines added to the master timeline

    - 2 labels

    - I use a .add(fn) with a condition in it to either play the loop again or go to 'end' label. I would like to use this with a (img) preloader. So whenever loading is finished, I want the loop to go to 'end'. 

    - end (infinite) loop

     

    The problem I faced so far is that the 'loop' variable, which is state in React, somehow doesn't work in the conditional in the .add function. 

     

    So I tried hacking this by adding each timeline to their own state, add them to the master and instead of a conditional for 'loop', I add a 'seekloop'. Then set state of 'loop', rerun the effect and this time remove the 'seekloop' and add a different seek.

     

    I hope this makes sense ?

     

     

    import React, { useEffect, useRef, useState } from "react"
    import { TweenMax, TimelineLite, Power3, Linear, Back } from "gsap"
    
    import {
      Wrap,
      WrapText,
      YesWrapper,
      Yes,
      Problem,
      ProblemText,
      ProblemYes,
      BG,
    } from "./styles"
    
    const Intro = () => {
      const [{ w, h }, setWindowSize] = useState({
        w: window.innerWidth,
        h: window.innerHeight,
      })
      const [loop, setLoop] = useState(true)
      const [aspect, setAspect] = useState(true)
      const [tlMaster, setAnimation] = useState(null)
      const [tlIntro, setTLIntro] = useState(null)
      const [tlLoop, setTLLoop] = useState(null)
      const [tlEnd, setTLEnd] = useState(null)
    
      const hyp = Math.sqrt(w * w + h * h)
      const angle = Math.floor(Math.sin(h / hyp) * (180 / Math.PI))
      const bounce = Back.easeOut.config(0.05)
    
      const refWrap = useRef(null)
      const refWrapText = useRef(null)
      const refYesWrapper = useRef(null)
      const refProblemText = useRef(null)
      const refProblemYes = useRef(null)
      const refBG = useRef(null)
    
      // initial effect to load and measure
      useEffect(() => {
        function init() {
          setWindowSize({ w: window.innerWidth, h: window.innerHeight })
    
          TweenMax.set(refProblemText.current, { yPercent: 100 })
          TweenMax.set(refYesWrapper.current, { y: h })
        }
    
        window.addEventListener("resize", init)
        return () => window.removeEventListener("resize", init)
      }, [h])
    
      useEffect(() => {
        setAspect(w / h)
    
        TweenMax.set(refWrapText.current, {
          xPercent: aspect > 1 ? 5 : 35,
          width: h,
        })
      }, [w, h])
    
      useEffect(() => {
        setAnimation(new TimelineLite({ repeat: 0, paused: true }))
      }, [])
    
      useEffect(() => {
        if (!tlMaster) return
    
        setTLIntro(
          new TimelineLite()
            .fromTo(refBG.current, 0.2, { y: 0 }, { y: h / 2 })
            .to(refWrap.current, 0.2, { rotation: -angle })
            .to(refProblemText.current, 0.2, { yPercent: 0, opacity: 1 })
            .staggerFromTo(
              refYesWrapper.current.childNodes,
              0.2,
              { y: -h },
              { opacity: 1, y: 0, ease: bounce },
              -0.1
            )
        )
      }, [tlMaster])
    
      useEffect(() => {
        if (!tlMaster) return
    
        setTLLoop(
          new TimelineLite()
            .to(refProblemText.current, 0.2, { x: w * 1.5 })
            .to(refProblemYes.current, 0.2, { yPercent: 100 })
            .staggerTo(
              refYesWrapper.current.childNodes,
              0.2,
              { yPercent: 100, opacity: 1, y: 0, ease: bounce },
              -0.1
            )
            .set(refProblemText.current, { x: 0, yPercent: 100 })
            .to(refProblemText.current, 0.2, { yPercent: 0 })
            .delay(0.3)
        )
      }, [tlMaster])
    
      useEffect(() => {
        if (!tlMaster) return
    
        const completedIntro = () => {
          TweenMax.to(refWrapText.current, 2, {
            y: 100,
            ease: Linear.easeNone,
          }).repeat(-1)
          //y:100 = yesHeight
          // dom.html.classList.remove("js--disable-scroll");
        }
    
        setTLEnd(
          new TimelineLite({ onComplete: completedIntro })
            .addLabel("start")
            .to(refWrap.current, 0.6, { rotation: -90 }, "start")
            .to(
              refWrap.current,
              0.6,
              { xPercent: 100, ease: Power3.easeOut },
              "start"
            )
            .to(
              refWrapText.current,
              0.6,
              { xPercent: aspect > 1 ? "-=5" : "-=35", ease: Power3.easeOut },
              "start"
            )
        )
      }, [tlMaster])
    
      useEffect(() => {
        if (!tlIntro || !tlLoop || !tlEnd) return
    
        tlMaster
          .add(tlIntro)
          .addLabel("loop")
          .add(tlLoop)
          .addLabel("end")
          .add(tlEnd)
    
        tlMaster.play(0)
      }, [tlIntro, tlLoop, tlEnd])
    
      useEffect(() => {
        if (!tlMaster || !tlLoop) return
    
        if (loop) {
          console.log("add")
          tlLoop.add(() => tlMaster.seek("loop"), "seekLoop")
          setLoop(false)
        } else {
          console.log("remove")
          tlMaster.removeLabel("seekLoop")
          tlLoop.add(() => tlMaster.seek("end"))
        }
      }, [tlMaster, tlLoop, loop])
    
      return (
        <Wrap ref={refWrap}>
          <WrapText ref={refWrapText}>
            <YesWrapper ref={refYesWrapper}>
              <Yes>Yes</Yes>
              <Yes>Yes</Yes>
              <Yes>Yes</Yes>
              <Yes>Yes</Yes>
              <Yes>Yes</Yes>
              <Yes>Yes</Yes>
              <Yes>Yes</Yes>
              <Yes>Yes</Yes>
            </YesWrapper>
    
            <Problem>
              <ProblemYes ref={refProblemYes}>Yes</ProblemYes>
              <ProblemText ref={refProblemText}>problem</ProblemText>
            </Problem>
          </WrapText>
    
          <BG ref={refBG} />
        </Wrap>
      )
    }
    
    export default Intro

     

  11. @StefanHinck

    I stayed with TransitionLink because it offered me the customization I needed for my animations. Anilink doesnt and its made for some quick out-of-the-box page-transitions but not much more than that. I had a quick look in the docs and I see no support for length of the animation

     

    The dev himself admits he really doesn't want you to use it :)

     

    No worries, we all start somewhere. I "should" be using chrome's debugger tools after 10years of frontend but still love console.log haha

     

    So:

    AniLink for some quick page transitions

    transitionLink for some cool custom work

×
×
  • Create New...