Skip to main content

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),
);
},
);