Velocity UI
Loading…
Menu

Hyper Text

A cyberpunk-inspired text effect that scrambles characters randomly before resolving to the final text on hover or load.

Preview

Live interactive preview.

Installation

Add this component to your project using the CLI:

terminal
npx -y vui-registry-cli-v1@latest add hyper-text

Source Code

hyper-text.tsx
'use client';

import { useEffect, useRef, useState } from 'react';
import { cn } from '@/lib/utils';

export default function HyperText({
  text = 'Velocity UI',
  className,
  duration = 800,
}: {
  text?: string;
  className?: string;
  duration?: number;
}) {
  const [displayText, setDisplayText] = useState(text.split(''));
  const [isAnimating, setIsAnimating] = useState(false);
  const intervalRef = useRef<NodeJS.Timeout | null>(null);
  const alphabets = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+';

  const startAnimation = () => {
    setIsAnimating(true);
    let iteration = 0;
    
    if (intervalRef.current) clearInterval(intervalRef.current);
    
    intervalRef.current = setInterval(() => {
      setDisplayText((currentText) =>
        text.split('').map((letter, index) => {
          if (letter === ' ') return letter;
          if (index < iteration) {
            return text[index];
          }
          return alphabets[Math.floor(Math.random() * alphabets.length)];
        })
      );

      if (iteration >= text.length) {
        if (intervalRef.current) clearInterval(intervalRef.current);
        setIsAnimating(false);
      }
      
      iteration += 1 / 3; 
    }, 30); 
  };

  // Trigger on mount for demo
  useEffect(() => {
    startAnimation();
  }, []);

  return (
    <div
      className={cn("flex overflow-hidden py-2 cursor-pointer select-none", className)}
      onMouseEnter={startAnimation}
    >
        <span className="sr-only">{text}</span>
        {displayText.map((char, i) => (
            <span key={i} className="font-mono inline-block w-[0.6em] text-center">
                {char}
            </span>
        ))}
    </div>
  );
}

Dependencies

  • framer-motion: latest