← all components
#09

Decrypt text reveal

Text that 'decrypts' itself: each character locks into place one by one while the unresolved characters flicker through random glyphs, like a terminal decoding a message. It runs on mount and again on hover. Pure JavaScript, no dependencies.

ReactJSText
// LIVE DEMO
// HOVER TO DECRYPT
DECRYPTING SIGNALaccess granted

Hover any line to run it again.

share this component →FacebookX / TwitterLinkedIn
// THE CODE
React
"use client";
import { useEffect, useRef, useState } from "react";

const GLYPHS = "!<>-_\\/[]{}=+*^?#0123456789ABCDEF";

export function Scramble({ text, className }) {
  const [out, setOut] = useState(text);
  const raf = useRef(0);
  const run = () => {
    const start = performance.now(), dur = 900;
    const per = text.split("").map(() => ({ delay: Math.random()*400, settle: 200 + Math.random()*300 }));
    const tick = (now) => {
      const t = now - start; let done = true;
      const chars = text.split("").map((ch, i) => {
        if (ch === " ") return " ";
        const c = per[i];
        if (t < c.delay) { done = false; return GLYPHS[(Math.floor(t/40)+i) % GLYPHS.length]; }
        if (t < c.delay + c.settle) { done = false; return GLYPHS[Math.floor(Math.random()*GLYPHS.length)]; }
        return ch;
      });
      setOut(chars.join(""));
      (!done && t < dur + 500) ? raf.current = requestAnimationFrame(tick) : setOut(text);
    };
    cancelAnimationFrame(raf.current); raf.current = requestAnimationFrame(tick);
  };
  useEffect(() => { run(); return () => cancelAnimationFrame(raf.current); }, [text]);
  return <span onMouseEnter={run} className={`font-mono cursor-pointer whitespace-pre ${className||""}`}>{out}</span>;
}
// HOW IT WORKS
  • 01Each character gets a random delay and a random settle time, so they resolve at staggered moments instead of all at once.
  • 02Before a character resolves it shows random glyphs from a set; after its settle window it snaps to the real letter.
  • 03A single requestAnimationFrame loop rebuilds the string each frame until every character is locked, then stops.
  • 04Spaces are preserved, and hovering re-triggers the whole decode.
Want a custom component for your product?
Let's build it →