Magic Cursor Override for Framer

Magic Cursor Override for Framer

Effect

Magic Cursor Override for Framer

This is a code override in Framer that you can apply to any frame. So, whenever that element is hovered over on the website, a magic cursor animation gets triggered. Feel free to remix the project and have fun playing with the effect.

Props to Hyperplexed for creating the CodePen, and to Canva for the original concept.

image of Nandi Muzsik

Created by

Magic Cursor Override for Framer
Magic Cursor Override for Framer
Magic Cursor Override for Framer

About the resource

This code override is super easy to use. You can just copy and paste the code into your Framer project and create the code override yourself from the assets panel.

It's also customizable. You can change the color of the stars by tweaking the RGB values here:

About the resource

This code override is super easy to use. You can just copy and paste the code into your Framer project and create the code override yourself from the assets panel.

It's also customizable. You can change the color of the stars by tweaking the RGB values here:

About the resource

This code override is super easy to use. You can just copy and paste the code into your Framer project and create the code override yourself from the assets panel.

It's also customizable. You can change the color of the stars by tweaking the RGB values here:

magic cursor color customize

Magic cursor color customization.

magic cursor color customize

Magic cursor color customization.

magic cursor color customize

Magic cursor color customization.

Below the RGB values, you can also specify three different sizes for the stars.

And here, you can specify the color of the glow, once more using an RGB value:

Below the RGB values, you can also specify three different sizes for the stars.

And here, you can specify the color of the glow, once more using an RGB value:

Below the RGB values, you can also specify three different sizes for the stars.

And here, you can specify the color of the glow, once more using an RGB value:

magic cursor glow color customize

Magic cursor glow color customization.

magic cursor glow color customize

Magic cursor glow color customization.

magic cursor glow color customize

Magic cursor glow color customization.

You can find and copy the code override below.

For the 3D effect, I used the 3D hover override that you can find on this link.

Code override for the magic cursor

Feel free to copy the override code from below and create the override yourself in your Framer project.

You can find and copy the code override below.

For the 3D effect, I used the 3D hover override that you can find on this link.

Code override for the magic cursor

Feel free to copy the override code from below and create the override yourself in your Framer project.

You can find and copy the code override below.

For the 3D effect, I used the 3D hover override that you can find on this link.

Code override for the magic cursor

Feel free to copy the override code from below and create the override yourself in your Framer project.

import { ComponentType, useEffect, useState } from "react"
import { motion, useSpring, useMotionValue } from "framer-motion"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faStar } from "@fortawesome/free-solid-svg-icons"
import ReactDOM from "react-dom"

export function withCursor(Component): ComponentType {
    return (props) => {
        const originPosition = { x: 0, y: 0 }
        const [isHover, setIsHover] = useState(false)
        const [count, setCount] = useState(0)
        const [last, setLast] = useState({
            starTimestamp: 0,
            starPosition: originPosition,
            mousePosition: originPosition,
        })

        const config = {
            starAnimationDuration: 1500,
            minimumTimeBetweenStars: 250,
            minimumDistanceBetweenStars: 75,
            glowDuration: 75,
            maximumGlowPointSpacing: 10,
            colors: ["144 211 252", "252 254 255"],
            sizes: ["1.4rem", "1rem", "0.6rem"],
            animations: ["fall-1", "fall-2", "fall-3"],
        }

        const rand = (min, max) =>
            Math.floor(Math.random() * (max - min + 1)) + min
        const selectRandom = (items) => items[rand(0, items.length - 1)]

        const withUnit = (value, unit) => `${value}${unit}`
        const px = (value) => withUnit(value, "px")
        const ms = (value) => withUnit(value, "ms")

        const calcDistance = (a, b) => {
            const diffX = b.x - a.x,
                diffY = b.y - a.y

            return Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2))
        }

        const calcElapsedTime = (start, end) => end - start

        const createStar = (position) => {
            const star = document.createElement("span")
            const color = selectRandom(config.colors)

            star.className = "star"

            // Use FontAwesomeIcon to render the star icon
            const iconComponent = <FontAwesomeIcon icon={faStar} />
            ReactDOM.render(iconComponent, star)

            star.style.left = px(position.x)
            star.style.top = px(position.y)
            star.style.fontSize = selectRandom(config.sizes)
            star.style.color = `rgb(${color})`
            star.style.textShadow = `0px 0px 1.5rem rgb(${color} / 0.5)`
            star.style.animationName = config.animations[count % 3]
            setCount((prevCount) => prevCount + 1)

            star.style.animationDuration = ms(config.starAnimationDuration)

            document.body.appendChild(star)

            setTimeout(
                () => document.body.removeChild(star),
                config.starAnimationDuration
            )
        }

        const createGlowPoint = (position) => {
            const glow = document.createElement("div")

            glow.className = "glow-point"

            glow.style.left = px(position.x)
            glow.style.top = px(position.y)

            document.body.appendChild(glow)

            setTimeout(
                () => document.body.removeChild(glow),
                config.glowDuration
            )
        }

        const determinePointQuantity = (distance) =>
            Math.max(Math.floor(distance / config.maximumGlowPointSpacing), 1)

        const createGlow = (lastPoint, currentPoint) => {
            const distance = calcDistance(lastPoint, currentPoint)
            const quantity = determinePointQuantity(distance)

            const dx = (currentPoint.x - lastPoint.x) / quantity
            const dy = (currentPoint.y - lastPoint.y) / quantity

            Array.from(Array(quantity)).forEach((_, index) => {
                const x = lastPoint.x + dx * index,
                    y = lastPoint.y + dy * index

                createGlowPoint({ x, y })
            })
        }

        const updateLastStar = (position) => {
            setLast((prevLast) => ({
                ...prevLast,
                starTimestamp: new Date().getTime(),
                starPosition: position,
            }))
        }

        const updateLastMousePosition = (position) => {
            setLast((prevLast) => ({
                ...prevLast,
                mousePosition: position,
            }))
        }

        const adjustLastMousePosition = (position) => {
            if (last.mousePosition.x === 0 && last.mousePosition.y === 0) {
                setLast((prevLast) => ({
                    ...prevLast,
                    mousePosition: position,
                }))
            }
        }

        const handleOnMove = (e) => {
            const mousePosition = { x: e.clientX, y: e.clientY }

            adjustLastMousePosition(mousePosition)

            const now = new Date().getTime()
            const hasMovedFarEnough =
                calcDistance(last.starPosition, mousePosition) >=
                config.minimumDistanceBetweenStars
            const hasBeenLongEnough =
                calcElapsedTime(last.starTimestamp, now) >
                config.minimumTimeBetweenStars

            if (isHover) {
                if (hasMovedFarEnough || hasBeenLongEnough) {
                    createStar(mousePosition)
                    updateLastStar(mousePosition)
                }

                createGlow(last.mousePosition, mousePosition)
            }

            updateLastMousePosition(mousePosition)
        }

        useEffect(() => {
            window.addEventListener("mousemove", handleOnMove)
            window.addEventListener("touchmove", (e) =>
                handleOnMove(e.touches[0])
            )
            document.body.addEventListener("mouseleave", () =>
                updateLastMousePosition(originPosition)
            )

            return () => {
                window.removeEventListener("mousemove", handleOnMove)
                window.removeEventListener("touchmove", (e) =>
                    handleOnMove(e.touches[0])
                )
                document.body.removeEventListener("mouseleave", () =>
                    updateLastMousePosition(originPosition)
                )
            }
        }, [last])

        return (
            <>
                <style>{`
          .glow-point {
            position: absolute;
            box-shadow: 0rem 0rem 1.2rem 0.6rem rgb(102, 242, 255, 0.85);
            pointer-events: none;
          }

          .star {
            position: absolute;
            z-index: 2;
            color: white;
            font-size: 1rem;
            animation-duration: 1500ms;
            animation-fill-mode: forwards;
            pointer-events: none;
          }

          @keyframes fall-1 {
            0% {
              transform: translate(0px, 0px) rotateX(45deg) rotateY(30deg) rotateZ(0deg) scale(0.25);
              opacity: 0;
            }
            
            5% {
              transform: translate(10px, -10px) rotateX(45deg) rotateY(30deg) rotateZ(0deg) scale(1);
              opacity: 1;
            }
            
            100% {
              transform: translate(25px, 200px) rotateX(180deg) rotateY(270deg) rotateZ(90deg) scale(1);
              opacity: 0;
            }
          }

          @keyframes fall-2 {
            0% {
              transform: translate(0px, 0px) rotateX(-20deg) rotateY(10deg) scale(0.25);
              opacity: 0;
            }
            
            10% {
              transform: translate(-10px, -5px) rotateX(-20deg) rotateY(10deg) scale(1);
              opacity: 1;
            }
            
            100% {
              transform: translate(-10px, 160px) rotateX(-90deg) rotateY(45deg) scale(0.25);
              opacity: 0;
            }
          }

          @keyframes fall-3 {
            0% {
              transform: translate(0px, 0px) rotateX(0deg) rotateY(45deg) scale(0.5);
              opacity: 0;
            }
            
            15% {
              transform: translate(7px, 5px) rotateX(0deg) rotateY(45deg) scale(1);
              opacity: 1;
            }
            
            100% {
              transform: translate(20px, 120px) rotateX(-180deg) rotateY(-90deg) scale(0.5);
              opacity: 0;
            }
          }
        `}</style>
                <Component
                    {...props}
                    onHoverStart={() => setIsHover(true)}
                    onHoverEnd={() => setIsHover(false)}
                />
            </>
        )
    }
}
import { ComponentType, useEffect, useState } from "react"
import { motion, useSpring, useMotionValue } from "framer-motion"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faStar } from "@fortawesome/free-solid-svg-icons"
import ReactDOM from "react-dom"

export function withCursor(Component): ComponentType {
    return (props) => {
        const originPosition = { x: 0, y: 0 }
        const [isHover, setIsHover] = useState(false)
        const [count, setCount] = useState(0)
        const [last, setLast] = useState({
            starTimestamp: 0,
            starPosition: originPosition,
            mousePosition: originPosition,
        })

        const config = {
            starAnimationDuration: 1500,
            minimumTimeBetweenStars: 250,
            minimumDistanceBetweenStars: 75,
            glowDuration: 75,
            maximumGlowPointSpacing: 10,
            colors: ["144 211 252", "252 254 255"],
            sizes: ["1.4rem", "1rem", "0.6rem"],
            animations: ["fall-1", "fall-2", "fall-3"],
        }

        const rand = (min, max) =>
            Math.floor(Math.random() * (max - min + 1)) + min
        const selectRandom = (items) => items[rand(0, items.length - 1)]

        const withUnit = (value, unit) => `${value}${unit}`
        const px = (value) => withUnit(value, "px")
        const ms = (value) => withUnit(value, "ms")

        const calcDistance = (a, b) => {
            const diffX = b.x - a.x,
                diffY = b.y - a.y

            return Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2))
        }

        const calcElapsedTime = (start, end) => end - start

        const createStar = (position) => {
            const star = document.createElement("span")
            const color = selectRandom(config.colors)

            star.className = "star"

            // Use FontAwesomeIcon to render the star icon
            const iconComponent = <FontAwesomeIcon icon={faStar} />
            ReactDOM.render(iconComponent, star)

            star.style.left = px(position.x)
            star.style.top = px(position.y)
            star.style.fontSize = selectRandom(config.sizes)
            star.style.color = `rgb(${color})`
            star.style.textShadow = `0px 0px 1.5rem rgb(${color} / 0.5)`
            star.style.animationName = config.animations[count % 3]
            setCount((prevCount) => prevCount + 1)

            star.style.animationDuration = ms(config.starAnimationDuration)

            document.body.appendChild(star)

            setTimeout(
                () => document.body.removeChild(star),
                config.starAnimationDuration
            )
        }

        const createGlowPoint = (position) => {
            const glow = document.createElement("div")

            glow.className = "glow-point"

            glow.style.left = px(position.x)
            glow.style.top = px(position.y)

            document.body.appendChild(glow)

            setTimeout(
                () => document.body.removeChild(glow),
                config.glowDuration
            )
        }

        const determinePointQuantity = (distance) =>
            Math.max(Math.floor(distance / config.maximumGlowPointSpacing), 1)

        const createGlow = (lastPoint, currentPoint) => {
            const distance = calcDistance(lastPoint, currentPoint)
            const quantity = determinePointQuantity(distance)

            const dx = (currentPoint.x - lastPoint.x) / quantity
            const dy = (currentPoint.y - lastPoint.y) / quantity

            Array.from(Array(quantity)).forEach((_, index) => {
                const x = lastPoint.x + dx * index,
                    y = lastPoint.y + dy * index

                createGlowPoint({ x, y })
            })
        }

        const updateLastStar = (position) => {
            setLast((prevLast) => ({
                ...prevLast,
                starTimestamp: new Date().getTime(),
                starPosition: position,
            }))
        }

        const updateLastMousePosition = (position) => {
            setLast((prevLast) => ({
                ...prevLast,
                mousePosition: position,
            }))
        }

        const adjustLastMousePosition = (position) => {
            if (last.mousePosition.x === 0 && last.mousePosition.y === 0) {
                setLast((prevLast) => ({
                    ...prevLast,
                    mousePosition: position,
                }))
            }
        }

        const handleOnMove = (e) => {
            const mousePosition = { x: e.clientX, y: e.clientY }

            adjustLastMousePosition(mousePosition)

            const now = new Date().getTime()
            const hasMovedFarEnough =
                calcDistance(last.starPosition, mousePosition) >=
                config.minimumDistanceBetweenStars
            const hasBeenLongEnough =
                calcElapsedTime(last.starTimestamp, now) >
                config.minimumTimeBetweenStars

            if (isHover) {
                if (hasMovedFarEnough || hasBeenLongEnough) {
                    createStar(mousePosition)
                    updateLastStar(mousePosition)
                }

                createGlow(last.mousePosition, mousePosition)
            }

            updateLastMousePosition(mousePosition)
        }

        useEffect(() => {
            window.addEventListener("mousemove", handleOnMove)
            window.addEventListener("touchmove", (e) =>
                handleOnMove(e.touches[0])
            )
            document.body.addEventListener("mouseleave", () =>
                updateLastMousePosition(originPosition)
            )

            return () => {
                window.removeEventListener("mousemove", handleOnMove)
                window.removeEventListener("touchmove", (e) =>
                    handleOnMove(e.touches[0])
                )
                document.body.removeEventListener("mouseleave", () =>
                    updateLastMousePosition(originPosition)
                )
            }
        }, [last])

        return (
            <>
                <style>{`
          .glow-point {
            position: absolute;
            box-shadow: 0rem 0rem 1.2rem 0.6rem rgb(102, 242, 255, 0.85);
            pointer-events: none;
          }

          .star {
            position: absolute;
            z-index: 2;
            color: white;
            font-size: 1rem;
            animation-duration: 1500ms;
            animation-fill-mode: forwards;
            pointer-events: none;
          }

          @keyframes fall-1 {
            0% {
              transform: translate(0px, 0px) rotateX(45deg) rotateY(30deg) rotateZ(0deg) scale(0.25);
              opacity: 0;
            }
            
            5% {
              transform: translate(10px, -10px) rotateX(45deg) rotateY(30deg) rotateZ(0deg) scale(1);
              opacity: 1;
            }
            
            100% {
              transform: translate(25px, 200px) rotateX(180deg) rotateY(270deg) rotateZ(90deg) scale(1);
              opacity: 0;
            }
          }

          @keyframes fall-2 {
            0% {
              transform: translate(0px, 0px) rotateX(-20deg) rotateY(10deg) scale(0.25);
              opacity: 0;
            }
            
            10% {
              transform: translate(-10px, -5px) rotateX(-20deg) rotateY(10deg) scale(1);
              opacity: 1;
            }
            
            100% {
              transform: translate(-10px, 160px) rotateX(-90deg) rotateY(45deg) scale(0.25);
              opacity: 0;
            }
          }

          @keyframes fall-3 {
            0% {
              transform: translate(0px, 0px) rotateX(0deg) rotateY(45deg) scale(0.5);
              opacity: 0;
            }
            
            15% {
              transform: translate(7px, 5px) rotateX(0deg) rotateY(45deg) scale(1);
              opacity: 1;
            }
            
            100% {
              transform: translate(20px, 120px) rotateX(-180deg) rotateY(-90deg) scale(0.5);
              opacity: 0;
            }
          }
        `}</style>
                <Component
                    {...props}
                    onHoverStart={() => setIsHover(true)}
                    onHoverEnd={() => setIsHover(false)}
                />
            </>
        )
    }
}
import { ComponentType, useEffect, useState } from "react"
import { motion, useSpring, useMotionValue } from "framer-motion"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faStar } from "@fortawesome/free-solid-svg-icons"
import ReactDOM from "react-dom"

export function withCursor(Component): ComponentType {
    return (props) => {
        const originPosition = { x: 0, y: 0 }
        const [isHover, setIsHover] = useState(false)
        const [count, setCount] = useState(0)
        const [last, setLast] = useState({
            starTimestamp: 0,
            starPosition: originPosition,
            mousePosition: originPosition,
        })

        const config = {
            starAnimationDuration: 1500,
            minimumTimeBetweenStars: 250,
            minimumDistanceBetweenStars: 75,
            glowDuration: 75,
            maximumGlowPointSpacing: 10,
            colors: ["144 211 252", "252 254 255"],
            sizes: ["1.4rem", "1rem", "0.6rem"],
            animations: ["fall-1", "fall-2", "fall-3"],
        }

        const rand = (min, max) =>
            Math.floor(Math.random() * (max - min + 1)) + min
        const selectRandom = (items) => items[rand(0, items.length - 1)]

        const withUnit = (value, unit) => `${value}${unit}`
        const px = (value) => withUnit(value, "px")
        const ms = (value) => withUnit(value, "ms")

        const calcDistance = (a, b) => {
            const diffX = b.x - a.x,
                diffY = b.y - a.y

            return Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2))
        }

        const calcElapsedTime = (start, end) => end - start

        const createStar = (position) => {
            const star = document.createElement("span")
            const color = selectRandom(config.colors)

            star.className = "star"

            // Use FontAwesomeIcon to render the star icon
            const iconComponent = <FontAwesomeIcon icon={faStar} />
            ReactDOM.render(iconComponent, star)

            star.style.left = px(position.x)
            star.style.top = px(position.y)
            star.style.fontSize = selectRandom(config.sizes)
            star.style.color = `rgb(${color})`
            star.style.textShadow = `0px 0px 1.5rem rgb(${color} / 0.5)`
            star.style.animationName = config.animations[count % 3]
            setCount((prevCount) => prevCount + 1)

            star.style.animationDuration = ms(config.starAnimationDuration)

            document.body.appendChild(star)

            setTimeout(
                () => document.body.removeChild(star),
                config.starAnimationDuration
            )
        }

        const createGlowPoint = (position) => {
            const glow = document.createElement("div")

            glow.className = "glow-point"

            glow.style.left = px(position.x)
            glow.style.top = px(position.y)

            document.body.appendChild(glow)

            setTimeout(
                () => document.body.removeChild(glow),
                config.glowDuration
            )
        }

        const determinePointQuantity = (distance) =>
            Math.max(Math.floor(distance / config.maximumGlowPointSpacing), 1)

        const createGlow = (lastPoint, currentPoint) => {
            const distance = calcDistance(lastPoint, currentPoint)
            const quantity = determinePointQuantity(distance)

            const dx = (currentPoint.x - lastPoint.x) / quantity
            const dy = (currentPoint.y - lastPoint.y) / quantity

            Array.from(Array(quantity)).forEach((_, index) => {
                const x = lastPoint.x + dx * index,
                    y = lastPoint.y + dy * index

                createGlowPoint({ x, y })
            })
        }

        const updateLastStar = (position) => {
            setLast((prevLast) => ({
                ...prevLast,
                starTimestamp: new Date().getTime(),
                starPosition: position,
            }))
        }

        const updateLastMousePosition = (position) => {
            setLast((prevLast) => ({
                ...prevLast,
                mousePosition: position,
            }))
        }

        const adjustLastMousePosition = (position) => {
            if (last.mousePosition.x === 0 && last.mousePosition.y === 0) {
                setLast((prevLast) => ({
                    ...prevLast,
                    mousePosition: position,
                }))
            }
        }

        const handleOnMove = (e) => {
            const mousePosition = { x: e.clientX, y: e.clientY }

            adjustLastMousePosition(mousePosition)

            const now = new Date().getTime()
            const hasMovedFarEnough =
                calcDistance(last.starPosition, mousePosition) >=
                config.minimumDistanceBetweenStars
            const hasBeenLongEnough =
                calcElapsedTime(last.starTimestamp, now) >
                config.minimumTimeBetweenStars

            if (isHover) {
                if (hasMovedFarEnough || hasBeenLongEnough) {
                    createStar(mousePosition)
                    updateLastStar(mousePosition)
                }

                createGlow(last.mousePosition, mousePosition)
            }

            updateLastMousePosition(mousePosition)
        }

        useEffect(() => {
            window.addEventListener("mousemove", handleOnMove)
            window.addEventListener("touchmove", (e) =>
                handleOnMove(e.touches[0])
            )
            document.body.addEventListener("mouseleave", () =>
                updateLastMousePosition(originPosition)
            )

            return () => {
                window.removeEventListener("mousemove", handleOnMove)
                window.removeEventListener("touchmove", (e) =>
                    handleOnMove(e.touches[0])
                )
                document.body.removeEventListener("mouseleave", () =>
                    updateLastMousePosition(originPosition)
                )
            }
        }, [last])

        return (
            <>
                <style>{`
          .glow-point {
            position: absolute;
            box-shadow: 0rem 0rem 1.2rem 0.6rem rgb(102, 242, 255, 0.85);
            pointer-events: none;
          }

          .star {
            position: absolute;
            z-index: 2;
            color: white;
            font-size: 1rem;
            animation-duration: 1500ms;
            animation-fill-mode: forwards;
            pointer-events: none;
          }

          @keyframes fall-1 {
            0% {
              transform: translate(0px, 0px) rotateX(45deg) rotateY(30deg) rotateZ(0deg) scale(0.25);
              opacity: 0;
            }
            
            5% {
              transform: translate(10px, -10px) rotateX(45deg) rotateY(30deg) rotateZ(0deg) scale(1);
              opacity: 1;
            }
            
            100% {
              transform: translate(25px, 200px) rotateX(180deg) rotateY(270deg) rotateZ(90deg) scale(1);
              opacity: 0;
            }
          }

          @keyframes fall-2 {
            0% {
              transform: translate(0px, 0px) rotateX(-20deg) rotateY(10deg) scale(0.25);
              opacity: 0;
            }
            
            10% {
              transform: translate(-10px, -5px) rotateX(-20deg) rotateY(10deg) scale(1);
              opacity: 1;
            }
            
            100% {
              transform: translate(-10px, 160px) rotateX(-90deg) rotateY(45deg) scale(0.25);
              opacity: 0;
            }
          }

          @keyframes fall-3 {
            0% {
              transform: translate(0px, 0px) rotateX(0deg) rotateY(45deg) scale(0.5);
              opacity: 0;
            }
            
            15% {
              transform: translate(7px, 5px) rotateX(0deg) rotateY(45deg) scale(1);
              opacity: 1;
            }
            
            100% {
              transform: translate(20px, 120px) rotateX(-180deg) rotateY(-90deg) scale(0.5);
              opacity: 0;
            }
          }
        `}</style>
                <Component
                    {...props}
                    onHoverStart={() => setIsHover(true)}
                    onHoverEnd={() => setIsHover(false)}
                />
            </>
        )
    }
}

Framer Navigator

Learn the fundamentals of Framer for free.

Build your ideas with ease by learning the basics of website building with Framer.

Nandi portrait's background
Nandi's portrait

Framer Navigator

Learn the fundamentals of Framer for free.

Build your ideas with ease by learning the basics of website building with Framer.

Nandi portrait's background
Nandi's portrait

Framer Navigator

Learn the fundamentals of Framer for free.

Build your ideas with ease by learning the basics of website building with Framer.

Nandi portrait's background
Nandi's portrait

More resources

More resources

    Show Once Code Override for Framer

    Show Once Code Override for Framer

    Effect

    Show Once Code Override for Framer

    Show Once Code Override for Framer

    Effect

    Show Once Code Override for Framer

    Show Once Code Override for Framer

    Effect

    2 Types of Horizontal Scrolling in Framer

    2 Types of Horizontal Scrolling Effect in Framer

    Effect

    2 Types of Horizontal Scrolling in Framer

    2 Types of Horizontal Scrolling Effect in Framer

    Effect

    2 Types of Horizontal Scrolling in Framer

    2 Types of Horizontal Scrolling Effect in Framer

    Effect