Skip to content

Playground

Type Carve on the left, see the rendered HTML on the right (and the raw HTML below). Everything runs client-side, no network round-trip — the same reference parser that backs the spec corpus.

Engine PHP ↗

Carve Feature Demo

A single document touching every core construct, plus a few renderer-dependent extensions at the end.

Level 1

Level 2

Level 3

Level 4

Level 5
Level 6

A heading carries an explicit id and classes from a block-attribute line on the line directly above it:

{#install .lead}
## Setup

Inline formatting

italic, bold, bold italic, underline, strikethrough, highlight, superscript and subscript. Inline code span, and raw inline passthrough HTML emitted verbatim.

Editorial markup: added text , deleted text , old phrase new phrase , and an editorial note .

Escapes keep specials literal: *not bold*, /not italic/, #not-a-tag.

Lists

Unordered:

  • apples
  • oranges
    • clementines
    • blood oranges
  • pears

Ordered:

  1. clone the repo
  2. install dependencies
    • run the build
    • run the tests
  3. ship it

Tasks:

  • write the grammar
  • write the corpus
  • write more demos

Definition list:

Carve
A post-Markdown lightweight markup language.
Djot
The markup language Carve evolves from.

Blockquotes

The best way to predict the future is to invent it.

Alan Kay

Tables

Table 1: column alignment - left, right, center.
FruitPriceStock
Apple1.20In
Banana0.50In
Dragon fruit4.00Out

Code and raw blocks

A fenced code block with a language:

def greet(name: str) -> str:
    return f"Hello, {name}!"

A quoted “header” after the language sets the block’s title (rendered as the title attribute on the <pre> - a filename bar or hover tooltip):

def greet(name: str) -> str:
    return f"Hello, {name}!"

A tilde fence works too:

key: value
list:
  - one
  - two

A raw block passes content through to a named format unchanged:

Native HTMLRendered as-is.

Math

Inline math uses a dollar before a code span: \(e = mc^2\).

Display math uses a double dollar:

\[e^{i\pi} + 1 = 0\]

A fenced math block is the GFM-style block form (mathBlock extension):

\[\sum_{k=1}^{n} k = \frac{n(n+1)}{2}\]

Admonitions and divs

A bare ::: fence with no admonition type is a generic styled container, not a colored callout. Its id and classes go on a block-attribute line directly above the fence:

This block has only an id and classes, so it renders as a plain <div id="callout" class="highlight"> wrapper you can target with your own CSS.

Mentions, tags, and inline extensions

Mention a person with @alice and reference a tag like #release-1.0. An inline extension names a role: press Ctrl+C to copy.

Footnotes

Carve supports footnotes1 with definitions collected anywhere.2

Smart typography

Dashes and ellipsis: an em dash — an en range 10–20 … and so on. Arrows and comparisons: → ← ↔ ⇒ , ≠ ≤ ≥ , © ® ™.


List tables (Tier-3 extension)

Quarterly results
RegionNotes
EMEA

Strong quarter.

Drivers:

  • new logos
  • renewals
APAC

Code groups (Tier-3 extension)

npm install @markup-carve/carve
pnpm add @markup-carve/carve
yarn add @markup-carve/carve

Mermaid (Tier-3 extension)

graph TD
    A[Write Carve] --> B{LSP diagnostics}
    B -->|clean| C[Preview]
    B -->|warnings| D[Quick fix]
    D --> A
    C --> E[Publish]
sequenceDiagram
    Author->>Editor: type Carve
    Editor->>LSP: textDocument/didChange
    LSP-->>Editor: diagnostics + semantic tokens
    Editor-->>Author: live preview

Charts (Tier-3 extension)

Spoilers (Tier-3 extension)

The killer is the lighthouse keeper - click the blur to reveal.

Plot ending

Everyone makes it home. The dog lives too.


  1. The reference and its definition are linked by label.

  2. Definitions can appear in any order.

JavaScript
<section id="top">
  <h1>Carve Feature Demo <a href="#top" class="permalink" aria-label="Permalink">¶</a></h1>
  <p>A single document touching every core construct, plus a few renderer-dependent
extensions at the end.</p>
  <section id="headings">
    <h2 class="featured">Headings and attributes <a href="#headings" class="permalink" aria-label="Permalink">¶</a></h2>
  </section>
</section>
<section id="Level-1">
  <h1>Level 1 <a href="#Level-1" class="permalink" aria-label="Permalink">¶</a></h1>
  <section id="Level-2">
    <h2>Level 2 <a href="#Level-2" class="permalink" aria-label="Permalink">¶</a></h2>
    <section id="Level-3">
      <h3>Level 3 <a href="#Level-3" class="permalink" aria-label="Permalink">¶</a></h3>
      <section id="Level-4">
        <h4>Level 4 <a href="#Level-4" class="permalink" aria-label="Permalink">¶</a></h4>
        <section id="Level-5">
          <h5>Level 5 <a href="#Level-5" class="permalink" aria-label="Permalink">¶</a></h5>
          <section id="Level-6">
            <h6>Level 6 <a href="#Level-6" class="permalink" aria-label="Permalink">¶</a></h6>
            <p>A heading carries an explicit id and classes from a block-attribute line on
the line directly above it:</p>
            <pre><code class="language-carve">{#install .lead}
## Setup
</code></pre>
          </section>
        </section>
      </section>
    </section>
  </section>
  <section id="Inline-formatting">
    <h2>Inline formatting <a href="#Inline-formatting" class="permalink" aria-label="Permalink">¶</a></h2>
    <p><em>italic</em>, <strong>bold</strong>, <strong><em>bold italic</em></strong>, <u>underline</u>, <s>strikethrough</s>, <mark>highlight</mark>,
super<sup>script</sup> and sub<sub>script</sub>. Inline <code>code span</code>, and raw inline passthrough
<abbr>HTML</abbr> emitted verbatim.</p>
    <p>Editorial markup: <ins> added text </ins>, <del> deleted text </del>,
<del> old phrase </del><ins> new phrase </ins>, and an <span class="critic-comment"> editorial note </span>.</p>
    <p>Escapes keep specials literal: *not bold*, /not italic/, #not-a-tag.</p>
  </section>
  <section id="Links-and-images">
    <h2>Links and images <a href="#Links-and-images" class="permalink" aria-label="Permalink">¶</a></h2>
    <p>Inline <a href="https://example.com" target="_blank" rel="noopener noreferrer">link</a>, titled
<a href="https://example.com" title="Hover title" target="_blank" rel="noopener noreferrer">link</a>, autolink <a href="https://example.com" target="_blank" rel="noopener noreferrer">https://example.com</a>,
email autolink <a href="mailto:hello@example.com">hello@example.com</a>, and a reference <a href="https://example.com" title="Reference definition" target="_blank" rel="noopener noreferrer">link</a>.</p>
    <p>A collapsed reference <a href="https://example.com" title="Reference definition" target="_blank" rel="noopener noreferrer">site</a> reuses the label as the reference.</p>
    <p>Cross-reference to a heading by id: jump to <a href="#top">Carve Feature Demo</a>.</p>
    <figure>
      <img src="/carve/images/diagram.png" alt="A descriptive alt text">
      <figcaption>Figure 1: images may carry a caption line.</figcaption>
    </figure>
  </section>
  <section id="Lists">
    <h2>Lists <a href="#Lists" class="permalink" aria-label="Permalink">¶</a></h2>
    <p>Unordered:</p>
    <ul>
      <li>apples</li>
      <li>oranges
        <ul>
          <li>clementines</li>
          <li>blood oranges</li>
        </ul>
      </li>
      <li>pears</li>
    </ul>
    <p>Ordered:</p>
    <ol>
      <li>clone the repo</li>
      <li>install dependencies
        <ul>
          <li>run the build</li>
          <li>run the tests</li>
        </ul>
      </li>
      <li>ship it</li>
    </ol>
    <p>Tasks:</p>
    <ul>
      <li><input type="checkbox" checked disabled> write the grammar</li>
      <li><input type="checkbox" checked disabled> write the corpus</li>
      <li><input type="checkbox" disabled> write more demos</li>
    </ul>
    <p>Definition list:</p>
    <dl>
      <dt>Carve</dt>
      <dd>A post-Markdown lightweight markup language.</dd>
      <dt>Djot</dt>
      <dd>The markup language Carve evolves from.</dd>
    </dl>
  </section>
  <section id="Blockquotes">
    <h2>Blockquotes <a href="#Blockquotes" class="permalink" aria-label="Permalink">¶</a></h2>
    <figure>
      <blockquote><p>The best way to predict the future is to invent it.</p></blockquote>
      <figcaption>Alan Kay</figcaption>
    </figure>
  </section>
  <section id="Tables">
    <h2>Tables <a href="#Tables" class="permalink" aria-label="Permalink">¶</a></h2>
    <table>
      <caption>Table 1: column alignment - left, right, center.</caption>
      <thead><tr><th>Fruit</th><th style="text-align: right;">Price</th><th style="text-align: center;">Stock</th></tr></thead>
      <tbody>
        <tr><td>Apple</td><td style="text-align: right;">1.20</td><td style="text-align: center;">In</td></tr>
        <tr><td>Banana</td><td style="text-align: right;">0.50</td><td style="text-align: center;">In</td></tr>
        <tr><td>Dragon fruit</td><td style="text-align: right;">4.00</td><td style="text-align: center;">Out</td></tr>
      </tbody>
    </table>
  </section>
  <section id="Code-and-raw-blocks">
    <h2>Code and raw blocks <a href="#Code-and-raw-blocks" class="permalink" aria-label="Permalink">¶</a></h2>
    <p>A fenced code block with a language:</p>
    <pre><code class="language-python">def greet(name: str) -&gt; str:
    return f"Hello, {name}!"
</code></pre>
    <p>A quoted “header” after the language sets the block’s title (rendered as the
<code>title</code> attribute on the <code>&lt;pre&gt;</code> - a filename bar or hover tooltip):</p>
    <pre title="greet.py"><code class="language-python">def greet(name: str) -&gt; str:
    return f"Hello, {name}!"
</code></pre>
    <p>A tilde fence works too:</p>
    <pre><code class="language-yaml">key: value
list:
  - one
  - two
</code></pre>
    <p>A raw block passes content through to a named format unchanged:</p>
<details><summary>Native HTML</summary>Rendered as-is.</details>
  </section>
  <section id="Math">
    <h2>Math <a href="#Math" class="permalink" aria-label="Permalink">¶</a></h2>
    <p>Inline math uses a dollar before a code span: <span class="math inline">\(e = mc^2\)</span>.</p>
    <p>Display math uses a double dollar:</p>
    <p><span class="math display">\[e^{i\pi} + 1 = 0\]</span></p>
    <p>A fenced <code>math</code> block is the GFM-style block form (mathBlock extension):</p>
    <div class="math display">\[\sum_{k=1}^{n} k = \frac{n(n+1)}{2}\]</div>
  </section>
  <section id="Admonitions-and-divs">
    <h2>Admonitions and divs <a href="#Admonitions-and-divs" class="permalink" aria-label="Permalink">¶</a></h2>
    <aside class="admonition note">
      <p>A plain note callout.</p>
    </aside>
    <aside class="admonition tip">
      <p class="admonition-title">With a title</p>
      <p>Admonitions accept an optional quoted title.</p>
    </aside>
    <aside class="admonition warning">
      <p>Heed this warning.</p>
    </aside>
    <aside class="admonition danger">
      <p>Critical information.</p>
    </aside>
    <p>A bare <code>:::</code> fence with no admonition type is a generic styled container, not a
colored callout. Its id and classes go on a block-attribute line directly above
the fence:</p>
    <div id="callout" class="highlight">
      <p>This block has only an id and classes, so it renders as a plain
<code>&lt;div id="callout" class="highlight"&gt;</code> wrapper you can target with your own CSS.</p>
    </div>
  </section>
  <section id="Mentions-tags-and-inline-extensions">
    <h2>Mentions, tags, and inline extensions <a href="#Mentions-tags-and-inline-extensions" class="permalink" aria-label="Permalink">¶</a></h2>
    <p>Mention a person with <span class="mention"><strong>@alice</strong></span> and reference a tag like <span class="tag"><strong>#release-1.0</strong></span>.
An inline extension names a role: press <kbd>Ctrl+C</kbd> to copy.</p>
  </section>
  <section id="Footnotes">
    <h2>Footnotes <a href="#Footnotes" class="permalink" aria-label="Permalink">¶</a></h2>
    <p>Carve supports footnotes<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a> with definitions collected anywhere.<a id="fnref2" href="#fn2" role="doc-noteref"><sup>2</sup></a></p>
  </section>
  <section id="Smart-typography">
    <h2>Smart typography <a href="#Smart-typography" class="permalink" aria-label="Permalink">¶</a></h2>
    <p>Dashes and ellipsis: an em dash — an en range 10–20 … and so on.
Arrows and comparisons: → ← ↔ ⇒ , ≠ ≤ ≥ , © ® ™.</p>
    <hr>
  </section>
  <section id="List-tables-Tier-3-extension">
    <h2>List tables (Tier-3 extension) <a href="#List-tables-Tier-3-extension" class="permalink" aria-label="Permalink">¶</a></h2>
    <table>
      <caption>Quarterly results</caption>
      <thead><tr><th>Region</th><th>Notes</th></tr></thead>
      <tbody>
        <tr><td>EMEA</td><td><p>Strong quarter.</p>
<p>Drivers:</p>
<ul>
  <li>new logos</li>
  <li>renewals</li>
</ul></td></tr>
        <tr><td colspan="2">APAC</td></tr>
      </tbody>
    </table>
  </section>
  <section id="Code-groups-Tier-3-extension">
    <h2>Code groups (Tier-3 extension) <a href="#Code-groups-Tier-3-extension" class="permalink" aria-label="Permalink">¶</a></h2>
    <div class="code-group">
<input type="radio" name="codegroup-1" id="codegroup-1-tab-1" class="code-group-radio" checked>
<label for="codegroup-1-tab-1" class="code-group-label">npm</label>
<input type="radio" name="codegroup-1" id="codegroup-1-tab-2" class="code-group-radio">
<label for="codegroup-1-tab-2" class="code-group-label">pnpm</label>
<input type="radio" name="codegroup-1" id="codegroup-1-tab-3" class="code-group-radio">
<label for="codegroup-1-tab-3" class="code-group-label">yarn</label>
<div class="code-group-panel"><pre><code class="language-bash">npm install @markup-carve/carve
</code></pre>
</div>
<div class="code-group-panel"><pre><code class="language-bash">pnpm add @markup-carve/carve
</code></pre>
</div>
<div class="code-group-panel"><pre><code class="language-bash">yarn add @markup-carve/carve
</code></pre>
</div>
    </div>
  </section>
  <section id="Mermaid-Tier-3-extension">
    <h2>Mermaid (Tier-3 extension) <a href="#Mermaid-Tier-3-extension" class="permalink" aria-label="Permalink">¶</a></h2>
    <pre class="mermaid">graph TD
    A[Write Carve] --> B{LSP diagnostics}
    B -->|clean| C[Preview]
    B -->|warnings| D[Quick fix]
    D --> A
    C --> E[Publish]</pre>
    <pre class="mermaid">sequenceDiagram
    Author->>Editor: type Carve
    Editor->>LSP: textDocument/didChange
    LSP-->>Editor: diagnostics + semantic tokens
    Editor-->>Author: live preview</pre>
  </section>
  <section id="Charts-Tier-3-extension">
    <h2>Charts (Tier-3 extension) <a href="#Charts-Tier-3-extension" class="permalink" aria-label="Permalink">¶</a></h2>
    <div class="chart"><script type="application/json">{"type":"bar","data":{"labels":["Q1","Q2","Q3","Q4"],"datasets":[{"label":"Revenue","data":[12,19,14,23]}]}}</script></div>
  </section>
  <section id="Spoilers-Tier-3-extension">
    <h2>Spoilers (Tier-3 extension) <a href="#Spoilers-Tier-3-extension" class="permalink" aria-label="Permalink">¶</a></h2>
    <p>The killer is <span class="spoiler">the lighthouse keeper</span> - click the blur to reveal.</p>
    <details class="spoiler">
      <summary>Plot ending</summary>
      <p>Everyone makes it home. The dog lives too.</p>
    </details>
  </section>
</section>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>The reference and its definition are linked by label.<a href="#fnref1" role="doc-backlink">↩</a></p>
    </li>
    <li id="fn2">
      <p>Definitions can appear in any order.<a href="#fnref2" role="doc-backlink">↩</a></p>
    </li>
  </ol>
</section>

Vite Plugin Dogfood

The docs build also imports a .crv file through @markup-carve/vite-plugin-carve and renders the generated HTML during the VitePress build.

Imported Carve

# Plugin Dogfood

This snippet is rendered from a `.crv` import by *vite-plugin-carve*.

Inline math like $`E = mc^2` and a display equation render with KaTeX:

$$`\int_0^\infty e^{-x^2}\,dx = \frac{\sqrt{\pi}}{2}`

Rendered HTML

Plugin Dogfood

This snippet is rendered from a .crv import by vite-plugin-carve.

Inline math like \(E = mc^2\) and a display equation render with KaTeX:

\[\int_0^\infty e^{-x^2}\,dx = \frac{\sqrt{\pi}}{2}\]

What this proves

  • Every construct in the Quick Reference and every pair in the Examples flows through the same parser → AST → renderer pipeline you see here.
  • Edits round-trip in single-digit milliseconds. Carve's linear-time parsing is the reason.
  • The current build comes from @markup-carve/carve, pinned to an exact carve-js commit in the repo's package.json.

Released under the MIT License.