How implement Speed text or Typewriter effect?
In a visual novel, it is very useful to have a typewriter effect.
For implement this effect, you can use the following code:
tsx
// react example
import { useEffect, useState } from 'react';
type ITypewriterProps = {
text: string;
delay: number;
};
export default function Typewriter({ text, delay }: ITypewriterProps) {
const [currentText, setCurrentText] = useState('');
const [currentIndex, setCurrentIndex] = useState(0);
useEffect(() => {
if (currentIndex < text.length) {
const timeout = setTimeout(() => {
setCurrentText(prevText => prevText + text[currentIndex]);
setCurrentIndex(prevIndex => prevIndex + 1);
}, delay);
return () => clearTimeout(timeout);
}
}, [currentIndex, delay, text]);
useEffect(() => {
setCurrentText('');
setCurrentIndex(0);
}, [text]);
return <span>{currentText}</span>;
};
You can achieve the same result using the library Framer Motion:
tsx
import { motion, Variants } from "framer-motion";
import { useMemo } from "react";
export default function Typewriter({ children, delay = 0 }: { children: string; delay?: number; }) {
const sentenceVariants: Variants = {
hidden: {},
visible: { opacity: 1, transition: { staggerChildren: delay / 1000 } },
};
const letterVariants = useMemo<Variants>(() => ({
hidden: { opacity: 0 },
visible: { opacity: 1, transition: { opacity: { duration: 0 } } },
}), [delay]);
return (
<motion.p
variants={sentenceVariants}
initial="hidden"
animate="visible"
>
{children.split("").map((char, i) => (
<motion.span key={`${char}-${i}`} variants={letterVariants}>
{char}
</motion.span>
))}
</motion.p>
)
};