Effect
Effect
Effect
Effect
Hover Reveal Override for Framer
Hover Reveal Override for Framer
Hover Reveal Override for Framer
Hover Reveal Override for Framer
This is a hover reveal effect, originally created by Matt Parry. I've turned it into a code override that works seamlessly in Framer, making it simple to apply to any element on your Framer website.
This is a hover reveal effect, originally created by Matt Parry. I've turned it into a code override that works seamlessly in Framer, making it simple to apply to any element on your Framer website.
This is a hover reveal effect, originally created by Matt Parry. I've turned it into a code override that works seamlessly in Framer, making it simple to apply to any element on your Framer website.
This is a hover reveal effect, originally created by Matt Parry. I've turned it into a code override that works seamlessly in Framer, making it simple to apply to any element on your Framer website.
Creator
Creator
Creator
Creator
Features
You can either copy the component and use the hover reveal effect with an image, or just copy the code override to create the override yourself in your Framer project and apply it to any element.
In this demo, I employed the hover reveal override in such a way that there's a separate image layer beneath the hover reveal image. It's set to 0.1 opacity, so you can still see the image even if it isn't fully revealed.
Step / 01
Remix the project.
Step / 02
See how it's built.
Step / 03
Try recreating it for practice, or copy and paste it to your project.
Code override for hover reveal effect
Feel free to copy the override code from below and create the override yourself in your Framer project.
import type { ComponentType } from "react"
import { useEffect, useState, useRef } from "react"
import {
animate,
motion,
useMotionValue,
useMotionTemplate,
} from "framer-motion"
export function withImageMask(Component): ComponentType {
return (props) => {
const [size, setSize] = useState<
{ width: number; height: number } | undefined
>(undefined)
const maskX = useMotionValue(0)
const maskY = useMotionValue(0)
const maskSize = useMotionValue(0)
const maskImage = useMotionTemplate`radial-gradient(circle at ${maskX}px ${maskY}px, black ${maskSize}px, transparent ${maskSize}px)`
const ref = useRef(null)
useEffect(() => {
if (!size || !ref.current) return
const transition = {
type: "spring",
stiffness: 200,
damping: 10,
}
const { width, height } = size
animate(maskSize, Math.sqrt(width * width + height * height), {
duration: 0.7,
})
animate(maskX, width / 2, transition)
animate(maskY, height / 2, transition)
}, [size])
return (
<motion.div
ref={ref}
onHoverStart={() => !size && animate(maskSize, 50)}
onHoverEnd={() => !size && animate(maskSize, 0)}
onPointerDown={() => !size && animate(maskSize, 40)}
onClick={() => setSize(ref.current.getBoundingClientRect())}
onPointerMove={(e) => {
if (size) return
const { top, left } = ref.current.getBoundingClientRect()
maskX.set(e.clientX - left)
maskY.set(e.clientY - top)
}}
style={{ WebkitMaskImage: maskImage, maskImage }}
{...props}
>
<Component {...props} />
</motion.div>
)
}
}
import type { ComponentType } from "react"
import { useEffect, useState, useRef } from "react"
import {
animate,
motion,
useMotionValue,
useMotionTemplate,
} from "framer-motion"
export function withImageMask(Component): ComponentType {
return (props) => {
const [size, setSize] = useState<
{ width: number; height: number } | undefined
>(undefined)
const maskX = useMotionValue(0)
const maskY = useMotionValue(0)
const maskSize = useMotionValue(0)
const maskImage = useMotionTemplate`radial-gradient(circle at ${maskX}px ${maskY}px, black ${maskSize}px, transparent ${maskSize}px)`
const ref = useRef(null)
useEffect(() => {
if (!size || !ref.current) return
const transition = {
type: "spring",
stiffness: 200,
damping: 10,
}
const { width, height } = size
animate(maskSize, Math.sqrt(width * width + height * height), {
duration: 0.7,
})
animate(maskX, width / 2, transition)
animate(maskY, height / 2, transition)
}, [size])
return (
<motion.div
ref={ref}
onHoverStart={() => !size && animate(maskSize, 50)}
onHoverEnd={() => !size && animate(maskSize, 0)}
onPointerDown={() => !size && animate(maskSize, 40)}
onClick={() => setSize(ref.current.getBoundingClientRect())}
onPointerMove={(e) => {
if (size) return
const { top, left } = ref.current.getBoundingClientRect()
maskX.set(e.clientX - left)
maskY.set(e.clientY - top)
}}
style={{ WebkitMaskImage: maskImage, maskImage }}
{...props}
>
<Component {...props} />
</motion.div>
)
}
}
Free Framer Course
Learn how to create stunning websites with ease by learning the fundamentals of Framer.
Free
Framer Course
Learn how to create stunning websites with ease by learning the fundamentals of Framer.
Free Framer Course
Learn how to create stunning websites with ease by learning the fundamentals of Framer.