Animation: CJK paragraphs only animate their first batch, and queued words pop in when isAnimating turns false
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 35/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- react, typescript
- Ambito
- frontend
Direzione di ricerca
Start with the word-splitting in the animate plugin behind createAnimatePlugin and its sep option, which splits text nodes on /\s/. Run the repro script from the issue with sep: "word" and sep: "char" to see the unanimated span output. The second problem is in how Streamdown drops the animate plugin when isAnimating turns false, so read the per-block plugin list there. Done means CJK paragraphs animate fully and the trailing stagger completes before the spans are removed; the issue's open design questions need a maintainer decision first.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Two problems with animated streaming in [email protected], both visible in Chinese/Japanese chat replies.
1. sep: "word" treats a whole CJK paragraph as one word, so most of it never animates
sep: "word" splits text nodes at whitespace (/\s/). CJK text has no spaces between words, so a paragraph is a single "word". A word that started before prevContentLength is treated as already rendered (duration 0ms), so every character appended to it after the first commit appears with no animation.
Repro with the exported createAnimatePlugin, simulating four streaming commits of one paragraph:
import { createAnimatePlugin } from "streamdown";
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkRehype from "remark-rehype";
const full = "量子電腦利用疊加與糾纏來平行處理資訊,因此在特定問題上遠快於傳統電腦。不過目前的硬體仍然很容易受到雜訊干擾。";
for (const sep of ["word", "char"]) {
const plugin = createAnimatePlugin({ sep });
let prev = 0;
for (const n of [12, 25, 40, full.length]) {
plugin.setPrevContentLength(prev);
const md = full.slice(0, n);
const tree = await unified().use(remarkParse).use(remarkRehype).use(plugin.rehypePlugin)
.run(unified().use(remarkParse).parse(md));
const spans = tree.children[0].children.filter((c) => c.tagName === "span");
const animated = spans.filter((s) => !s.properties.style.includes("--sd-duration:0ms"));
console.log(sep, n, animated.map((s) => s.children[0].value).join("|"));
prev = n;
}
}
word 12 量子電腦利用疊加與糾纏來
word 25 <- nothing animates
word 40
word 54
char 12 量|子|電|腦|利|用|疊|加|與|糾|纏|來
char 25 平|行|處|理|資|訊|,|因|此|在|特|定|問
...
So with the default sep, a CJK reply fades in its first few characters and then pops in for the rest of each paragraph. sep: "char" works, but turns Latin text into a per-letter typewriter, so mixed-language replies have no good setting.
Suggestion: split words with Intl.Segmenter(undefined, { granularity: "word" }) (falling back to whitespace where unavailable). It segments CJK into words and leaves Latin text as today. The @streamdown/cjk plugin doesn't touch the animate plugin, so it doesn't help here.
2. Characters still waiting for their stagger appear all at once when isAnimating turns false
With stagger (default 40ms) the shared timeline schedules new words up to maxBacklogMs (default 320ms) ahead of wall-clock. When the stream ends and isAnimating becomes false, Streamdown stops adding the animate plugin to each block's rehype plugins immediately, so every block re-renders without the data-sd-animate spans. Words still waiting on --sd-delay, plus those mid-fade, become fully visible in that frame. The end of every reply visibly "pops", more so with sep: "char" or a fast model, where the backlog is longest.
Expected: after isAnimating goes false, keep the animate plugin until the timeline's last scheduled delay plus duration has elapsed, then drop the spans. We currently work around it by holding isAnimating true for maxBacklogMs + duration after the stream ends.
Also
stagger and maxBacklogMs are real AnimateOptions (in the types and source) but aren't on https://streamdown.ai/docs/animation. We had set stagger: 0 without knowing it disables the per-batch spread, which made streaming look chunky.
Environment: streamdown 2.7.0, React 19.3. Issue 1 reproduced with the script above; issue 2 is from reading dist/chunk-*.js (the per-block plugin list only includes the animate plugin while isAnimating).
- Lingua principale
- TypeScript
- Stelle
- 5.7k
- Fork
- 307
- Merge medio
- 1g 22h
- PR unite (30g)
- 22
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di vercel/streamdown
-
`mode="static"` parses the whole document twice on mount (since the caret host in 2.7)Forse già presa @akhil9tiet l’ha presa 1 giorno fa. Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
vercel/streamdown#673 · 3 commenti · 2 reazioni ·
I maintainer di solito rispondono entro 1 giorno
-
remend: unclosed `$$` in a table cell is closed on a new line when an earlier line has mathForse già presa @orinnz l’ha presa 13 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
vercel/streamdown#652 ·
I maintainer di solito rispondono entro 1 giorno
-
`data-*` and `aria-*` props passed to `<Streamdown>` are never set on its root elementForse già presa @xyrolle l’ha presa 1 giorno fa. Aperta
Difficoltà 3/5 Mezza giornata Idoneità per principianti 55/100
vercel/streamdown#675 ·
I maintainer di solito rispondono entro 1 giorno
-
CJK autolink boundary handling keeps `**` in the URL when a bold URL is followed by CJK punctuationForse già presa @mikemikimike l’ha presa 1 giorno fa. Apertabug
Difficoltà 3/5 Mezza giornata Idoneità per principianti 50/100
vercel/streamdown#672 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Mermaid shows an error for a partial chart while its fence is still streamingForse già presa @slavco86 l’ha presa 3 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 25/100
vercel/streamdown#667 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di vercel/streamdown
Issue simili
-
bnv-manager-v2: accept_invite creates the Mailcow domain admin before the commitForse già presa @myOmikron l’ha presa oggi. Apertabug ready-for-agent
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
-
Windows: mio 1.2.3 named-pipe use-after-free panics the native IPC broker and hangs every toolApertaplatform:windows tool triaged wontfix
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
nicolettas-muggelbude/RechnungsFee#448 ·
I maintainer di solito rispondono entro 1 giorno
-
Android bug feature/error-tracking react-native team/error-tracking
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
PostHog/posthog-js#5310 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno