Example
Move your cursor around
Installation
Copy and paste the source code into your project.
"use client";
import { motion } from "framer-motion";
import React, { useEffect, useState } from "react";
type RollingTextCursorProps = {
text: string;
size?: number;
slackWhenFollowing?: number;
circleSpeed?: number;
className?: string;
};
/**
* RollingTextCursor component.
*
* A component that displays a rolling text cursor that follows the mouse movement.
*
* @param {string} [props.text] - The text to be displayed by the cursor.
* @param {number} [props.size=150] - The size of the cursor.
* @param {number} [props.slackWhenFollowing=0.5] - The duration of the cursor's animation when following the mouse movement.
* @param {number} [props.circleSpeed=10] - The speed of the circular animation of the cursor.
* @param {string} [props.className] - The additional CSS class for the text.
*/
export const RollingTextCursor = ({
text,
size = 150,
slackWhenFollowing = 0.5,
circleSpeed = 10,
className,
}: RollingTextCursorProps) => {
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
const handleMouseMove = (e: MouseEvent) => {
setMousePosition({ x: e.clientX, y: e.clientY });
};
useEffect(() => {
window.addEventListener("mousemove", handleMouseMove);
return () => {
window.removeEventListener("mousemove", handleMouseMove);
};
}, []);
const offset = size / 2;
const radius = size / 2;
const circumference = 2 * Math.PI * radius;
const textWithSpaceInTheEnd = `${text} \u00A0`;
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 1, ease: "easeOut" }}
className={`fixed top-0 left-0 w-full h-full pointer-events-none z-50`}
>
<motion.div
animate={{
x: mousePosition.x - offset,
y: mousePosition.y - offset,
}}
transition={{
type: "tween",
ease: "backOut",
duration: slackWhenFollowing,
}}
style={{
transform: "translate(-50%, -50%)",
}}
>
<motion.svg
width={size}
height={size}
className="pointer-events-none absolute z-10"
animate={{
rotate: 360,
}}
transition={{
duration: circleSpeed,
repeat: Infinity,
ease: "linear",
}}
>
<path
id="circlePath"
d={`M${size / 2},${size / 2} m-${radius},0 a${radius},${radius} 0 1,0 ${size},0 a${radius},${radius} 0 1,0 -${size},0`}
fill="none"
></path>
<text>
<textPath
href="#circlePath"
fill="currentColor"
className={className}
textLength={circumference}
>
{textWithSpaceInTheEnd}
</textPath>
</text>
</motion.svg>
</motion.div>
</motion.div>
);
};
Update the import paths to match your project setup.
Props
Prop | Type | Default | Description |
---|---|---|---|
text | string | - | The text to be displayed by the cursor. |
size | number | 150 | The size of the cursor. |
slackWhenFollowing | number | 0.5 | The duration of the cursor's animation when following the mouse movement. |
circleSpeed | number | 10 | The speed of the circular animation of the cursor. |
className | string | - | The additional CSS class for the text. |