Quick Start
Create and start one parser for each active Markdown stream:
final parser = MarkdownStreamParser();
await parser.start();
Use replace when you receive a full document snapshot:
final result = await parser.replace('# Hello');
Use append when you receive only the next chunk:
final next = await parser.append('\n\nStreaming **markdown** chunk...');
Render the latest parsed blocks:
AnimatedStreamingMarkdown(
blocks: next.blocks,
tokenStaggerDelay: const Duration(milliseconds: 120),
tokenAnimationDuration: const Duration(milliseconds: 220),
enableSelection: true,
);
Dispose the parser when the stream is finished:
parser.dispose();
Render a Complete Markdown String
For short, already-complete Markdown, use the synchronous factory to parse and paint without starting an isolate-backed stream parser:
AnimatedStreamingMarkdown.fromMarkdown(
markdown: '# Hello\n\nRendered from a complete Markdown string.',
tokenStaggerDelay: Duration.zero,
tokenAnimationDuration: Duration.zero,
);
Use MarkdownStreamParser for long-running streams. Use
AnimatedStreamingMarkdown.fromMarkdown when you already have a full Markdown
snapshot and want the shortest setup path.
Warm Up Parser Resources
Warm parser resources before the first visible render when startup latency is important:
await warmUpStreamingMarkdownParser(includeWorker: true);
Sliver Layouts
Set asSliver when the renderer is placed inside a CustomScrollView:
CustomScrollView(
slivers: [
AnimatedStreamingMarkdown(
blocks: result.blocks,
asSliver: true,
),
],
);
Custom Token Animation
Use tokenAnimationBuilder to customize each token reveal:
AnimatedStreamingMarkdown(
blocks: result.blocks,
tokenStaggerDelay: const Duration(milliseconds: 80),
tokenAnimationDuration: const Duration(milliseconds: 240),
tokenAnimationBuilder: (context, token) {
final t = Curves.easeOutCubic.transform(token.value);
return Transform.translate(
offset: Offset(0, (1 - t) * 8),
child: Opacity(opacity: t, child: token.child),
);
},
);