Declart
Declare what to show. The engine decides how it looks.
Declart is a declarative diagram engine. You write a TOML file describing the structure of your diagram, and Declart renders it to SVG. No layout coordinates. No styling choices. Just content.
Quick Start
CLI
# Install
cargo install declart-cli
# Scaffold a starter diagram
declart init flow > diagram.toml
# Render to SVG
declart render diagram.toml
# Render to PNG
declart render diagram.toml --format png
# Watch and auto-rebuild on changes
declart watch diagram.toml
# Validate without rendering
declart validate diagram.toml
Node.js
const declart = require('@iyulab/declart');
const svg = declart.render(`
kind = "flow"
view = "cycle"
title = "PDCA"
[[items]]
label = "Plan"
[[items]]
label = "Do"
`);
Rust (library)
#![allow(unused)] fn main() { use declart_core::{parse, render}; use declart_core::render::DEFAULT_THEME; let diagram = parse(input)?; let svg = render(&diagram, &DEFAULT_THEME)?; }
Supported Kinds
| Kind | Views |
|---|---|
flow | process (default), cycle, funnel, swimlane |
tier | pyramid (default) |
hierarchy | org_chart (auto), fishbone (auto) |
timeline | — |
matrix | — |
hub_spoke | — |
venn | — |
comparison | — |
state | — |
Design Philosophy
See Principles for the full design rationale. The key idea: declarations express what exists, not how it looks. The engine owns visual decisions.
Interactive Playground
→ Open the Declart Playground — no installation required
Edit TOML declarations and see your diagrams rendered live in the browser. All 8 diagram kinds are available, with default and monochrome themes.
Note: The playground requires HTTP to load the WASM module. Use
mdbook serve docs/for local testing rather than opening the file directly.
Declart Grammar Principles
These principles govern every declaration file format in Declart, across all diagram kinds and all implementations.
-
Design exclusion. Declaration files contain no visual information: no colors, coordinates, fonts, sizes, margins, or layout hints. These are the engine's domain.
-
Semantics only. Fields express meaning, not appearance.
emphasis: primaryis allowed;color: redis not. The engine decides how emphasis looks. -
LLM-predictable. Field names are single English words. Structure is flat or exactly one level deep (
[[items]]). A language model must be able to generate a correct declaration without examples. -
Minimal and concise. Each kind defines only its required fields. Optional fields are added only when proven necessary across multiple use cases. When in doubt, leave it out.
-
One representation per diagram. Each
kind + viewpair has exactly one valid schema. No aliases, structural variants, or flags that change interpretation. Two declarations expressing the same diagram are byte-for-byte identical except for whitespace.
Common Schema Rules
Rules that apply to every Declart declaration file.
Required fields
| Field | Type | Description |
|---|---|---|
| kind | string | One of: flow, tier, hierarchy, timeline, matrix, hub_spoke, venn, comparison |
Optional fields
| Field | Type | Description |
|---|---|---|
| title | string | Display title rendered above the diagram. Omit to suppress. |
| view | string | Rendering intent within the kind. Valid values depend on kind. Omit to let the engine select automatically. |
Item arrays
- Items are declared as
[[items]]TOML array-of-tables. - At least one item is required for
flowandtier. Thematrixkind uses[[quadrants]];hierarchyuses[[nodes]];timelineuses[[events]];hub_spokeuses[[spokes]];vennuses[[sets]];comparisonuses[[columns]]and[[rows]]. - Item order in the file is rendering order.
Forbidden fields
Any field not listed in a kind's spec document is forbidden. Forbidden fields cause a parse error. This includes but is not limited to: color, fill, stroke, font, size, x, y, width, height, style, class.
Emphasis (shared optional item field)
When a kind supports item-level emphasis, it uses this field:
| Value | Meaning |
|---|---|
primary | Most important item in the diagram |
secondary | Secondary importance |
The engine decides visual representation. Omitting emphasis means default weight.
primary: white outline stroke + bold textsecondary: lighter color tint
Using Claude or GPT to Generate Declart Diagrams
Declart's TOML format is designed for LLM generation. The structure is explicit and validated — an LLM can produce a well-formed diagram in one shot, and declart validate catches any mistakes before rendering.
Why Declart works well with LLMs
- No layout decisions: the LLM only writes content (labels, structure). The engine handles all visual choices.
- Strict schema:
deny_unknown_fieldsmeans invalid keys are caught immediately. The LLM cannot silently produce a broken diagram. - Explicit kind: the
kindfield tells the parser exactly what to expect. No ambiguity. - Short format: a typical diagram is 5–20 lines of TOML.
Kind and View
Declart v0.16+ uses a two-level structure:
kind— the data contract (determines which fields are valid)view— the semantic intent (determines how the engine renders it)
| kind | views | Notes |
|---|---|---|
flow | process (default), cycle, funnel | view optional — defaults to process |
tier | pyramid (default) | Ranked levels — view optional |
hierarchy | org_chart, fishbone | view optional — auto-selected by root count |
timeline | — | No view field |
matrix | — | No view field |
hub_spoke | — | No view field |
venn | — | No view field |
comparison | — | No view field |
Workflow
1. Prompt LLM → TOML output
2. declart validate diagram.toml # catches errors with clear messages
3. declart render diagram.toml # produces SVG
If validate fails, paste the error message back to the LLM and ask it to fix the specific field.
Prompt Templates
Tier (Pyramid) — Hierarchies, priority layers
Prompt: "Generate a Declart TOML diagram showing Maslow's hierarchy of needs as a pyramid. Use kind = 'tier', include a title, and list the 5 levels as items from top (apex) to bottom (base)."
kind = "tier"
title = "Maslow's Hierarchy of Needs"
[[items]]
label = "Self-Actualization"
[[items]]
label = "Esteem"
[[items]]
label = "Love & Belonging"
[[items]]
label = "Safety"
[[items]]
label = "Physiological"
emphasis = "primary"
Process — Sequential steps, workflows
Prompt: "Create a Declart TOML diagram for a 4-step CI/CD pipeline. Use kind = 'flow' (process view is the default)."
kind = "flow"
title = "CI/CD Pipeline"
[[items]]
label = "Build"
[[items]]
label = "Test"
emphasis = "primary"
[[items]]
label = "Stage"
[[items]]
label = "Deploy"
Cycle — Closed loops, PDCA, lifecycles
Prompt: "Generate a Declart TOML diagram for the PDCA improvement cycle. Use kind = 'flow' and view = 'cycle'."
kind = "flow"
view = "cycle"
title = "PDCA Cycle"
[[items]]
label = "Plan"
[[items]]
label = "Do"
[[items]]
label = "Check"
[[items]]
label = "Act"
Matrix 2×2 — Prioritization, Eisenhower
Prompt: "Create an Eisenhower Matrix in Declart TOML with x_axis = 'Importance' and y_axis = 'Urgency'."
kind = "matrix"
title = "Eisenhower Matrix"
x_axis = "Importance"
y_axis = "Urgency"
[[quadrants]]
label = "Do First"
position = "top-right"
emphasis = "primary"
[[quadrants]]
label = "Schedule"
position = "top-left"
[[quadrants]]
label = "Delegate"
position = "bottom-right"
[[quadrants]]
label = "Eliminate"
position = "bottom-left"
Note: Use
positionto explicitly place quadrants. Valid values:top-left,top-right,bottom-left,bottom-right.
Hub-and-Spoke — Central concept with related items
Prompt: "Make a Declart hub-and-spoke diagram with 'Cloud Architecture' as the center and 5 services as spokes."
kind = "hub_spoke"
title = "Cloud Architecture"
center = "API Gateway"
[[spokes]]
label = "Auth Service"
[[spokes]]
label = "User DB"
[[spokes]]
label = "Payment"
[[spokes]]
label = "Notifications"
[[spokes]]
label = "Analytics"
Venn — Set intersections, overlapping groups
Prompt: "Generate a 2-set Venn diagram showing the overlap between 'Frontend Skills' and 'Backend Skills'."
kind = "venn"
title = "Full-Stack Skills"
[[sets]]
label = "Frontend"
[[sets]]
label = "Backend"
[[intersections]]
sets = ["Frontend", "Backend"]
label = "TypeScript"
Timeline — Date-anchored events
Prompt: "Create a Declart timeline of 5 product launch milestones in 2024, using ISO dates."
kind = "timeline"
title = "Product Launch 2024"
[[events]]
date = "2024-01-15"
label = "Alpha"
[[events]]
date = "2024-03-01"
label = "Beta"
[[events]]
date = "2024-06-01"
label = "RC1"
[[events]]
date = "2024-09-15"
label = "GA"
[[events]]
date = "2024-12-01"
label = "v2 Plan"
Rule: dates accept
YYYY,YYYY-MM, orYYYY-MM-DD. Partial forms are placed at the start of that year/month. Declart sorts events automatically.
Fishbone / Ishikawa — Root cause analysis
Prompt: "Generate a Declart fishbone diagram where the effect is 'Slow API Response' with 4 cause categories and sub-causes. Use kind = 'hierarchy' and view = 'fishbone'. Each cause category is a root node; sub-causes have parent = the category label."
kind = "hierarchy"
view = "fishbone"
title = "Slow API Response"
[[nodes]]
label = "Database"
[[nodes]]
label = "Missing indexes"
parent = "Database"
[[nodes]]
label = "N+1 queries"
parent = "Database"
[[nodes]]
label = "Network"
[[nodes]]
label = "High latency"
parent = "Network"
[[nodes]]
label = "Code"
[[nodes]]
label = "Blocking I/O"
parent = "Code"
[[nodes]]
label = "Infrastructure"
Structure: Root nodes (no
parent) become cause categories on the spine. Child nodes become sub-causes. Theeffectfield is rendered as the spine-end effect label; ifeffectis omitted,titleis used as fallback.Limit: 2–20 root nodes (cause categories). Recommend 8 or fewer for readability.
Org Chart — Hierarchical trees
Prompt: "Create a Declart org chart for a small engineering team with a CTO at the top. Use kind = 'hierarchy'. With a single root node, the engine automatically renders as an org chart."
kind = "hierarchy"
title = "Engineering Team"
[[nodes]]
label = "CTO"
[[nodes]]
label = "Frontend Lead"
parent = "CTO"
[[nodes]]
label = "Backend Lead"
parent = "CTO"
[[nodes]]
label = "FE Developer"
parent = "Frontend Lead"
[[nodes]]
label = "BE Developer"
parent = "Backend Lead"
Rule: exactly one root node (no
parent).parentreferences another node'sid(preferred) orlabel. For stable references that survive label renames, addid = "stable-key"to each node and use that inparent. To explicitly select the view:view = "org_chart".
Funnel — Conversion funnels, sales pipelines
Prompt: "Generate a Declart funnel for a 5-stage sales pipeline. Use kind = 'flow' and view = 'funnel'."
kind = "flow"
view = "funnel"
title = "Sales Pipeline"
[[items]]
label = "Leads"
[[items]]
label = "Qualified"
[[items]]
label = "Proposal"
[[items]]
label = "Negotiation"
[[items]]
label = "Closed Won"
emphasis = "primary"
Limit: 2–10 stages.
Comparison — Feature matrices, trade-off tables
Prompt: "Generate a Declart comparison table for three JavaScript frameworks across four criteria."
kind = "comparison"
title = "JavaScript Framework Comparison"
[[columns]]
label = "Performance"
[[columns]]
label = "Ecosystem"
[[rows]]
label = "React"
Performance = "★★★★"
Ecosystem = "★★★★★"
[[rows]]
label = "Vue"
Performance = "★★★★"
Ecosystem = "★★★"
[[rows]]
label = "Svelte"
Performance = "★★★★★"
Limits: 1–10 rows, 1–8 columns. Declare
[[columns]]first for column order. Cell values are inline in each row, keyed by column label. Missing cells are rendered empty. Column label must not be"label"(reserved). Use TOML quoted keys ("My Column" = "val") if a column name contains spaces.
Tips for LLMs
| Rule | Detail |
|---|---|
kind is required | Always include it as the first field |
view is optional | Omit to use the default; include to declare intent explicitly |
| No unknown fields | Don't add color, style, or other keys not in the spec |
emphasis values | Only "primary" or "secondary" |
| Flow views | kind = "flow" + view: process (default), cycle, funnel |
| Tier views | kind = "tier" + view: pyramid (default and only) |
| Hierarchy nodes | label must be unique; parent references id (preferred) or label of another node |
Hierarchy id | Add id = "key" to nodes for stable parent references that survive label renames |
| Hierarchy auto-select | 1 root → org_chart; 2+ roots → fishbone (or set view explicitly) |
Fishbone effect | Rendered as the spine-end effect label; falls back to title if omitted |
| Matrix quadrants | Always exactly 4 [[quadrants]] entries |
| Timeline dates | ISO 8601: YYYY, YYYY-MM, or YYYY-MM-DD |
| Venn sets | Only 2 or 3 sets supported |
| Comparison cells | Column label in each row must match an existing [[columns]] label |
Validating LLM Output
declart validate diagram.toml
Error messages include field names and hints:
invalid value `(missing)` for field `position`
= hint: When any quadrant has position, all must specify it.
Valid: top-left, top-right, bottom-left, bottom-right
Paste the error back to the LLM to get a corrected TOML.
Flow
A flow diagram represents an ordered list of labeled items. The view field determines how the flow is interpreted and rendered.
Fields
| Field | Required | Type | Description |
|---|---|---|---|
kind | yes | "flow" | Must be exactly "flow" |
view | no | string | Rendering intent. Default: process |
title | no | string | Title rendered above the diagram |
items | yes | array of Item | At least one item required |
Item fields
| Field | Required | Type | Description |
|---|---|---|---|
label | yes | string | Text displayed in the item |
emphasis | no | string | "primary" or "secondary". See schema. |
View values
| value | Meaning | Min items | Max items |
|---|---|---|---|
process | Linear left-to-right steps (default) | 1 | — |
cycle | Closed loop — last item connects to first | 2 | — |
funnel | Tapering stages (conversion/filtering) | 2 | 10 |
swimlane | Steps grouped into horizontal actor lanes, top→down | 2 | — |
When view is omitted, the engine uses process.
For ranked/layered visuals (pyramid), use
kind = "tier"instead.
Swimlane item fields
When view = "swimlane", each item gains one additional required field:
| Field | Required | Type | Description |
|---|---|---|---|
actor | yes | string | Lane owner of this step |
actor is ignored by all other views. At least 2 distinct actor values are required.
Swimlane example
Example
Tier
A tier diagram represents a ranked set of labeled items — levels differentiated by importance, abstraction, or priority. The view field determines how the tiers are rendered.
Fields
| Field | Required | Type | Description |
|---|---|---|---|
kind | yes | "tier" | Must be exactly "tier" |
view | no | string | Rendering intent. Default: pyramid |
title | no | string | Title rendered above the diagram |
items | yes | array of Item | At least one item required |
Item fields
| Field | Required | Type | Description |
|---|---|---|---|
label | yes | string | Text displayed in the tier level |
emphasis | no | string | "primary" or "secondary". See schema. |
View values
| value | Meaning | Min items | Max items |
|---|---|---|---|
pyramid | Stacked layers from apex (first) to base (last) | 1 | — |
When view is omitted, the engine uses pyramid.
Example
Hierarchy
A hierarchy diagram represents a tree of labeled nodes connected by parent-child relationships. The view field determines how the tree is rendered.
Fields
| Field | Required | Type | Description |
|---|---|---|---|
kind | yes | "hierarchy" | Must be exactly "hierarchy" |
view | no | string | Rendering intent. Auto-selected if omitted. |
title | no | string | Chart title (rendered above the diagram) |
effect | no | string | Fishbone view only: spine-end effect label. Falls back to title if omitted. |
nodes | yes | array of Node | At least one node required |
Node fields
| Field | Required | Type | Description |
|---|---|---|---|
label | yes | string | Display text |
id | no | string | Stable identifier for parent references. If set, other nodes reference this node by id, not label. |
parent | no | string | id (preferred) or label of the parent node; omit for root nodes |
View values
| value | Meaning | Auto-selected when |
|---|---|---|
org_chart | Top-down tree; exactly one root required | exactly 1 root node |
fishbone | Cause-and-effect diagram | 2+ root nodes |
Auto-selection: When view is omitted, the engine selects org_chart for exactly one root node, fishbone for two or more root nodes. The CLI emits a warning when view is auto-selected; add an explicit view to suppress it.
View-specific constraints
org_chart: exactly one root node required.
fishbone: 2–20 root nodes (cause categories); effect (or title if effect is omitted) is rendered as the effect label at the right end of the spine. Recommend 8 or fewer root nodes — 9+ cause categories on the same side of the spine may overlap.
Example — org_chart view (auto-selected)
Example — fishbone view
Example — org_chart with stable id references
Timeline
A timeline diagram. Events are placed along a horizontal axis at positions proportional to their dates. Used for project histories, product roadmaps, and chronological narratives.
Fields
| Field | Required | Type | Description |
|---|---|---|---|
| kind | yes | "timeline" | Must be exactly "timeline" |
| title | no | string | Title rendered above the diagram |
| events | yes | array of Event | At least two events required |
Event fields
| Field | Required | Type | Description |
|---|---|---|---|
| date | yes | string | Date as YYYY, YYYY-MM, or YYYY-MM-DD. Partial forms are placed at the start of that year/month. |
| label | yes | string | Text displayed above or below the event marker |
Rendering rules
- Events are sorted by date and placed along a horizontal axis.
- The horizontal position of each event is proportional to its date within the overall date range.
- Event labels alternate above and below the axis to reduce overlap.
- The date string is displayed below each event marker.
- At least two events are required to establish a time range.
Example
Matrix 2×2
A two-by-two matrix diagram. Used for prioritization, strategy frameworks, and categorization with two independent axes.
Fields
| Field | Required | Type | Description |
|---|---|---|---|
| kind | yes | "matrix" | Must be exactly "matrix" |
| title | no | string | Title rendered above the diagram |
| x_axis | yes | string | Label for the horizontal axis |
| y_axis | yes | string | Label for the vertical axis |
| quadrants | yes | array of 4 | Exactly 4 quadrants, in reading order |
Quadrant fields
| Field | Required | Type | Description |
|---|---|---|---|
| label | yes | string | Text displayed in the quadrant |
| emphasis | no | string | "primary" or "secondary". See schema. |
| position | no | string | Explicit cell: "top-left", "top-right", "bottom-left", "bottom-right" |
Quadrant order
Without position (default): Quadrants are declared in reading order (left-to-right, top-to-bottom):
- Top-left (high Y, low X)
- Top-right (high Y, high X)
- Bottom-left (low Y, low X)
- Bottom-right (low Y, high X)
With position: All four quadrants must each declare a distinct position. Order in the file does not matter.
When any quadrant has position, all four must specify it.
Rendering rules
- The diagram is a 2×2 grid divided by a horizontal and vertical axis line.
- Each quadrant occupies one cell of the grid and displays its label centered.
x_axisis rendered below the horizontal center line.y_axisis rendered to the left of the vertical center line, rotated 90°.- Exactly 4 quadrants are required; more or fewer is a parse error.
Example
Hub-and-Spoke
A hub-and-spoke diagram. A central node radiates connections to surrounding spoke nodes. Used for showing a central concept with related elements, or a hub with connected services.
Fields
| Field | Required | Type | Description |
|---|---|---|---|
| kind | yes | "hub_spoke" | Must be exactly "hub_spoke" |
| title | no | string | Title rendered above the diagram |
| center | yes | string | Label for the central hub node |
| spokes | yes | array of Spoke | At least two spokes required |
Spoke fields
| Field | Required | Type | Description |
|---|---|---|---|
| label | yes | string | Text displayed in the spoke node |
| emphasis | no | string | "primary" or "secondary". See schema. |
Rendering rules
- The center node is rendered at the center of the diagram.
- Spoke nodes are arranged evenly around the center in a circle.
- Lines connect the center node to each spoke node.
- The center node is visually distinguished from spoke nodes (larger, different color).
- Spoke nodes use the base color; the center uses the apex color.
Example
Venn
A Venn diagram. Two or three overlapping circles represent sets. Intersection regions may be labeled. Used for showing set relationships, similarities, and differences.
Fields
| Field | Required | Type | Description |
|---|---|---|---|
| kind | yes | "venn" | Must be exactly "venn" |
| title | no | string | Title rendered above the diagram |
| sets | yes | array of Set | 2 or 3 sets required |
| intersections | no | array of Intersection | Labeled regions in the overlap areas |
Set fields
| Field | Required | Type | Description |
|---|---|---|---|
| label | yes | string | Name of the set |
Intersection fields
| Field | Required | Type | Description |
|---|---|---|---|
| sets | yes | array of string | Set labels identifying which overlap region this labels |
| label | yes | string | Text displayed in the overlap region |
Rendering rules
- Circles are arranged to overlap: two sets side-by-side; three sets in a triangle.
- Each circle is rendered with partial opacity so overlaps are visible.
- Set labels appear near the outer edge of each circle (non-overlapping region).
- Intersection labels appear in the center of the overlap region.
- Exactly 2 or 3 sets are required; other counts are a parse error.
Example
Comparison Table Kind — Specification
Purpose
Presents a matrix of items (rows) evaluated against criteria (columns). Each cell value is declared inline within the row entry.
TOML Schema
kind = "comparison"
title = <string>? # optional diagram title
[[columns]]
label = <string> # evaluation criterion (required, unique)
[[rows]]
label = <string> # item being compared (required, unique)
<ColumnLabel> = <string> # cell value for that column (optional, omit = empty cell)
Constraints
| Constraint | Rule |
|---|---|
| Rows | 1–10 |
| Columns | 1–8 |
| Column label | Must not be "label" (reserved for the row identifier) |
| Cell keys in rows | Must match a declared columns[].label; unknown keys are an error |
| Missing cells | Treated as empty (allowed) |
Rendering Specification
- Canvas: 800px wide, height = title_area + 45px column header + rows × 50px + 20px padding
- Row header column: 180px wide, apex-tinted background
- Column header row: 45px tall, apex color background, bold white/dark text
- Data cells: 50px tall, equal width distributing remaining canvas; alternating even/odd row backgrounds
- Grid borders: 1px lines using apex-background interpolated color
- Text: Noto Sans, 13px; truncated with
…if wider than available cell width
Example
Example Files
valid/basic.toml— 2 rows × 2 columns, inline cellsvalid/no_title.toml— title omittedvalid/empty_cells.toml— no cells defined (sparse table)valid/basic.json— JSON formatinvalid/no_rows.toml— missing rows → errorinvalid/no_columns.toml— missing columns → errorinvalid/invalid_cell_ref.toml— row uses undeclared column key → errorinvalid/too_many_columns.toml— 9 columns exceeds limit → error
State
A state diagram represents a system's lifecycle as a set of named states and directed transitions between them.
Fields
| Field | Required | Type | Description |
|---|---|---|---|
kind | yes | "state" | Must be exactly "state" |
title | no | string | Rendered above the diagram |
states | yes | array of State | At least 2 states required |
transitions | no | array of Transition | May be empty (unconnected states) |
State fields
| Field | Required | Type | Description |
|---|---|---|---|
label | yes | string | Display text. Must be unique unless id is set. |
id | no | string | Stable identifier for from/to references. Falls back to label if omitted. |
role | no | string | "initial" or "terminal". At most one "initial"; multiple "terminal" allowed. |
Transition fields
| Field | Required | Type | Description |
|---|---|---|---|
from | yes | string | id (preferred) or label of source state |
to | yes | string | id (preferred) or label of target state |
trigger | no | string | Event or condition causing this transition |
type | no | string | "normal" (default) or "exception" — semantic type |
Self-loop transitions (from = to) are valid. Transition without trigger is valid (unconditional).
Cross-reference resolution
If a state has an id, use id in from/to. If it has no id, use label.
Unknown references → validation error. Duplicate labels without id → validation error.