name: markstream-vue
description: Integrate markstream-vue into a Vue 3 app. Use when Codex needs to add the Vue 3 renderer, import CSS in the right order, choose mode="chat", mode="docs", or mode="minimal", choose between content and nodes, coordinate long AI timelines with MarkstreamVirtualTimeline, useMarkstreamVirtualAdapter, or vue-virtual-scroller, enable optional peers like Mermaid, KaTeX, D2, Monaco, or stream-markdown, or wire scoped custom components in a non-Nuxt Vue repository.
Markstream Vue 3
Use this skill when the host app is plain Vue 3, typically Vite-based, and not Nuxt.
Workflow
- Confirm the repo is Vue 3 and not Nuxt.
- Install
markstream-vueplus only the optional peers required by the requested features. - Import
markstream-vue/index.cssafter resets.- In Tailwind or UnoCSS projects, use
@import 'markstream-vue/index.css' layer(components);. - The root JS import does not inject styles; use
markstream-vue/index.cssormarkstream-vue/index.px.cssexplicitly.
- In Tailwind or UnoCSS projects, use
- Start with
contentand choose the renderer mode by surface.- Use
mode="chat"for AI chat or SSE output. It uses lightweight batches,<pre>code rendering by default,fade=false, andmax-live-nodes=0;smooth-streaming="auto"paces visible output. - Use
mode="docs"for rich document surfaces. It is the default, enables larger batches, tooltips, fade, and Monaco-backed code blocks when the peer is installed. - Use
mode="minimal"when the surface is lightweight but not chat. - If a docs page does not need Monaco-backed code blocks, set
:render-code-blocks-as-pre="true". typewriteronly controls the blinking cursor and defaults tofalse.- Set
:smooth-streaming="false"to preserve raw chunk cadence; set:smooth-streaming="true"to force smooth pacing even on first-screen content (may cause hydration mismatch in SSR). - When overriding mode defaults on a high-frequency stream, pair smooth streaming with
:fade="false"to avoid delta fade (280 ms) stacking with high-commit pacing. - Streaming vs recovering history: in chat UIs the same
MarkdownRenderstarts streaming and later switches to history whenfinal=true.- Streaming:
mode="chat",smooth-streaming="auto",:fade="false",typewriter=true. - Recovering/completed chat history: keep
mode="chat"on the same chat row to avoid switching code renderer or layout strategy whenfinal=true; use:smooth-streaming="false",typewriter=false, and only set:fade="true"when the host explicitly wants a history-entry animation. - Use
mode="minimal"for lightweight non-chat recovered content, and usemode="docs"only for rich document surfaces, not for finalizing an existing chat message.
- Streaming:
- Switch to
nodesplusfinalonly when the app needs custom AST control, worker preparsing, or structural updates beyond pacing. - Remember that
html-policynow defaults tosafe, and Mermaid strict mode is on by default throughmermaid-props.
- Use
- For long AI transcripts or existing message virtualizers, choose the virtual-scroll path.
- Prefer
MarkstreamVirtualTimelinewhen the app does not already own timeline virtualization. - If the app already uses
vue-virtual-scrollerDynamicScroller, useuseMarkstreamVirtualAdapter()and bindadapter.markdownProps(item, index)to Markdown items. - Put
adapter.measureItem(item, index, el)on the outer timeline row so row chrome is included in item height. - Use Markstream's reported logical height (
metrics.totalHeightthrough the adapter/virtualizer), not the renderer element's currentoffsetHeight, because Markdown node virtualization may only mount the live window. - On thread switches, save
adapter.captureThreadState()together with the scroller cache; restore the scroller cache before restoring the Markstream anchor.
- Prefer
- Use
custom-idplus scopedsetCustomComponents(...)for local overrides, or import{ VueRendererMarkdown }frommarkstream-vueand install it when the repo already has an app-level plugin entry. - Validate with the smallest useful dev, build, or typecheck command.
Default Decisions
- Vue 3 apps default to
content; choosemodebefore fine-tuning lower-level render props. - Omit
modeonly when the surface should use rich docs defaults. - Smooth streaming (
smooth-streaming="auto") is on by default whentypewriterormax-live-nodes <= 0. It only paces thecontentpath;nodesmode is never affected. - For manual pacing with
nodes, useuseSmoothMarkdownStreamdirectly:enqueue()chunks,finish()when done, render fromvisible, and wait forcaughtUpbefore final parsing. - Streaming vs recovering history: keep the same renderer mode for a given chat row; when
final=true, disable smooth streaming/typewriter and optionally enable fade. Switch tomode="docs"only when moving content into a separate rich document surface. Seedocs/guide/ai-chat-streaming.mdfor full examples. - Prefer local component registration unless the repo already uses a shared plugin entry.
- If a Vue 3 app already virtualizes messages, keep that outer virtualizer in charge and enable
virtual-scrollonly on large Markdown messages. - For
vue-virtual-scroller, keepsessionKeytied to content identity (thread:item:revision) andmeasurementKeytied to layout identity such as width, theme, font, and density. - When Monaco code blocks need app-level preloading, import
preloadCodeBlockRuntimefrommarkstream-vue. ExistinggetUseMonaco()preloads remain valid; do not importstream-monacodirectly just to warm workers. - Keep
html-policy="safe"and Mermaid strict mode unless the task is explicitly preserving trusted legacy behavior. - If a trusted surface needs pre-hardening behavior, opt out locally with
html-policy="trusted"and:mermaid-props="{ isStrict: false }", and call out the trust boundary in the final handoff. - If the host is actually Nuxt, leave SSR-specific setup to
markstream-nuxt.
Useful Doc Targets
docs/guide/quick-start.mddocs/guide/installation.mddocs/guide/usage.mddocs/guide/ai-chat-streaming.mddocs/guide/performance.mddocs/guide/component-overrides.md