Jump to content
Search Community

Scroll Sueqence Image

Okaka test
Moderator Tag

Recommended Posts

I am not a native English speaker and my writing may be poor, but thank you in advance.

What I want to do
Final Goal.
* As a Wordpress block, I want to create a component that switches images as it scrolls, like a GIF.

Specifications
1. the image changes by scrolling 2. the block is like a sticky
Ideally, the block should behave like a sticky. 2. When the scrolling brings the block to a given location, in this case the middle, the animation of the image switching will start, and when it switches to the last image, the sticky-like behavior will resume. 3.
3. The number of images and the amount of scrolling per image should be adjustable.
4. Use Next/image for performance.

However, we are currently unable to meet most of the specifications.
Please advise.

https://codesandbox.io/p/devbox/mutable-sunset-phspgm?layout=%7B%22sidebarPanel%22%3A%22EXPLORER%22%2C%22rootPanelGroup%22%3A%7B%22direction%22%3A%22horizontal%22%2C%22contentType%22%3A%22UNKNOWN%22%2C%22type%22%3A%22PANEL_GROUP%22%2C%22id%22%3A%22ROOT_LAYOUT%22%2C%22panels%22%3A%5B%7B%22type%22%3A%22PANEL_GROUP%22%2C%22contentType%22%3A%22UNKNOWN%22%2C%22direction%22%3A%22vertical%22%2C%22id%22%3A%22clpgsu9rd000c3b6hk9fvt80r%22%2C%22sizes%22%3A%5B70%2C30%5D%2C%22panels%22%3A%5B%7B%22type%22%3A%22PANEL_GROUP%22%2C%22contentType%22%3A%22EDITOR%22%2C%22direction%22%3A%22horizontal%22%2C%22id%22%3A%22EDITOR%22%2C%22panels%22%3A%5B%7B%22type%22%3A%22PANEL%22%2C%22contentType%22%3A%22EDITOR%22%2C%22id%22%3A%22clpgsu9rd00033b6hgs78ghyh%22%7D%5D%7D%2C%7B%22type%22%3A%22PANEL_GROUP%22%2C%22contentType%22%3A%22SHELLS%22%2C%22direction%22%3A%22horizontal%22%2C%22id%22%3A%22SHELLS%22%2C%22panels%22%3A%5B%7B%22type%22%3A%22PANEL%22%2C%22contentType%22%3A%22SHELLS%22%2C%22id%22%3A%22clpgsu9rd00093b6h4tuvn8da%22%7D%2C%7B%22type%22%3A%22PANEL%22%2C%22contentType%22%3A%22SHELLS%22%2C%22id%22%3A%22clpgsv2wp00as3b6h9q1zxkca%22%7D%5D%2C%22sizes%22%3A%5B50%2C50%5D%7D%5D%7D%2C%7B%22type%22%3A%22PANEL_GROUP%22%2C%22contentType%22%3A%22DEVTOOLS%22%2C%22direction%22%3A%22vertical%22%2C%22id%22%3A%22DEVTOOLS%22%2C%22panels%22%3A%5B%7B%22type%22%3A%22PANEL%22%2C%22contentType%22%3A%22DEVTOOLS%22%2C%22id%22%3A%22clpgsu9rd000b3b6hz66bjsev%22%7D%5D%2C%22sizes%22%3A%5B100%5D%7D%5D%2C%22sizes%22%3A%5B50%2C50%5D%7D%2C%22tabbedPanels%22%3A%7B%22clpgsu9rd00033b6hgs78ghyh%22%3A%7B%22id%22%3A%22clpgsu9rd00033b6hgs78ghyh%22%2C%22tabs%22%3A%5B%5D%7D%2C%22clpgsu9rd000b3b6hz66bjsev%22%3A%7B%22tabs%22%3A%5B%7B%22id%22%3A%22clpgsu9rd000a3b6hs7vcy8u6%22%2C%22mode%22%3A%22permanent%22%2C%22type%22%3A%22TASK_PORT%22%2C%22taskId%22%3A%22dev%22%2C%22port%22%3A3000%2C%22path%22%3A%22%2F%22%7D%5D%2C%22id%22%3A%22clpgsu9rd000b3b6hz66bjsev%22%2C%22activeTabId%22%3A%22clpgsu9rd000a3b6hs7vcy8u6%22%7D%2C%22clpgsu9rd00093b6h4tuvn8da%22%3A%7B%22tabs%22%3A%5B%7B%22id%22%3A%22clpgsu9rd00043b6ht4kjqek2%22%2C%22mode%22%3A%22permanent%22%2C%22type%22%3A%22TASK_LOG%22%2C%22taskId%22%3A%22dev%22%7D%2C%7B%22id%22%3A%22clpgsu9rd00053b6hea0ksahd%22%2C%22mode%22%3A%22permanent%22%2C%22type%22%3A%22TASK_LOG%22%2C%22taskId%22%3A%22build%22%7D%2C%7B%22id%22%3A%22clpgsu9rd00063b6hps2cukre%22%2C%22mode%22%3A%22permanent%22%2C%22type%22%3A%22TASK_LOG%22%2C%22taskId%22%3A%22start%22%7D%2C%7B%22id%22%3A%22clpgsu9rd00073b6hr3bn3ejy%22%2C%22mode%22%3A%22permanent%22%2C%22type%22%3A%22TASK_LOG%22%2C%22taskId%22%3A%22lint%22%7D%2C%7B%22id%22%3A%22clpgsu9rd00083b6hay6mh0wm%22%2C%22mode%22%3A%22permanent%22%2C%22type%22%3A%22TASK_LOG%22%2C%22taskId%22%3A%22install%22%7D%5D%2C%22id%22%3A%22clpgsu9rd00093b6h4tuvn8da%22%2C%22activeTabId%22%3A%22clpgsu9rd00083b6hay6mh0wm%22%7D%2C%22clpgsv2wp00as3b6h9q1zxkca%22%3A%7B%22tabs%22%3A%5B%7B%22id%22%3A%22clpgsutp300ao3b6hzundduq5%22%2C%22mode%22%3A%22permanent%22%2C%22type%22%3A%22TERMINAL%22%2C%22shellId%22%3A%22clpgsv34k00hwefge61fm17o6%22%7D%5D%2C%22id%22%3A%22clpgsv2wp00as3b6h9q1zxkca%22%2C%22activeTabId%22%3A%22clpgsutp300ao3b6hzundduq5%22%7D%7D%2C%22showDevtools%22%3Atrue%2C%22showShells%22%3Atrue%2C%22showSidebar%22%3Atrue%2C%22sidebarPanelSize%22%3A15%7D

Link to comment
Share on other sites

Hi @Okaka welcome to the forum!

 

I have the feeling you're going about this in the wrong direction. My advies remove ScrollTrigger. The best thing to do when working with ScrollTrigger is to remove it! This seems counter intuitive, but ScrollTrigger is just animating something on scroll, so just focus on the animation at first and only when you're happy with the animation add ScrollTrigger back in. This way you can focus on one part at a time and it will save a lot of headache when debugging. 

 

Here is a topic discussing an image sequence with GSAP, it uses one image with the background position, but you could easily just stack all the images on top of each other and animate their opacity (or what ever property you want). But below example uses just one ScrollTrigger with a tween, that would also be the recommendation I would give you, right now each image has a ScrollTrigger with all their own tweens, this means none of the ScrollTriggers are aware of each other and nothing will line up. 

 

 

I would suggest creating a timeline (with ScrollTrigger disabled) and just create the animation of the images fading in and out, if you have that working add ONE ScrollTrigger to that timeline that animates that timeline on scroll. 

 

But the most important step when working with React is doing proper clean up, if you're using GSAP with React, you must read this, hope it helps and happy tweening!  

 

  • Like 2
Link to comment
Share on other sites

Thanks for the reply.
I am stuck in this situation because I was coding without understanding anything in depth.
As you advised, I will go back to the basics and read the documentation and try to figure it out, but I would welcome any examples of implementations that are close to my concept.
I'm very stumped and any advice would be appreciated.
Thank you very much.

29 minutes ago, mvaneijgen said:

Hi @Okaka welcome to the forum!

 

I have the feeling you're going about this in the wrong direction. My advies remove ScrollTrigger. The best thing to do when working with ScrollTrigger is to remove it! This seems counter intuitive, but ScrollTrigger is just animating something on scroll, so just focus on the animation at first and only when you're happy with the animation add ScrollTrigger back in. This way you can focus on one part at a time and it will save a lot of headache when debugging. 

 

Here is a topic discussing an image sequence with GSAP, it uses one image with the background position, but you could easily just stack all the images on top of each other and animate their opacity (or what ever property you want). But below example uses just one ScrollTrigger with a tween, that would also be the recommendation I would give you, right now each image has a ScrollTrigger with all their own tweens, this means none of the ScrollTriggers are aware of each other and nothing will line up. 

 

 

I would suggest creating a timeline (with ScrollTrigger disabled) and just create the animation of the images fading in and out, if you have that working add ONE ScrollTrigger to that timeline that animates that timeline on scroll. 

 

But the most important step when working with React is doing proper clean up, if you're using GSAP with React, you must read this, hope it helps and happy tweening!  

 

 

Link to comment
Share on other sites

Here is a simple timeline that tweens through images,

 

Instead of having a tween for each image you probably want to create a loop or use the stagger object https://gsap.com/resources/getting-started/Staggers

 

See the Pen GRzWQeP?editors=0010 by mvaneijgen (@mvaneijgen) on CodePen

 

if you would hook this up to ScrollTrigger it would just work.

 

See the Pen QWYBvLm?editors=1010 by mvaneijgen (@mvaneijgen) on CodePen

  • Like 2
Link to comment
Share on other sites

On 11/27/2023 at 10:55 PM, mvaneijgen said:

Here is a simple timeline that tweens through images,

 

Instead of having a tween for each image you probably want to create a loop or use the stagger object https://gsap.com/resources/getting-started/Staggers

 

 

 

 

if you would hook this up to ScrollTrigger it would just work.

 

 

 

Thank you for your reply and advice.
I am aiming to implement this in Next.js.
I have tried to implement the suggested code here in Next.js.
While it works for reverse scrolling, it does not work for forward scrolling.
The pin works incorrectly.

 

import React, { useLayoutEffect, useRef } from "react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/dist/ScrollTrigger";
import { css } from "../../../../styled-system/css";

gsap.registerPlugin(ScrollTrigger);

const Parallax07 = () => {
  const imagesRef = useRef<HTMLDivElement | null>(null);

  const styles = {
    imageStyle: css({
      position: "absolute",
      top: 0,
      left: 0,
      width: "600px",
      opacity: 0,
    }),
  };

  useLayoutEffect(() => {
    const images = imagesRef.current?.children;

    if (!images) return;

    const tl = gsap.timeline({
      scrollTrigger: {
        trigger: imagesRef.current,
        start: "top top",
        end: "bottom+=3000px top",
        scrub: true,
        pin: true,
        markers: true,
      },
    });

    Array.from(images).forEach((img, index) => {
      tl.to(img, {
        opacity: 1,
        duration: 1,
        ease: "none",
      }).to(
        img,
        {
          opacity: 0,
          duration: 1,
          ease: "none",
        },
        `+=${index}`
      );
    });
  }, []);

  return (
    <>
      <div>
        <h1>Parallax07</h1>
      </div>
      <div
        id="images"
        className={css({ position: "relative" })}
        ref={imagesRef}
      >
        <img
          className={styles.imageStyle}
          src="https://images.pexels.com/photos/346529/pexels-photo-346529.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=400&w=600"
        />
        <img
          className={styles.imageStyle}
          src="https://images.pexels.com/photos/206359/pexels-photo-206359.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=400&w=600"
        />
        <img
          className={styles.imageStyle}
          src="https://images.pexels.com/photos/709552/pexels-photo-709552.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=400&w=600"
        />
      </div>
      <section style={{ height: "500vh", backgroundColor: "pink" }}>
        <h1>Extra space just for demo, remove this</h1>
      </section>
    </>
  );
};

export default Parallax07;

 

Link to comment
Share on other sites

Hi there! I see you're using React -

Proper animation cleanup is very important with frameworks, but especially with React. React 18 runs in strict mode locally by default which causes your useEffect() and useLayoutEffect() to get called TWICE.

In GSAP 3.11, we introduced a new gsap.context() feature that helps make animation cleanup a breeze. All you need to do is wrap your code in a context call. All GSAP animations and ScrollTriggers created within the function get collected up in that context so that you can easily revert() ALL of them at once.

Here's the structure:

// typically it's best to useLayoutEffect() instead of useEffect() to have React render the initial state properly from the very start.
useLayoutEffect(() => {
  let ctx = gsap.context(() => {
    // all your GSAP animation code here
  });
  return () => ctx.revert(); // <- cleanup!
}, []);

This pattern follows React's best practices, and one of the React team members chimed in here if you'd like more background.

We strongly recommend reading the React information we've put together at https://gsap.com/resources/React/

Happy tweening!

  • Like 1
Link to comment
Share on other sites

7 minutes ago, GSAP Helper said:

Hi there! I see you're using React -

Proper animation cleanup is very important with frameworks, but especially with React. React 18 runs in strict mode locally by default which causes your useEffect() and useLayoutEffect() to get called TWICE.

In GSAP 3.11, we introduced a new gsap.context() feature that helps make animation cleanup a breeze. All you need to do is wrap your code in a context call. All GSAP animations and ScrollTriggers created within the function get collected up in that context so that you can easily revert() ALL of them at once.

Here's the structure:

// typically it's best to useLayoutEffect() instead of useEffect() to have React render the initial state properly from the very start.
useLayoutEffect(() => {
  let ctx = gsap.context(() => {
    // all your GSAP animation code here
  });
  return () => ctx.revert(); // <- cleanup!
}, []);

This pattern follows React's best practices, and one of the React team members chimed in here if you'd like more background.

We strongly recommend reading the React information we've put together at https://gsap.com/resources/React/

Happy tweening!

Thanks for the reply!
I see that it consisted of the React v18 spec.
I'm very impressed with your advice, which is based on a wide range of knowledge.

Link to comment
Share on other sites


https://codesandbox.io/p/devbox/mutable-sunset-phspgm

The advice was taken into account for implementation.
Appreciate it.
I haven't yet been able to make the outermost component move like position: sticky and have the ability to control the start and end of the animation when the sticky element is in the middle, but I'm working hard on implementing it now.

Link to comment
Share on other sites


https://codesandbox.io/p/devbox/mutable-sunset-phspgm
 

Your advice so far has been very helpful.
My ultimate goal is to create this as a wordpress block.
One of the things I am wondering is if it is possible to place an arbitrary DOM element or component and have it end at that location, instead of determining the end of the animation or pin (fixed end) based on the number of images.
If you have any ideas, I would like to hear them.
Thank you in advance.

demo 
# gsap demo
https://codesandbox.io/p/devbox/mutable-sunset-phspgm?file=%2Fapp%2Fpage.tsx%3A93%2C75

# canva demo
https://codesandbox.io/p/devbox/mutable-sunset-phspgm?file=%2Fapp%2Fcanvademo%2Fpage.tsx%3A21%2C14

Link to comment
Share on other sites

Hi,

 

I'm not 100% sure I follow exactly what you're trying to do, but maybe you're looking for the endTrigger config property in ScrollTrigger:

https://gsap.com/docs/v3/Plugins/ScrollTrigger/#config-object

 

endTrigger
String | Element - The element (or selector text for the element) whose position in the normal document flow is used for calculating where the ScrollTrigger ends. You don't need to define an endTrigger unless it's DIFFERENT than the trigger element because that's the default.

 

Hopefully this helps.

Happy Tweening!

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...