Skip to content
CorvidLabsPublic

About

🧊 Markdown with a Z axis. A plain-text format for documents with depth (time, layers, frames, space), with conformance-verified parsers in Swift, TypeScript, and Rust.

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

135 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

3md

CI spec coverage Release License: MIT Live demo

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.

The 3md interactive demo: planes stacked along the Z axis with a synced source view

---
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.

Why

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.

Installation

Swift Package Manager

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.

JavaScript / TypeScript

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);

Rust

The threemd crate's publication workflow targets crates.io. Install an available published version with:

cargo add threemd

The 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"

Library usage

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)

Binary storage and reusable documents

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.

Linked files

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.

Command-line tool

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 stdout

validate, info, links, and check-links also accept --json for CI, editor integrations, and other tooling.

Format at a glance

  • A required --- frontmatter block declares 3md: (the version, and the file's magic marker), an optional axis:, an optional title:, 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.

Examples

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:

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).

Development

This repo uses the CorvidLabs trust toolchain. Run the complete repository gate before calling a change done:

fledge trust verify

Trust 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.

Status

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.

License

MIT (c) CorvidLabs. See LICENSE.

About

🧊 Markdown with a Z axis. A plain-text format for documents with depth (time, layers, frames, space), with conformance-verified parsers in Swift, TypeScript, and Rust.

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages