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>
    )
}

video