D2-Diagramme
D2 ist eine deklarative Sprache: Du beschreibst Formen und die Verbindungen zwischen ihnen, und eine Layout-Engine entscheidet, wo alles platziert wird. Du setzt niemals manuell Koordinaten. Deshalb ist ein D2-Diagramm kurz, diffbar und später leicht zu bearbeiten, und auch der Grund, warum die meisten Fehler aus Syntax- und Layout-Engine-Eigenheiten stammen, nicht aus dem Design.
Diese Fähigkeit ist ein vollständiges, praxiserprobtes Wissen über D2 v0.9.x, verifiziert gegen den echten Compiler. Jedes Beispiel in references/ und assets/templates/ lässt sich kompilieren.
Arbeitsablauf
- Prüfe das Werkzeug. Führe
d2 --version(oderscripts/d2check.sh --version) aus. Fehltd2, informiere den Benutzer und bietebrew install d2odercurl -fsSL https://d2lang.com/install.sh | sh -s --an; installiere nicht stillschweigend. - Wähle den Diagrammtyp und lies die passende Referenz (Tabelle unten). Beginne mit einer Vorlage aus
assets/templates/, falls eine passend ist. - Schreibe die
.d2-Datei neben dem gewünschten Speicherort (Standard:diagrams/<name>.d2). - Kompiliere und rendere mit
scripts/d2check.sh <datei.d2> [ausgabeverzeichnis] [pdf|pptx|gif](Formatiert, kompiliert, rendert SVG, erstellt eine PNG-Vorschau inausgabeverzeichnis/preview/und ggf. weitere Formate). Verlasse dich nie allein aufd2 validate: Es parst nur die Syntax. Falsche Shape-Namen, nicht unterstützte Layoutfunktionen und fehlende Importe passieren allevalidateund schlagen erst beim Kompilieren fehl. - Betrachte das Bild. Öffne das PNG in
preview/(Read-Tool auf der.png-Datei) und beurteile es: überlappende Labels, verhedderte Kanten, falsche Flussrichtung, ein unausgeglichenes Layout. Korrigiere und rendere erneut. Ein Diagramm, das zwar kompiliert, aber unlesbar ist, ist nicht fertig. - Liefere die
.d2-Quelldatei sowie die gerenderte Datei aus und gib an, welche Layout-Engine, welches Theme und welche Richtung du verwendet hast, damit der Benutzer sie ändern kann.
Für eine schnelle Einmal-Nutzung ohne Dateien: echo 'a -> b' | d2 - out.svg.
Syntax auf einen Blick
direction: right # up | down | right | left (Root-Ebene; nur TALA erlaubt pro Container)
# Shapes: Schlüssel, optionales Label, optionale Attribute
web: Web App {shape: rectangle} # Schlüssel `web`, Label "Web App"
db: Postgres {shape: cylinder}
user: Customer {shape: person}
# Verbindungen: -> <- <-> -- (verwende immer SCHLÜSSEL, niemals Labels)
user -> web: verwendet
web -> db: SQL {style.stroke-dash: 3}
web -> cache: liest # undeklarierte Schlüssel werden spontan erzeugt
# Container: Punkte oder verschachtelte Maps
backend: {
api -> worker: enqueue
worker -> _.db: schreibt # _ = übergeordneter Gültigkeitsbereich
}
web -> backend.api: HTTPS
# Styling lebt in Attributen
db.style.fill: "#e6f2ff" # Alles, was mit # beginnt, in Anführungszeichen setzen
(web -> db)[0].style.stroke: red # Verbindung über Index stylen
# Wiederverwendung: Klassen, Variablen, Globs
classes: {
store: {shape: cylinder; style.fill: "#e6f2ff"}
}
cache.class: store
vars: {env: prod}
note: Läuft in ${env}
*.style.border-radius: 8
Semikolons trennen Elemente in einer Zeile. # beginnt einen Kommentar, """ ... """ ist ein Blockkommentar. Schlüssel sind Groß-/Kleinschreibung-unabhängig und wiederholte Deklarationen werden zusammengeführt (API, api und Api: Gateway sind ein Shape mit dem Label "Gateway").
Anführungszeichen: Die häufigste Fehlerquelle
Unquotierte Zeichenketten sind praktisch, aber einige Zeichen haben eine Bedeutung. Setze das gesamte Label ("..." oder '...') in Anführungszeichen, wenn es eines dieser Zeichen enthält, sonst erzeugt der Compiler entweder einen Fehler oder, schlimmer noch, kürzt das Label stillschweigend:
| Zeichen | Was ohne Anführungszeichen passiert | Beispiel-Korrektur |
|---|---|---|
# irgendwo | Rest der Zeile wird zum Kommentar: a: C# language rendert "C" | a: "C# language" |
[ am Anfang | Wird als Array geparst: a: [JSON/HTTPS] rendert nur "a" | a: "[JSON/HTTPS]" |
. in einem Schlüssel | Erzeugt einen Container: svc v1.2 wird zu svc v1 > 2 | "svc v1.2" |
& oder [ ] in einem Schlüssel | Parse-Fehler (& ist der Glob-Filter-Marker) | "R&D", "svc[0]" |
$ gefolgt von allem außer { | "Substitutions must begin on {" | Einfache Anführungszeichen: 'kostet $5' |
{ } ` | ` am Label-Anfang | Öffnet eine Map oder einen Block-String |
Reservierte Wörter als Shape-Schlüssel (label, link, class, top, style, shape, icon, near, direction, vars …) | "Reserved keywords are prohibited in edges" | "link" -> b, oder anderen Schlüssel wählen |
-> oder : innerhalb eines Kanten-Labels | Funktioniert in der Praxis (a -> b: Zeit: 10s funktioniert) | Keine Anführungszeichen nötig |
Nicht-ASCII-Interpunktion wie : (vollbreites Doppelpunkt) | Wird nicht als Doppelpunkt erkannt | ASCII : ; . verwenden |
Hex-Farben müssen in Anführungszeichen gesetzt werden ("#fff"), da # einen Kommentar beginnt. Einfache Anführungszeichen deaktivieren auch ${...}-Substitution.
Zeilenumbrüche in Labels: \n in einem quotierten oder unquotierten Label, oder ein Block-String |md ... | für Rich-Text.
Fallstricke (vor dem Debuggen lesen)
- Dagre, die Standard-Layout-Engine, kann keine Verbindung zwischen einem Container und seinem eigenen Nachfahren zeichnen (
a -> a.b), kann Container nicht dimensionieren (width/height) und kannnear: <objekt>nicht verwenden. Sie liefert einen Fehler beim Kompilieren. Wechsle zu--layout=elk(odervars.d2-config.layout-engine: elk), anstatt das Diagramm umzuschreiben. - Reservierte Wörter werden unabhängig von der Groß-/Kleinschreibung erkannt. Ein Shape oder eine UML-Klasse namens
Shape,Label,Class,Style,Link,Icon… kollidiert mit dem Schlüsselwort (reserved field shape does not accept composite). Benenne es um. - Verbinde Schlüssel, nicht Labels. Nach
be: BackenderzeugtBackend -> xein neues Shape namens Backend. Verwendebe -> x. - Wiederholte Verbindungen werden nicht zusammengeführt;
a -> bzweimal zeichnet zwei Pfeile. Adressiere sie als(a -> b)[0],(a -> b)[1]. d2-legendist eine Variable, kein Shape: platziere sie innerhalb vonvars: { d2-legend: { ... } }. Eind2-legend: ""auf oberster Ebene ist nur ein gewöhnliches Shape namens "d2-legend".- Sequenzdiagramme: Die Reihenfolge der Deklaration ist die Reihenfolge auf dem Bildschirm, Akteure sollten zuerst deklariert werden, und innerhalb von Gruppen kannst du nur auf Akteure verweisen, die auf oberster Ebene existieren.
- SQL-Tabellen und UML-Klassen: Verbinde Zeilen (
orders.user_id -> users.id), und verwende ELK oder TALA, damit die Kanten auf der exakten Zeile landen. - Pfeilspitzen-Formen werden nur an einem Ende gerendert, das einen Pfeil hat:
A -> Bmitsource-arrowhead.shape: diamondzeichnet nichts bei A (und--zeichnet überhaupt keine Formen). Drehe die Kante um, sodass die Form am Ziel ist, oder verwende<->. d2 fmtschreibt Labels mit reservierten Wörtern um (lnk: Linkwird zulnk: link), undscripts/d2check.shführt fmt direkt in deiner Datei aus. Setze solche Labels in Anführungszeichen (lnk: "Link").- Block-Strings
|md ... |enden beim nächsten|. Ein wörtlicher Pipe-Strich im Inneren benötigt ein längeres Trennzeichen:|md ...|oder||md ... ||. - Numerische Style-Bereiche werden erzwungen:
stroke-width0–15,opacity0–1,font-size8–100.text-transformakzeptiertnone|uppercase|lowercase|capitalize(die Website sagttitle; der Compiler lehnt es ab).3dfunktioniert nur bei Rechteck, Quadrat und Sechseck. - Füge
animated: trueoderdark-theme-idnicht hinzu, wenn nicht danach gefragt. Animation impliziert Laufzeit-Datenfluss; ein dunkles Theme wechselt stillschweigend die Farben für Betrachter, deren Betriebssystem den Dunkelmodus verwendet. - Füllfarben auf Shapes überschreiben das Theme. Bevorzuge das Theme und ein paar
classes; verwende explizite Farben nur, wenn Farbe eine Bedeutung trägt (und füge dann eine Legende hinzu). - PNG/PDF/PPTX/GIF rendern in v0.9+ ohne Browser. Ältere Versionen (<0.8) benötigen Playwright/Chromium, das bei der ersten Verwendung heruntergeladen wird. Prüfe
d2 --version. - TALA ist in v0.9 enthalten (
--layout=tala), aber nicht deterministisch: Eine winzige Label-Änderung kann das Layout neu anordnen. Fixiere es mitdata.tala-seeds, wenn Reproduzierbarkeit wichtig ist. - Multi-Board-Dateien (
layers/scenarios/steps) exportieren SVG und PNG als Verzeichnisse (x/index.svg,x/layers/a.svg), und das Rendern von PNG mit demselben Namen ersetzt das SVG-Verzeichnis. Halte Formate in getrennten Ordnern (das Skript macht das). Für ein Drill-Down-Ergebnis verwende PDF (eine Seite pro Board, anklickbarlink: layers.x) und zeichne keine "Zurück"-Shapes von Hand: Der Export fügt automatisch eine Breadcrumb-Leiste hinzu. Siehereferences/composition.md. - Die Existenz einer Ausgabedatei bedeutet nicht Erfolg. D2 kann bei einem Fehler ein partielles Rendering schreiben. Überprüfe den Exit-Code (das Skript macht das).
Layout, Richtung und Theme wählen
- Layout-Engine:
dagre(Standard, schnell, geschwungene Kanten) ->elk(orthogonale Routenführung, am besten für Architektur, SQL-Tabellen, Container-zu-Container-Kanten) ->tala(Symmetrie,directionpro Container,near: objekt, festetop/left). Verwende standardmäßig ELK für alles mit Containern oder Tabellen. - Richtung:
rightfür Pipelines, Request-Flows und breite Bildschirme;downfür Hierarchien und Organigramme. Wähle eine Richtung für das gesamte Board. - Theme:
theme-id: 0Standard;4Cool Classics und3Flagship Terrastruct wirken modern;1neutrales Grau für sachliche Dokumente;8ist farbenblind-sicher;300/301Terminal;303C4;200/201dunkel. Vollständige Tabelle inreferences/cli-and-rendering.md. - Platziere Render-Einstellungen in der Datei, damit sie mit ihr reisen:
vars: {
d2-config: {
layout-engine: elk
theme-id: 4
pad: 40
}
}
(CLI-Flags und D2_*-Umgebungsvariablen überschreiben diesen Block.)
Gestaltungshinweise
- 3 bis 12 Shapes pro Board. Darüber hinaus teile mit
layers(Vergrößerung),scenarios(Varianten) odersteps(Aufbau) auf, oder verwende Container zur Gruppierung. - Benennung nach Schlüssel, Label für Menschen: kurze stabile Schlüssel (
pg,auth), lesbare Labels (pg: PostgreSQL). - Kanten-Labels sind Verben oder Protokolle (
liest,veröffentlicht,HTTPS), keine Sätze und nicht der Name des Ziels. - Shape der Bedeutung anpassen:
cylinderSpeicher,queue,person,cloudextern,diamondEntscheidung,hexagonDienst,document/page,package,step. Nicht alles als Rechteck belassen. - Farbe kodiert Bedeutung oder nichts. Maximal ~5 Kategorien, angewendet über
classes, mit einemd2-legendnur, wenn die Farben Informationen vermitteln, die die Labels nicht tun. - Eine Abstraktionsebene pro Board.
- D2 dient der Dokumentation von Software und Systemen im Whiteboard-Maßstab (bis zu ein paar hundert Shapes). Es hat bewusst keine Gantt-Diagramme, Mindmaps, Venn-Diagramme, Sankey-, Kreis-/Balkendiagramme oder geografische Karten, und ein Objekt kann nicht in zwei Containern gleichzeitig sein. Sage das und schlage ein anderes Werkzeug vor, anstatt D2 zu verbiegen.
Referenzkarte
Lies nur, was die Aufgabe benötigt.
| Aufgabe | Lese dies |
|---|---|
| Syntax-Zweifel: Schlüssel, Labels, Verbindungen, Container, Strings, Escaping, Kommentare, reservierte Schlüsselwörter | references/language.md |
Shapes, jeder Style-Key und sein Bereich, Pfeilspitzen, Text/Markdown/LaTeX/Code, Icons, near-Positionierung, Größen, Themes | references/shapes-and-styling.md |
| Sequenzdiagramme, SQL-Tabellen (ERD), UML-Klassen, Gitter, Legenden, Tooltips/Links, C4 | references/diagram-types.md |
Klassen, Variablen, Globs und Filter, Überschreibungen und null, Importe, suspend-Modelle | references/reuse-and-globs.md |
| Layer, Szenarien, Schritte, Boards verlinken, Importe für große Diagramme, Multi-Board-Export | references/composition.md |
CLI-Flags, Layout-Engines, Themen-Tabelle, Exportformate, d2-config, Einbettung in Docs/CI, D2.js | references/cli-and-rendering.md |
| Fertige Muster pro Diagrammfamilie (Architektur, Flussdiagramm, Zustand, ERD, C4, Organigramm …) | references/recipes.md + assets/templates/*.d2 |
| Konvertierung aus Mermaid / PlantUML / Graphviz | references/recipes.md (Abschnitt Konvertierung) |
| Eine Fehlermeldung oder ein Diagramm, das falsch rendert | references/troubleshooting.md |
Wenn die Kompilierung fehlschlägt
Führe scripts/d2check.sh datei.d2 aus. Fehler erscheinen als datei:ZEILE:SPALTE: nachricht. Schlage die Nachricht in references/troubleshooting.md nach; die üblichen Übeltäter sind Anführungszeichen (oben), eine Layout-Engine-Grenze (zu ELK wechseln), ein unbekanntes Shape oder ein außerhalb des Bereichs liegender Style sowie Einrückungen von Block-Strings. Korrigiere einen Fehler nach dem anderen und führe erneut aus: Spätere Fehler sind oft Folgen des ersten.