TextReveal
textreveal-1779379671865.tsx
'use client'
import { useState, useEffect, useRef } from 'react'
const EFFECTS = ['stagger', 'typewriter', 'scramble', 'gradient'] as const
type Effect = typeof EFFECTS[number]
const CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*'
const TEXT = 'Build faster with Empire UI'
function useTypewriter(text: string, speed = 60) {
const [displayed, setDisplayed] = useState('')
useEffect(() => {
setDisplayed('')
let i = 0
const t = setInterval(() => {
setDisplayed(text.slice(0, ++i))
if (i >= text.length) clearInterval(t)
}, speed)
return () => clearInterval(t)
}, [text, speed])
return displayed
}
function ScrambleText({ text }: { text: string }) {
const [displayed, setDisplayed] = useState(text)
const frame = useRef(0)
useEffect(() => {
let iter = 0
cancelAnimationFrame(frame.current)
frame.current = requestAnimationFrame(function tick() {
setDisplayed(text.split('').map((c, i) => {
if (c === ' ') return ' '
if (i < iter) return c
return CHARS[Math.floor(Math.random() * CHARS.length)]
}).join(''))
if (iter < text.length) { iter += 0.3; frame.current = requestAnimationFrame(tick) }
})
return () => cancelAnimationFrame(frame.current)
}, [text])
return <span>{displayed}</span>
}
export default function TextReveal() {
const [effect, setEffect] = useState<Effect>('stagger')
const [key, setKey] = useState(0)
const typewritten = useTypewriter(key > 0 ? TEXT : TEXT, 50)
function replay() { setKey(k => k + 1) }
const words = TEXT.split(' ')
return (
<div style={{ padding: 40, background: '#0A0A0A', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 32 }}>
{/* Effect picker */}
<div style={{ display: 'flex', gap: 6 }}>
{EFFECTS.map(e => (
<button key={e} onClick={() => { setEffect(e); replay() }} style={{ background: effect === e ? 'rgba(201,168,76,0.12)' : 'rgba(255,255,255,0.04)', border: '1px solid', borderColor: effect === e ? 'rgba(201,168,76,0.3)' : 'rgba(255,255,255,0.08)', color: effect === e ? '#C9A84C' : 'rgba(255,255,255,0.4)', borderRadius: 6, padding: '5px 12px', cursor: 'pointer', fontSize: 12 }}>{e}</button>
))}
</div>
{/* Animation */}
<div style={{ fontSize: 36, fontWeight: 800, textAlign: 'center', minHeight: 48, lineHeight: 1.3 }}>
{effect === 'stagger' && (
<span key={key} style={{ display: 'inline' }}>
{words.map((word, i) => (
<span key={i} style={{ display: 'inline-block', marginRight: 10, animation: `slideUp 0.5s ${i * 0.1}s both ease`, color: '#F5F5F0' }}>{word}</span>
))}
</span>
)}
{effect === 'typewriter' && (
<span key={key} style={{ color: '#F5F5F0' }}>
{typewritten}<span style={{ borderRight: '2px solid #C9A84C', marginLeft: 2, animation: 'blink 0.7s step-end infinite' }} />
</span>
)}
{effect === 'scramble' && <span key={key} style={{ color: '#C9A84C', fontFamily: 'monospace' }}><ScrambleText text={TEXT} /></span>}
{effect === 'gradient' && (
<span key={key} style={{ background: 'linear-gradient(90deg, #C9A84C 0%, #6366f1 33%, #22c55e 66%, #C9A84C 100%)', backgroundSize: '300% auto', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent', animation: 'gradMove 2s linear infinite' }}>{TEXT}</span>
)}
</div>
<button onClick={replay} style={{ background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.1)', color: '#F5F5F0', borderRadius: 8, padding: '8px 20px', cursor: 'pointer', fontSize: 13 }}>Replay ↺</button>
<style>{`
@keyframes slideUp { from { opacity:0; transform:translateY(20px) } to { opacity:1; transform:translateY(0) } }
@keyframes blink { 0%,100% { opacity:1 } 50% { opacity:0 } }
@keyframes gradMove { to { background-position: 300% center } }
`}</style>
</div>
)
}Component info
CategoryAnimations & Cursors
Frameworkreact
TierFREE
Views0
Copies0
About
Animated text reveal with staggered word animation, typewriter, scramble, and gradient sweep effects
More from Animations & Cursors
'use client'
import { useState, useEffect, useRef } from 'react'
interface AnimatedNumberProps {
target: number
duration?: number
prefix?: string
suffix?: string
decimals?: number
onComplete?: () => void
}
function AnimatedNumber({ targCounterAnimation
Animations & Cursors
import React from 'react';
import { motion } from 'framer-motion';
interface MorphCursorProps {
children: React.ReactNode;
}
const MorphCursor: React.FC<MorphCursorProps> = ({ children }) => {
const [cursorType, setCursorType] = React.useState(MorphCursor
Animations & Cursors
import { useEffect, useState } from 'react';
interface Dot {
x: number;
y: number;
opacity: number;
}
const TrailCursor = () => {
const [dots, setDots] = useState<Dot[]>([]);
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0TrailCursor
Animations & Cursors
import { useState, useEffect } from 'react';
import { motion } from 'framer-motion';
interface PixelCursorProps {
color: string;
}
const PixelCursor: React.FC<PixelCursorProps> = ({ color }) => {
const [mousePosition, setMousePosition] = useStaPixelCursor
Animations & Cursors