drawlang
Precision diagrams as code — a DSL and Rust renderer built for AI-agent authors.
Most diagram source is now written by coding agents, which iterate by reading text, not by looking at pixels. drawlang closes that loop: the renderer is also a verifier. Every render can emit machine-readable geometry and visual lints, so an agent converges on a clean diagram the same way it converges on a green test suite.
The source for that diagram is examples/gpu-topology.drawl —
a parameterized GPU component instantiated in a loop, ports with sides, an
NVLink ring via (i + 1) % 4, and two layout constraints. The PCIe lanes are
routed by an obstacle-avoiding orthogonal router that nests parallel runs.
Why another diagram language
- Layout is a gradient, not a binary. Auto-layout by default →
row/column/gridcontainers → constraints (align,gap,below) solved with Cassowary → absolutepinas the escape hatch. You pay only for the precision you need — the thing Mermaid can't do and Figma can't automate. - The feedback loop is machine-readable.
render --reportemits every element's bbox and port positions plus lints: label overflow, box overlap, edges cutting through nodes, label collisions, crossing counts — each with a concretefixfield. - Rust-quality errors. Full error recovery (every error in one pass),
spans, did-you-mean suggestions, instantiation traces, stable codes with
drawlang explain E0214. - Deterministic. Same input → byte-identical SVG. Labels are measured with the bundled font (DejaVu Sans via ttf-parser), so boxes fit their text by construction and PNG output matches exactly.
- Layout stability.
drawlang freezelocks solved positions into a.locksidecar; later edits stop reshuffling a diagram you've approved.
Quick start
cargo install drawlang
drawlang check arch.drawl # parse + semantic lints, all at once
drawlang render arch.drawl -o arch.svg --report
drawlang render arch.drawl -o arch.png --scale 2 --theme dark
drawlang query arch.drawl 'gpus[2]' # one element's resolved geometry
drawlang fmt arch.drawl # canonical formatting
drawlang freeze arch.drawl # pin today's layout
drawlang explain W0410 # what a diagnostic means + how to fix
drawlang cheatsheet # one-page guide to paste into an LLM
The language in 30 seconds
drawl 0.1
canvas { theme: paper; flow: right }
def gpu(i) {
label: "GPU {i}"
port nvlink { side: top }
port pcie { side: bottom }
}
group host "Host" { cpu { label: "EPYC 9754" } }
gpus: row { for i in 0..4 { gpu(i) } }
for i in 0..4 { host.cpu -> gpus[i].pcie : "PCIe 5.0 x16" { class: bus } }
for i in 0..4 { gpus[i].nvlink <-> gpus[(i + 1) % 4].nvlink : "NVLink" }
constrain {
align(gpus[*], top)
gap(host, gpus, 48)
}
class bus { stroke: 2; color: @accent; routing: orthogonal }
Structure, layout intent, and style are orthogonal layers: an edit to one
never disturbs the others, and diffs stay local. Everything is addressable by
a stable path (host.cpu, gpus[2].pcie) — in constraints, in query, in
every error message, and in the geometry report.
The full syntax reference is docs/CHEATSHEET.md — the
same text drawlang cheatsheet prints, sized for an LLM context window.
More examples in examples/, rendered output in
examples/renders/:
a CPU die (grid containers, nested components,
width: fill) and an inference pipeline
(dark theme, bidirectional cache traffic, dashed orthogonal return path).
Workspace
crates/drawlang-syntax lexer, parser (error recovery), AST, formatter
crates/drawlang-core semantic model, layout, constraints, router, report
crates/drawlang-render SVG writer, themes, PNG via resvg
crates/drawlang the CLI
docs/DESIGN.md design rationale + milestone history
Licensed under Apache-2.0. The bundled DejaVu fonts ship under
their own permissive license (see crates/drawlang-core/assets).