Mouse Wave Text
Per-character y-displacement driven by cursor x-position using useMotionValue + useSpring. Creates a sine-wave ripple that follows the mouse.
Use and inspectUse this when the motion supports the surrounding content. Connect callbacks and state to your app, keep the reset preview as a local demonstration, and add a reduced-motion fallback for movement or looping. The preview is synthetic; it does not call a backend.Next: inspect the source below and replace the demo inputs with your own data.
Mouse Wave TextPer-character y-displacement driven by cursor x-position using useMotionValue + useSpring. Creates a sine-wave ripple that follows the mouse.
"use client";
import { useRef } from "react";
import { motion, useMotionValue, useSpring, useTransform, type MotionValue } from "framer-motion";
type MouseWaveTextProps = {
text: string;
amplitude?: number;
};
function WaveChar({
char,
mouseX,
amplitude,
}: {
char: string;
mouseX: MotionValue<number>;
amplitude: number;
}) {
const ref = useRef<HTMLSpanElement>(null);
const rawY = useTransform(mouseX, (mx) => {
if (!ref.current) return 0;
const rect = ref.current.getBoundingClientRect();
const cx = rect.left + rect.width / 2;
const dist = Math.abs(mx - cx);
return -amplitude * Math.max(0, 1 - dist / 56);
});
const y = useSpring(rawY, { stiffness: 320, damping: 22, mass: 0.5 });
return (
<motion.span
ref={ref}
style={{ y, display: "inline-block" }}
className="mp-mouse-wave-char"
>
{char}
</motion.span>
);
}
export function MouseWaveText({ text, amplitude = 14 }: MouseWaveTextProps) {
const mouseX = useMotionValue(-9999);
const chars = text.split("");
return (
<span
className="mp-mouse-wave-text"
onMouseMove={(e) => mouseX.set(e.clientX)}
onMouseLeave={() => mouseX.set(-9999)}
>
{chars.map((char, i) => (
<WaveChar
key={i}
char={char === " " ? "\u00A0" : char}
mouseX={mouseX}
amplitude={amplitude}
/>
))}
</span>
);
}Install
npm install framer-motionProps
| Prop | Type | Default | Description |
|---|---|---|---|
| textrequired | string | — | Text to apply wave effect to |
| amplitude | number | 14 | Max vertical displacement in px |