Text Scramble — Free HTML CSS JS Decode Snippet
Text Scramble · Animations · Plain HTML, CSS & JS · Live preview
Copy & paste
Source Code
<div class="scene">
<h1 id="text">Hover to decode</h1>
<div class="buttons">
<button class="btn" onclick="scramble('Hello World')">Hello World</button>
<button class="btn" onclick="scramble('UI Snippets')">UI Snippets</button>
<button class="btn" onclick="scramble('Ship It Fast')">Ship It Fast</button>
<button class="btn" onclick="scramble('Build Beautiful')">Build Beautiful</button>
</div>
</div>* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #050810; display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 20px; }
.scene { text-align: center; display: flex; flex-direction: column; align-items: center; gap: 32px; }
h1 {
font-size: clamp(28px, 6vw, 56px);
font-weight: 800;
letter-spacing: 0.05em;
color: #0ff;
font-family: 'Courier New', monospace;
text-shadow: 0 0 20px rgba(0,255,255,0.4);
min-height: 1.3em;
}
.buttons { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.btn {
padding: 8px 18px; font-size: 12px; font-weight: 600;
font-family: 'Courier New', monospace;
background: transparent; color: #0ff8;
border: 1px solid #0ff3; border-radius: 4px;
cursor: pointer; transition: border-color 0.15s, color 0.15s;
}
.btn:hover { border-color: #0ff; color: #0ff; }const chars = '!@#$%^&*<>?/|ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const el = document.getElementById('text');
let frame, frameReq;
function scramble(target) {
let iteration = 0;
cancelAnimationFrame(frameReq);
frameReq = requestAnimationFrame(function anim() {
el.textContent = target.split('').map((ch, i) => {
if (ch === ' ') return ' ';
if (i < iteration) return target[i];
return chars[Math.floor(Math.random() * chars.length)];
}).join('');
if (iteration < target.length) {
iteration += 0.3;
frameReq = requestAnimationFrame(anim);
}
});
}
el.addEventListener('mouseenter', () => scramble(el.textContent));
scramble('Hover to decode');Extend with AI
Take This Snippet Further With AI
The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.
What's included
Features
About this UI Snippet
Text Scramble — requestAnimationFrame Decode, Iteration Counter & Random Char Pool

The text scramble effect reveals a word by cycling random characters at each position before "locking in" the correct letter — a matrix-style decode that makes text appear to materialise from noise — pair it with a matrix rain background and glitch text. Used on dark-themed developer tools, hacker aesthetic interfaces, and cyberpunk products. For a simpler character-by-character reveal, see the typewriter.
The scramble algorithm
scramble(target) runs a requestAnimationFrame loop. Each frame: target.split('').map((ch, i) => { if (ch === ' ') return ' '; if (i < iteration) return ch; return chars[Math.floor(Math.random() * chars.length)]; }). Characters at indices below iteration show the correct letter; characters at indices above it show random noise from the 90-character pool. iteration increments by 0.5 each frame — locking two characters every frame but with a fractional counter so the reveal has a gentle pace.
The chars pool
const chars = '!@#$%^&*<>?/|ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' — 90 characters combining symbols, letters, and numbers. The variety of character widths creates visible noise that makes the reveal effect more dramatic. Narrow the pool to symbols-only for a pure matrix aesthetic.
cancelAnimationFrame on re-trigger
cancelAnimationFrame(frameReq) at the start of scramble() cancels any in-progress animation before starting a new one. This prevents overlapping decode animations when the user clicks buttons in rapid succession.
The decode algorithm
The scramble effect works by iterating the target text character by character. For each character position, the function either: (a) reveals the final character if the position index is below the current reveal threshold, or (b) shows a random character from a 90-character pool (uppercase, lowercase, digits, symbols). A requestAnimationFrame loop increments the reveal threshold by a fraction each frame. The result is characters "decoding" from random noise into the final text from left to right.
The character pool
The 90-character scramble pool includes uppercase A-Z, lowercase a-z, digits 0-9, and special characters. Using a large, varied pool makes the scramble feel genuinely random and cryptographic. A smaller pool (just digits, or just uppercase) creates a more specific aesthetic — use numbers-only for a hacker terminal effect, use uppercase for a classified document decode feel.
Triggering and cycling
The snippet cycles through multiple words — "DESIGN", "BUILD", "SHIP", "REPEAT" — scrambling between each transition. Each word scrambles in over ~800ms. A setTimeout between words pauses at the final state before beginning the next scramble.
Step by step
How to Use
- 1Click the buttonsClick each phrase button to see the scramble decode animation run. Click a different button mid-animation to see it cancel and start fresh.
- 2Update the target phrasesIn the HTML panel, update the button onclick scramble() arguments to your own phrases.
- 3Change the decode speedIn the JS panel, update the iteration increment (currently 0.5) to make the reveal faster or slower.
- 4Narrow the character poolIn the JS panel, edit the chars string to limit it to symbols-only for a purer matrix effect.
- 5Change the text colourUpdate color: #0ff (cyan) on h1 in the CSS panel to your brand colour. The text-shadow colour should match.
- 6Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Each frame, characters at index < iteration show the correct target character. Characters at index >= iteration show a random char from the pool. Incrementing iteration by 0.5 each frame reveals approximately one character every two frames.
chars is a string of 90 characters. Math.floor(Math.random() * chars.length) picks a random index. Remove character groups from the string to narrow the noise. Use only symbols for a pure matrix look, or only uppercase letters for a more legible scramble.
If the user clicks a new phrase button before the current animation finishes, a new requestAnimationFrame loop would start while the old one is still running, causing two animations to write to the element simultaneously. cancelAnimationFrame(frameReq) stops the previous loop first.
Call scramble("Your Text") immediately after the JS code. The animation starts running as soon as the script executes.
Add el.addEventListener("mouseenter", () => scramble(el.textContent)) and cancelAnimationFrame(frameReq) on mouseleave. The element scrambles when hovered and cancels when the mouse leaves.
Yes. Click "JSX" for a React component. In React, use useRef for the element and frameReq, and useEffect to attach the scramble logic. Store the target text in a prop and call scramble(target) from the component.