hoodquidity/apps/web/src/components/fx/Scramble.tsx
Денис Зефиров dba2811447 Hoodquidity: liquidity campaigns for Robinhood Chain stock token markets
Full build: Vite/React acid-terminal frontend (BEARER design system,
Panchang/Sentient/Fragment Mono, neon layer, palette audit script),
HoodquidityVaults Foundry contracts (single+dual deposits via Chainlink-style
feeds, hybrid exit, 10% platform fee, boost, Genesis LP), Reown AppKit wallet
connect with Robinhood Chain testnet (46630), live data from Dexscreener and
onchain reads, partner portal, design-sync setup for claude.ai/design.

Deploy: static via Forgejo Actions platform, BUILD_DIR=apps/web/dist (.env).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 08:32:28 +04:00

64 lines
1.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useEffect, useRef, useState } from "react";
import { motionEnabled } from "@/lib/motion";
const GLYPHS =
"アイウエオカキクケコサシスセソタチツテトナニヌネハヒフヘホマミムメモヤユヨラリルレロワヲン0123456789▚▞▮◎";
/**
* Cyberdeck decode: the label periodically dissolves into katakana and
* terminal glyphs, then settles back left to right. Decorative labels only,
* never live figures.
*/
export function Scramble({
text,
interval = 9000,
className,
}: {
text: string;
interval?: number;
className?: string;
}) {
const [display, setDisplay] = useState(text);
const raf = useRef(0);
useEffect(() => {
if (!motionEnabled) {
setDisplay(text);
return;
}
let cancelled = false;
const decode = () => {
const start = performance.now();
const dur = 950;
const tick = (t: number) => {
if (cancelled) return;
const p = Math.min((t - start) / dur, 1);
const settled = Math.floor(p * text.length);
let out = text.slice(0, settled);
for (let i = settled; i < text.length; i++) {
const ch = text[i];
out +=
ch === " "
? " "
: GLYPHS[(Math.floor(t / 48) + i * 7) % GLYPHS.length];
}
setDisplay(out);
if (p < 1) raf.current = requestAnimationFrame(tick);
else setDisplay(text);
};
raf.current = requestAnimationFrame(tick);
};
decode();
const jitter = (text.length * 137) % 3000;
const timer = setInterval(decode, interval + jitter);
return () => {
cancelled = true;
clearInterval(timer);
cancelAnimationFrame(raf.current);
};
}, [text, interval]);
return <span className={className}>{display}</span>;
}