From 45e4d4fcba3393348bdaaebd82b6306c06ff0fd9 Mon Sep 17 00:00:00 2001 From: Baptiste Leproux Date: Mon, 20 Apr 2026 17:35:07 +0200 Subject: [PATCH 1/9] docs(kb): why comark --- docs/content/7.kb/0.why-comark.md | 163 ++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 docs/content/7.kb/0.why-comark.md diff --git a/docs/content/7.kb/0.why-comark.md b/docs/content/7.kb/0.why-comark.md new file mode 100644 index 0000000..8a7fc79 --- /dev/null +++ b/docs/content/7.kb/0.why-comark.md @@ -0,0 +1,163 @@ +--- +title: Why Comark is the Future of UI Authoring +description: Markdown has become the shared language between humans and AI. Comark extends it all the way to interactive UI. +navigation: + title: Why Markdown? +seo: + title: Why Markdown is the Future of UI Authoring + description: Markdown is human-readable, token-efficient, and AI-parseable. Discover why it has become the lingua franca for building UI and how Comark extends it to interactive components. +links: + - label: Comark Syntax + icon: i-lucide-file-text + to: /syntax/components + color: neutral + variant: soft + - label: Streaming API + icon: i-lucide-radio + to: /api/auto-close + color: neutral + variant: soft +--- + +This page answers two questions. + +First, why Markdown has become the default format for both human authoring and machine consumption and why that convergence is not accidental. + +Second, why Comark extends it: what standard Markdown is lacking when you need components and how Comark adds that without sacrificing readability, portability, or parser compatibility. + +## Why Markdown? + +### The Dual Audience Problem + +Every piece of content on the web is consumed by at least two types of reader: + +- **Humans** who need scannable structure, comfortable prose, and visual hierarchy +- **Machines** who need predictable tokens, explicit structure, and minimum noise + +HTML was designed for the first audience. JSON was designed for the second. Neither was designed for both. + +**Markdown** was designed for humans but it turns out machines love it too. + +### Why Machines Prefer Markdown + +The evidence is clearest in token economics. + +The same page served as HTML versus Markdown to an AI agent can use **80% fewer tokens** in Markdown form. At scale, that is not a formatting preference, it is an infrastructure decision. Lower token counts mean faster responses, lower costs, and longer effective context windows. + +Beyond token count, Markdown's explicit structure maps cleanly to how language models reason. A `##` heading is unambiguously a section boundary. HTML carries the same information buried in `

` but the signal-to-noise ratio is far worse. + +### AI as a First-Class Audience + +The tooling industry has converged on this conclusion. [Streamdown](https://github.com/vercel/streamdown) (an open-source renderer by Hayden Bleasel, DX Engineer at Vercel) was built precisely because LLMs stream token by token and existing renderers like `react-markdown` assume a complete document, making them unable to handle unterminated blocks gracefully. Because LLMs tend to produce Markdown by default, Streamdown integrates directly with the [Vercel AI SDK](https://sdk.vercel.ai)'s `useChat` and streaming patterns to render it correctly as it arrives. Together they reflect a deliberate recognition that AI agents are now a _primary_ consumer of content, not a secondary one. + +The same shift is visible in developer tooling. Files like `AGENTS.md` and `.cursorrules` are Markdown documents that configure AI coding assistants. GitHub Copilot reads them across sessions. Cursor injects them into every prompt. Claude Code uses `CLAUDE.md`. The format that humans write is the same format that machines act on. + +This is new. For most of computing history, human-authored content and machine-readable configuration were different artifacts in different formats. Markdown is collapsing that boundary. + +## Why Comark? + +Markdown solves the dual-audience problem. But standard Markdown stops at document structure (headings, lists, code blocks, emphasis...). It has no way to express a warning callout, a tabbed code group, a video embed, or a pricing card. + +### The Next Iteration of MDC + +Comark is the next iteration of [mdc](https://github.com/nuxt-content/mdc), the MDC parser that has powered [Nuxt Content](https://content.nuxt.com)'s component syntax for over five years. MDC proved the concept syntax for embedding components inside Markdown. + +Comark takes that foundation and extends it in four directions: + +- **Streaming and auto-closing:** the [auto-close](/api/auto-close) parser completes unterminated blocks on the fly, so AI-generated or live-streamed Markdown renders correctly at every frame without buffering +- **Compact AST for SSR:** instead of a verbose object tree, Comark produces compact tuples `['tag', props, ...children]` that reduce payload size when serialized and sent over the wire +- **Multiple rendering targets:** the same source renders to Vue, React, Svelte, Nuxt, plain HTML and ANSI terminal output without changing the content + +### The Gap Between Document and UI + +The current workarounds for going beyond standard Markdown are: + +- **Raw HTML** — works, but immediately breaks the plain-text properties that make Markdown human-readable and reintroduces the token overhead it removes for AI. +- **MDX** — extends Markdown with JSX, but it is a *compiler*: `.mdx` files are transformed to JSX at build time. Shipping new content means triggering a rebuild and a redeploy. + +Comark's position is that component syntax should stay in plain text, parse at runtime, and work across any renderer. That is the design constraint every other decision follows from. + +### The Improved Syntax + +#### Block Components + +Comark's component syntax is a superset of standard Markdown, inspired by the [Markdown directives proposal](https://talk.commonmark.org/t/generic-directives-plugins-syntax/444), a CommonMark effort to standardize a generic extension point without breaking parsers or leaving plain text. + +```mdc +::alert{type="warning"} +This action cannot be undone. +:: +``` + +This is still plain text. No bundler, no compiler step. A human can read it and understand it. An AI agent can parse it as structured data: a component named `alert` with a `type` attribute and text content. + +That shift makes Markdown data, not code. Because `parse(markdown)` is a pure function returning a [Comark AST](/syntax/comark-ast), the full CMS pattern becomes possible: + +1. A database, CMS, or headless service stores the raw Markdown (including `::` components) +2. On request, the server runs `parse()` and gets the compact AST +3. The AST is sent to the client +4. `` renders it by looking up each tag name in a components map at runtime + +#### Slots + +Raw HTML does break down at one point: **slots** (named regions inside a component). In HTML syntax, nesting code fences or inner Markdown blocks inside a tag is awkward at best. In Comark, slots are first-class: inner `::` blocks are full Markdown throughout: + +````mdc +::tabs + ::tab-item{label="Vue"} + ```bash + pnpm add @comark/vue + ``` + :: + ::tab-item{label="React"} + ```bash + pnpm add @comark/react + ``` + :: +:: +```` + +### One Source, Every Renderer + +MDX is tied to React. @nuxtjs/mdc was tied to Nuxt. Most Markdown renderers are tied to a single output target. Comark decouples the parse step from the render step entirely. + +The same `.md` source file renders to: + +- [`` in Vue](/rendering/vue) — async components, streaming, slot-based composition +- [`` in React](/rendering/react) — Server Components and client-side rendering +- [`` in Nuxt](/rendering/nuxt) — zero-config module with auto-imports and Nuxt UI integration +- [`` in Svelte 5](/rendering/svelte) — snippets and streaming +- [`renderHTML()` in @comark/html](/rendering/html) — server-side HTML strings, RSS, emails, static builds +- [`renderANSI()` in @comark/ansi](/rendering/ansi) — styled terminal output for CLIs + +The content layer outlasts any particular rendering technology. Write your content once, choose your renderer at the call site. + +### An AST Built for Machines + +Most Markdown parsers produce verbose object trees: + +```typescript +{ type: 'element', tag: 'p', props: {}, children: [{ type: 'text', value: 'Hello' }] } +``` + +The [Comark AST](/syntax/comark-ast) uses compact tuples instead: + +```typescript +['p', {}, 'Hello'] +``` + +The same information, a fraction of the allocations. This matters for static site generators, build pipelines, and AI content endpoints, where the parser stops being the bottleneck. The same philosophy that makes Markdown token-efficient for LLMs makes Comark's AST memory-efficient for the JavaScript runtime. + +Because Comark can parse on the server and send only the compact AST over the wire, the client receives what it needs to render. For Markdown-driven websites serving many readers, this is a meaningful payload and CPU reduction at every request. + +### Streaming by Design + +AI models generate content token by token. A renderer built on the assumption of a complete document breaks immediately when the input is a live stream. + +Comark is built for this case. The [auto-close](/api/auto-close) parser handles incomplete syntax by automatically completing it so the UI renders correctly at every frame. The `streaming` prop on `` and `` pipes AI-generated Markdown directly into your component tree as it arrives, with no intermediate buffering. + +This is the same problem addressed by [Streamdown](https://github.com/vercel/streamdown). Comark takes the same premise further: not just streaming plain Markdown, but streaming Markdown with component syntax, so AI output can include interactive UI elements rendered in real time. + +--- + +Markdown has become the connective tissue between human authorship and machine intelligence. Comark extends that connective tissue all the way to interactive UI by using component syntax that stays readable, one source that renders anywhere, an AST built for machines, and streaming that works out of the box. From d3217e7ac804a9c0a280a2d7f1a0ab998c9f7196 Mon Sep 17 00:00:00 2001 From: Baptiste Leproux Date: Tue, 21 Apr 2026 10:01:36 +0200 Subject: [PATCH 2/9] typo --- docs/content/7.kb/0.why-comark.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/7.kb/0.why-comark.md b/docs/content/7.kb/0.why-comark.md index 8a7fc79..d1cfd6d 100644 --- a/docs/content/7.kb/0.why-comark.md +++ b/docs/content/7.kb/0.why-comark.md @@ -62,7 +62,7 @@ Markdown solves the dual-audience problem. But standard Markdown stops at docume Comark is the next iteration of [mdc](https://github.com/nuxt-content/mdc), the MDC parser that has powered [Nuxt Content](https://content.nuxt.com)'s component syntax for over five years. MDC proved the concept syntax for embedding components inside Markdown. -Comark takes that foundation and extends it in four directions: +Comark takes that foundation and extends it in three directions: - **Streaming and auto-closing:** the [auto-close](/api/auto-close) parser completes unterminated blocks on the fly, so AI-generated or live-streamed Markdown renders correctly at every frame without buffering - **Compact AST for SSR:** instead of a verbose object tree, Comark produces compact tuples `['tag', props, ...children]` that reduce payload size when serialized and sent over the wire From 2e4ef279c382cf5d08e8034d68687d86342af8d4 Mon Sep 17 00:00:00 2001 From: Baptiste Leproux Date: Tue, 21 Apr 2026 12:13:59 +0200 Subject: [PATCH 3/9] up --- docs/content/7.kb/0.why-comark.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/7.kb/0.why-comark.md b/docs/content/7.kb/0.why-comark.md index d1cfd6d..c84a11c 100644 --- a/docs/content/7.kb/0.why-comark.md +++ b/docs/content/7.kb/0.why-comark.md @@ -48,7 +48,7 @@ Beyond token count, Markdown's explicit structure maps cleanly to how language m ### AI as a First-Class Audience -The tooling industry has converged on this conclusion. [Streamdown](https://github.com/vercel/streamdown) (an open-source renderer by Hayden Bleasel, DX Engineer at Vercel) was built precisely because LLMs stream token by token and existing renderers like `react-markdown` assume a complete document, making them unable to handle unterminated blocks gracefully. Because LLMs tend to produce Markdown by default, Streamdown integrates directly with the [Vercel AI SDK](https://sdk.vercel.ai)'s `useChat` and streaming patterns to render it correctly as it arrives. Together they reflect a deliberate recognition that AI agents are now a _primary_ consumer of content, not a secondary one. +The tooling industry has converged on this conclusion. [Streamdown](https://github.com/vercel/streamdown) (an open-source renderer by Hayden Bleasel, DX Engineer at Vercel) was built precisely because LLMs stream token by token and existing renderers like `react-markdown` assume a complete document, making them unable to handle unterminated blocks gracefully. Because LLMs tend to produce Markdown by default, Streamdown is a React component designed to render it correctly as chunks arrive — pairing naturally with `useChat` and other streaming patterns from `@ai-sdk/react`. Together they reflect a deliberate recognition that AI agents are now a _primary_ consumer of content, not a secondary one. The same shift is visible in developer tooling. Files like `AGENTS.md` and `.cursorrules` are Markdown documents that configure AI coding assistants. GitHub Copilot reads them across sessions. Cursor injects them into every prompt. Claude Code uses `CLAUDE.md`. The format that humans write is the same format that machines act on. @@ -156,7 +156,7 @@ AI models generate content token by token. A renderer built on the assumption of Comark is built for this case. The [auto-close](/api/auto-close) parser handles incomplete syntax by automatically completing it so the UI renders correctly at every frame. The `streaming` prop on `` and `` pipes AI-generated Markdown directly into your component tree as it arrives, with no intermediate buffering. -This is the same problem addressed by [Streamdown](https://github.com/vercel/streamdown). Comark takes the same premise further: not just streaming plain Markdown, but streaming Markdown with component syntax, so AI output can include interactive UI elements rendered in real time. +Comark takes the same premise as [Streamdown](https://github.com/vercel/streamdown) further: not just streaming plain Markdown, but streaming Markdown with component syntax so AI output can include interactive UI elements rendered in real time. --- From 6be6c046749d0189cae64009286817e9d180ca8d Mon Sep 17 00:00:00 2001 From: Baptiste Leproux Date: Tue, 21 Apr 2026 12:19:29 +0200 Subject: [PATCH 4/9] Update docs/content/7.kb/0.why-comark.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Chopin --- docs/content/7.kb/0.why-comark.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/7.kb/0.why-comark.md b/docs/content/7.kb/0.why-comark.md index c84a11c..21a9d73 100644 --- a/docs/content/7.kb/0.why-comark.md +++ b/docs/content/7.kb/0.why-comark.md @@ -4,7 +4,7 @@ description: Markdown has become the shared language between humans and AI. Coma navigation: title: Why Markdown? seo: - title: Why Markdown is the Future of UI Authoring + title: Why Comark is the Future of UI Authoring description: Markdown is human-readable, token-efficient, and AI-parseable. Discover why it has become the lingua franca for building UI and how Comark extends it to interactive components. links: - label: Comark Syntax From 22e6f8ba0751ae4bbd3a4a694c1f72fe8b40082e Mon Sep 17 00:00:00 2001 From: Baptiste Leproux Date: Tue, 21 Apr 2026 12:19:52 +0200 Subject: [PATCH 5/9] Update docs/content/7.kb/0.why-comark.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Chopin --- docs/content/7.kb/0.why-comark.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/7.kb/0.why-comark.md b/docs/content/7.kb/0.why-comark.md index 21a9d73..656edf6 100644 --- a/docs/content/7.kb/0.why-comark.md +++ b/docs/content/7.kb/0.why-comark.md @@ -2,7 +2,7 @@ title: Why Comark is the Future of UI Authoring description: Markdown has become the shared language between humans and AI. Comark extends it all the way to interactive UI. navigation: - title: Why Markdown? + title: Why Comark? seo: title: Why Comark is the Future of UI Authoring description: Markdown is human-readable, token-efficient, and AI-parseable. Discover why it has become the lingua franca for building UI and how Comark extends it to interactive components. From d71e83fc60990d24b2c6fe1fff4ef2ea31b49356 Mon Sep 17 00:00:00 2001 From: Baptiste Leproux Date: Tue, 21 Apr 2026 12:20:20 +0200 Subject: [PATCH 6/9] Update docs/content/7.kb/0.why-comark.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Chopin --- docs/content/7.kb/0.why-comark.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/7.kb/0.why-comark.md b/docs/content/7.kb/0.why-comark.md index 656edf6..fbc6d4a 100644 --- a/docs/content/7.kb/0.why-comark.md +++ b/docs/content/7.kb/0.why-comark.md @@ -126,7 +126,7 @@ The same `.md` source file renders to: - [`` in Vue](/rendering/vue) — async components, streaming, slot-based composition - [`` in React](/rendering/react) — Server Components and client-side rendering - [`` in Nuxt](/rendering/nuxt) — zero-config module with auto-imports and Nuxt UI integration -- [`` in Svelte 5](/rendering/svelte) — snippets and streaming +- [`` in Svelte](/rendering/svelte) — snippets and streaming - [`renderHTML()` in @comark/html](/rendering/html) — server-side HTML strings, RSS, emails, static builds - [`renderANSI()` in @comark/ansi](/rendering/ansi) — styled terminal output for CLIs From 3fcfd3418d9f5b036006511e74635d1eccbb9f59 Mon Sep 17 00:00:00 2001 From: Baptiste Leproux Date: Tue, 21 Apr 2026 12:27:02 +0200 Subject: [PATCH 7/9] atinux review --- .../1.getting-started/0.introduction.md | 6 +++- docs/content/7.kb/0.why-comark.md | 29 +++++++++---------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/docs/content/1.getting-started/0.introduction.md b/docs/content/1.getting-started/0.introduction.md index 0057a7d..f24d53b 100644 --- a/docs/content/1.getting-started/0.introduction.md +++ b/docs/content/1.getting-started/0.introduction.md @@ -29,7 +29,11 @@ This is an important message! :: ``` -The `::alert` is a block component that supports properties and children (also known as slots). Learn more about the [Component Syntax](/syntax/components). +The `::alert` is a block component that supports properties and children (also known as slots). + +::tip{to="/kb/why-comark"} +Want to know more about the Comark design and why we've created it? [Why Comark](/kb/why-comark) explains the reasoning behind this design choice. +:: Comark parses this into an [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) that can be rendered to [HTML](/rendering/html). It also supports rendering to [Vue](/rendering/vue), [Nuxt](/rendering/nuxt), [React](/rendering/react), and [Svelte](/rendering/svelte), turning your Markdown into fully interactive content. diff --git a/docs/content/7.kb/0.why-comark.md b/docs/content/7.kb/0.why-comark.md index fbc6d4a..26a14a1 100644 --- a/docs/content/7.kb/0.why-comark.md +++ b/docs/content/7.kb/0.why-comark.md @@ -100,22 +100,21 @@ That shift makes Markdown data, not code. Because `parse(markdown)` is a pure fu #### Slots -Raw HTML does break down at one point: **slots** (named regions inside a component). In HTML syntax, nesting code fences or inner Markdown blocks inside a tag is awkward at best. In Comark, slots are first-class: inner `::` blocks are full Markdown throughout: - -````mdc -::tabs - ::tab-item{label="Vue"} - ```bash - pnpm add @comark/vue - ``` - :: - ::tab-item{label="React"} - ```bash - pnpm add @comark/react - ``` - :: +Raw HTML does break down at one point: **slots** (named regions inside a component). In HTML syntax, placing rich Markdown content into specific named regions of a tag is awkward at best. In Comark, slots are first-class: `#slotname` markers let you place full Markdown into any named region of a component: + +```mdc +::hero +#title +Build UIs from **Markdown** + +#description +Comark parses component syntax at runtime — no compiler, no rebuild. +Supports Vue, React, Nuxt, and Svelte out of the box. + +#cta +[Get started](/getting-started) :: -```` +``` ### One Source, Every Renderer From ff25b627f9171fc9b978eb99228ba7798d663f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Tue, 21 Apr 2026 20:40:23 +0200 Subject: [PATCH 8/9] Apply suggestion from @atinux --- docs/content/1.getting-started/0.introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/1.getting-started/0.introduction.md b/docs/content/1.getting-started/0.introduction.md index f24d53b..7370f21 100644 --- a/docs/content/1.getting-started/0.introduction.md +++ b/docs/content/1.getting-started/0.introduction.md @@ -32,7 +32,7 @@ This is an important message! The `::alert` is a block component that supports properties and children (also known as slots). ::tip{to="/kb/why-comark"} -Want to know more about the Comark design and why we've created it? [Why Comark](/kb/why-comark) explains the reasoning behind this design choice. +Learn why we created Comark and the principles behind its design in [Why Comark](https://github.com/kb/why-comark). :: Comark parses this into an [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) that can be rendered to [HTML](/rendering/html). It also supports rendering to [Vue](/rendering/vue), [Nuxt](/rendering/nuxt), [React](/rendering/react), and [Svelte](/rendering/svelte), turning your Markdown into fully interactive content. From f045a8a3b7c60d7a2d136c3a955d43a16501933a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Tue, 21 Apr 2026 21:19:27 +0200 Subject: [PATCH 9/9] final rewrite --- docs/content/7.kb/0.why-comark.md | 113 +++++++++++------------------- 1 file changed, 40 insertions(+), 73 deletions(-) diff --git a/docs/content/7.kb/0.why-comark.md b/docs/content/7.kb/0.why-comark.md index 26a14a1..7d819cb 100644 --- a/docs/content/7.kb/0.why-comark.md +++ b/docs/content/7.kb/0.why-comark.md @@ -1,42 +1,32 @@ --- -title: Why Comark is the Future of UI Authoring -description: Markdown has become the shared language between humans and AI. Comark extends it all the way to interactive UI. +title: 'Comark: From Markdown to Interactive UI' +description: Markdown is human-readable, token-efficient, and AI-native. Comark extends it to interactive components with runtime parsing, multi-framework rendering, and first-class streaming. navigation: title: Why Comark? -seo: - title: Why Comark is the Future of UI Authoring - description: Markdown is human-readable, token-efficient, and AI-parseable. Discover why it has become the lingua franca for building UI and how Comark extends it to interactive components. links: - label: Comark Syntax icon: i-lucide-file-text to: /syntax/components color: neutral variant: soft - - label: Streaming API - icon: i-lucide-radio - to: /api/auto-close + - label: Installation + to: /getting-started/installation color: neutral variant: soft + icon: i-lucide-download --- -This page answers two questions. - -First, why Markdown has become the default format for both human authoring and machine consumption and why that convergence is not accidental. - -Second, why Comark extends it: what standard Markdown is lacking when you need components and how Comark adds that without sacrificing readability, portability, or parser compatibility. +Markdown won the authoring war. But it stops at document structure: headings, lists, code blocks, emphasis. No components, no interactivity. Comark picks up where Markdown ends. ## Why Markdown? -### The Dual Audience Problem - -Every piece of content on the web is consumed by at least two types of reader: +Every piece of web content serves two audiences: +- **Humans** who need scannable prose +- **Machines** who need predictable structure -- **Humans** who need scannable structure, comfortable prose, and visual hierarchy -- **Machines** who need predictable tokens, explicit structure, and minimum noise +HTML is powerful but verbose. That verbosity costs even more in an era where AI agents pay per token. JSON is structured but no one wants to write a blog post in it. -HTML was designed for the first audience. JSON was designed for the second. Neither was designed for both. - -**Markdown** was designed for humans but it turns out machines love it too. +**Markdown occupies rare middle ground.** The source text is comfortable prose for a human author and token-efficient structured data for a machine consumer. That convergence wasn't part of [Gruber's original design](https://daringfireball.net/projects/markdown/). He was solving for readability in 2004. But it explains why Markdown has become the default format for both human authoring and AI consumption. ### Why Machines Prefer Markdown @@ -56,32 +46,27 @@ This is new. For most of computing history, human-authored content and machine-r ## Why Comark? -Markdown solves the dual-audience problem. But standard Markdown stops at document structure (headings, lists, code blocks, emphasis...). It has no way to express a warning callout, a tabbed code group, a video embed, or a pricing card. - -### The Next Iteration of MDC +Standard Markdown has no way to express a warning callout, a tabbed code group, a video embed, or a pricing card. The current workarounds each come with a cost. -Comark is the next iteration of [mdc](https://github.com/nuxt-content/mdc), the MDC parser that has powered [Nuxt Content](https://content.nuxt.com)'s component syntax for over five years. MDC proved the concept syntax for embedding components inside Markdown. +**Raw HTML works**, but it immediately breaks the plain-text readability that makes Markdown valuable and reintroduces the token overhead that Markdown removes for AI. -Comark takes that foundation and extends it in three directions: +**MDX** made Markdown programmable, but at a cost: `.mdx` files are compiled to JSX at build time. Shipping new content means triggering a rebuild and a redeploy. Your content becomes code, locked to a build pipeline. -- **Streaming and auto-closing:** the [auto-close](/api/auto-close) parser completes unterminated blocks on the fly, so AI-generated or live-streamed Markdown renders correctly at every frame without buffering -- **Compact AST for SSR:** instead of a verbose object tree, Comark produces compact tuples `['tag', props, ...children]` that reduce payload size when serialized and sent over the wire -- **Multiple rendering targets:** the same source renders to Vue, React, Svelte, Nuxt, plain HTML and ANSI terminal output without changing the content +Comark takes a different position. Component syntax should stay in plain text, parsing can happen at build time or runtime, your choice, and work across any renderer. That is the design constraint every other decision follows from. -### The Gap Between Document and UI +### Built on Five Years of MDC -The current workarounds for going beyond standard Markdown are: +Comark is the next generation of [MDC](https://github.com/nuxt-content/mdc), the parser that has powered [Nuxt Content](https://content.nuxt.com)'s component syntax for over five years. MDC proved the concept. Comark extends it in three directions. -- **Raw HTML** — works, but immediately breaks the plain-text properties that make Markdown human-readable and reintroduces the token overhead it removes for AI. -- **MDX** — extends Markdown with JSX, but it is a *compiler*: `.mdx` files are transformed to JSX at build time. Shipping new content means triggering a rebuild and a redeploy. +**AI models stream token by token.** Comark's [auto-close](/api/auto-close) parser renders correctly at every incomplete frame, no buffering, no broken UI. Use `` to pipe AI-generated Markdown directly into your component tree as chunks arrive, including interactive components rendered in real time. -Comark's position is that component syntax should stay in plain text, parse at runtime, and work across any renderer. That is the design constraint every other decision follows from. +**Payloads should be small.** Instead of verbose object trees, Comark produces compact nodes `['tag', props, ...children]` that reduce serialization size when the AST travels over the wire or included during server-side rendering. The same philosophy that makes Markdown token-efficient for LLMs, applied to the JavaScript runtime. -### The Improved Syntax +**Content should outlast frameworks.** The same `.md` source renders to Vue, React, Svelte, Nuxt, plain HTML, and ANSI terminal output. No rewrite when you switch stacks. -#### Block Components +### Markdown as Data, Not Code -Comark's component syntax is a superset of standard Markdown, inspired by the [Markdown directives proposal](https://talk.commonmark.org/t/generic-directives-plugins-syntax/444), a CommonMark effort to standardize a generic extension point without breaking parsers or leaving plain text. +Comark's component syntax is a superset of standard Markdown, inspired by the [Markdown directives proposal](https://talk.commonmark.org/t/generic-directives-plugins-syntax/444), a CommonMark effort to standardize a generic extension point without breaking parsers. ```mdc ::alert{type="warning"} @@ -89,18 +74,24 @@ This action cannot be undone. :: ``` -This is still plain text. No bundler, no compiler step. A human can read it and understand it. An AI agent can parse it as structured data: a component named `alert` with a `type` attribute and text content. +Still plain text. No bundler, no compiler step. A human reads it and understands it. An AI agent parses it as structured data: a component named `alert` with a `type` attribute and text content. -That shift makes Markdown data, not code. Because `parse(markdown)` is a pure function returning a [Comark AST](/syntax/comark-ast), the full CMS pattern becomes possible: +**That shift makes Markdown data, not code.** Because `parse(markdown)` is a pure function returning a [Comark AST](/syntax/comark-ast), the full CMS pattern becomes possible: -1. A database, CMS, or headless service stores the raw Markdown (including `::` components) -2. On request, the server runs `parse()` and gets the compact AST +1. A database, CMS, or headless service stores the raw Markdown, components included +2. On request, the server runs `parse(markdown)` and gets the compact AST 3. The AST is sent to the client -4. `` renders it by looking up each tag name in a components map at runtime +4. `` renders it by looking up each tag name in a components map at runtime -#### Slots +No build step between authoring and rendering. Content is live the moment it is saved. -Raw HTML does break down at one point: **slots** (named regions inside a component). In HTML syntax, placing rich Markdown content into specific named regions of a tag is awkward at best. In Comark, slots are first-class: `#slotname` markers let you place full Markdown into any named region of a component: +::tip +A more efficient way would be to store the AST directly in the database and use the [`renderMarkdown(ast)`](/api/render) when having to display Markdown. +:: + +### First-Class Slots + +Where HTML breaks down is **slots**: placing rich Markdown content into named regions of a component. In Comark, slots are first-class citizens. `#slotname` markers let you compose full Markdown into any named region: ```mdc ::hero @@ -116,9 +107,11 @@ Supports Vue, React, Nuxt, and Svelte out of the box. :: ``` +This is still Markdown. Readable in a text editor, parseable by a machine, renderable by any framework. + ### One Source, Every Renderer -MDX is tied to React. @nuxtjs/mdc was tied to Nuxt. Most Markdown renderers are tied to a single output target. Comark decouples the parse step from the render step entirely. +MDX is tied to React. The original MDC was tied to Nuxt. Most Markdown renderers are locked to a single output target. Comark decouples parsing from rendering entirely. The same `.md` source file renders to: @@ -129,34 +122,8 @@ The same `.md` source file renders to: - [`renderHTML()` in @comark/html](/rendering/html) — server-side HTML strings, RSS, emails, static builds - [`renderANSI()` in @comark/ansi](/rendering/ansi) — styled terminal output for CLIs -The content layer outlasts any particular rendering technology. Write your content once, choose your renderer at the call site. - -### An AST Built for Machines - -Most Markdown parsers produce verbose object trees: - -```typescript -{ type: 'element', tag: 'p', props: {}, children: [{ type: 'text', value: 'Hello' }] } -``` - -The [Comark AST](/syntax/comark-ast) uses compact tuples instead: - -```typescript -['p', {}, 'Hello'] -``` - -The same information, a fraction of the allocations. This matters for static site generators, build pipelines, and AI content endpoints, where the parser stops being the bottleneck. The same philosophy that makes Markdown token-efficient for LLMs makes Comark's AST memory-efficient for the JavaScript runtime. - -Because Comark can parse on the server and send only the compact AST over the wire, the client receives what it needs to render. For Markdown-driven websites serving many readers, this is a meaningful payload and CPU reduction at every request. - -### Streaming by Design - -AI models generate content token by token. A renderer built on the assumption of a complete document breaks immediately when the input is a live stream. - -Comark is built for this case. The [auto-close](/api/auto-close) parser handles incomplete syntax by automatically completing it so the UI renders correctly at every frame. The `streaming` prop on `` and `` pipes AI-generated Markdown directly into your component tree as it arrives, with no intermediate buffering. - -Comark takes the same premise as [Streamdown](https://github.com/vercel/streamdown) further: not just streaming plain Markdown, but streaming Markdown with component syntax so AI output can include interactive UI elements rendered in real time. +Your content outlasts your framework choice. --- -Markdown has become the connective tissue between human authorship and machine intelligence. Comark extends that connective tissue all the way to interactive UI by using component syntax that stays readable, one source that renders anywhere, an AST built for machines, and streaming that works out of the box. +Markdown gave humans and machines a shared language. Comark makes it interactive. Write once, render anywhere, stream in real time.