Jump to content
Search Community

bradjdouglas

Members
  • Posts

    5
  • Joined

  • Last visited

Posts posted by bradjdouglas

  1. 18 hours ago, ZachSaucier said:

    Sweet! Good work.

     

    A couple of usability comments:

    • Make the "scroll down" when you click on a page more clear. I didn't notice it and wasn't sure when the page was done loading.
    • Allow a way to go back to the main page from the top of the specific pages. I like to take a peek at some and then go to others :) 
    • When I scrolled to the bottom of a specific page it locked me in and I couldn't scroll any longer. That's a bit disorienting. 

    I love the transitions!

     

    Thanks! And thanks for the feedback. I'll definitely  look for a way to address these. For what it's worth, the Logo acts as the way back to the home page from any point on the site. 

  2. 29 minutes ago, ZachSaucier said:

    Hey Brad, cool site! Welcome to the forums.

     

    Your animations look pretty smooth to me (given I don't scroll too fast too many times right in a row - I think that's more of a logical error. Is that what you're referencing?). Is it a particular browser that's giving you trouble? or a part of the site's animation that it happens with?

     

    That's a bit of code to look through even though most of it is unrelated. Guessing somewhat blindly, I'd guess that it's because the overwrite property has a different default in GSAP3. In GSAP 2 it was "auto" by default but in GSAP 3 it's false. You can test it by putting gsap.defaults({overwrite:"auto"}); to the top of your script.

     

    P.S. Small note: "out" is the default ease, so you can just say "expo" instead of "expo.out" if you want to.

     

    Zach, thanks for the quick reply! I updated the overwrite value to 'auto' like you said and it helped a bit, but there were still some funky things going on. I then realized - based on your 'if I don't scroll too quickly' comment - that I didn't have a way to stop the animation from going again and again. I added 'isAnimating' to my state and set it before running the masterTL and resetting after. 

     

    That seemed to do the trick! Appreciate the help!

    • Like 2
  3. Hello

     

    Just heard - and read about - the v3 news and immediately updated for my newest project. I'm really excited for all of this. 

     

    However, I'm running into an issue and I'm hoping somebody can spot my error. Before I switched the version, the animations were buttery smooth but now the bg image and even titles blink multiple times, etc. The animations are triggered by 'scrolling' up or down. 

     

    In my code, there are three methods - imageTL, initialTitleTL, numberTL - which are being called and added to masterTL. Inside of the three timeline, I have the old code commented out so you can see how I was doing it compared to how I am doing it now. 

     

    Any help is much appreciated.

     

    My code is below and this is a live link to see it in action: https://gsap3-issue.netlify.com/


     

    import React, { Component } from "react"
    import { StaticQuery, graphql } from "gatsby"
    import { gsap } from "gsap"
    import * as THREE from "three"
    import TransitionLink from "gatsby-plugin-transition-link"
    import { Link } from "gatsby"
    
    const HOME_QUERY = graphql`
    
    query HomeQuery {
    
    	allPrismicProject {
    		nodes {
    			id
    			slugs
    			data {
                  featured_image {
                    localFile {
                      childImageSharp {
                        original {
                          src
                        }
                      }
                  }
                }
                project_title {
                  text
                }
              }
            }
          }
        }
    `
    
    
    
    const vertex = `
    
    varying vec2 vUv;
    
    void main() {
    
    vUv = uv;
    
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    
    }
    
    `
    
    
    
    const fragment = `
    
    varying vec2 vUv;
    
    
    
    uniform sampler2D currentImage;
    
    uniform sampler2D nextImage;
    
    
    
    uniform float dispFactor;
    
    
    
    void main() {
    
    
    
    vec2 uv = vUv;
    
    vec4 _currentImage;
    
    vec4 _nextImage;
    
    float intensity = 0.3;
    
    
    
    vec4 orig1 = texture2D(currentImage, uv);
    
    vec4 orig2 = texture2D(nextImage, uv);
    
    
    
    _currentImage = texture2D(currentImage, vec2(uv.x, uv.y + dispFactor * (orig2 * intensity)));
    
    
    
    _nextImage = texture2D(nextImage, vec2(uv.x, uv.y + (1.0 - dispFactor) * (orig1 * intensity)));
    
    
    
    vec4 finalTexture = mix(_currentImage, _nextImage, dispFactor);
    
    
    
    gl_FragColor = finalTexture;
    
    
    
    }
    
    `
    
    
    
    class Slider extends Component {
    
    constructor(props) {
    
    super(props)
    
    // this.images = bgImages
    
    this.images = [
    
    ...this.props.data.allPrismicProject.nodes.map(
    
    node =>
    
    node.data.featured_image.localFile.childImageSharp.original
    
    .src
    
    ),
    
    ]
    
    this.titles = [
    
    ...this.props.data.allPrismicProject.nodes.map(
    
    node => node.data.project_title.text
    
    ),
    
    ]
    
    this.slugs = [
    
    ...this.props.data.allPrismicProject.nodes.map(
    
    node => node.slugs[0]
    
    ),
    
    ]
    
    this.render = this.render.bind(this)
    
    this.titleRef = React.createRef()
    
    this.numberRef = React.createRef()
    
    this.touchStart = null
    
    this.state = {
    
    current: 0,
    
    previous: null,
    
    }
    
    }
    
    
    
    build = () => {
    
    this.renderWidth = Math.max(
    
    document.documentElement.clientWidth,
    
    window.innerWidth || 0
    
    )
    
    this.renderHeight = Math.max(
    
    document.documentElement.clientHeight,
    
    window.innerHeight || 0
    
    )
    
    this.renderW = ""
    
    this.renderH = ""
    
    
    
    if (this.renderWidth < this.renderHeight) {
    
    this.renderW = this.renderHeight
    
    this.renderH = this.renderHeight
    
    } else {
    
    this.renderW = this.renderWidth
    
    this.renderH = this.renderWidth
    
    }
    
    
    
    this.scene = new THREE.Scene()
    
    this.setCamera().setRenderer()
    
    this.mount.appendChild(this.renderer.domElement)
    
    
    
    this.setLoader()
    
    .setTextures()
    
    .setMaterial()
    
    .setGeometry()
    
    .setMesh()
    
    
    
    this.scene.add(this.mesh)
    
    
    
    window.addEventListener("resize", e => {
    
    this.renderer.setSize(this.renderW, this.renderH)
    
    })
    
    }
    
    
    
    setCamera = () => {
    
    this.camera = new THREE.OrthographicCamera(
    
    this.renderWidth / -2,
    
    this.renderWidth / 2,
    
    this.renderHeight / 2,
    
    this.renderHeight / -2,
    
    1,
    
    1000
    
    )
    
    
    
    this.camera.position.z = 1.0
    
    
    
    return this
    
    }
    
    
    
    setGeometry = () => {
    
    this.geometry = new THREE.PlaneBufferGeometry(
    
    this.mount.offsetWidth,
    
    this.mount.offsetHeight,
    
    1.0
    
    )
    
    
    
    return this
    
    }
    
    
    
    setLoader = () => {
    
    this.loader = new THREE.TextureLoader()
    
    // this.loader.setCrossOrigin("")
    
    
    
    return this
    
    }
    
    
    
    setTextures = () => {
    
    this.bgImages = []
    
    
    
    this.images.forEach(img => {
    
    let image = this.loader.load(img)
    
    image.magFilter = image.minFilter = THREE.LinearFilter
    
    image.anisotropy = this.renderer.capabilities.getMaxAnisotropy()
    
    this.bgImages.push(image)
    
    })
    
    return this
    
    }
    
    
    
    setMaterial = () => {
    
    this.material = new THREE.ShaderMaterial({
    
    uniforms: {
    
    dispFactor: { type: "f", value: 0.0 },
    
    currentImage: {
    
    type: "t",
    
    value: this.bgImages[this.state.current],
    
    },
    
    nextImage: {
    
    type: "t",
    
    value: this.bgImages[this.state.next],
    
    },
    
    },
    
    vertexShader: vertex,
    
    fragmentShader: fragment,
    
    transparent: true,
    
    opacity: 1.0,
    
    })
    
    return this
    
    }
    
    
    
    setMesh = () => {
    
    this.mesh = new THREE.Mesh(this.geometry, this.material)
    
    this.mesh.position.set(0, 0, 0)
    
    
    
    return this
    
    }
    
    
    
    render() {
    
    this.renderer.render(this.scene, this.camera)
    
    }
    
    
    
    animate = () => {
    
    this.frameId = window.requestAnimationFrame(this.animate)
    
    this.renderer.render(this.scene, this.camera)
    
    }
    
    
    
    setRenderer = () => {
    
    this.renderer = new THREE.WebGLRenderer({
    
    antialias: false,
    
    alpha: true,
    
    })
    
    this.renderer.setPixelRatio(window.devicePixelRatio)
    
    this.renderer.setClearColor(0xffffff, 0.0)
    
    this.renderer.setSize(this.renderW, this.renderH)
    
    
    
    return this
    
    }
    
    
    
    handleScrollEvents = event => {
    
    let next
    
    
    
    if (event.deltaY > 20) {
    
    next =
    
    this.state.current === this.titles.length - 1
    
    ? 0
    
    : this.state.current + 1
    
    this.masterTL(next)
    
    } else if (event.deltaY < -20) {
    
    next =
    
    this.state.current - 1 < 0
    
    ? this.titles.length - 1
    
    : this.state.current - 1
    
    this.masterTL(next)
    
    }
    
    }
    
    
    
    handleTouchEvents = event => {
    
    console.log(this.touchStart, event.touches[0].clientY)
    
    }
    
    
    
    imageTL = next => {
    
    this.material.uniforms.nextImage.value = this.bgImages[next]
    
    this.material.uniforms.nextImage.needsUpdate = true
    
    
    
    // const tl = new TimelineMax()
    
    let tl = gsap.timeline()
    
    
    
    tl.to(this.material.uniforms.dispFactor, {
    
    duration: 1.4,
    
    value: 1,
    
    ease: "expo.inOut",
    
    onComplete: () => {
    
    this.material.uniforms.currentImage.value = this.bgImages[next]
    
    this.material.uniforms.currentImage.needsUpdate = true
    
    this.material.uniforms.dispFactor.value = 0.0
    
    },
    
    })
    
    
    
    return tl
    
    }
    
    
    
    initialTitleTL = next => {
    
    // const tl = new TimelineMax({
    
    // onComplete: () => {
    
    // this.setState({ current: next })
    
    
    
    // TweenMax.fromTo(
    
    // this.titleRef.current,
    
    // 1,
    
    // { opacity: 0, filter: "blur(10px)", y: 48 },
    
    // {
    
    // opacity: 1,
    
    // filter: "blur(0px)",
    
    // y: 0,
    
    // ease: Expo.easeOut,
    
    // }
    
    // )
    
    // },
    
    // })
    
    let tl = gsap.timeline({
    
    onComplete: () => {
    
    this.setState({ current: next })
    
    
    
    gsap.fromTo(
    
    this.titleRef.current,
    
    { autoAlpha: 0, filter: "blur(10px)", y: 48 },
    
    {
    
    duration: 1,
    
    autoAlpha: 1,
    
    filter: "blur(0px)",
    
    y: 0,
    
    ease: "expo.out",
    
    }
    
    )
    
    },
    
    })
    
    
    
    tl.to(this.titleRef.current, {
    
    duration: 1,
    
    autoAlpha: 0,
    
    filter: "blur(10px)",
    
    y: -48,
    
    ease: "expo.inOut",
    
    })
    
    
    
    return tl
    
    }
    
    
    
    numberTL = () => {
    
    // const tl = new TimelineMax({
    
    // onComplete: () => {
    
    // TweenMax.fromTo(
    
    // this.numberRef.current,
    
    // 0.7,
    
    // {
    
    // opacity: 0,
    
    // // transform: "perspective(300px) translateY(80%) rotateX(-30deg)",
    
    // xPercent: -101,
    
    // },
    
    // {
    
    // opacity: 1,
    
    // // transform:
    
    // // "perspective(300px) translateY(0) rotateX(0)",
    
    // xPercent: 0,
    
    // y: 0,
    
    // ease: Expo.easeOut,
    
    // }
    
    // )
    
    // },
    
    // })
    
    let tl = gsap.timeline({
    
    onComplete: () => {
    
    gsap.fromTo(
    
    this.numberRef.current,
    
    {
    
    opacity: 0,
    
    xPercent: -101,
    
    },
    
    {
    
    duration: 0.7,
    
    opacity: 1,
    
    xPercent: 0,
    
    y: 0,
    
    ease: "expo.out",
    
    }
    
    )
    
    },
    
    })
    
    
    
    tl.to(this.numberRef.current, {
    
    duration: 1,
    
    opacity: 0,
    
    xPercent: -101,
    
    ease: "expo.inOut",
    
    })
    
    
    
    return tl
    
    }
    
    
    
    masterTL = next => {
    
    // const masterTL = new TimelineMax()
    
    let masterTL = gsap.timeline()
    
    
    
    masterTL
    
    .add(this.imageTL(next), "<")
    
    .add(this.initialTitleTL(next), "<")
    
    .add(this.numberTL(next), "<")
    
    // .call(this.imageTL(next), 0)
    
    // .call(this.initialTitleTL(next), 0)
    
    // .call(this.numberTL(next), 0)
    
    
    
    return masterTL
    
    }
    
    
    
    componentDidMount() {
    
    this.build()
    
    this.animate()
    
    }
    
    
    
    componentWillUnmount() {
    
    cancelAnimationFrame(this.frameId)
    
    this.mount.removeChild(this.renderer.domElement)
    
    }
    
    
    
    render() {
    
    const { current, previous } = this.state
    
    const { scrollPosition } = this.props
    
    return (
    
    <>
    
    <section
    
    className="slideshow"
    
    onWheel={this.handleScrollEvents}
    
    onTouchStart={event =>
    
    (this.touchStart = event.touches[0].clientY)
    
    }
    
    onTouchMove={this.handleTouchEvents}
    
    >
    
    <div
    
    className="slideshow__bg"
    
    ref={mount => {
    
    this.mount = mount
    
    }}
    
    style={{ width: `100vw`, height: `100vh` }}
    
    ></div>
    
    <div className="slide">
    
    <div className="slide__wrapper">
    
    <h1 className="h1 slide__title" ref={this.titleRef}>
    
    <Link to={`/${this.slugs[current]}`}>
    
    {this.titles[current]}
    
    </Link>
    
    </h1>
    
    </div>
    
    </div>
    
    <div className="numbers">
    
    <div className="numbers__wrapper">
    
    <div className="number number--large">
    
    <span ref={this.numberRef}>0{current + 1}</span>
    
    </div>
    
    <div className="number">
    
    <span>/0{this.titles.length}</span>
    
    </div>
    
    </div>
    
    </div>
    
    </section>
    
    </>
    
    )
    
    }
    
    }
    
    
    
    export default props => (
    
    <StaticQuery
    
    query={HOME_QUERY}
    
    render={data => <Slider data={data} {...props} />}
    
    />
    
    )
    
    
    

     

×
×
  • Create New...