# GEML vs. other markup formats *English | [中文](COMPARISON_CN.md)* How GEML compares to **Markdown** (GitHub-flavored), **HTML**, **CommonMark** (strict core), **AsciiDoc**, **Org-mode**, and **Pandoc Markdown**. Note on Pandoc: it is really a *converter* plus its own **Pandoc Markdown** — the most feature-complete Markdown dialect. Its attribute syntax `{#id .class key=val}` is in fact the ancestor of GEML's. Pandoc's own super-powers — multi-format conversion and programmable **Lua filters** — sit on a different axis than the per-element comparison below. GEML is not the widest format here — AsciiDoc, in particular, ships more built-in elements out of the box. GEML's case rests on three things no other format here offers together: 1. **One primitive for every structured block** — lowest syntax surface to learn, parse, or *generate* (which is why it's friendly to AI). 2. **Build-time reference checking** — a broken cross-reference is an error, not a silent dead link — and it covers *content*, not just links: a transcluded block, an external CSV, a `.jsonl` log, a code line range. 3. **Self-contained version history** (`.gemlhistory`) — without git or any online service. Legend: ✓ native · ◐ via extension/convention · ✗ none · *(H)* needs raw HTML. For a construct-by-construct walk through **CommonMark 0.31.2** alone — every leaf block, container block and inline, with what GEML does to each — see [GEML vs. CommonMark](GEML-vs-CommonMark.md). ## Capability matrix | Element / capability | GEML | Markdown (GFM) | HTML | CommonMark | AsciiDoc | Org-mode | Pandoc Markdown | |---|---|---|---|---|---|---|---| | Headings | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Bold / italic | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Inline code | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Code block (with language) | ✓ | ✓ | ◐ | ✓ | ✓ | ✓ | ✓ | | Lists | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Links / images | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Audio / video embed | ✓ | ✗ *(H)* | ✓ | ✗ | ✓ | ◐ | ✗ *(H)* | | Tables | ✓ | ✓ | ✓ | ✗ | ✓ | ✓ | ✓ | | Data / computed-column tables | ✓ | ✗ | ✗ | ✗ | ◐ csv | ◐ formulas | ✗ | | Structured data as a **verified** block | ✓ json/jsonl | ✗ | ◐ unchecked | ✗ | ◐ unchecked | ◐ babel | ✗ | | Body pulled from an external file | ✓ checked | ✗ | ✗ | ✗ | ✓ unchecked | ✓ unchecked | ◐ filter | | Admonitions / callouts | ✓ | ◐ alerts | ◐ | ✗ | ✓ | ◐ | ◐ fenced div | | Footnotes | ✓ | ✓ | ◐ | ✗ | ✓ | ✓ | ✓ | | Definition lists | ✗ | ✗ | ✓ | ✗ | ✓ | ✓ | ✓ | | Super/subscript, inline spans | ✗ | ✗ | ✓ | ✗ | ✓ | ◐ | ✓ | | Math (inline / block) | ✓ | ◐ | ◐ | ✗ | ✓ | ✓ | ✓ | | Diagrams (hosted DSL) | ✓ | ◐ mermaid | ✗ | ✗ | ✓ | ✓ | ◐ filter | | Chart bound to a table or data block | ✓ | ✗ | ✗ | ✗ | ◐ | ◐ | ✗ | | Citations / bibliography | ✗ | ✗ | ✗ | ✗ | ◐ | ✓ | ✓ | | Document metadata | ✓ native block | ◐ frontmatter | ✓ | ✗ | ✓ | ✓ | ✓ | | Block id + cross-reference | ✓ | ◐ headings only | ✓ | ◐ | ✓ | ✓ | ✓ | | Transclusion (another document's block, in place) | ✓ checked | ✗ | ◐ iframe | ✗ | ✓ preprocessor | ✓ | ◐ filter | | **Build-time reference checking** | ✓ error | ✗ | ✗ | ✗ | ✓ warns | ◐ | ✗ | | Raw-HTML escape hatch | ✗ *(by design)* | ✓ | — | ✓ | ✓ | ✓ | ✓ | | Plain-text legible (no rendering) | ✓ | ✓ | ✗ | ✓ | ✓ | ✓ | ✓ | | Programmable filters / macros | ✗ *(by design)* | ✗ | ✗ | ✗ | ◐ | ✓ | ✓ Lua | | **One primitive for all blocks** | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Self-contained version history** | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | The three bold rows are GEML's real differentiators. "Raw HTML = ✗" is a feature, not a gap: it keeps semantics portable and tied to no backend. Pandoc Markdown is the broadest column here — it adds citations, definition lists, and Lua filters — yet it still lacks the one primitive, build-time checking, and self-contained history. ## Side-by-side syntax ### Code block ``` GEML === code {#hello lang=python} print("hi") === Markdown ```python print("hi") ``` HTML
print("hi")
CommonMark ```python print("hi") ``` AsciiDoc [source,python] ---- print("hi") ---- Org-mode #+begin_src python print("hi") #+end_src Pandoc ```{.python} print("hi") ``` ``` ### Document metadata ``` GEML === meta title = "Budget plan" === Markdown --- (YAML frontmatter — convention, not spec) title: Budget plan --- HTML CommonMark (no mechanism) AsciiDoc = Budget plan :version: 0.1 Org-mode #+TITLE: Budget plan Pandoc --- (YAML metadata block — first-class) title: Budget plan --- ``` ### Admonition / callout ``` GEML === note {#risks} Vendor lock-in is the main risk. === Markdown > [!NOTE] (GitHub extension) > Vendor lock-in is the main risk. HTML
Vendor lock-in is the main risk.
CommonMark (no mechanism — plain blockquote only) AsciiDoc [NOTE] ==== Vendor lock-in is the main risk. ==== Org-mode (no standard — special block, export-dependent) Pandoc ::: {.note} Vendor lock-in is the main risk. ::: ``` ### Cross-reference, and whether it is checked ``` GEML See [[#budget]] → #budget missing ⇒ build ERROR Markdown See [budget](#budget) → broken link passes silently HTML See … → not checked CommonMark See [budget](#budget) → not checked AsciiDoc See <> → processor WARNS on unresolved xref Org-mode See [[budget]] → partially checked on export Pandoc See [budget](#budget) → not checked (xref via pandoc-crossref filter) ``` ### Transclusion — content that lives in another document ``` GEML === embed {src=handbook.geml#refund} === → renders that block here. src= is reference-checked, a transclusion cycle is an error, and handbook.geml is PARSED AS ITS OWN DOCUMENT — its metadata and its relative paths resolve against itself, not against this file. Inline form: ![[handbook.geml#refund]] (inside a sentence) Markdown (no mechanism — Obsidian's ![[note]] is an app extension) HTML