Jump to content
Search Community

velkas

Members
  • Posts

    33
  • Joined

  • Last visited

Everything 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
  2. Exactly what I was looking for. Thank you.
  3. Marquee seems to break on resize. Loads and runs as expected on refresh. Any ideas?
  4. 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
  5. Removing spaces between elements in HTML resolved the issue. Additionally I think a better alternative is to use flexbox. I've updated the pen to use flexbox.
  6. 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.
  7. 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?
  8. 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...