Scramble
A GSAP registered effect that decodes text with staggered character-by-character reveal animation. Weighted character sets and per-character jittered timing for an organic feel.
'use client'
import * as React from 'react'
import { ScrambleButton } from '@/components/scramble-button'
import { Switch } from '@/components/ui/switch'
function ScrambleButtonDemo() {
const [scrambled, setScrambled] = React.useState(false)
return (
<div className="flex min-h-48 flex-col items-center justify-center gap-8 overflow-hidden p-8 font-mono">
<div className="flex flex-col items-center gap-3 sm:flex-row">
<ScrambleButton
text="GET STARTED"
scramble={scrambled}
variant="default"
/>
<ScrambleButton
text="LEARN MORE"
scramble={scrambled}
chars="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
variant="secondary"
/>
<ScrambleButton
text="SUBSCRIBE"
scramble={scrambled}
chars="01"
variant="outline"
/>
</div>
{/* Mobile fallback: switch to trigger scramble */}
<label className="flex cursor-pointer items-center gap-3 sm:hidden">
<Switch checked={scrambled} onCheckedChange={setScrambled} />
<span className="text-muted-foreground text-xs tracking-wider uppercase">
Toggle scramble
</span>
</label>
</div>
)
}
export default ScrambleButtonDemo
Installation
Usage
Import the effect file to register it, then use gsap.effects.scramble() on any element:
import gsap from 'gsap'
import '@/registry/lib/gsap/effects/scramble'
// Scramble an element's text
gsap.effects.scramble('.heading', {
text: 'DECODED TEXT',
duration: 0.8,
})On a timeline
The effect has extendTimeline: true, so you can chain it:
const tl = gsap.timeline()
tl.scramble('.line-1', { text: 'SYSTEM ONLINE' }).scramble(
'.line-2',
{ text: 'ALL MODULES LOADED' },
'+=0.2'
)Custom character sets
Repeated characters increase their probability, creating visual breathing room:
// Hacker terminal (default) — underscores add visual pauses
gsap.effects.scramble(el, { chars: '!<>-_\\/[]{}—=+*^?#________' })
// Clean uppercase
gsap.effects.scramble(el, { chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' })
// Binary
gsap.effects.scramble(el, { chars: '01' })
// Block drawing
gsap.effects.scramble(el, { chars: '░▒▓█▀▄■□▪▫●○◆◇◈' })Config
| Prop | Type | Default | Description |
|---|---|---|---|
text | string | Element's textContent | The final text to reveal |
chars | string | !<>-_\\/[]{}—=+*^?#________ | Character set used for scrambling |
duration | number | 0.5 | Duration in seconds. 0 = auto-scale with text length |
ease | string | 'none' | GSAP ease string |
cycles | number | 2 | Randomization cycles per character before resolving (higher = more chaotic) |
chance | number | 1 | Probability (0–1) that each character scrambles |
overflow | boolean | true | Show all character positions from the start rather than growing in |
ignoreReducedMotion | boolean | false | Skip prefers-reduced-motion check |