Three ways to use it

This page describes orz-markdown 2.7 · orz-mdhtml 1.2 · orz-slides 1.2 · orz-paged 1.2

Pick what fits: write in the browser editor, generate a single-file document with a CLI, or render with the parser in your own code.

The editor (nothing to install)

Open the editor and start typing. It renders live with orz-markdown. In Chrome or Edge you can install it (the install icon in the address bar), and then:

  • It opens in its own window and works offline.
  • It registers as a .md handler. Set it as your default and double-click any .md to edit it; Ctrl/⌘ S saves back to the same file.
  • Switch the preview theme and toggle dark mode from the toolbar.

Open, file association and in-place Save use Chromium-only APIs (Chrome, Edge). In other browsers the editor still renders and edits what you type or paste, and Save / Save as download a .md file.

Start from an authentic blank editable file

For .md.html, .slides.html, and .paged.html, use the official starter buttons on this website. Each button opens a genuine editable file in a new tab; click the pencil button, make your changes, then Save or download your own local copy. This is safer than copying starter HTML from an unknown source.

See the document family guide →

Open the editor →

Generate a single-file document

Each tool (Node 20.16 or newer; nothing to install with npx) starts a text, then builds one portable, editable .html from it:

# a continuous document
npx orz-mdhtml@1 new notes.md --title "Field notes"
npx orz-mdhtml@1 notes.md                        # -> notes.md.html

# a slide deck (from a deck template: slides need slide markers)
npx orz-slides@1 new talk.slides.md --template talk
npx orz-slides@1 talk.slides.md                  # -> talk.slides.html

# a print / PDF document
npx orz-paged@1 new paper.paged.md --template article-page
npx orz-paged@1 paper.paged.md                   # -> paper.paged.html

Edit the text (by hand or with an AI agent) between the two commands. An existing Markdown file works too: npx orz-mdhtml@1 notes.md and npx orz-paged@1 report.md (→ report.paged.html) take it as it is. A deck needs a <!-- slide --> line before each slide: orz-slides refuses a plain x.md without one (it says the text is an orz-mdhtml document; --force makes a deck of it as it is), and a x.slides.md without one assembles, with a warning, into a deck with no slides. Open the .html to read, present, or print; click the pencil to change it and Save in place. Files carry their engine by default; --cdn makes a small file that loads it from jsDelivr. Every tool also has extract (the text back out of a file), upgrade (an older file) and inspect (what a file is and what to do next; orz-slides inspect --layout also checks that every box of a deck fits).

References: documents (orz-mdhtml) · slides (orz-slides) · print (orz-paged) · which one?

Render with the parser

Install orz-markdown and render Markdown to HTML:

import { md } from 'orz-markdown';

const html = md.render('# Hello {{emoji wave}}');
// place inside <article class="markdown-body">…</article>
// with one of the bundled themes

The parser emits raw HTML as written, so sanitize untrusted input. File includes ({{md ./file}}) stay off unless you pass markdownBasePath or readFile in the render env (confine them with markdownIncludeRoot; changed in 2.0 — 1.x read from the working directory). URL includes are resolved beforehand with prepareSources(); outside a browser it fetches only from the allowedHosts you name (or through your own fetcher).

To show the output in a page, wrap it in <article class="markdown-body"> with a theme and call enhanceDocument(article) from orz-markdown/preview-frame: it loads only the libraries the content needs (highlighting, Mermaid, SMILES, charts) and the copy-as-Markdown runtime. Add measure-wide or measure-full to the article for longer lines.

Entry points and the carrier kit

Besides the parser, the package has the browser runtime (orz-markdown/runtime), the preview helpers (orz-markdown/preview-frame), the theme list (orz-markdown/themes), document metadata (orz-markdown/doc-meta) and the carrier kit (orz-markdown/carrier…) that orz-mdhtml, orz-slides and orz-paged are built on — the text form, the editor component, saving, the quiet update and the shared CLI core. The README's entry-point table lists them all; their specifications ship in the package (node_modules/orz-markdown/spec/, on GitHub).

See the features for the full syntax, the README for themes and the API, and the agent skill for using it with an AI agent. Upgrading from orz-markdown 1.x: the README's upgrade notes and the CHANGELOG for 2.0.0.

Words you will meet

WordPlain meaning
text, text twinThe document itself, as a plain Markdown file: notes.md, talk.slides.md, report.paged.md. You (or an agent) edit it; it works in git and on GitHub. "Twin" because it sits beside the .html file made from it.
file, self-editing fileThe .md.html / .slides.html / .paged.html you open, share and save. It carries the exact text inside it, and can edit itself in the browser.
assembleMake the file from the text (npx orz-mdhtml@1 notes.md). The same text always gives the same file; extract gives the text back.
headerThe {{nyml kind: document … }} block at the very top of the text: title, author, theme and the other settings.
nymlThe header's small syntax: {{nyml on its own line, then one key: value per line, then }}. Everything after the colon is the value — a # note on the line becomes part of it, so keep notes out of the header.
uidThe document's id in the header (uid: doc-…). new, upgrade, New document and Save as new copy write one; Save keeps it. A text without one (a starter, your own Markdown) is fine. Once a document has one, keep it: it tells the tools that a text and a file are the same document.
shellEverything in a file except the text: the engine that renders, edits and saves it. It can be rebuilt at any time (upgrade, or the file's own Update), and the text stays exactly as it was.
format 1 (text format 1)The shared shape of the text and the file used by every 1.0 tool. Files from the 0.x releases predate it and need upgrading once.
inline / cdnWhether the engine is inside the file (inline, the default) or loaded from jsDelivr (--cdn, a small file for the web).
islandA block of data inside the file, such as <script type="text/markdown" id="orz-src">, which holds the exact text. It is data, not a program: the file's only running script is its engine.
known stateA text the CLI itself last wrote or read for a text/file pair, or a version of the text committed in git. The CLI replaces a known state without asking; anything else (an edit made since, a file saved in the browser) needs --force, which keeps a ~ backup.
--replaces <sha256>"Replace the file only if it still holds this text." The sha256 is the fingerprint of a text that assemble, extract (to a file), inspect and upgrade print, and every --json result that wrote a text carries. Pass it back and the replace works with no cache and no git, but never over newer work.
flattened previewThe slides editor's preview: every slide's content in one scrolling column, a thin divider per slide, instead of slide-sized pages. The live slide card in its corner shows the slide under the caret as it presents; its Edit opens the layout editor for that slide.

Portable authorship and license metadata

Put the title, author, license, canonical source, date, description and keywords in the header, the {{nyml kind: document}} block at the very top of the text — the same for a document, a deck and a print document. The tool's new command writes the header with carrier and a uid; add the rest, one key: value per line (no comments):

{{nyml
kind: document
carrier: md
uid: doc-7kq2m9x4p1r8s3t5
title: Field Notes
author: Your Name
license: CC-BY-4.0
license_url: https://creativecommons.org/licenses/by/4.0/
source: https://example.org/field-notes
date: 2026-07-11
}}

The file writes them into standard HTML head tags and a machine-readable #orz-meta record. The header stays in the text, so edits in the browser keep the head tags current. Files from the 0.x releases kept metadata in a separate {{nyml kind: meta}} block (or, for decks, a <!-- deck --> block); upgrade moves it into the header.

Upgrading from 0.x

Files made by orz-mdhtml 0.9.3, orz-slides 0.8.5, orz-paged 0.7.x or earlier still open as they were, but the 1.0 tools read them only after a one-time upgrade. For each file, ask what it is, then upgrade it:

npx orz-mdhtml@1 inspect old.md.html       # what it is, what upgrade changes
npx orz-mdhtml@1 upgrade old.md.html       # -> a 1.0 old.md.html + its text old.md

npx orz-slides@1 inspect old.slides.html
npx orz-slides@1 upgrade old.slides.html   # -> a 1.0 file + old.slides.md
npx orz-slides@1 upgrade deck.md           # a 0.x deck source -> deck.slides.md

npx orz-paged@1 inspect old.paged.html
npx orz-paged@1 upgrade old.paged.html     # -> a 1.0 file + old.paged.md

The source is kept exactly; the old metadata and settings become the header, and the file gets a uid. If a text with the twin's name already exists (often the 0.x source), upgrade will not overwrite it: add --text old.browser.md (or .browser.slides.md / .browser.paged.md) and merge the two. A 0.x file's own "Framework 1.0.0 available" offer cannot make this move — dismiss it and run upgrade. Details per tool: documents · slides · print.

orz-markdown 1.x → 2.x (the parser, for developers): file includes became opt-in and URL includes outside a browser need an allow-list; rendered output and the themes changed. See the README's upgrade notes and the CHANGELOG for 2.0.0.

Verifying a file someone sent you

These documents are programs: opening one runs its embedded code. Before trusting a file from an untrusted source, run it through the verifier. It checks the embedded framework against the genuine published packages (a 1.0 file must be reproduced byte for byte, from the text it carries, by the published package of its version) and scans the content for embedded scripts, entirely in your browser. Treat anything it cannot confirm like a downloaded app.

Open the verifier →