Streaming markdown for every platform. One Rust core — incremental parse with speculative closure for mid-stream constructs, stable block identities so unchanged blocks never re-reconcile — compiled to WASM for the web and to native libraries for mobile and desktop. Every boundary emits the same versioned JSON wire, byte-for-byte. 100% CommonMark 0.31 + GFM.
In the browser, wire each LLM stream to a BrookClient
and the markdown renders incrementally off the main thread, block by block — so many concurrent streams render without melting the UI thread.
** Live demo** ·
·
npm i brookmd
js
import { BrookMarkdown } from "brookmd/react";
// `stream` is an AsyncIterable<string> (SSE deltas), a Response, or a ReadableStream
<BrookMarkdown stream={stream} />;
Off the main thread— a pooled Web Worker per stream; the parser re-parses only the active tail on each token, patches cross the worker boundary as verified splices (emitted bytes stay O(n) even for one giant growing block — wire delta mode, contract v1.2.0), and heavy renderers (highlighting, math, mermaid) defer until a block closes.SSR-safe— imports andrenderToString
cleanly on the server across React, Vue, Solid, and Svelte; the worker is created lazily on the client.Structuredblock.data
channel*(opt-in, default off)*— tables, headings, code, math, and lists are exposed astyped, streaming data onblock.kind.data
, so you build toolbars (sort/filter/CSV), tables of contents, charts, and copy buttons from data — no HTML re-parsing, no AST tree to walk.Renderers for every stack— React, Vue 3, Svelte (4 & 5), Solid, a framework-agnostic<brook-markdown>
Web Component, and a vanilla DOM mount on the web; a React Native renderer and Swift/Kotlin/Flutter bindings over the native core (experimental — seePlatforms).Zero runtime dependencies. The whole engine is one WASM binary plus a small TypeScript client.
See the ** package README** for the full API, per-stream config, framework bindings, security model, and scaling helpers (
virtualize
, stickToBottom
).| Path | What |
|---|---|
packages/brookmd |
crates/brookmd-core
crates.io; compiled to WASM for the npm package. Emits the versioned JSONwire contract.crates/brookmd-ffi
crates/brookmd-cabi
packages/brookmd-react-native
(experimental).brookmd-react-native
packages/brookmd-flutter
bindings/kotlin
bindings/swift
web
md.hsingh.app).The same Rust core streams the same versioned JSON wire (WIRE.md) across every boundary; golden tests pin every binding to byte-identical output.
| Platform | Use | Status |
|---|---|---|
| Browser / Node / SSR | ||
brookmd |
Stable— publishedon crates.iobrookmd-core
Stable— publishedon npm — native parser via JSI, RN rendererbrookmd-react-native
— SPM packagebindings/swift
BrookMd
over an XCFramework— Android library + uniffi bindingsbindings/kotlin
over the C ABIpackages/brookmd-flutter
+crates/brookmd-cabi
include/brook_md.h
Swift/Kotlin/C-ABI bindings ship prebuilt from CI as checksummed
release assets (Android .so
per ABI, Apple XCFrameworks with iOS + macOS slices); the React Native package vendors its binaries in the npm tarball.
bun install
bun run build:wasm # compile the Rust core → WASM
cd packages/brookmd && bun test
CI enforces the CommonMark 652/652 + GFM conformance floors, the JS test suite, a fresh-process SSR cold-import check, and that the published tarball ships the WASM.