Skip to content

Instantly share code, notes, and snippets.

@mattgperry
Created July 3, 2025 08:05
Show Gist options
  • Save mattgperry/ad76704eb2e5f2bf0ca942c6dda8f5d4 to your computer and use it in GitHub Desktop.
Save mattgperry/ad76704eb2e5f2bf0ca942c6dda8f5d4 to your computer and use it in GitHub Desktop.
"use client"
import {
frame,
motion,
useMotionValue,
useSpring,
useTransform,
useVelocity,
} from "motion/react"
import { useEffect, useRef } from "react"
export default function MotionBlur() {
const ref = useRef<HTMLDivElement>(null)
const x = useSpring(0, spring)
const y = useSpring(0, spring)
const xVelocity = useVelocity(x)
const yVelocity = useVelocity(y)
const width = useMotionValue(100)
const height = useMotionValue(100)
const xFrameOffset = useTransform(() => Math.abs(xVelocity.get() / 1000))
const yFrameOffset = useTransform(() => Math.abs(yVelocity.get() / 1000))
// const stdDeviation = useTransform(
// () => `${xStdDeviation.get()},${yStdDeviation.get()}`
// )
const blur = useTransform(() =>
Math.max(xFrameOffset.get(), yFrameOffset.get())
)
const filter = useTransform(() => `blur(${blur.get()}px)`)
const transform = useTransform(() => {
const w = width.get()
const h = height.get()
const b = blur.get()
const scaleX = w / (w + 2 * b)
const scaleY = h / (h + 2 * b)
return `translate(${x.get() - xFrameOffset.get()}px, ${
y.get() - yFrameOffset.get()
}px) scale(${scaleX}, ${scaleY})`
// ;`translate(${x.get() - xStdDeviation.get() / 2}px, ${
// y.get() - yStdDeviation.get() / 2
// }px) scaleY())`
})
useEffect(() => {
const element = ref.current
if (!element) return
const moveElement = (event: MouseEvent) => {
frame.read(() => {
x.set(
event.clientX - element.offsetLeft - element.offsetWidth / 2
)
y.set(
event.clientY - element.offsetTop - element.offsetHeight / 2
)
})
}
window.addEventListener("pointerdown", moveElement)
return () => {
window.removeEventListener("pointerdown", moveElement)
}
}, [])
return (
<>
<motion.div ref={ref} style={{ ...ball, transform, filter }}>
test
</motion.div>
{/* <svg>
<defs>
<filter id="blur">
<motion.feGaussianBlur
in="SourceGraphic"
stdDeviation={stdDeviation}
/>
</filter>
</defs>
</svg> */}
<style>
{`
body { overflow: hidden; }
`}
</style>
</>
)
}
const spring = { damping: 3, stiffness: 50, restDelta: 0.001 }
/**
* ============== Styles ================
*/
const ball = {
width: 100,
height: 100,
backgroundColor: "var(--hue-1)",
// borderRadius: "50%",
// willChange: "transform, filter",
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment