Hyper Text

A hyper changing text animation as you hover.

H

Y

P

E

R

T

E

X

T

Installation

Install the following dependencies:

npm install framer-motion

Copy and paste the following code into your project.

"use client"
 
import { useEffect, useRef, useState } from "react"
import { AnimatePresence, Variants, motion } 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))
    // Clean up interval on unmount
    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>
  )
}

Update the import paths to match your project setup.

Props

PropTypeDescriptionDefault
classNamestringThe class name to be applied to the component
durationnumberThe duration for which the animation runs.80
textstringText to animate""
framerPropsVariantsAn object containing framer-motion animation props
animateOnLoadbooleanPlay animation on loadtrue