Jump to content
Search Community

velkas

Members
  • Posts

    33
  • Joined

  • Last visited

Posts posted by velkas

  1. After some fiddling, the solution I came up with was to conditionally render the children. The scroll requires a ref to the scroll container so the init function is placed inside useEffect to guarantee the ref is defined. And because this component is at the "top level" we don't need to pass location to the useEffect callback. This seems to work but any improvements or suggestions are welcome 🤷‍♂️

     

    import React, { useRef, useEffect, useState } from "react"
    import Navbar from "./navbar"
    import Scroll from './scroll'
    import '../styles/smooth-scrollbar.css'
    
    
    const Layout = ({ children }) => {
      
      let scrollerRef = useRef()
      let [scrollDefined, setScrollDefined] = useState(false)
    
      const initScroll = () => {
        Scroll(scrollerRef)
        setScrollDefined(true)
      }
    
      useEffect(() => {
        initScroll()
      }, [])
      
      return (
        <div className="global-wrapper scroller h-screen overflow-hidden" ref={scrollerRef}>
    
          <header className="global-header animate__animated animate__fadeIn">
            <Navbar />
          </header>
        
          <main>{ scrollDefined && children }</main>
    
          <footer>
            {/* © {new Date().getFullYear()}, Built with */}
            {` `}
            {/* <a href="https://www.gatsbyjs.com">Gatsby</a> */}
          </footer>
          
        </div>
      )
    }
    
    export default Layout

     

    import { gsap } from "gsap";
    import { ScrollTrigger } from "gsap/ScrollTrigger";
    import Scrollbar from 'smooth-scrollbar'
    import SoftScrollPlugin from './plugins/SoftScrollPlugin'
    
    const Scroll = (scrollerRef) => { 
      
      const scroller = scrollerRef.current
      
      Scrollbar.use(SoftScrollPlugin)
      
      const bodyScrollBar = Scrollbar.init(scroller, { damping: 0.1, delegateTo: document, alwaysShowTracks: true })
      
      window.bodyScrollBar = bodyScrollBar
      
      gsap.registerPlugin(ScrollTrigger)
      
      ScrollTrigger.defaults({ scroller: scroller })
      
      ScrollTrigger.scrollerProxy(scroller, {
        scrollTop(value) {
          if (arguments.length) {
            bodyScrollBar.scrollTop = value
          }
          return bodyScrollBar.scrollTop
        }
      })
    
      ScrollTrigger.refresh()
      bodyScrollBar.addListener(ScrollTrigger.update)
    }
    
    export default Scroll

     

    • Like 1
  2. I am using Gatsby JS and initializing smooth-scrollbar within a layout component and I've also configured the scroller proxy. Within a child component, I'm trying to setup an animation using scroll trigger but I'm not sure how to configure this. Also, the config does work after HMR fires but not after page refresh. I removed most of the markup from the page as I know the animation works - I think the issue is with syncing the scrollers.

     

    layout.js:

    import React, { useRef, useEffect } from "react"
    import Navbar from "./navbar"
    import { gsap } from "gsap";
    import { ScrollTrigger } from "gsap/ScrollTrigger";
    import Scrollbar from 'smooth-scrollbar'
    // import "../styles/locomotive-scroll.css"
    
    
    const Layout = ({ children, location }) => {
      
      const scrollerRef = useRef()
    
      useEffect(() => {
        
        gsap.registerPlugin(ScrollTrigger)
        
        const scroller = scrollerRef.current
    
        const bodyScrollBar = Scrollbar.init(scrollerRef.current, { damping: 0.1, delegateTo: document, alwaysShowTracks: true })
    
        window.bodyScrollBar = bodyScrollBar
    
        ScrollTrigger.scrollerProxy(scrollerRef.current, {
          scrollTop(value) {
            if (arguments.length) {
              bodyScrollBar.scrollTop = value
            }
            return bodyScrollBar.scrollTop
          }
        })
    
        window.scroller = scrollerRef.current
    
        bodyScrollBar.addListener(ScrollTrigger.update)
    
        ScrollTrigger.defaults({ scroller: scroller })
    
        // ScrollTrigger.refresh()
        
        return () => {
          if (bodyScrollBar) bodyScrollBar.destroy()
          bodyScrollBar.removeListener(ScrollTrigger.update)
        }
      }, [location])
      
      return (
        <div className="global-wrapper scroller h-screen overflow-hidden" ref={scrollerRef}>
    
          <header className="global-header animate__animated animate__fadeIn">
            <Navbar />
          </header>
    
    
          <main>{children}</main>
          <footer>
            {/* © {new Date().getFullYear()}, Built with */}
            {` `}
            {/* <a href="https://www.gatsbyjs.com">Gatsby</a> */}
          </footer>
          
        </div>
      )
    }
    
    export default Layout

    index.js:

    import React, { useEffect, useRef } from "react"
    import { gsap } from "gsap";
    import { ScrollTrigger } from "gsap/ScrollTrigger";
    
    
    function Index() {
    
      const outroRef = useRef()
      const outroContentRef = useRef()
    
      useEffect(() => {
    
        gsap.registerPlugin(ScrollTrigger)
    
        gsap.fromTo(outroContentRef.current, {
          yPercent: "-50"
        }, {
          yPercent: "0",
          scrollTrigger: {
            scroller: window.scroller,
            trigger: outroRef.current,
            end: "bottom bottom",
            scrub: true,
            markers: true
          }, ease: "none"
        })
    
      }, []);
    
        return (
          <>
            {/* Page content */}
          </>
        )
    }
    
    export default Index

     

  3. I've seen a lot of posts about trying to create a marquee section similar to the one on Cuberto's home page. I'm trying to recreate the marquee but the animation seems to "jump" when looping. I'm thinking my math maybe off in the modifier callback?

     

    EDIT: Inspecting the dom elements it seems the row items are overflowing the row slightly possibly because of whitespace generated from using inline-blocks.

    See the Pen gOgwzpw?editors=0010 by connorhansen (@connorhansen) on CodePen

  4. Thanks, that all makes sense.

     

    The one part I'm having trouble understanding is the "dummy object". I understand the concept but am having trouble implementing the solution. I've created a minimal demo here: https://codesandbox.io/s/react-threejs-gsap-i0id1?file=/src/index.js

     

    And to reiterate, as the sections are scrolled, I would like to update the intensity (and other props) simultaneously. Again, the ultimate goal is to smoothly transition the blob colors from red to green to blue as the sections are scrolled. Hope that makes sense and let me know if there's anything I can clarify. 

     

    Thanks for your response!

     

    EDIT:

    Seems that I was able to get the intensity demo working using get syntax and some temp variables - is there a way to optimize the configuration in the demo?

  5. My goal is update a Three JS scene (colors, camera position, material properties, etc.) based on state properties set by the timeline. My scene is rendered inside of the BlobScene component which accepts an intensity prop. In the sample below, I'd like to update the intensity as the timeline is scrubbed which then updates the light intensity of my scene.

     

    In the pinned section, there are two columns: the left column contains text that will be translated into view and the right column contains the BlobScene. My ultimate goal is to change the color of the blob for each corresponding text section. So when the user scrolls from the red section to the green section, for example, the blob mesh would smoothly transition it's material color from red to green.

     

    Am I going about this the wrong way? I can create a minimal demo if needed.

     

    import React, { useState, useEffect } from "react"
    import { gsap } from "gsap";
    import { ScrollTrigger } from "gsap/ScrollTrigger";
    import BlobScene from '../components/blob-scene'
    
    function Index() {
    
      let [intensity, setIntensity] = useState({value: 1.5})
    
      useEffect(() => {
    
        gsap.registerPlugin(ScrollTrigger)
    
        // Verticals Pinned Section Story
        const tl = gsap.timeline()
    
        tl.from(".red", {y: "100%"})
          .from(".green", {y: "100%"})
          .from(".blue", {y: "100%"});
    
        // PROBLEM LINE
        tl.to(intensity, { value: setIntensity(0.5) })
        
        ScrollTrigger.create({
            animation: tl,
            trigger: "#verticals",
            scroller: "#___gatsby",
            start: "top top",
            end: "+=4000", 
            scrub: true,
            pin: true,
            anticipatePin: 1
        });
    
        // each time the window updates, we should refresh ScrollTrigger and then update LocomotiveScroll. 
        ScrollTrigger.addEventListener('refresh', () => window.scroll.update())
    
        ScrollTrigger.refresh()
    
      }, [intensity]);
    
        return (
          <React.Fragment>
            <div className="page">
    
                <section id="verticals" className="h-screen flex items-center relative w-full overflow-hidden">
                    <div className="grid grid-cols-2 gap-6 h-full w-full">
                        
                        {/* Grid Column 1 */}
                        <div className="flex items-center">
                        <div className="relative w-full overflow-hidden h-80">
                        <div className="panel absolute h-full w-full red bg-red-500 text-black">
                            <h2>Panel 1</h2>
                        </div>
                        <div className="panel absolute h-full w-full green bg-green-500">
                            <h2>Panel 2</h2>
                        </div>
                        <div className="panel absolute h-full w-full blue bg-blue-500">
                            <h2>Panel 3</h2>
                        </div>    
                        </div>
                        </div>
    
                        {/* Grid Column 2 */}
                        <div className="flex items-center">
                            <BlobScene intensity={intensity.value}></BlobScene>
                        </div>
    
                    </div>
                </section>
            </div>
          </React.Fragment>
        )
    }
    
    export default Index

     

×
×
  • Create New...