Code Mode
LLM writes ~10 lines of TypeScript against a typed SDK. The SDK handles all Excalidraw complexity — labels, bindings, arrow math.
Code Mode
LLM writes ~10 lines of TypeScript against a typed SDK. The SDK handles all Excalidraw complexity — labels, bindings, arrow math.
Automatic Layout
Graphviz dot engine (Sugiyama algorithm) with crossing minimization and orthogonal edge routing.
28 Color Presets
10 semantic presets + 18 cloud provider presets for AWS, Azure, GCP, and Kubernetes.
Multiple Outputs
.excalidraw files, shareable excalidraw.com URLs, PNG images, and SVG exports.
Edit Existing Diagrams
Diagram.fromFile() loads .excalidraw files for modification — find, update, and remove nodes.
Deploy Anywhere
Local stdio, local HTTP, or Cloudflare Workers for remote MCP access.
Traditional MCP diagram tools ask the LLM to produce raw Excalidraw JSON — hundreds of lines with pixel coordinates, bound text element pairs, arrow binding math, and edge routing. This is fragile and error-prone.
drawmode flips the approach: the LLM writes ~10 lines of TypeScript against a typed SDK. The SDK handles all the Excalidraw complexity (labels need two elements, arrows need binding math, elbow routing needs specific flags). Graphviz handles layout. The result is always valid.
Traditional: LLM → 500 lines of JSON (~25,000 tokens) → broken diagramsdrawmode: LLM → 10 lines of TypeScript (~500 tokens) → SDK + Graphviz → valid diagramsThis ~50x context compression is not accidental — it’s the core thesis. Code is the optimal serialization format for LLM context windows because it’s semantically dense, composable, and LLM-native. Read more in Code-First Context Management.
const d = new Diagram();const api = d.addBox("API Gateway", { row: 0, col: 1, color: "backend" });const db = d.addBox("Postgres", { row: 1, col: 0, color: "database" });const cache = d.addBox("Redis", { row: 1, col: 2, color: "cache" });d.connect(api, db, "queries");d.connect(api, cache, "reads", { style: "dashed" });d.addGroup("Data Layer", [db, cache]);return d.render({ format: "url" });