logo

VELOCIUI

Hyper Text

A hover-triggered text animation with random letter effects using Framer Motion.


Component Preview

V

E

L

O

C

I

U

I


Usage

npm install framer-motion
hyper-text.tsx
"use client";
import { useEffect, useRef, useState } from "react";
import { AnimatePresence, motion, Variants } from "framer-motion";
import { cn } from "@/lib/utils";
interface HyperTextProps {
text: string;
duration?: number;
framerProps?: Variants;
className?: string;
animateOnLoad?: boolean;
}
const alphabets = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
const getRandomInt = (max: number) => Math.floor(Math.random() * max);
export function HyperText({
text,
duration = 800,
framerProps = {
initial: { opacity: 0, y: -10 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: 3 },
},
className,
animateOnLoad = true,
}: HyperTextProps) {
const [displayText, setDisplayText] = useState(text.split(""));
const [trigger, setTrigger] = useState(false);
const interations = useRef(0);
const isFirstRender = useRef(true);
const triggerAnimation = () => {
interations.current = 0;
setTrigger(true);
};
useEffect(() => {
const interval = setInterval(
() => {
if (!animateOnLoad && isFirstRender.current) {
clearInterval(interval);
isFirstRender.current = false;
return;
}
if (interations.current < text.length) {
setDisplayText((t) =>
t.map((l, i) =>
l === " "
? l
: i <= interations.current
? text[i]
: alphabets[getRandomInt(26)],
),
);
interations.current = interations.current + 0.1;
} else {
setTrigger(false);
clearInterval(interval);
}
},
duration / (text.length * 10),
);
return () => clearInterval(interval);
}, [text, duration, trigger, animateOnLoad]);
return (
<div
className="overflow-hidden py-2 flex cursor-default scale-100"
onMouseEnter={triggerAnimation}
>
<AnimatePresence mode="wait">
{displayText.map((letter, i) => (
<motion.h1
key={i}
className={cn("font-mono", letter === " " ? "w-3" : "", className)}
{...framerProps}
>
{letter.toUpperCase()}
</motion.h1>
))}
</AnimatePresence>
</div>
);
}

Props for Hyper Text

PropTypeDefaultDescription
className
string
undefined

Optional class name to apply custom styling.

duration
number
800

The duration (in ms) for the animation cycle.

text
string
""

The text to animate.

framerProps
Variants
opacity and y values

Framer Motion props to customize animation transitions (initial, animate, exit).

animateOnLoad
boolean
true

If true, plays the animation on initial load; if false, only triggers on hover.