Scramble Text
Hover to decode — each character cycles through random symbols before locking into place, left to right. The hacker-decode text effect showing up across 2025/2026 tech and portfolio sites, done in plain React state + requestAnimationFrame (no dependency).
import { useEffect, useRef, useState } from "react";
const SCRAMBLE_CHARS = "!<>-_\\/[]{}—=+*^?#________";
export function ScrambleText({ text = "Hover to decode" }) {
const [display, setDisplay] = useState(text);
const frame = useRef(0);
const raf = useRef(null);
function stop() {
if (raf.current !== null) cancelAnimationFrame(raf.current);
raf.current = null;
}
function scramble() {
stop();
frame.current = 0;
const totalFrames = text.length * 3;
const tick = () => {
frame.current += 1;
const revealed = Math.floor((frame.current / totalFrames) * text.length);
setDisplay(
text
.split("")
.map((ch, i) => {
if (ch === " ") return " ";
if (i < revealed) return ch;
return SCRAMBLE_CHARS[Math.floor(Math.random() * SCRAMBLE_CHARS.length)];
})
.join(""),
);
if (frame.current < totalFrames) {
raf.current = requestAnimationFrame(tick);
} else {
setDisplay(text);
}
};
raf.current = requestAnimationFrame(tick);
}
useEffect(() => stop, []);
return (
<span onMouseEnter={scramble} className="cursor-pointer select-none font-mono">
{display}
</span>
);
}How it works
Scramble Text is a hand-built text component for React, styled with Tailwind and animated with Framer Motion — no heavy dependency tree, no 60-package install. Drop it in, keep your bundle lean, and it stays performant on real devices. It's free — copy the code above and ship it.
← Browse all components