exploding-text
ui
桃李春风一杯酒,江湖夜雨十年灯。
src
exploding-text.tsx
TSX
"use client"
import { useEffect, useRef, useState } from "react";
import { wrap, mix, animate, delay, AnimationSequence } from "motion/react";
import { splitText } from "motion-plus";
import { cn } from "@/lib/tailwind";
interface ExplodingTextProps {
text: string[];
minVelocity?: number;
maxVelocity?: number;
delayNextLine?: number;
className?: string;
}
export function ExplodingText({
text,
minVelocity = 200,
maxVelocity = 400,
delayNextLine = 1,
className
}: ExplodingTextProps) {
const ref = useRef<HTMLDivElement>(null);
const [ index, setIndex ] = useState<number>(0);
useEffect(() => {
if (!ref.current) {
return;
}
const { chars } = splitText(ref.current!);
const sequence: AnimationSequence = chars.map((char) => {
const velocity = mix(minVelocity, maxVelocity, Math.random());
const angle = 2 * Math.PI * Math.random();
return [
char,
{
opacity: 0,
x: Math.cos(angle) * velocity,
y: Math.sin(angle) * velocity,
scale: 3,
color: `hsl(${ Math.random() * 360 } 100% 50%)`
},
{
type: "inertia",
velocity,
at: "<",
},
]
})
const animation = animate(sequence, { delay: 0.5 });
animation.finished.then(() => {
delay(() => setIndex(wrap(0, text.length, index + 1)), delayNextLine);
});
return () => animation.stop()
}, [ index ])
return (
<div className={ cn(className) } ref={ ref }>{ text[index] }</div>
)
}
page.tsx
TSX
import { ExplodingText } from "@/examples/exploding-text/exploding-text";
export default function Page() {
const lines = [
"桃李春风一杯酒,江湖夜雨十年灯。",
"春风又绿江南岸,明月何时照我还?",
"羌笛何须怨杨柳,春风不度玉门关。",
"天长地久有时尽,此恨绵绵无绝期。",
]
return (
<div className="h-160 bg-black flex justify-center items-center overflow-hidden">
<ExplodingText className="text-white text-2xl md:text-4xl lg:text-5xl duration-300"
text={ lines }/>
</div>
)
}