Text scramble
Random characters shuffle and then lock into the real word, letter by letter, like a decoding effect.
JavaScriptIntermediate
<h1 id="t" aria-label="Decoding signal">Decoding signal</h1>
<p class="hint">Click the text to scramble again</p>
h1{margin:0;font:700 clamp(1.8rem,8vw,3.4rem)/1.2 ui-monospace,Consolas,monospace;letter-spacing:.02em;color:#f08a5d;cursor:pointer;text-align:center}
.hint{position:fixed;bottom:16px;color:#a6938f;font-size:13px}
const el = document.getElementById('t');
const chars = '!<>-_\\/[]{}=+*^?#ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const final = el.textContent;
function scramble() {
let frame = 0;
const total = 40;
const timer = setInterval(() => {
el.textContent = [...final].map((ch, i) => {
if (ch === ' ') return ' ';
const lockAt = (i / final.length) * total * 0.8 + 6; // earlier letters lock first
return frame >= lockAt ? ch : chars[Math.floor(Math.random() * chars.length)];
}).join('');
if (++frame > total) { clearInterval(timer); el.textContent = final; }
}, 35);
}
el.onclick = scramble;
scramble();
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Text scramble</title>
<style>
*{box-sizing:border-box}
html,body{margin:0;height:100%}
body{display:grid;place-items:center;background:#140807;color:#fffffc;font:16px/1.5 system-ui,-apple-system,"Segoe UI",sans-serif}
h1{margin:0;font:700 clamp(1.8rem,8vw,3.4rem)/1.2 ui-monospace,Consolas,monospace;letter-spacing:.02em;color:#f08a5d;cursor:pointer;text-align:center}
.hint{position:fixed;bottom:16px;color:#a6938f;font-size:13px}
</style></head>
<body>
<h1 id="t" aria-label="Decoding signal">Decoding signal</h1>
<p class="hint">Click the text to scramble again</p>
<script>
const el = document.getElementById('t');
const chars = '!<>-_\\/[]{}=+*^?#ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const final = el.textContent;
function scramble() {
let frame = 0;
const total = 40;
const timer = setInterval(() => {
el.textContent = [...final].map((ch, i) => {
if (ch === ' ') return ' ';
const lockAt = (i / final.length) * total * 0.8 + 6; // earlier letters lock first
return frame >= lockAt ? ch : chars[Math.floor(Math.random() * chars.length)];
}).join('');
if (++frame > total) { clearInterval(timer); el.textContent = final; }
}, 35);
}
el.onclick = scramble;
scramble();
</script>
</body></html>
Good for
Tech and gaming brands, hover states on headings, and short title swaps.
Watch out for
Use a monospace or tabular font so the width does not jitter while the letters change.
Accessibility
Wrap motion in @media (prefers-reduced-motion: reduce) and switch it off or shorten it for people who ask for less movement.