Skip to content

SDK Reference

The Diagram class is the main interface for creating diagrams. All methods return element IDs that can be used with connect(), addGroup(), and editing methods.

Create a new diagram with optional configuration:

const d = new Diagram(); // defaults
const d = new Diagram({ direction: "LR" }); // left-to-right layout
const d = new Diagram({ theme: "sketch" }); // hand-drawn style
const d = new Diagram({ type: "sequence" }); // sequence diagram mode

Constructor options:

OptionTypeDefaultDescription
direction"TB" | "LR" | "RL" | "BT""TB"Layout direction (top-bottom, left-right, etc.)
theme"default" | "sketch" | "blueprint" | "minimal""default"Visual theme preset
type"architecture" | "sequence""architecture"Diagram type

Set a theme preset that applies defaults to all subsequently added shapes.

d.setTheme("sketch"); // hand-drawn: hachure fill, roughness 2
d.setTheme("blueprint"); // technical: clean lines, Cascadia font
d.setTheme("minimal"); // minimal: thin strokes, Helvetica, 90% opacity

Available themes:

ThemeFill StyleRoughnessStroke WidthFontOpacity
defaultsolidVirgil
sketchhachure2Virgil
blueprintsolid01Cascadia
minimalsolid01Helvetica90

Per-node options always override theme defaults.

Set the layout direction after construction.

d.setDirection("LR"); // switch to left-to-right

Add a rectangle element. Returns the element ID. Labels support \n for line breaks — the shape auto-sizes to fit.

const id = d.addBox("API Gateway", { row: 0, col: 1, color: "backend" });
const id2 = d.addBox("Master DO\n(Single Writer)", { color: "storage" }); // multi-line

Add an ellipse element. Returns the element ID.

const id = d.addEllipse("Start", { row: 0, col: 0, color: "users" });

Add a diamond shape (for flowchart decisions). Returns the element ID.

const id = d.addDiamond("Is Valid?", { row: 1, col: 1, color: "orchestration" });

Add standalone text (no container). Returns the element ID.

const id = d.addText("System Overview", {
x: 100, y: 50,
fontSize: 24,
fontFamily: 2, // Helvetica
});

Text options:

OptionTypeDescription
xnumberAbsolute x position
ynumberAbsolute y position
fontSizenumberFont size (default 16)
fontFamily1 | 2 | 3Virgil / Helvetica / Cascadia
colorColorPresetSemantic color preset
strokeColorstringHex color override

Add a line element. Returns the element ID.

const id = d.addLine([[0, 0], [200, 100]], {
strokeColor: "#e03131",
strokeWidth: 2,
strokeStyle: "dashed",
});

Group elements with a dashed boundary. Returns the group ID.

const db = d.addBox("Postgres", { row: 1, col: 0, color: "database" });
const cache = d.addBox("Redis", { row: 1, col: 1, color: "cache" });
d.addGroup("Data Layer", [db, cache]);
d.addGroup("VPC", [svc1, svc2], { padding: 50, strokeColor: "#e03131" });

Group options:

OptionTypeDefaultDescription
paddingnumber30Pixels of padding around children
strokeColorstring#868e96Hex color for the group boundary
strokeStyle"solid" | "dashed" | "dotted""dashed"Boundary line style
opacitynumber60Group boundary opacity (0-100)

Add a native Excalidraw frame container. Returns the frame ID.

const svc1 = d.addBox("Service A", { color: "backend" });
const svc2 = d.addBox("Service B", { color: "backend" });
d.addFrame("Microservices", [svc1, svc2]);

Remove a group or frame container. Children are kept.

Connect two elements with an arrow.

d.connect(api, db, "queries");
d.connect(api, cache, "reads", { style: "dashed" });
d.connect(a, b, "flow", { startArrowhead: "dot", endArrowhead: "triangle" });
d.connect(a, b, "near source", { labelPosition: "start" });
d.connect(a, b, "near target", { labelPosition: "end" });

Load an existing .excalidraw file for modification.

const d = await Diagram.fromFile("diagram.excalidraw");

Find node IDs by label match. Substring match by default, exact with opts.exact.

const ids = d.findByLabel("API"); // substring match
const ids = d.findByLabel("API", { exact: true }); // exact match

Get all node IDs.

const allNodes = d.getNodes();

Get all edges.

const edges = d.getEdges();
// [{ from: "id1", to: "id2", label: "queries" }, ...]

Get properties of a specific node by ID.

const info = d.getNode(id);
// → { label, type, width, height, backgroundColor, strokeColor, row, col }

Returns undefined if the ID doesn’t exist.

Update a node’s properties.

d.updateNode(ids[0], { label: "New API", color: "ai" });

Update an existing edge’s properties. Optional matchLabel disambiguates when there are multiple edges between the same nodes.

d.updateEdge(api, db, { label: "writes", style: "dashed" });

Remove a node and its connected edges.

d.removeNode(d.findByLabel("Old Service")[0]);

Remove an edge between two nodes. Optional label disambiguates multi-edges.

d.removeEdge(api, db, "queries");

Create sequence diagrams with actors and messages:

const d = new Diagram({ type: "sequence" });
const client = d.addActor("Client");
const api = d.addActor("API Server");
const db = d.addActor("Database");
d.message(client, api, "POST /login");
d.message(api, db, "SELECT user");
d.message(db, api, "user record");
d.message(api, client, "JWT token");
// Self-messages
d.message(api, api, "validate token");
return d.render();

Add a sequence diagram actor. Returns the actor ID. Uses the same ShapeOpts as addBox.

Add a message between actors. Uses the same ConnectOpts as connect. Self-messages (same actor) render as rectangular loops.

Convert the current diagram state back to TypeScript SDK code. Produces compact, readable code that recreates the diagram — useful for debugging, sharing, and editing existing diagrams.

const code = d.toCode();
// Returns TypeScript like:
// const d = new Diagram();
// const api = d.addBox("API Gateway", { row: 0, col: 1, color: "backend" });
// ...
// With a file path for render output:
const code = d.toCode({ path: "architecture.excalidraw" });

Features:

  • Reverse-maps hex colors back to named presets ("#d0bfff""backend")
  • Generates camelCase variable names from labels
  • Extracts shared styles when 3+ nodes share the same non-positional options
  • Avoids JavaScript reserved words in variable names

A .drawmode.ts sidecar file containing toCode() output is automatically written alongside any file output from render().

Convert Mermaid syntax into a Diagram for further modification:

const d = Diagram.fromMermaid(`
graph LR
A[API Gateway] --> B[Auth Service]
A --> C[Order Service]
B --> D[(Database)]
`);
d.updateNode(d.findByLabel("API Gateway")[0], { color: "backend" });
return d.render();

Supported: graph TD/LR/RL/BT, node shapes ([], {}, (()), [()]), edges (-->, ---, -..->, ==>), edge labels (|label|), subgraphs, chained edges.

Render the diagram. Always return this from your code.

return d.render(); // default: excalidraw JSON
return d.render({ format: "url" }); // shareable URL
return d.render({ format: "excalidraw", path: "out.excalidraw" }); // write file
return d.render({ format: "png", path: "out.png" }); // PNG image
return d.render({ format: "svg", path: "out.svg" }); // SVG markup
return d.render({ format: ["excalidraw", "svg"] }); // both formats at once

Render options:

OptionTypeDefaultDescription
formatstring | string[]"excalidraw"Output format(s). Pass an array for multiple outputs.
pathstringBase file path (extensions derived per format)

Return type (RenderResult):

FieldTypeDescription
jsonobjectRaw Excalidraw JSON
urlstring?excalidraw.com shareable link
filePathstring?Local file path if written
filePathsstring[]?All file paths written (multi-format)
pngBase64string?Base64-encoded PNG (format=“png”)
svgStringstring?SVG markup string (format=“svg”)

A .drawmode.ts sidecar file is always written alongside any file output, preserving the source code for future iteration.

Nodes placed with row and col are positioned on a grid with these constants:

ConstantValueDescription
Column spacing280pxHorizontal distance between columns
Row spacing220pxVertical distance between rows
Base position(100, 100)Top-left starting position
Default shape width180pxMinimum width (auto-expands for long labels)
Default shape height80pxHeight (+24px per additional \n line)

For precise control, use x and y in ShapeOpts to bypass the grid entirely.

Options for addBox, addEllipse, and addDiamond:

OptionTypeDefaultDescription
rownumberGrid row position
colnumberGrid column position
colorColorPresetSemantic color preset
widthnumberElement width
heightnumberElement height
xnumberAbsolute x position (bypasses grid)
ynumberAbsolute y position (bypasses grid)
strokeColorstringHex stroke color override
backgroundColorstringHex background color override
fillStyle"solid" | "hachure" | "cross-hatch" | "zigzag""solid"Fill style
strokeWidthnumber2Stroke width
strokeStyle"solid" | "dashed" | "dotted""solid"Stroke style
roughnessnumber0=architect, 1=artist, 2=cartoonist
opacitynumber0-100
roundness{ type: number } | nullCorner roundness
fontSizenumber16Label font size
fontFamily1 | 2 | 31Virgil / Helvetica / Cascadia
textAlign"left" | "center" | "right"Text alignment
verticalAlign"top" | "middle"Vertical alignment
linkstring | nullHyperlink URL
customDataRecord<string, unknown> | nullArbitrary metadata
iconstringIcon preset ("database", "cloud", "lock", "server", "docker", "lambda", "api", "queue", "cache", "user", "k8s") or raw emoji

Options for connect():

OptionTypeDefaultDescription
style"solid" | "dashed" | "dotted""solid"Stroke style
strokeColorstringHex stroke color
strokeWidthnumberStroke width
roughnessnumberRoughness level
opacitynumber0-100
startArrowheadArrowheadnullStart arrowhead type
endArrowheadArrowhead"arrow"End arrowhead type
elbowedbooleanOrthogonal routing (Graphviz handles routing by default)
labelFontSizenumberLabel font size
labelPosition"start" | "middle" | "end""middle"Where to place the edge label along the arrow
customDataRecord<string, unknown> | nullArbitrary metadata

null | "arrow" | "bar" | "dot" | "triangle" | "diamond" | "diamond_outline"

See Color Presets for the full list with hex values.