About reladraw
reladraw is a text language for producing standalone SVG diagrams, aimed at designers and developers who need explicit control over node placement and lines. It does not auto-arrange layouts; it draws the relative positions in the source and reports issues such as overlaps.
Key features
- 01Describe diagrams and relative positions in text
- 02Generate SVG without runtime dependencies
- 03Define nodes, containers, styles, and edges
- 04Check and report diagram overlaps
- 05Format files and explain syntax errors
Use cases
- 01Draw system diagrams with predictable placement
- 02Specify exact layouts for nodes and edges
- 03Check diagrams for text or line overlaps
- 04Format and maintain .reladraw source files
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ reladraw/ reladraw --skill reladrawAfter installing, type/reladrawin Claude Code to confirm it loaded.
Bundled filesreference/syntax.md
Details
From the project READMEreladraw
A text language for diagrams. Source in, standalone SVG out, no runtime dependencies.
Every other diagram language hands the arrangement to a layout engine, so where things land is an output you can't predict from what you wrote. reladraw inverts that: the file states the arrangement in the terms a person would say out loud (right of api, below worker (gap: tight), even with queue), and the tool draws exactly that. It never chooses an arrangement, never moves a box to make room, and never routes a line round anything.
That matters here specifically. You can't see the SVG you produced. With auto-layout that leaves you guessing; with reladraw the arrangement is in the sentences you just wrote, and where the picture may not read as meant, the tool tells you in words.
Check it is installed, and the same version as this skill
This skill teaches reladraw 0.19.0. Once per session, before the first render, run:
reladraw --version
- The same: say nothing.
- Older, or
--versionisn't recognized (it arrived in 0.17.1): the tool is older than this page and will refuse some of what it teaches. Tell the user, and give themnpm install -g reladraw@latest. - Newer: this skill is out of date. Tell the user, and give them
npx skills add reladraw/reladraw -gto refresh it. Carry on meanwhile; where an error names a replacement spelling, trust the error over this page.
If reladraw isn't installed, npx reladraw works without installing, and npm install -g reladraw installs it.
The loop
- Write a
.reladrawfile. reladraw render diagram.reladraw -o diagram.svg. (-o -writes to stdout; the default is the input path with.svg.)- If it fails, the error names the line and what to write instead. Fix and re-run.
- If it succeeds, read the findings it printed. Each is one line saying what may not read as meant, where, and how much:
diagram.reladraw:12: warning(text-overlap): text "statements" covers the top-left corner of node resolver; the overlap is 3 units wide and 2 units tall
diagram.reladraw:9: warning(edge-node-overlap): line api -> db crosses node cache, in and out of its top
- Fix each finding in the source, by placing something differently or saying where a line goes, and re-run until there are none.
reladraw check diagram.reladrawprints the findings without writing the SVG. reladraw format diagram.reladrawbefore handing the file over. It lines statements up in columns and evens out spacing, by the project's.reladraw-formatif there is one, and changes nothing about what the file draws. A file you wrote then reads like one the user's project already has.
A file with no errors and no findings has nothing on top of anything. That is still not the same as a good picture: re-read your source to confirm the arrangement says what you meant, and for a large diagram tell the user you have checked the findings but not seen the render.
The one idea
The file says where things go, and the tool draws exactly that. A gap is the distance you wrote. A box goes where its placements put it and nothing pushes it. A line is straight between its two boxes unless you say it is square or curved or name the places it passes. Anything that overlaps is drawn overlapping and reported.
So the fix for a problem is always more said in the source, never hoping the tool will sort it out. Two boxes on one spot: place one against the other. A line through a box: say where it passes with via:. A text crowding a box: widen the gap.
Writing a file
A statement starts at the beginning of a line. A long one continues onto following lines that are indented; a blank or unindented line ends it. Indentation never puts one thing inside another. // starts a comment and may trail a statement.
A statement is a positional head (the keyword, a name, then a text) followed by attributes and placements in any order. A word ending in a colon opens an attribute and nothing else does.
Nodes
node <name> ["<text>" [(<text settings>)]] [<placement> | <attribute>] ...
Leave the text out and the node shows its name (node parser reads "parser"). Write "" for a deliberately blank node. Inside a text, / (a slash with a space on each side) is a line break; TCP/IP and URLs survive.
The body is shape: rectangle | document | circle | diamond | pill | parallelogram | hexagon | trapezoid | triangle | cylinder | none (none is bare text, for notes and captions; a flowchart shape with no geometric name is flow- and its meaning, such as flow-subprocess or flow-delay; settings follow in a bracket, shape: triangle (aim: up)) or icon: disk | desktop | laptop | package | cubes | cube | database, a picture with no box. badge: <icon> puts a picture beside the text as part of the label. A picture outside the set is declared with icon <name> and SVG between """ marks; prefer the built-ins.
node dump "nightly dump" shape: document
node unit icon: cube right of dump
node drive "External HD" badge: disk below dump
node aside "a remark that folds" (wrap: 20) shape: none right of drive
Placing
above X below X left of X right of X
above-left of X above-right of X below-left of X below-right of X
even with X top even with X bottom even with X left even with X right even with X
- Exactly one node in the file is unplaced, the anchor. Every other is placed against something, directly or through others.
- A gap is exact:
none,tight,normal(the default) orwide, in the placement's bracket,right of a (gap: tight), or a number of the file's unit in front,2 right of a. A normal box is about 4 units tall. - A lone direction also centers on its target.
right of aalone puts the box level witha. Another placement on that axis replaces the centering:right of a even with b. - Each axis is stated once. Two placements on one axis are refused. The one exception:
right of a left of bcenters the box in the space between them, and then something must say how high. - Several targets are one region:
below a and bsits under the pair, centered between them. - Nothing moves a box. Two boxes placed
right of aboth land on one spot and are reported. Chain them (b right of a,c right of b) or put them in a container with a layout.
Containers
A dotted name is a child: server.api is inside server, and the parent is declared first. A container is the box round its children. Arrange them one of two ways:
node server "Server" layout: column (widths: match)
node server.api "API"
node server.worker "Worker"
node lab "Lab" right of server (gap: wide)
node lab.pc "PC"
node lab.nas "NAS" right of lab.pc (gap: tight)
layout: column or layout: row puts the children in written order; its bracket takes gap:, widths: match, and align-children: left | center | right. Without a layout, exactly one child is unplaced and the rest are placed against it. shape: none on a container draws no box, which makes a group you can place things against as one shape.
A title goes (inside top) by default, centered along it; (inside top, align: left) puts it at the top left, and (on top) or (outside top) sit it on or above the border.
Text
Everything a text says about itself goes in brackets after it: color, size (small | normal | large), wrap (fold every n characters) and align.
style dim text: (color: theme-muted)
node grinder "Grinder / [dim]medium-fine[/dim]"
node note "a longer remark that folds" (size: small, wrap: 30) shape: none below grinder (gap: tight)
[dim]…[/dim] borrows a style's look for a stretch of text. A style hangs the bracket off a key: style aside text: (size: small, color: theme-muted). Always give bare text a (wrap: n), or a sentence is one long line across whatever is beside it.
Lines
edge [<name>] <from> -> <to> ["<text>" [(<placement>)]] [attributes]
<-, <-> and -- work too, and each end may carry a mark: a <|-- b, a *--o b, a diamond--> b. from: and to: name the side of the first and second name written: from: right to: left.
- Straight by default, between the two boxes and through anything in between, which is reported.
line: (path: square)orline: (path: curved)for a route read off the line's own two boxes and sides. via:lists the places a line passes:via: cache topruns just abovecache;via: between a and bgoes through the point between them;via: proxygoes through a box's center. This is how to take a line round something.- A text sits at the middle of its line. Place it with
(at: start),(at: 1/4),(above edge),(on: longest level)or(above some_box). Texts never move boxes, so give a labeled line room: anormalgap is too short for a word, so use(gap: 12)or so between boxes joined by a labeled line. line: (pattern: dashed, thickness: thick, corners: rounded, color: #d2904e);line: redalone is the color.
Against a part of a box
node bob "Bob the builder" (inside top) height: 7
node bob_link "bob.example.com" (size: small) inside bob bottom-center shape: none
node count "3" on bob top-right shape: circle
A box's parts are its text, its sides top, bottom, left, right, and nine points (top-left, top-center, … center … bottom-right). inside tucks a node within the box against that part, outside puts it beyond, on centers it on the part.
Styles and colors
style store fill: theme-primary-subtle border: theme-primary badge: database
node records "Records" style: store
fill is a box's area, border its outline, line an edge's line, and a text's color goes in its bracket. corners: sharp squares a box's rounded corners. Prefer theme colors, which read in light and dark themes alike: theme-primary and theme-secondary are the accents, -subtle is an accent softened toward the page (the one to fill a box with), theme-muted is quieter text. A hex or CSS color stays fixed in every theme.
A complete small file
// A request path, left to right.
style store fill: theme-primary-subtle border: theme-primary badge: database
node browser "Browser"
node api "API server" right of browser (gap: 10)
node db "Postgres" right of api (gap: 10) style: store
node worker "Worker" below api (gap: wide)
edge browser -> api "HTTP"
edge api -> db "SQL"
edge worker -> db "writes" to: bottom line: (path: square)
node aside "The worker shares the database / but takes no HTTP traffic." (wrap: 30) shape: none below worker (gap: tight)
What will bite you
- Two boxes placed the same way.
node b right of aandnode c right of aputbandcon one spot. Placecagainstb, or use a container withlayout:. - A labeled line between close boxes. The text sits on the line and nothing widens the gap, so it covers the boxes and is reported. Give the placement a larger gap.
- Two unplaced boxes. Only one may be. The error names both.
- Saying an axis twice.
right of a even with ais fine;below a even with bis two statements about height, and refused. - Old syntax.
level withiseven with;gap:on a node goes in a placement's bracket; edge clauses likebelow candbetween a and barevia: c bottomandvia: between a and b;contents:islayout: column (…);at:on a node's text is(inside top, align: left)and the like;deck:is a container,layout: deck cards: "Drive 1" "Drive 2". Each is refused with what to write instead. note,boxorlink. Not statements: a note isnode … shape: none, and the keywords arenodeandedge.- A coordinate. None exist. Every position is relative to something in the diagram.
#as a comment. It opens a hex color; comments are//.- Guessing from another language. No braces, no semicolons, no subgraphs. If you want something not written here, check
reference/syntax.mdbefore inventing it.
Reference
reference/syntax.md is the full syntax reference: every construct, points and regions, waypoints and named legs, bundles, sizes, guides, drawing order, the findings, what the language refuses and why, and what changed in each version. Read it when you need a construct this page doesn't cover, or when an error or a finding points at behavior you didn't expect.