Jump to content
Search Community

GSAP ScrollTrigger script + GSAP React code in Framer

Adam Kozel test
Moderator Tag

Go to solution Solved by GSAP Helper,

Recommended Posts

I am using framer.com for web development

I have created this code component for myself so i can import self-hosted ScrollSmoother easily in any project i have:

import { useEffect } from "react"
import { Frame, addPropertyControls, ControlType } from "framer"

export function GSAPScrollSmoother(props) {
    const { url, smooth, effects, smoothTouch } = props

    useEffect(() => {
        const script1 = document.createElement("script")
        script1.src =
            "https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.4/gsap.min.js"
        document.head.appendChild(script1)

        const script2 = document.createElement("script")
        script2.src =
            "https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.4/ScrollTrigger.min.js"
        document.head.appendChild(script2)

        const script3 = document.createElement("script")
        script3.src = url
        document.head.appendChild(script3)

        script3.onload = () => {
            const script4 = document.createElement("script")
            script4.text = `
        gsap.registerPlugin(ScrollSmoother)
        const smoother = ScrollSmoother.create({
          wrapper: '[data-framer-name="smooth-wrapper"]',
          content: '[data-framer-name="page-wrapper"]',
          smooth: ${smooth},
          effects: ${effects},
          smoothTouch: ${smoothTouch},
        })
      `
            document.head.appendChild(script4)
        }
    }, [url, smooth, effects, smoothTouch])

    return <Frame size="0px" background="" style={{ userSelect: "none" }} />
}

GSAPScrollSmoother.defaultProps = {
    url: "",
    smooth: 1.5,
    effects: true,
    smoothTouch: 0.1,
}

addPropertyControls(GSAPScrollSmoother, {
    url: {
        type: ControlType.String,
        title: "URL",
        placeholder: "https://example.com/ScrollSmoother.min.js",
        description:
            "Upload your minified ScrollSmoother javascript file to CDN to get the link.\n\nFor further instructions check [documentation](https://www.lipsum.com).",
    },
    smooth: {
        type: ControlType.Number,
        title: "Smooth",
        min: 1,
        max: 50,
    },
    smoothTouch: {
        type: ControlType.Number,
        title: "Smooth Touch",
        min: 0,
        max: 50,
        step: 0.1,
    },
    effects: {
        type: ControlType.Boolean,
        title: "Effects",
    },
})


Then i proceed and create gsap animations with scrolltrigger and gsap core in my code overrides in framer in react code:

import * as React from "react"
import gsap from "gsap"
import { ScrollTrigger } from "gsap/ScrollTrigger"
import { Override } from "framer"
import SplitType from "split-type"

gsap.registerPlugin(ScrollTrigger)

export function workexperience(): Override {
    const containerRef = React.useRef(null)

    React.useEffect(() => {
        const containerElement = containerRef.current
        if (!containerElement) return

        const childrenElement = containerElement.children[0] // Assuming only one child for simplicity
        if (!childrenElement) return

        const containerHeight = containerElement.offsetHeight
        const childrenHeight = childrenElement.offsetHeight

        gsap.fromTo(
            childrenElement,
            {
                y: 0, // Starting position on Y-axis
            },
            {
                y: containerHeight - childrenHeight, // Destination position on Y-axis
                ease: "linear", // Easing function
                scrollTrigger: {
                    trigger: containerElement,
                    start: "top center-=40%", // Adjust start position as needed
                    end: `+=${containerHeight}`, // Use `+=` to dynamically add the container height
                    scrub: 1, // Adjust scrubbing intensity
                },
            }
        )
    }, [])

    return {
        ref: containerRef,
    }
}


Problem is that my scrolltrigger is not synced from <script> to react so when i scroll my scrolltriggers are scrolling normally apart from scrollsmoother. It's just not synced.

Link to comment
Share on other sites

i have also tried this approach:

 

import { useEffect } from "react"
import { Frame, addPropertyControls, ControlType } from "framer"
import { gsap } from "gsap"
import { ScrollTrigger } from "gsap/ScrollTrigger"
import ScrollSmoother from "https://res.cloudinary.com/ScrollSmoother.js"

export function GSAPScrollSmoother(props) {
    const { smooth, effects, smoothTouch } = props

    useEffect(() => {
        gsap.registerPlugin(ScrollTrigger, ScrollSmoother)
        const smoother = ScrollSmoother.create({
            wrapper: '[data-framer-name="smooth-wrapper"]',
            content: '[data-framer-name="page-wrapper"]',
            smooth: smooth,
            effects: effects,
            smoothTouch: smoothTouch,
        })
    }, [smooth, effects, smoothTouch])

    return <Frame size="0px" background="" style={{ userSelect: "none" }} />
}

GSAPScrollSmoother.defaultProps = {
    smooth: 1.5,
    effects: true,
    smoothTouch: 0.1,
}

addPropertyControls(GSAPScrollSmoother, {
    smooth: {
        type: ControlType.Number,
        title: "Smooth",
        min: 1,
        max: 50,
    },
    smoothTouch: {
        type: ControlType.Number,
        title: "Smooth Touch",
        min: 0,
        max: 50,
        step: 0.1,
    },
    effects: {
        type: ControlType.Boolean,
        title: "Effects",
    },
})

but i get error:
TypeError: Cannot set property window of #<Window> which has only a getter

Link to comment
Share on other sites

  • Solution

Hi there! I see you're using React -

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

 

Since GSAP 3.12, we have the useGSAP() hook (the NPM package is here) that simplifies creating and cleaning up animations in React (including Next, Remix, etc). It's a drop-in replacement for useEffect()/useLayoutEffect(). All the GSAP-related objects (animations, ScrollTriggers, etc.) created while the function executes get collected and then reverted when the hook gets torn down.

 

Here is how it works:

const container = useRef(); // the root level element of your component (for scoping selector text which is optional)

useGSAP(() => {
  // gsap code here...
}, { dependencies: [endX], scope: container }); // config object offers maximum flexibility

Or if you prefer, you can use the same method signature as useEffect():

useGSAP(() => {
  // gsap code here...
}, [endX]); // simple dependency Array setup like useEffect()

This pattern follows React's best practices.

 

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

 

As for your specific question, it's very difficult to troubleshoot by just looking at some excerpts of code. I'm not sure what exactly you mean by "ScrollTriggers are not synchronized with ScrollSmoother". Can you please provide a minimal demo, like on Stackblitz, that illustrates the problem? Here's a React starter template that you can fork to create a minimal demo illustrating whatever issue you're running into. You can use the gsap-trial package to reference ScrollSmoother. 

Link to comment
Share on other sites

i have updated my approach for useGSAP

 

import { Frame, addPropertyControls, ControlType } from "framer"
import { useGSAP } from "@gsap/react"
import { ScrollTrigger } from "gsap/ScrollTrigger"
import ScrollSmoother from "https://res.cloudinary.com/dm1wlzcab/raw/upload/v1705246683/ScrollSmoother.min_h7sufi.js"

export function GSAPScrollSmoother(props) {
    const { smooth, effects, smoothTouch } = props

    useGSAP(() => {
        gsap.registerPlugin(ScrollTrigger, ScrollSmoother)
        const smoother = ScrollSmoother.create({
            wrapper: '[data-framer-name="smooth-wrapper"]',
            content: '[data-framer-name="page-wrapper"]',
            smooth: smooth,
            effects: effects,
            smoothTouch: smoothTouch,
        })
    }, [smooth, effects, smoothTouch])

    return <Frame size="0px" background="" style={{ userSelect: "none" }} />
}

now i get error saying that my url for minified club GSAP ScrollSmoother plugin does not provide an export named default
 

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