summaryrefslogtreecommitdiff
path: root/makima/frontend/src/hooks/useTextScramble.ts
diff options
context:
space:
mode:
Diffstat (limited to 'makima/frontend/src/hooks/useTextScramble.ts')
-rw-r--r--makima/frontend/src/hooks/useTextScramble.ts52
1 files changed, 52 insertions, 0 deletions
diff --git a/makima/frontend/src/hooks/useTextScramble.ts b/makima/frontend/src/hooks/useTextScramble.ts
new file mode 100644
index 0000000..bb3f365
--- /dev/null
+++ b/makima/frontend/src/hooks/useTextScramble.ts
@@ -0,0 +1,52 @@
+import { useState, useCallback, useRef } from "react";
+
+const GLYPHS = "▒▓░█#@*+:-/[]{}<>_";
+
+export function useTextScramble(originalText: string) {
+ const [displayText, setDisplayText] = useState(originalText);
+ const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
+ const iterationRef = useRef(0);
+
+ const scramble = useCallback(() => {
+ // Clear any existing animation
+ if (timerRef.current) {
+ clearInterval(timerRef.current);
+ }
+
+ iterationRef.current = 0;
+
+ timerRef.current = setInterval(() => {
+ const text = originalText;
+ const iteration = iterationRef.current;
+
+ const display = text
+ .split("")
+ .map((char, index) => {
+ if (index < iteration) return char;
+ return GLYPHS.charAt(Math.floor(Math.random() * GLYPHS.length));
+ })
+ .join("");
+
+ setDisplayText(display);
+ iterationRef.current += 1;
+
+ if (iteration > text.length + 2) {
+ if (timerRef.current) {
+ clearInterval(timerRef.current);
+ timerRef.current = null;
+ }
+ setDisplayText(originalText);
+ }
+ }, 26);
+ }, [originalText]);
+
+ const reset = useCallback(() => {
+ if (timerRef.current) {
+ clearInterval(timerRef.current);
+ timerRef.current = null;
+ }
+ setDisplayText(originalText);
+ }, [originalText]);
+
+ return { displayText, scramble, reset };
+}