Skip to content

Commit 90ffa3c

Browse files
committed
[berlix] Install text scramble
1 parent 874e930 commit 90ffa3c

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"use client";
2+
3+
import { useEffect, useState } from "react";
4+
5+
import { motion } from "framer-motion";
6+
7+
interface TextScrambleProps {
8+
children: string;
9+
speed?: number;
10+
characterSet?: string;
11+
className?: string;
12+
}
13+
14+
const DEFAULT_CHARS =
15+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
16+
17+
function getRandomChar(charSet: string) {
18+
return charSet[Math.floor(Math.random() * charSet.length)];
19+
}
20+
21+
export const TextScramble = ({
22+
children,
23+
speed = 50,
24+
characterSet = DEFAULT_CHARS,
25+
className,
26+
...motionProps
27+
}: TextScrambleProps) => {
28+
const [text, setText] = useState(children);
29+
30+
useEffect(() => {
31+
let step = 0;
32+
const interval = setInterval(() => {
33+
let scrambled = "";
34+
35+
for (let i = 0; i < children.length; i++) {
36+
if (i < step) {
37+
scrambled += children[i];
38+
} else if (children[i] === " ") {
39+
scrambled += " ";
40+
} else {
41+
scrambled += getRandomChar(characterSet);
42+
}
43+
}
44+
45+
setText(scrambled);
46+
step++;
47+
48+
if (step > children.length) {
49+
clearInterval(interval);
50+
setText(children);
51+
}
52+
}, speed);
53+
54+
return () => clearInterval(interval);
55+
}, [children, speed, characterSet]);
56+
57+
return (
58+
<motion.span className={className} {...motionProps}>
59+
{text}
60+
</motion.span>
61+
);
62+
};

0 commit comments

Comments
 (0)