Skip to content

Instantly share code, notes, and snippets.

@ekaone
Created October 24, 2024 02:23
Show Gist options
  • Select an option

  • Save ekaone/34c34ba9143db3536263e782ec08643c to your computer and use it in GitHub Desktop.

Select an option

Save ekaone/34c34ba9143db3536263e782ec08643c to your computer and use it in GitHub Desktop.
Animated Text likes streaming-text on AI
// Dependencies: npm i framer-motion
// Hooks
"use client";
import { animate } from "framer-motion";
import { useEffect, useState } from "react";
const delimiter = ""; // or " " to split by word
export function useAnimatedText(text: string) {
const [cursor, setCursor] = useState(0);
const [startingCursor, setStartingCursor] = useState(0);
const [prevText, setPrevText] = useState(text);
if (prevText !== text) {
setPrevText(text);
setStartingCursor(text.startsWith(prevText) ? cursor : 0);
}
useEffect(() => {
const controls = animate(startingCursor, text.split(delimiter).length, {
// Tweak the animation here
duration: 4,
ease: "easeOut",
onUpdate(latest) {
setCursor(Math.floor(latest));
},
});
return () => controls.stop();
}, [startingCursor, text]);
return text.split(delimiter).slice(0, cursor).join(delimiter);
}
// Usage
function Page() {
const [prompt, setPrompt] = useState('');
const [text, setText] = useState('');
const animatedText = useAnimatedText(text);
async function handleSubmit() {
const { textStream } = await streamText({
model: openai('gpt-4-turbo'),
prompt,
});
for await (const textPart of textStream) {
setText((prev) => prev + textPart);
}
}
return (
<>
<form onSubmit={handleSubmit}>
<input
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="Ask anything"
/>
</form>
<p>{animatedText}</p>
</>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment