v0.2 · Author diagrams

Learn the small Schemd grammar

Place nodes, connect named ports, and choose a route or UML relationship.

01 / NodesPlace a component on a bounded canvas

Every fence opens with a promise about space: bounds="WIDTHxHEIGHT", where both dimensions are integers from 64 to 4096. The compiler reserves exactly that canvas before it reads a single declaration — which is precisely why a schemd diagram never reflows the page it lands on.

A node, then, has one predictable shape. It is worth reading once, slowly:

kind:ID "label" at (x, y) color [options]

IDs are case-sensitive; coordinates live in the viewBox you just declared; and the [options] that follow depend entirely on the kind you chose. The color is a built-in token such as #blue, a safe CSS color, or a theme alias you resolve yourself.

port:VIN "Signal" at (60, 160) #blue
resistor:R1 "10 k\Omega" at (250, 160) #amber
capacitor:C1 "100 nF" at (470, 160) #cyan
port:VOUT "Filtered" at (700, 160) #emerald

VIN.out -> R1.in #blue [line]
R1.out -> C1.in #amber [ortho]
C1.out -> VOUT.in #emerald [line marker-end=arrow]
compiled by @schemd/core → shown in the rail

02 / ConnectionsConnect named ports

A connection is just as small — two named ports and an arrow between them:

ID.port -> ID.port color [options]

Now choose how the wire travels: line for a straight segment, bezier for a curve, or ortho for the obstacle-aware route. An orthogonal connection leaves each component through a short escape segment, steers clear of every other node's bounds, and — this is the part that matters — fails loudly with a useful error when no clear path exists, rather than drawing a junction that lies about the circuit.

Markers are optional on either end: marker-start=... and marker-end=... accept none, arrow, open-arrow, dot, triangle, diamond, or diamond-filled.

port:A "A" at (60, 90) #blue
port:B "B" at (60, 250) #slate
xor:G1 "Parity" at (390, 170) #cyan [inputs=2 outputs=1]
port:Y "Result" at (720, 170) #emerald

A.out -> G1.in1 #blue [bezier]
B.out -> G1.in2 #slate [ortho]
G1.out -> Y.in #emerald [line marker-end=arrow]
compiled by @schemd/core → shown in the rail

03 / UMLUse relationship names instead of hand-built markers

UML relationships are nothing more exotic than connection options: you name the relationship, and schemd supplies the marker and dash pattern the notation already expects. When you disagree with a default, an explicit marker — or a plain solid/dashed flag — overrides it.

Relation Default style
association Solid line
dependency Dashed, open arrow
generalization Hollow triangle at the target
realization Dashed, hollow triangle at the target
aggregation Hollow diamond at the source
composition Filled diamond at the source
message, transition Open arrow
include, extend Dashed, open arrow, automatic label

Add label="text" whenever the connector needs a name of its own.

class:Account "Account" at (220, 150) #slate [attributes="- id: UUID" operations="+ close(): void"]
class:Admin "Admin" at (620, 120) #blue [operations="+ suspend(): void"]
class:Session "Session" at (620, 310) #emerald [attributes="- token: string"]

Admin.left -> Account.right #blue [ortho generalization]
Account.right -> Session.left #emerald [ortho composition label="owns"]
compiled by @schemd/core → shown in the rail