Jump to content
Search Community

Levin Riegner

Business
  • Posts

    27
  • Joined

  • Last visited

Posts posted by Levin Riegner

  1. Hey, a quick one. When using the HorizontalLoop / SeamlessLoop (https://gsap.com/docs/v3/HelperFunctions/helpers/seamlessLoop) helper function, the reversed option doesnt change anything.

     

    My example code:
     

    // ... React useEffect code surrounding this.
    const logos = logoRefs.map((ref) => ref.current);
    
    const loop = horizontalLoop(logos, {
      reversed: true, // Doesnt work
      speed: 1, // Works
      paused: false, // Works
      repeat: -1, // Works
    });
    
    const performanceTimeline = gsap.timeline({
      scrollTrigger: {
        trigger: main.current,
        start: 'top bottom',
        end: 'bottom top',
        scrub: true,
        onEnter: () => loop.play(),
        onLeave: () => loop.pause(),
        onEnterBack: () => loop.play(),
        onLeaveBack: () => loop.pause(),
      },
    });

     

    Im expecting my marquee to animate to the right vs to the left which its currently doing.

     

     

     

    As im writing this it turns out the timeline causing the reverse to not work - specifically the onEnter etc.Why is this effecting the ability to reverse? Im pausing for performance reasons (offscreen = paused, onScreen = play)

  2. I have an infinite marquee, that i thought was working, however it jumps at the very end slightly, im not quite sure why im wondering based on the code provided below if theres anything that looks wrong in what im doing?

     

    JSX File: 

    const MobileMarquee = ({ client }) => {
      // NOTE • Refs
      const main = React.useRef();
      const first = React.useRef();
      const last = React.useRef();
    
      React.useLayoutEffect(() => {
        const ctx = gsap.context(() => {
          // Split characters
          const split = new SplitText(first.current, {
            type: "chars",
            charsClass: "char",
          });
    
          // Split characters count + timing calculation
          const charsTotal = split.chars.length;
          const timingFactor = charsTotal * 0.25;
    
          let timeline1 = gsap.timeline();
          let timeline2 = gsap.timeline();
    
          timeline1.fromTo(
            first.current,
            {
              xPercent: 0,
            },
            {
              xPercent: -100,
              repeat: -1,
              duration: timingFactor,
              ease: "none",
            }
          );
    
          timeline2.fromTo(
            last.current,
            {
              xPercent: 0,
            },
            {
              xPercent: -100,
              repeat: -1,
              duration: timingFactor,
              ease: "none",
            }
          );
        }, main);
    
        return () => ctx.revert();
      }, []);
    
      return (
        <Jacket isPaused={isPaused} ref={main}>
          <div>
            <ul ref={first}>
              {words.map(({ word, uid }) => (
                <li key={uid} className="el">
                  {word}&nbsp;–&nbsp;
                </li>
              ))}
            </ul>
    
            {/* Dupl */}
            <ul aria-hidden="true" ref={last}>
              {words.map(({ word, uid }) => (
                <li className="el" key={uid}>
                  {word}&nbsp;–&nbsp;
                </li>
              ))}
            </ul>
          </div>
        </Jacket>
      );
    };

    CSS/JS:

    // Imports
    // ------------
    import styled, { css } from "styled-components";
    
    // Exports
    // ------------
    export const Jacket = styled.h1(
      (props) => css`
        position: relative;
        z-index: 3;
        overflow: hidden;
        width: 100vw;
    
        div {
          display: flex;
          width: fit-content;
        }
    
        ul {
          display: flex;
          width: fit-content;
          position: relative;
          justify-content: flex-start;
          transform: translateX(0);
    
          li {
            display: flex;
            align-items: center;
    
            font-weight: ${props.theme.font.weight.reg};
            font-family: ${props.theme.font.type.heading};
            font-size: 6rem;
            line-height: 1.2;
            color: ${props.theme.colors.brand.bc4};
            user-select: none;
            white-space: nowrap;
          }
        }
      `
    );

     

     

    Codesandbox Recreation:
    https://codesandbox.io/s/react-hooks-example-w-clicker-t6yno?file=/src/pages/index.js

  3. Heres my example code:
     

    // Imports
    // ------------
    import React, { useRef, useLayoutEffect } from 'react';
    import { gsap } from 'gsap';
    import { SplitText } from 'gsap/all';
    
    // Styles
    // ------------
    import { Jacket } from './styles';
    
    // Component
    // ------------
    const ScrollAnimatedText = ({ children }) => {
    	// NOTE • refs
    	const comp = useRef();
    
    	// NOTE • Animation
    	useLayoutEffect(() => {
    		let timer;
    		let split;
    
    		const ctx = gsap.context(() => {
    			timer = setTimeout(() => {
    				const childText = comp.current.firstChild;
    
    				split = new SplitText(childText, {
    					tag: 'span',
    					type: 'lines,words,chars',
    					linesClass: 'line',
    				});
    
    				const lines = comp.current.querySelectorAll('.line');
    
    				for (const line of lines) {
    					gsap.to(line, {
    						ease: 'none',
    						opacity: 1,
    						y: `0%`,
    						scrollTrigger: {
    							trigger: line,
    							start: 'top bottom',
    							end: 'top top+=60%',
    							scrub: true,
    							markers: false,
    						},
    						stagger: {
    							each: 0.08,
    							from: 'start',
    						},
    					});
    				}
    			}, 150);
    		}, comp);
    
    		return () => {
    			clearTimeout(timer);
    			ctx.revert();
    		};
    	}, []);
    
    	return <Jacket ref={comp}>{children}</Jacket>;
    };
    
    export default React.memo(ScrollAnimatedText);

     

  4. On 1/3/2023 at 12:23 PM, Rodrigo said:

    Hi @nightlock82 and welcome to the GreenSock forums!

     

    Your can specify the tag in the SplitText config object

     

    tag

    String - by default, SplitText wraps things in <div> elements, but you can define any tag like tag: "span"

     

    Happy Tweening!

    There is no option for "tag", Chrome is complaining that i cannot have Divs inside a <p> tag, so it need it to be a span

  5. Okay I got it working with this code - but it doesnt make sense why this would work vs the other

     

    const Marquee = React.forwardRef((props, ref) => {
    	const first = useRef();
    	const last = useRef();
    
    	useLayoutEffect(() => {
    		const width1 = first.current.offsetWidth;
    		const width2 = first.current.offsetWidth;
    
    		const timeline1 = gsap.timeline();
    		const timeline2 = gsap.timeline();
    
    		timeline1.fromTo(
    			first.current,
    			{
    				xPercent: 0,
    			},
    			{
    				xPercent: -100,
    				repeat: -1,
    				repeatRefresh: true,
    				duration: 5,
    				ease: 'none',
    			}
    		);
    
    		timeline2.fromTo(
    			last.current,
    			{
    				xPercent: 0,
    			},
    			{
    				xPercent: -100,
    				repeat: -1,
    				repeatRefresh: true,
    				duration: 5,
    				ease: 'none',
    			}
    		);
    	}, []);
    
    	return (
    		<Jacket isPaused={props.isPaused} ref={ref}>
    			<div>
    				<ul ref={first}>
    					{props.text.map(({ word, uid }) => (
    						<li key={uid} className='el'>
    							{word}&nbsp;–&nbsp;
    						</li>
    					))}
    				</ul>
    
    				{/* Dupl */}
    				<ul aria-hidden='true' ref={last}>
    					{props.text.map(({ word, uid }) => (
    						<li className='el' key={uid}>
    							{word}&nbsp;–&nbsp;
    						</li>
    					))}
    				</ul>
    			</div>
    		</Jacket>
    	);
    });

     

  6. I have created this React component which should be repeating infinitely, but it only plays once.

    I feel like im going insane, why is it only playing once??

     

    const Marquee = React.forwardRef((props, ref) => {
    	const first = useRef();
    	const last = useRef();
    
    	useLayoutEffect(() => {
    		const tl = gsap.to(first.current, {
    			xPercent: -100,
    			repeat: -1,
    			duration: 5,
    			ease: 'none',
    			repeatRefresh: true,
    		});
    
    		const tl2 = gsap.to(last.current, {
    			xPercent: -100,
    			repeat: -1,
    			duration: 5,
    			ease: 'none',
    			repeatRefresh: true,
    		});
    	}, []);
    
    	return (
    		<Jacket isPaused={props.isPaused} ref={ref}>
    			<div>
    				<ul ref={first}>
    					{props.text.map(({ word, uid }) => (
    						<li key={uid} className='el'>
    							{word}&nbsp;–&nbsp;
    						</li>
    					))}
    				</ul>
    
    				{/* Dupl */}
    				<ul aria-hidden='true' ref={last}>
    					{props.text.map(({ word, uid }) => (
    						<li className='el' key={uid}>
    							{word}&nbsp;–&nbsp;
    						</li>
    					))}
    				</ul>
    			</div>
    		</Jacket>
    	);
    });

    For reference:
    https://codesandbox.io/s/divine-sun-7kksyk?file=/src/Marquee/index.jsx

    See the Pen Marquee by s (@s) on CodePen

  7. Fixed!

    I needed to do this instead:
     

    // NOTE Before render, calculate smooth scrolling
    useLayoutEffect(() => {
      const ctx = gsap.context(() => {
        smoother.current = ScrollSmoother.create({
          smooth: 2, // seconds it takes to "catch up" to native scroll position
          effects: true, // look for data-speed and data-lag attributes on elements and animate accordingly
          onUpdate: (self) => {
            let scrollY = self.scrollTop();
    
            console.log(scrollY);
          }
        });
      }, main);
    
      return () => ctx.revert();
    }, []);

     

  8. I need to access the scroll position.

     

    I have a function that looks to when the user scrolls 100px then fires a function, and the same on scroll back up. However ofcourse window doesnt work.

     

    How do you access this in ScrollSMoother?

    Heres my current code, that doesnt work.

     

    // NOTE Before render, calculate smooth scrolling
    useLayoutEffect(() => {
      const ctx = gsap.context(() => {
        smoother.current = ScrollSmoother.create({
          smooth: 2, // seconds it takes to "catch up" to native scroll position
          effects: true, // look for data-speed and data-lag attributes on elements and animate accordingly
          onUpdate: update
        });
      }, main);
    
      return () => ctx.revert();
    }, []);
    
    const update = () => {
      // Get scrollY position
      const scrollY = smoother.current.scroll.y; // Scroll doesnt exist
      console.log(scrollY);
    };

     

×
×
  • Create New...