A model’s output arrives on a network timeline. A reader experiences headings, sentences, lists, tables, and code. Smoothstream connects those two timelines by deciding when the received Markdown is ready to present and pacing its entrance.
You supply the accumulated Markdown and whether input is still open. The library handles the presentation lifecycle:
This process repeats as source arrives. Content already in the schedule keeps its identity and timing.
Input and presentation have different lifetimes
An answer can finish arriving while its last paragraphs are still revealing. A network pause can also leave nothing new to show while the answer is still incomplete.
That is why receiving and mode have separate purposes. receiving={false} closes input and lets the tail finish parsing; mode="streaming" continues its reveal. Static mode is for completed Markdown that should appear immediately when mounted.
There is no separate simulation mode. Passing a complete string to streaming mode gives the same scheduler all of its input at once.
Why input is append-only
Reparsing a longer Markdown snapshot can produce new tree objects for text the reader has already seen. Smoothstream uses source-based identities to recognize that content and preserve its place in the schedule.
Replacing or editing earlier source would invalidate those identities. The append-only contract makes a response’s history dependable: accepted text stays at the same source positions while later text is added. A different answer gets a new instance.
Accumulated snapshots also keep the transport simple. Your application does not need to preserve the original token boundaries, and adapters can coalesce updates within a frame without losing source text.
Why some content waits
The current parse is not always the final interpretation. A line containing pipes might become a table header. An unfinished link might gain a destination. A word might still grow and wrap onto another line.
Smoothstream uses the source already received to look ahead before committing that content. Prose can reveal its safe prefix, code can commit complete lines, and a table can wait for its boundary so its full geometry is available.
The tradeoff is deliberate latency near unresolved syntax. Smoothstream favors presenting confirmed structure over guessing formatting that might need to be undone. Markdown behavior describes the visible consequences by element.
Why the schedule persists
Each new reveal unit receives a place on a persistent timeline. Submitting a known unit again does not restart its entrance. Later snapshots can add eligible content without replaying previous words.
This decouples pacing from packet size, but it cannot reveal text before that text arrives. If the timeline runs out of work during a network pause, new content resumes from the current time. The guarantee is stable scheduling for accepted units, not identical wall-clock playback under every delivery pattern.
interval controls the base cadence and duration controls entrance length. Entrances can overlap; Smoothstream does not wait for each character’s animation to finish before starting the next one.
Why reveal markup is temporary
During character reveal, the browser needs enough geometry to lay out a word before all its characters are visible. Temporary wrappers allow the full word to occupy its place while its characters enter. Other structures, such as tables and images, need their own layout handling.
Once a block is confirmed and its scheduled work has finished, Smoothstream compacts temporary reveal markup back into semantic HTML. This preserves familiar headings, lists, links, tables, and code for styling and navigation, and limits the amount of animation markup retained in a long response. Functional wrappers such as table scroll containers and code controls can remain.
Compaction is also why component overrides must render the supplied children and forward functional properties. Those children can change shape while the semantic element remains the same.
Shared behavior, native framework integration
| Package | Responsibility |
|---|---|
@smoothstream/core | Markdown analysis, stable identities, scheduling, and presentation state. |
@smoothstream/react, @smoothstream/vue, @smoothstream/dom | Runtime rendering, lifecycle, browser resources, and accessibility announcements. |
@smoothstream/styles | Shared functional CSS and the default prose theme. |
@smoothstream/code | Optional Shiki loading and tokenization. |
The core receives time and resource readiness from an adapter; it does not access the browser or import a framework. Web adapters also share a pure HTML presentation model from @smoothstream/core/web, then materialize it as React elements, Vue VNodes, or DOM nodes.
This boundary keeps Markdown behavior consistent while allowing framework-native APIs and lifecycle handling. Vue consumes an explicit markdown prop because it is input data; React accepts a Markdown string as children. React and Vue can produce static HTML during SSR, while the imperative DOM adapter mounts in a browser.
For normal application use, install the adapter. Its core and styles dependencies are included automatically.
Optional features have explicit boundaries
Syntax highlighting is optional because applications that only need Markdown should not need Shiki. The CodeHighlighter contract also allows an application to supply its own tokenizer or asset-loading strategy without replacing the renderer.
The same separation applies to CSS: unstyled removes the default visual theme while retaining the layout and animation rules that make reveal work. It does not replace the rendering pipeline.
Accessibility follows the presentation lifecycle too. Repeated character updates would be noisy inside a live region, so the Markdown remains a normal semantic subtree. A separate status region announces readiness after presentation settles. Reduced motion keeps structural stabilization but presents safe content immediately. See Accessibility.
What this design costs
Structural analysis, scheduling, and layout coordination do more work than immediately rendering a parsed snapshot. Smoothstream reparses accumulated source as it prepares new input; its persistent session does not imply a fully incremental Markdown parser or constant-time updates.
Adapters coalesce incoming updates, reuse presentation work, and compact settled blocks, but response length and content still matter. Profile your own workload when presenting very long answers or many simultaneous streams. The reason to choose this design is control over the reading experience while content is arriving, rather than a claim that every parse is cheaper than alternatives.