Scrambled Text
Detects cursor position and applies a distortion effect to text.
Nameless UI - Find the perfect React UI component in seconds, build beautiful interfaces faster
import ScrambledText from "@/components/core/scrambled-text";
export default function ScrambledTextExample() {
return (
<ScrambledText
style={{ color: "currentColor" }}
radius={50}
duration={1.2}
speed={0.5}
scrambleChars={".:"}
>
Nameless UI - Find the perfect React UI component in seconds, build
beautiful interfaces faster
</ScrambledText>
);
}
Installation
Install the following dependencies:
npm install gsapCopy and paste the following code into your project:
"use client";
import React, { useEffect, useRef } from "react";
import { gsap } from "gsap";
import { SplitText } from "gsap/SplitText";
import { ScrambleTextPlugin } from "gsap/ScrambleTextPlugin";
gsap.registerPlugin(SplitText, ScrambleTextPlugin);
export interface ScrambledTextProps {
radius?: number;
duration?: number;
speed?: number;
scrambleChars?: string;
className?: string;
style?: React.CSSProperties;
children: React.ReactNode;
}
const ScrambledText: React.FC<ScrambledTextProps> = ({
radius = 100,
duration = 1.2,
speed = 0.5,
scrambleChars = ".:",
className = "",
style = {},
children,
}) => {
const rootRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
if (!rootRef.current) return;
const split = SplitText.create(rootRef.current.querySelector("p"), {
type: "chars",
charsClass: "inline-block will-change-transform",
});
split.chars.forEach((el) => {
const c = el as HTMLElement;
gsap.set(c, { attr: { "data-content": c.innerHTML } });
});
const handleMove = (e: PointerEvent) => {
split.chars.forEach((el) => {
const c = el as HTMLElement;
const { left, top, width, height } = c.getBoundingClientRect();
const dx = e.clientX - (left + width / 2);
const dy = e.clientY - (top + height / 2);
const dist = Math.hypot(dx, dy);
if (dist < radius) {
gsap.to(c, {
overwrite: true,
duration: duration * (1 - dist / radius),
scrambleText: {
text: c.dataset.content || "",
chars: scrambleChars,
speed,
},
ease: "none",
});
}
});
};
const el = rootRef.current;
el.addEventListener("pointermove", handleMove);
return () => {
el.removeEventListener("pointermove", handleMove);
split.revert();
};
}, [radius, duration, speed, scrambleChars]);
return (
<div
ref={rootRef}
className={`m-[7vw] max-w-[800px] font-mono text-[clamp(14px,4vw,32px)] text-white ${className}`}
style={style}
>
<p>{children}</p>
</div>
);
};
export default ScrambledText;
Update the import paths to match your project setup.
Usage
import ScrambledText from "@/components/core/scrambled-text";
export default function ScrambledTextExample() {
return (
<ScrambledText
style={{ color: "currentColor" }}
radius={50}
duration={1.2}
speed={0.5}
scrambleChars={".:"}
>
Nameless UI - Find the perfect React UI component in seconds, build
beautiful interfaces faster
</ScrambledText>
);
}
Props
| Prop | Type | Default |
|---|---|---|
radius? | number | 100 |
duration? | number | 1.2 |
speed? | number | 0.5 |
scrambleChars? | string | .: |
children | React.ReactNode | - |
className? | string | '' |
style? | React.CSSProperties | {} |