Streaming Benchmarks
This page holds the technical details behind the plain-language claims on the Svelte Streamdown comparison and the LLM Streaming guide. If you only want the summary: on most content Svelte Markdown does less work per frame, on a single open code block, on citation-heavy text, and on HTML blocks Svelte Streamdown does less, and every number below can be reproduced from the repository.
What is measured
Main-thread work per animation frame, in milliseconds. For each frame the harness adds up:
- The time spent synchronously when the content changes.
- The time spent in deferred work before the next frame renders.
- A forced style and layout pass, so the cost of the DOM a renderer produced is charged to that renderer.
A frame that takes longer than 16.7 ms cannot be shown at 60 frames per second; those are counted as frames over budget.
Wall-clock time is deliberately not the metric. A renderer that defers work to the next frame looks instant if you only time the content assignment, and any per-frame measurement collapses to the display’s frame period if you time the whole frame.
How it is measured
| Setting | Value |
|---|---|
| Browser | Headless production Chromium via Playwright |
| Input | The growing content string, 32 characters added per frame (about 480 tokens per second) |
| Documents | About 24 KB per scenario, plus closed prefixes of 24, 96, and 384 KB |
| Runs | One warmup, then five iterations; both renderers run back to back in alternating order; two full suites |
| Competitor | svelte-streamdown 4.2.0 with animation, controls, and highlighting off |
| Date and machine | 2026-09-28 (the numbered list and HTML block rows: 2026-09-29), Intel Core i7-6700K, Ubuntu 26.04 |
Two safeguards keep the numbers honest:
- Parity check. Every 25 frames and at the end, the streamed token tree is compared field by field with a fresh one-shot parse of the same text. All 210 runs reported zero mismatches.
- No double counting. When a frame overruns, the next frame’s window starts where the previous one ended.
Results
Median of five iterations. Ranges span the two suites. The ratio is their total work divided by ours, so a value above 1 means Svelte Markdown did less work.
| Scenario | Ours (ms) | Streamdown (ms) | Ratio | Ours over budget | Theirs over budget |
|---|---|---|---|---|---|
| Mixed prose, 1 update per frame | 1,797–1,932 | 2,266–2,333 | 1.21–1.26 | 0 of 765 | 0 |
| Mixed prose, 4 updates per frame | 537–559 | 1,103–1,206 | 2.05–2.16 | 0 of 192 | 0–1 |
| One open bullet list (~200 items) | 3,501–3,625 | 9,111–9,377 | 2.51–2.68 | 1 of 754 | 224–236 |
| One open table (~150 rows) | 1,569–1,620 | 3,577–3,745 | 2.28–2.31 | 1–2 of 314 | 81–95 |
| One open code fence | 1,542–1,570 | 1,162–1,178 | 0.75 | 0 of 753 | 0 |
| Citation-heavy prose | 1,456–1,703 | 1,405–1,445 | 0.85–0.97 | 0 of 753 | 0 |
| Numbered list with blank lines between items | 4,334–4,425 | 10,770–10,896 | 2.43–2.51 | 1–4 of 753 | 293–306 |
| HTML blocks with markdown inside | 3,686–4,007 | 2,352–2,401 | 0.60–0.64 | 6–9 of 751 | 0 |
| 24 KB closed prefix + 2 KB tail | 113–120 | 156–162 | 1.35–1.37 | 0 of 67 | 0 |
| 96 KB closed prefix + 2 KB tail | 231–232 | 417–425 | 1.81–1.83 | 0 of 67 | 0 |
| 384 KB closed prefix + 2 KB tail | 906–909 | 2,436–2,454 | 2.69–2.70 | 14 of 67 | 67 of 67 |
| 20 KB closed nested list + 2 KB tail | 84–85 | 186–187 | 2.18–2.22 | 0 of 67 | 1 |
Page weight
Element counts at the end of each stream, identical across all runs:
| Content | Ours | Streamdown |
|---|---|---|
| Mixed prose | 1,381 | 1,704 |
| Plain bullet list | 768 | 769 |
| Code fence | 4 | 797 |
| Citation-heavy prose | 776 | 519 |
Caveats
- Citations are not a like-for-like comparison. Svelte Streamdown rendered none of the reference-style links in that document; Svelte Markdown rendered 258. Resolving them is part of our cost.
- HTML blocks are not a like-for-like comparison. By default Svelte Streamdown shows raw HTML as plain text, and the benchmark keeps that default. It builds none of the
<div>and<details>elements that Svelte Markdown renders. - Some documents are parsed in full on every update. This trades speed for correct output. It applies to documents with Windows line endings (
\r\n), and to documents that currently end inside an unfinished HTML tag, comment, or element. The HTML blocks row above includes this cost. - Code fences differ in structure. Svelte Streamdown wraps every line in its own element. Svelte Markdown emits one text node per line with no wrapper elements.
- Large documents include a full layout every frame. The harness forces a layout of the whole document each frame, which both renderers pay. At 384 KB that pass is most of the frame. Svelte Markdown’s own parsing and rendering work stays nearly flat: about 1.4 ms per frame at 24 KB and 1.9 ms at 384 KB.
- Milliseconds are machine-specific. The ratios are the claim. Absolute totals moved by tens of percent between captures on the same machine.
- One workload family. Cumulative string updates at a fixed rate. Your transport, content, and device will differ.
Where the time goes
One traced run per scenario, Svelte Markdown only, in milliseconds per frame:
| Scenario | Total | Parse and diff | Other JavaScript | Style and layout |
|---|---|---|---|---|
| Mixed prose | 2.70 | 0.19 | 1.32 | 0.62 |
| One open bullet list | 5.35 | 2.52 | 2.05 | — |
| One open code fence | 2.01 | — | 0.73 | 0.73 |
| Citation-heavy prose | 2.49 | 0.28 | 1.20 | — |
An open list is re-lexed in full on every frame by design, which is why parsing dominates there.
Reproduce it
pnpm build
pnpm preview --host 127.0.0.1 --port 4173 --strictPort
# in another shell
STREAM_COMPARE_URL=http://127.0.0.1:4173/test/stream-compare pnpm perf:stream-comparepnpm build
pnpm preview --host 127.0.0.1 --port 4173 --strictPort
# in another shell
STREAM_COMPARE_URL=http://127.0.0.1:4173/test/stream-compare pnpm perf:stream-compareUseful options:
| Variable | Purpose |
|---|---|
STREAM_COMPARE_SCENARIO | Run a single scenario |
STREAM_COMPARE_ITERATIONS / STREAM_COMPARE_WARMUPS | Change the run counts |
STREAM_COMPARE_URL_A / STREAM_COMPARE_URL_B | Compare two builds of Svelte Markdown against each other |
node scripts/stream-compare-attribute.mjs records a browser trace and CPU profile for one scenario and prints the per-frame breakdown.
The raw logs, JSON, and per-change A/B results are archived in the repository under .agents/.plans-closed/stream-vs-streamdown/evidence/.