Blue Reveal
Mysterious blur reveal animation, just feels awesome.
The fog slowly faded away as the wind blew.The fog slowly faded away as the wind blew.
TSX
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122"use client"; import { AnimatePresence, motion } from "motion/react"; import type React from "react"; export interface BlurRevealProps { children: string; className?: string; delay?: number; speedReveal?: number; speedSegment?: number; trigger?: boolean; onAnimationComplete?: () => void; onAnimationStart?: () => void; as?: keyof React.JSX.IntrinsicElements; style?: React.CSSProperties; inView?: boolean; once?: boolean; letterSpacing?: string | number; } const BlurReveal = ({ children, className, delay = 0, speedReveal = 1.5, speedSegment = 0.5, trigger = true, onAnimationComplete, onAnimationStart, as = "p", style, inView = false, once = true, letterSpacing, }: BlurRevealProps) => { const MotionTag = motion[as as keyof typeof motion] as typeof motion.div; const stagger = 0.03 / speedReveal; const baseDuration = 0.3 / speedSegment; const containerVariants = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: stagger, delayChildren: delay, }, }, exit: { transition: { staggerChildren: stagger, staggerDirection: -1, }, }, }; const itemVariants = { hidden: { opacity: 0, filter: "blur(12px)", y: 10 }, visible: { opacity: 1, filter: "blur(0px)", y: 0, transition: { duration: baseDuration, }, }, exit: { opacity: 0, filter: "blur(12px)", y: 10 }, }; return ( <AnimatePresence mode="popLayout"> {trigger && ( <MotionTag initial="hidden" whileInView={inView ? "visible" : undefined} animate={inView ? undefined : "visible"} exit="exit" variants={containerVariants} viewport={{ once }} className={className} onAnimationComplete={onAnimationComplete} onAnimationStart={onAnimationStart} style={style} > <span className="sr-only">{children}</span> {children && children.split(" ").map((word, wordIndex, wordsArray) => ( <span key={`word-${wordIndex}`} className="inline-block whitespace-nowrap" aria-hidden="true" > {word.split("").map((char, charIndex) => ( <motion.span key={`char-${wordIndex}-${charIndex}`} variants={itemVariants} className="inline-block" style={ letterSpacing ? { marginRight: letterSpacing } : undefined } > {char} </motion.span> ))} {wordIndex < wordsArray.length - 1 && ( <motion.span key={`space-${wordIndex}`} variants={itemVariants} className="inline-block" > </motion.span> )} </span> ))} </MotionTag> )} </AnimatePresence> ); }; export default BlurReveal;
Installation
pnpm dlx shadcn@latest add @satoriui/blur-reveal