Jump to content
Search Community

Restarting a timeline animation when section in view again

Visual23 test
Moderator Tag

Recommended Posts

Hi all,

 

If you look at the link below I have the section animations playing when a section is in view. It works by scrolling or using the dot navigation. After I go to a section and it animates in as intended. I'd like to be able to leave that section, reset it so when I come back it plays again. I've tried adding toggleActions but it doesn't seem to work. Thanks in advance!

 

Username: demo

Password: demopass

https://v23static.wpengine.com/story-of-water.php 

 

My GSAP code:
 

const timelines = [];

timelines[0] = gsap.timeline({
  scrollTrigger: {
    trigger: "#section-0",    
    start: () => {
      return `top top`
    },
    end: () => {
      return `bottom bottom`
    },
    //markers: true,
    id: "section-0", 
    onLeaveBack: () => video_00.play(),
  }
})

timelines[1] = gsap.timeline({
  scrollTrigger: {
    trigger: "#section-1",
    start: () => {
      return `top top`
    },
    end: () => {
      return `bottom bottom`
    },
    //markers: true,
    id: "section-1",
    //onEnter: () => video_00.pause()

  }
})

timelines[2] = gsap.timeline({
  scrollTrigger: {
    trigger: "#section-2",
    start: () => {
      return `top top`
    },
    end: () => {
      return `bottom bottom`
    },
    //markers: true,
    id: "section-2"
  }
})

timelines[3] = gsap.timeline({
  scrollTrigger: {
    trigger: "#section-3",
    start: () => {
      return `top top`
    },
    end: () => {
      return `bottom bottom`
    },
    //markers: true,
    id: "section-3",
  }
})

timelines[4] = gsap.timeline({
  scrollTrigger: {
    trigger: "#section-4",
    start: () => {
      return `top top`
    },
    end: () => {
      return `bottom bottom`
    },
    //markers: true,
    id: "section-4"
  }
})

timelines[5] = gsap.timeline({
  scrollTrigger: {
    trigger: "#section-5",
    start: () => {
      return `top top`
    },
    end: () => {
      return `bottom bottom`
    },
    //markers: true,
    id: "section-5"
  }
})

timelines[6] = gsap.timeline({
  scrollTrigger: {
    trigger: "#section-6",
    start: () => {
      return `top top`
    },
    end: () => {
      return `bottom bottom`
    },
    //markers: true,
    id: "section-6"
  }
})

timelines[1]
.fromTo('.section-menu', {
    opacity:0    
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    delay: 0,    
  })
.fromTo('#section-1 .svg-wrapper', {
    opacity:0,
    scale: "1.5",    
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    scale: "1", 
    delay: 0,    
  })
  .fromTo('#section-1 #title', {
    opacity:0
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    scale: "1", 
    delay: 0
  })  
  .from("#section-1 #mask-path-1", { 
    duration: 2, 
    drawSVG: 0, 
    ease: "none" 
  })
  .from("#section-1 #mask-path-2", { 
    duration: .5, 
    drawSVG: 0, 
    ease: "none" 
  },">-0.05")
  .fromTo('#section-1 .blob-wrapper', {
    opacity:0, 
    scale: ".5"
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "back",
    scale: "1", 
    delay: 0
  },">-0.05")
  .fromTo('#section-1 .panel', {
    opacity:0
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "power1.out",
    y: "-=25",
    delay: 0
  }) 


timelines[2]
.fromTo('#section-2 .svg-wrapper', {
    opacity:0,
    scale: "1.5",
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    scale: "1", 
    delay: 0,
  })
  .from("#section-2 #mask-path-1", { 
    duration: .3, 
    drawSVG: 0, 
    ease: "none" 
  })
  .from("#section-2 #mask-path-2", { 
    duration: .2, 
    drawSVG: 0, 
    ease: "none" 
  },">-0.1")
  .fromTo('#section-2 .blob-wrapper', {
    opacity:0, 
    scale: ".5"
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "back",
    scale: "1", 
    delay: 0
  })
.fromTo('#section-2 .panel', {
    opacity:0
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "power1.out",
    y: "-=25",
    delay: 0
  })


timelines[3]
.fromTo('#section-3 .svg-wrapper', {
    opacity:0,
    scale: "1.5",
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    scale: "1", 
    delay: 0,
  })
  .fromTo('#section-3 #mini-tower-1', {
    opacity:0, 
  }, {
    opacity:1, 
    duration:0.3, 
    ease: "linear",
    delay: .5
  },">-0.4")
  .fromTo(
      "#section-3 #mini-tower-1 .water", 
      { transform: "translateY(36px)" },
      { transform: "translateY(0px)", duration: 1 
    },">-0.3")
  .fromTo(
      "#section-3 #mini-tower-1 .water-waves", 
      { transform: "translateX(44px)" },
      { transform: "translateX(1px)", duration: 1,ease: "linear", repeat: -1 
    },">-0.8")
  .fromTo('#section-3 #mini-tower-2', {
    opacity:0, 
  }, {
    opacity:1, 
    duration:0.3, 
    ease: "linear",
    delay: 0
  },">-1")
  .fromTo(
      "#section-3 #mini-tower-2 .water", 
      { transform: "translateY(36px)" },
      { transform: "translateY(0px)", duration: 1 
    },">-0.3")
  .fromTo(
      "#section-3 #mini-tower-2 .water-waves", 
      { transform: "translateX(44px)" },
      { transform: "translateX(1px)", duration: 1,ease: "linear", repeat: -1 
    },">-0.8")
  .fromTo('#section-3 #mini-tower-3', {
    opacity:0, 
  }, {
    opacity:1, 
    duration:0.3, 
    ease: "linear",
    delay: 0
  },">-1")
  .fromTo(
      "#section-3 #mini-tower-3 .water", 
      { transform: "translateY(36px)" },
      { transform: "translateY(0px)", duration: 1 
    },">-0.3")
  .fromTo(
      "#section-3 #mini-tower-3 .water-waves", 
      { transform: "translateX(44px)" },
      { transform: "translateX(1px)", duration: 1,ease: "linear", repeat: -1 
    },">-0.8")
  .fromTo('#section-3 #mini-tower-4', {
    opacity:0, 
  }, {
    opacity:1, 
    duration:0.3, 
    ease: "linear",
    delay: 0
  },">-1")
  .fromTo(
      "#section-3 #mini-tower-4 .water", 
      { transform: "translateY(36px)" },
      { transform: "translateY(0px)", duration: 1 
    },">-0.3")
  .fromTo(
      "#section-3 #mini-tower-4 .water-waves", 
      { transform: "translateX(44px)" },
      { transform: "translateX(1px)", duration: 1,ease: "linear", repeat: -1 
    },">-0.8")
  .fromTo('#section-3 #mini-tower-5', {
    opacity:0, 
  }, {
    opacity:1, 
    duration:0.3, 
    ease: "linear",
    delay: 0
  },">-1")
  .fromTo(
      "#section-3 #mini-tower-5 .water", 
      { transform: "translateY(36px)" },
      { transform: "translateY(0)", duration: 1 
    },">-0.3")
  .fromTo(
      "#section-3 #mini-tower-5 .water-waves", 
      { transform: "translateX(44px)" },
      { transform: "translateX(1px)", duration: 1,ease: "linear", repeat: -1 
    },">-0.8")
  .fromTo('#section-3 #mini-tower-6', {
    opacity:0, 
  }, {
    opacity:1, 
    duration:0.3, 
    ease: "linear",
    delay: 0
  },">-1")
  .fromTo(
      "#section-3 #mini-tower-6 .water", 
      { transform: "translateY(36px)" },
      { transform: "translateY(0)", duration: 1 
    },">-0.3")
  .fromTo(
      "#section-3 #mini-tower-6 .water-waves", 
      { transform: "translateX(44px)" },
      { transform: "translateX(1px)", duration: 1,ease: "linear", repeat: -1 
    },">-0.8")
  .fromTo('#section-3 .panel', {
    opacity:0
  }, {
    opacity:1, 
    duration:0.3, 
    ease: "power1.out",
    y: "-=25",
    delay: 0
  },">-0.8")
  .call(initSection3) 


  timelines[4]  
  .fromTo('#section-4 .svg-wrapper', {
    opacity:0,
    scale: "1.5",
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    scale: "1",
    delay: 0,
  })
  .fromTo('#section-4 .dc-wrapper', {
    opacity:0,
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    delay: 0
  }) 
  .fromTo('#section-4 .panel', {
    opacity:0
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "power1.out",
    y: "-=25",
    delay: 0
  })


  timelines[5]  
  .fromTo('#section-5 .svg-wrapper', {
    opacity:0,
    scale: "1.5",
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    scale: "1",
    delay: 0,
  })
  .from("#section-5 #mask-path-1", { 
    duration: .3, 
    drawSVG: 0, 
    ease: "none" 
  })
  .fromTo('#section-5 .blob-wrapper', {
    opacity:0, 
    scale: ".5"
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "back",
    scale: "1", 
    delay: 0
  })  
  .fromTo('#section-5 .panel', {
    opacity:0
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "power1.out",
    y: "-=25",
    delay: 0
  })


  timelines[6]  
  .to('.scroll-to-continue', {
    opacity:0
  })
  .fromTo('#section-6 .svg-wrapper', {
    opacity:0,
    scale: "1.5",
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    scale: "1",
    delay: 0,
  })
  .fromTo('#section-6 #title', {
    opacity:0
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    scale: "1", 
    delay: 0
  })  
  .from("#section-6 #mask-path-2", { 
    duration: .3, 
    drawSVG: 0, 
    ease: "none" 
  },">-0")
  .from("#section-6 #mask-path-1", { 
    duration: .6, 
    drawSVG: 0, 
    ease: "none" 
  },">-0")
  .fromTo('#section-6 .blob-wrapper', {
    opacity:0, 
    scale: ".5"
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "back",
    scale: "1", 
    delay: 0
  })
  .fromTo('#section-6 .panel', {
    opacity:0
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "power1.out",
    y: "-=25",
    delay: 0
  })

 

See the Pen oNMywPR by visual23 (@visual23) on CodePen

Link to comment
Share on other sites

Hi,

 

Sorry to hear that you're having problems, but it's impossible for us to debug a live site, plus your site requires a user and password for accessing 🤷‍♂️. Please provide a minimal demo that clearly illustrates the problem you're having and include just a few elements, not a complete fork of your project.

 

Be sure that you're using the latest version of GSAP and ScrollTrigger (don't mix them, use the same version for the core and plugins).

 

Happy Tweening!

Link to comment
Share on other sites

Hi,

 

There is an issue in your setup with your start and end points on your ScrollTrigger instances config. You have this right now:

gsap.timeline({
  scrollTrigger: {
    start: "top top",
    end: "bottom bottom",
  },
});

That tells GSAP to start when the top of the element reaches the top of the viewport and to end when the bottom of the element reaches the bottom of the viewport. Since each section's height is 100vh both points are reached at the same time, so that triggers the enter/leave and enterBack/leaveBack triggers/callbacks at the same time. So you have to tinker with those a bit in order to have them working in the way you intend.

 

In order to run just the h2 animation with the rest of the timeline and just re-run that when the section is visible again and since the rest of the animations run only once, you can use the callback events with a simple check for each section in order to animate just the titles. Something like this (this just shows the first two sections but this can run easily inside a loop):

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

 

I also changed the start and end points.

 

Hopefully this helps.

Happy Tweening!

Link to comment
Share on other sites

Hi @Rodrigo

 

I think I'm getting close. Everything is great when I'm going forward the first time and then backwards but when I get back to section 1 and go forward again, it get's whacky. I included the code for timeline 1. If I understand your example, onEnter and onEnterBack are basically the "to" items and onLeave and onLeaveBack are the "from" items. Is that correct?

 

Thanks!!!

 

timelines[1] = gsap.timeline({
  scrollTrigger: {
    trigger: "#section-1",
    start: () => {
      return `top center`;
    },
    end: () => {
      return `bottom center`;
    },
    //markers: true,
    id: "section-1",
    //onEnter: () => video_00.pause()
    onEnter: () => {
        if (sectionChecks[1]) {
          console.log('s1 - onEnter')
          gsap.to('.section-menu', {
            opacity:1, 
            duration:0.5, 
            ease: "none",
            delay: 0,    
          })
          gsap.to('#section-1 .svg-wrapper', {
            opacity:1, 
            duration:0.5, 
            ease: "none",
            scale: "1", 
            delay: 0,    
          })
          gsap.to('#section-1 #title', {
            opacity:1, 
            duration:0.5, 
            ease: "none",
            scale: "1", 
            delay: 0
          })  
          gsap.from("#section-1 #mask-path-1", { 
            duration: 2, 
            drawSVG: 0, 
            ease: "none" 
          })
          gsap.from("#section-1 #mask-path-2", { 
            duration: .5, 
            drawSVG: 0, 
            ease: "none" 
          })
          gsap.to('#section-1 .blob-wrapper', {
            opacity:1, 
            duration:0.5, 
            ease: "back",
            scale: "1", 
            delay: 0
          })
          gsap.to('#section-1 .panel', {
            opacity:1, 
            duration:0.5, 
            ease: "power1.out",
            y: "-=25",
            delay: 3
          });
        } else {
          sectionChecks[1] = true;
        }
    },
    onEnterBack: () => {
      console.log('s1 - onEnterBack')
        gsap.to('.section-menu', {
          opacity:1, 
          duration:0.5, 
          ease: "none",
          delay: 0,    
        })
        gsap.to('#section-1 .svg-wrapper', {
          opacity:1, 
          duration:0.5, 
          ease: "none",
          scale: "1", 
          delay: 0,    
        })
        gsap.to('#section-1 #title', {
          opacity:1, 
          duration:0.5, 
          ease: "none",
          scale: "1", 
          delay: 0
        })  
        gsap.from("#section-1 #mask-path-1", { 
          duration: 2, 
          drawSVG: 0, 
          ease: "none" 
        })
        gsap.from("#section-1 #mask-path-2", { 
          duration: .5, 
          drawSVG: 0, 
          ease: "none" 
        },">-0.05")
        gsap.to('#section-1 .blob-wrapper', {
          opacity:1, 
          duration:0.5, 
          ease: "back",
          scale: "1", 
          delay: 0
        },">-0.05")
        gsap.to('#section-1 .panel', {
          opacity:1, 
          duration:0.5, 
          ease: "power1.out",
          y: "-=25",
          delay: 3
        });
    },
    onLeave: () => {
        if (sectionChecks[1]) {
          console.log('s1 - onLeave')
          gsap.to('#section-1 .svg-wrapper', {
            opacity:0,
            scale: "1.5",
            duration:0.1,
            ease: 'none'  
          })
          gsap.to('#section-1 #title', {
            opacity:0, 
            duration:0.1,
            ease: 'none' 
          })  
          gsap.from("#section-1 #mask-path-1", { 
            duration: 0.1, 
            drawSVG: 0, 
            ease: "none" 
          })
          gsap.from("#section-1 #mask-path-2", { 
            duration: 0.1, 
            drawSVG: 0, 
            ease: "none" 
          })
          gsap.to('#section-1 .blob-wrapper', {
            opacity:0, 
            scale: ".5", 
            duration:0.1,
            ease: 'none' 
          })
          gsap.to('#section-1 .panel', {
            opacity:0, 
            duration:0.1,
            ease: 'none', 
            y: "-=0",
          });
        } else {
          sectionChecks[1] = true;
        }
    },
    onLeaveBack: () => {
      console.log('s1 - onLeaveBack')
      gsap.to('#section-1 .svg-wrapper', {
        opacity:0,
        scale: "1.5",
        duration:0.1,
        ease: 'none'  
      })
      gsap.to('#section-1 #title', {
        opacity:0, 
        duration:0.1,
        ease: 'none' 
      })  
      gsap.from("#section-1 #mask-path-1", { 
        duration: 0.1, 
        drawSVG: 0, 
        ease: "none" 
      })
      gsap.from("#section-1 #mask-path-2", { 
        duration: 0.1, 
        drawSVG: 0, 
        ease: "none" 
      })
      gsap.to('#section-1 .blob-wrapper', {
        opacity:0, 
        scale: ".5", 
        duration:0.1,
        ease: 'none' 
      })
      gsap.to('#section-1 .panel', {
        opacity:0, 
        duration:0.1,
        ease: 'none', 
        y: "-=0",
      });
    }
  }
})
.fromTo('.section-menu', {
    opacity:0    
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    delay: 0,    
  })
.fromTo('#section-1 .svg-wrapper', {
    opacity:0,
    scale: "1.5",    
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    scale: "1", 
    delay: 0,    
  })
  .fromTo('#section-1 #title', {
    opacity:0
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    scale: "1", 
    delay: 0
  })  
  .from("#section-1 #mask-path-1", { 
    duration: 2, 
    drawSVG: 0, 
    ease: "none" 
  })
  .from("#section-1 #mask-path-2", { 
    duration: .5, 
    drawSVG: 0, 
    ease: "none" 
  },">-0.05")
  .fromTo('#section-1 .blob-wrapper', {
    opacity:0, 
    scale: ".5"
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "back",
    scale: "1", 
    delay: 0
  },">-0.05")
  .fromTo('#section-1 .panel', {
    opacity:0
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "power1.out",
    y: "-=25",
    delay: 0
  });

 

Link to comment
Share on other sites

Hi,

 

You just mentioned an h2 on each section not a bunch of elements. In the case of the DrawSVG instances it would be a good idea to create some set instances before creating the ScrollTrigger-controlled Timelines and draw the svgs to 0% and 100%. Check this example and in the array replace 10% with 0% and click the Run button in order to restart the codepen and see what happens when you get to that point.

 

If you keep having issues, please create a minimal demo in order to have a better look.

Happy Tweening!

Link to comment
Share on other sites

Hello,

 

I have been messing with this for hours and I finally see what is happening. If you scroll at normal speed through each section and then go back and forth to each section everything works fine but if you can faster and an animation hasn't finished, it will keep happening in the background and what I have in onLeave and onLeave back doesn't reset the elements. It's almost like on onLeave and onLeaveBack I need to kill the animations. You can see what I mean in the codepen above.

 

Thanks in advance!

 

Link to comment
Share on other sites

Woohoo! I finally got it all working perfectly. I created my timeline for each section and then a scrollTrigger for each section. In each scrollTrigger I have the "animation" set to the section timeline and the toggleActions to play onEnter/onEnterBack and reset onLeave/onLeaveBack.

 

Thanks for all of your help!

 

const animate_01 =  gsap.timeline({paused:true})
.fromTo('#section-1 .svg-wrapper', {
    opacity:0,
    scale: "1.5",    
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    scale: "1", 
    delay: 0,    
  })
  .fromTo('#section-1 #title', {
    opacity:0
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "none",
    scale: "1", 
    delay: 0
  })  
  .from("#section-1 #mask-path-1", { 
    duration: 2, 
    drawSVG: 0, 
    ease: "none" 
  })
  .from("#section-1 #mask-path-2", { 
    duration: .5, 
    drawSVG: 0, 
    ease: "none" 
  },">-0.05")
  .fromTo('#section-1 .blob-wrapper', {
    opacity:0, 
    scale: ".5"
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "back",
    scale: "1", 
    delay: 0
  },">-0.05")
  .fromTo('#section-1 .panel', {
    opacity:0
  }, {
    opacity:1, 
    duration:0.5, 
    ease: "power1.out",
    y: "-=25",
    delay: 0
  });

ScrollTrigger.create({
    trigger: '#section-1',
    animation: animate_01,
    toggleActions:"play reset play reset",
    start: () => {
      return `top center`;
    },
    end: () => {
      return `bottom center`;
    }
});

 

  • Like 2
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...