ThreeMD 2.0.0 adds linked file composition: map a character to another 3md filename, resolve host-supplied files in any of the three libraries, and share a self-contained bundle. See the nested LinkedVillage example and the 2.0.0 release notes.
Markdown with a Z axis. A .3md file is ordinary Markdown extended along
one free axis: stack your content into planes and tell the reader what the
depth means. Time for a daily planner. Frames for an animation. Layers for
annotations. Space for a scene.
Try the interactive demo (also on
corvidlabs.xyz/3md), open the
viewer & editor (paste any
.3md and share a link), read the
docs, or
browse the curated animated gallery,
or flip through the
animated deck
where the strongest examples appear as motion cards.
This repo eats its own dog food: every doc here is also combined into one
docs.3md (each Markdown file is a plane). GitHub can't preview
.3md natively, so open all the docs in the 3md viewer
and scrub through them.
---
3md: 0.1
axis: time
title: My Week
---
@plane z=0 label="Monday"
# Monday
- [ ] Standup
@plane z=1 label="Tuesday"
# Tuesday
This repository holds the format specification (SPEC.md), example
documents (Examples/), three parsers kept in lockstep (ThreeMD, a
cross-platform Swift parser; a TypeScript port in js/; and a Rust crate
in rust/), and a shared cross-implementation conformance suite
(conformance/) that all three pass.
ThreeMD 2.0.0 adds general .3mdb storage, self-contained document
composition, linked file composition, stable optional identities, atomic
revision-checked edits and structured diagnostics in Swift, TypeScript and Rust.
The uncompressed container and shared extension fixtures are portable. LZFSE is
available only through Swift's conditional Apple backend; the ports return an
explicit unsupported-backend error. These library APIs perform no file or
network I/O. See the release notes and migration guide
and editing capability matrix.
Cross-language file interchange is verified by a development gate: each Swift, TypeScript and Rust writer feeds every reader, for all nine pairings. It checks canonical text, uncompressed binary, composition references, linked-file bundles and imported edits. The interchange catalog states the cases, exact-byte checks and platform exceptions. This does not claim portable LZFSE or a shared JSON snapshot/patch transport.
Markdown is two dimensional. Plenty of documents are not: a planner moves through time, an annotated contract has overlay layers, an ASCII animation is a stack of frames. 3md keeps Markdown's plain-text simplicity and adds one axis, with the author declaring what that axis means. Nothing comparable ships today; the closest prior art renders existing Markdown into 3D rather than giving the text a depth dimension of its own.
Add the package to your Package.swift:
.package(url: "https://github.com/CorvidLabs/3md", from: "2.0.0")Then depend on the ThreeMD library product:
.product(name: "ThreeMD", package: "3md")Existing projects can stay on from: "1.0.0". Read the
migration guide before
upgrading: legacy serialization output can change for string values that earlier
writers serialized lossily.
A TypeScript library lives in js/, alongside the
<three-md> web component (@corvidlabs/three-md-element).
All three implementations (Swift, TypeScript, and the Rust crate in rust/)
are kept in sync by the shared conformance suite (conformance/).
The publication workflow publishes to the public npm registry. Install with:
bun add @corvidlabs/threemd@corvidlabs/threemd and @corvidlabs/three-md-element 2.0.0 are published by
the release workflows. If an older installation maps @corvidlabs to GitHub
Packages, point that scope at the public npm registry. The web component keeps
text rendering; the library exports the storage, composition, linked-file and
editing APIs.
No install needed just to use it: try the hosted editor and
viewer, or load the self-contained
component bundle directly with <script type="module" src=".../three-md.js">.
import { danglingLinks, linkGraph, parse, serialize } from "@corvidlabs/threemd";
const document = parse(source);
console.log(document.axis); // "time"
console.log(danglingLinks(document)); // unresolved [[z=N]] references
console.log(linkGraph(document)); // compact source -> target edge list
// Round trips back to text:
const text = serialize(document);The threemd crate's publication workflow
targets crates.io. Install an available published version with:
cargo add threemdThe 2.0.0 crate pins unicode-normalization =0.1.25 as its runtime
dependency. Its serde/serde_json dependencies are development-only. The release
workflow publishes threemd 2.0.0 to crates.io when the CRATES_IO_TOKEN
repository secret is configured. Releases between 1.0.0 and 2.0.0 never reached
crates.io, which stayed at 1.0.0, because the old workflow rewrote the crate
version and left the tree dirty; 2.0.0 fixes that workflow. The secret is not
configured yet, so confirm that crates.io lists 2.0.0 before depending on it.
let document = threemd::parse(source)?;
println!("{}", document.axis); // "time"ThreeMD 2.0.0 adds optional stable plane/reference identities, immutable revision-checked document/composition patches and structured diagnostics above the existing parser in Swift, TypeScript and Rust. General uncompressed binary, composition and linked-file APIs are implemented in all three. See the release scope and capability matrix. Releases before 2.0.0 do not contain these APIs.
import ThreeMD
let document = try Parser().parse(source)
print(document.axis) // Axis(rawValue: "time")
for plane in document.planesByZ {
print(plane.label ?? "", plane.body)
}
print(document.danglingLinks()) // unresolved [[z=N]] references
print(document.linkGraph()) // compact source -> target edge list
// Round trips back to text:
let text = Serializer().render(document)ThreeMD 2.0.0 provides bounded general-document storage and self-contained composition in Swift, TypeScript and Rust. The examples below use Swift; see EDITING-RELEASE.md for the TypeScript and Rust equivalents. The existing text parsers, command-line tool and hosted viewer retain their current text behavior.
import ThreeMD
let document = try Parser().parse(source)
let binary = try DocumentStorageCodec.encode(
document, format: .binary(compression: .none)
)
let restored = try DocumentStorageCodec.decode(binary)
// Optional on platforms with Apple's Compression framework:
let compressed = try DocumentStorageCodec.encode(
document, format: .binary(compression: .lzfse)
)The general .3mdb container holds canonical UTF-8 3md text with explicit
lengths and a corruption checksum. Its magic is 3mdbin\r\n; it is separate
from Sculpt/Rook's older voxel-specific 3MDB container. Defaults cap encoded
and decoded data at 64 MiB, with limits for records, planes and physical lines.
Unavailable compression, malformed headers, excess limits and cancellation
produce errors. CRC detects corruption and does not authenticate content.
Composition preserves a library of named documents and ordered references:
let root = Document(version: "0.1", axis: .layer, planes: [
Plane(z: 0, body: "# Collection")
])
let composition = try DocumentComposition(rootID: "root", entries: [
DocumentEntry(id: "root", document: root, references: [
DocumentReference(targetID: "chapter", attributes: ["role": "first"]),
DocumentReference(targetID: "chapter", attributes: ["role": "again"])
]),
DocumentEntry(id: "chapter", document: document)
])
let text = try DocumentCompositionCodec.encode(composition)
let reloaded = try DocumentCompositionCodec.decode(text)
// The profile is itself a normal Document, so binary storage also works.
let profile = try DocumentCompositionCodec.document(for: composition)
let binaryComposition = try DocumentStorageCodec.encode(
profile, format: .binary(compression: .none)
)Each definition is saved once. All references resolve inside the supplied library, with checked IDs, targets, cycles, depth and work limits, including unused definitions. Documents keep their own axes; attributes have no built-in voxel or layout meaning. The library performs no file reads, URL resolution or automatic flattening. See SPEC.md for the binary layout and the composition profile.
The package keeps its existing deployment baseline. These synchronous APIs check cooperative task cancellation on macOS 10.15, iOS 13, tvOS 13, watchOS 6 and later, and supported non-Apple platforms. On earlier Apple runtimes that check is a no-op; storage and validation remain synchronous and available.
Actual canonical fixtures are in Examples/Extensions: readable canopy, portable binary canopy, readable shared grove, and portable binary shared grove. The fixture directory also includes LZFSE variants and a byte/hash manifest. The public Swift APIs generated all six documents and decoded them back to equal values. This demonstrates storage and references, without promising automatic character-to-model expansion or hosted viewer support.
An ordinary document can name other 3md files in a 3md-files metadata ledger
that maps single printable ASCII characters to relative filenames:
3md-files: "{\"1\":\"models/house.3md\",\"2\":\"models/tree.3md\"}"
The host reads the files it chooses and supplies their bytes. The library resolves the graph and can bundle it into the self-contained profile above:
let linked = try DocumentFileComposition.resolve(
rootPath: "scene.3md",
sources: [DocumentFileSource(path: "scene.3md", data: sceneBytes),
DocumentFileSource(path: "models/house.3md", data: houseBytes),
DocumentFileSource(path: "models/tree.3md", data: treeBytes)]
)
let portable = try DocumentCompositionCodec.encode(linked.composition)Paths are project-relative POSIX paths that cannot escape the root. Missing files, cycles, invalid ledgers and exceeded limits are refused without partial results. See FILE-COMPOSITION.md, SPEC.md section 12.3 and the LinkedVillage example.
The threemd CLI ships with the package and self-documents (run threemd --help). A path of - reads from standard input.
swift run threemd validate <file> # parse a file; print "ok" or exit non-zero with the error
swift run threemd info <file> # print version, axis, title, and each plane's position
swift run threemd links <file> # list cross-plane links and dangling references
swift run threemd check-links <file> # exit non-zero when any [[z=N]] target is missing
swift run threemd html <file> # render the document to HTML on stdoutvalidate, info, links, and check-links also accept --json for CI,
editor integrations, and other tooling.
- A required
---frontmatter block declares3md:(the version, and the file's magic marker), an optionalaxis:, an optionaltitle:, and free metadata. @plane z=... label="..."directives start planes; the Markdown between directives is the plane body.- A plain Markdown file with a 3md header and no directives is a valid one-plane document.
See SPEC.md for the full grammar and conformance rules.
The Examples/ directory holds the source example documents across 13 axis types - from medical charts, weather, and file transfers to games, maps, and animations. The gallery viewer highlights the curated animated set; a few source examples:
daily-planner.3md-axis: time, one plane per day.animation.3md-axis: frame, one plane per frame.layered-notes.3md-axis: layer, stacked overlay layers.dungeon.3md-axis: space, rooms wired with[[z=N]]cross-plane links.tide-pool.3md-axis: depth, authored by an AI from the spec alone (see docs/PROOF.md).game-of-life.3md-axis: frame, a real 24-generation Conway run (animates, and renders as a 3D object in the viewer's blend view).3md-in-3md.3md- 3md explained in 3md, with a@planeinside a code fence.- Plus
recipe,changelog,resume, andkanban.
Want to see it work? docs/PROOF.md records how 3md was verified for machines (a blind AI authored valid 3md from the spec; all three parsers agreed) and for people (plain, readable, diffable text).
This repo uses the CorvidLabs trust toolchain. Run the complete repository gate before calling a change done:
fledge trust verifyTrust validates the SpecSync contract, risk policy, and provenance posture, and
composes the native fledge lanes run verify lane. That native lane runs the
Swift format check, build, and tests plus the Rust crate, TypeScript parser
parity, generated web-component bundle drift, and VS Code grammar tests. See
AGENTS.md for the standing rules every contributor and agent follows.
Browser UI tests are exposed separately with fledge lanes run ui.
Each implementation has its own tests, and all three implementations run the shared 43-vector conformance suite in conformance/, which is the cross-implementation contract that keeps the parsers behaving identically.
The 1.0 text grammar remains frozen. Specification 1.1 adds independently
versioned binary storage, composition and linked file authoring without changing
that grammar. ThreeMD 2.0.0, released on 2026-10-06, implements those extensions
in Swift, TypeScript and Rust; the package version is separate from the format
version. Older 3md: 0.1 documents remain valid: the parser is version-lenient
and never rejects a document by its version string.
MIT (c) CorvidLabs. See LICENSE.
