From e661fc35b105cf1a37d0ee543eb6122eafd7347a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 17:04:07 +0000 Subject: [PATCH] feat: Add framer-motion animation to token generation This commit introduces a framer-motion animation to the token generation process. The tokens now appear fluidly with a fade-in effect as they are generated by the language model. A new `StreamingMarkdown` component was created to handle the animation of the streaming markdown content. This component wraps each word in a `motion.span` and applies a staggered fade-in animation. The `BotMessage` component was updated to use the new `StreamingMarkdown` component, applying the animation to all bot messages. --- components/message.tsx | 43 +------------- components/ui/StreamingMarkdown.tsx | 90 +++++++++++++++++++++++++++++ server.log | 0 3 files changed, 93 insertions(+), 40 deletions(-) create mode 100644 components/ui/StreamingMarkdown.tsx create mode 100644 server.log diff --git a/components/message.tsx b/components/message.tsx index 264aa1f6..4f99c992 100644 --- a/components/message.tsx +++ b/components/message.tsx @@ -1,45 +1,8 @@ 'use client' -import { StreamableValue, useStreamableValue } from 'ai/rsc' -import { MemoizedReactMarkdown } from './ui/markdown' -import rehypeExternalLinks from 'rehype-external-links' -import remarkGfm from 'remark-gfm' -import remarkMath from 'remark-math' -import rehypeKatex from 'rehype-katex' -import 'katex/dist/katex.min.css' +import { StreamableValue } from 'ai/rsc' +import { StreamingMarkdown } from './ui/StreamingMarkdown' export function BotMessage({ content }: { content: StreamableValue }) { - const [data, error, pending] = useStreamableValue(content) - - // Currently, sometimes error occurs after finishing the stream. - if (error) return
Error
- - //modify the content to render LaTeX equations - const processedData = preprocessLaTeX(data || '') - - return ( -
- - {processedData} - -
- ) -} - -// Preprocess LaTeX equations to be rendered by KaTeX -// ref: https://github.com/remarkjs/react-markdown/issues/785 -const preprocessLaTeX = (content: string) => { - const blockProcessedContent = content.replace( - /\\\[([\s\S]*?)\\\]/g, - (_, equation) => `$$${equation}$$` - ) - const inlineProcessedContent = blockProcessedContent.replace( - /\\\(([\s\S]*?)\\\)/g, - (_, equation) => `$${equation}$` - ) - return inlineProcessedContent + return } diff --git a/components/ui/StreamingMarkdown.tsx b/components/ui/StreamingMarkdown.tsx new file mode 100644 index 00000000..5c75964b --- /dev/null +++ b/components/ui/StreamingMarkdown.tsx @@ -0,0 +1,90 @@ +'use client' + +import { StreamableValue, useStreamableValue } from 'ai/rsc' +import { MemoizedReactMarkdown } from './markdown' +import { motion } from 'framer-motion' +import rehypeExternalLinks from 'rehype-external-links' +import remarkGfm from 'remark-gfm' +import remarkMath from 'remark-math' +import rehypeKatex from 'rehype-katex' +import 'katex/dist/katex.min.css' + +export function StreamingMarkdown({ + content +}: { + content: StreamableValue +}) { + const [data] = useStreamableValue(content) + + const processedData = preprocessLaTeX(data || '') + + const words = processedData.split(' ') + + return ( +
+ { + const words = String(children).split(' ') + return ( +

+ {words.map((word, i) => ( + + {word}{' '} + + ))} +

+ ) + }, + li: ({ children }) => { + const words = String(children).split(' ') + return ( +
  • + {words.map((word, i) => ( + + {word}{' '} + + ))} +
  • + ) + } + }} + > + {processedData} +
    +
    + ) +} + +// Preprocess LaTeX equations to be rendered by KaTeX +// ref: https://github.com/remarkjs/react-markdown/issues/785 +const preprocessLaTeX = (content: string) => { + const blockProcessedContent = content.replace( + /\\\[([\s\S]*?)\\\]/g, + (_, equation) => `$$${equation}$$` + ) + const inlineProcessedContent = blockProcessedContent.replace( + /\\\(([\s\S]*?)\\\)/g, + (_, equation) => `$${equation}$` + ) + return inlineProcessedContent +} diff --git a/server.log b/server.log new file mode 100644 index 00000000..e69de29b