VGL Guide — User-defined notations (`vnotation`)
Estimated reading time: 7 minutes.
User-defined notations (vnotation)
vnotation defines a notation schema inline in a VGL file, with no Swift changes. Everything a built-in notation provides — node types, edge types, layout direction — can be expressed this way.
vnotation <Name> [extends <BuiltinNotation>] {
layout: <topToBottom | leftToRight | rightToLeft | bottomToTop>
icon <IconName> [viewBox: "<minX minY width height>", path: "<svg path data>"]
node type: <TypeName> [nodeStyle: <name>, backgroundColor: "#hex", icon: "<IconName>", ...]
edge type: <edge_id> from: <TypeName> to: <TypeName> [color: "#hex"]
group type: <GroupTypeName> [boundaryDash: "8,4", boundaryColor: "#hex", ...]
}
group type: names a kind of plain group, so group g: <GroupTypeName> { … } is accepted and group type: view rules can select it.
Boundary look. node type: and group type: both take four keys for the boundary an unfolded group draws: boundaryDash (an SVG dash pattern, "" for a solid line), boundaryColor, boundaryFill (hex, #rrggbbaa for transparency) and boundaryRadius. On a node type it is the boundary of its detailed nodes; on a group type, of its groups. A key left out keeps the look the type already had, so group type: Organisation [boundaryColor: "#00aa00"] in a block extending C4 recolours the boundary and keeps its dashes. A type with no boundary of its own, from the block or the notation it extends, draws the generic cluster. These are the only keys group type: takes; a group type declared in a vnotation folds into the generic folded box.
A vgraph then references it by name exactly like a built-in notation. vnotation blocks must appear before any vgraph or metagraph that references them, which allows single-pass parsing.
backgroundColor: is the fill. color: is accepted as an older spelling of it on input, but backgroundColor is what a document exports — the same name a node instance stores it under, so the two surfaces agree.
qualityCheck: <name> adds a quality check by name — a graph criterion such as noParallelEdges; an unknown name is refused with the list of available ones. transform: <name> adds a step that rewrites the graph before layout — mergeRelations, say, which merges Concept Map relations — refused the same way when unknown.
nodeStyle: — required on every node type
The parser treats the value as an opaque string; the semantic layer validates it against this table.
nodeStyle: |
Additional parameters | Description |
|---|---|---|
iconWithText |
backgroundColor: (required), icon:, iconColor: (default white), iconSize: (default 24) |
Icon above text, coloured background |
simpleRoundedText |
backgroundColor: |
Text in a rounded rectangle |
simpleRoundedBox |
backgroundColor: |
Plain rounded box (roundedBox is accepted as an older spelling) |
withCategory |
backgroundColor:, category: (short header label) |
Box with a coloured category bar on top |
withCategoryAndIcon |
backgroundColor:, category:, icon:, iconColor:, iconSize: |
Category bar plus icon |
iconOnly |
icon:, iconColor: (default black), iconSize: |
Icon without text |
circle |
backgroundColor: |
Circular node |
bareText |
— | Plain text, no decoration |
hidden |
— | Not rendered |
custom |
— | Falls back to bareText; reserved for future style expressions |
icon — artwork of your own
icon: on a node type names an icon. A set of names is built into VGraph; a
vnotation can add its own, so a notation is not limited to the icons that happened to ship.
vnotation RiskMap {
icon shield [viewBox: "0 0 24 24", path: "M12 1 3 5v6c0 5.5 3.8 10.7 9 12 5.2-1.3 9-6.5 9-12V5z"]
node type: Control [nodeStyle: iconWithText, backgroundColor: "#339933", icon: "shield"]
}
The artwork travels inside the document, so it draws wherever VGL draws — website, both plugins, the CLI — with nothing to fetch and no cooperation from the host.
viewBox:andpath:are both required. The viewBox is four numbers, as in an SVG file; there is no default, because artwork drawn at a guessed scale is worse than a document that says what is wrong.- One shape, not a picture. One path, no colours of its own:
iconColor:fills it at the point of use, which is what makes the same icon work in white on a dark node and in black on a light one. path:takes SVG path data and only that — the path commands, digits,.,+-eEand spaces, up to 4096 characters. Anything else is refused where it is written.- Your name wins. A name resolves against the notation's own artwork first and the built-in set second, so declaring
andyourself replaces it for that document — and an icon added to VGraph in some later release can never change how your document looks. - A name nobody has is not fatal. It draws a placeholder and is reported in the quality report, naming the node type and the icon. The rest of the diagram is untouched.
Forty-eight icon names are built in, all drawn for VGraph; the design system's Icons section holds the masters. A name says what the icon means, and several names share one drawing, so need, answer and undesirable-effect look alike.
| Used for | Names |
|---|---|
| Whole node, with its own circle | and, or (the junctors), conflict, default (drawn when an icon style names no icon) |
| Reality trees | undesirable-effect, intermediate-effect, desirable-effect, given, changeable |
| Questions and decisions | question, answer, pro, con, decision-point, choice, outcome, assumption |
| Goals and obstacles | goal, objective, intermediate-objective, common-objective, investment-objective, critical-success-factor, necessary-condition, obstacle, need, want, solution |
| Change and delivery | benefit, business-change, enabler, impact, actor, deliverable, event |
| Attack and defence | attack, defense |
| General | concept, variable, annotation, warning |
| Arithmetic | plus, minus, times, divide, equals, not-equal |
| Brand | vithanco (the logo) |
Anything else a document draws, it declares. The SF Symbols-style names and the desktop app's icons that earlier versions shipped draw the placeholder until a
vnotation declares them.
extends
Adds every node and edge type from a built-in notation, on top of which yours adds more:
vnotation RichIBIS extends IBIS {
node type: Stakeholder [nodeStyle: withCategory, backgroundColor: "#884499", category: "S"]
edge type: stakeholder_raises from: Stakeholder to: Question
edge type: stakeholder_answers from: Stakeholder to: Answer
}
Only built-in notations can be extended — vnotation A extends B where B is itself a vnotation is not supported.
detailedBy: — a hierarchical notation
A node type can name the types its nodes are detailed by, the way a software system is made of containers and databases:
vnotation Architecture {
node type: System [nodeStyle: withCategory, backgroundColor: "#1168bd", detailedBy: (Container, Database)]
node type: Container [nodeStyle: withCategory, backgroundColor: "#438dd5"]
node type: Database [nodeStyle: withCategory, backgroundColor: "#438dd5"]
}
- Every name in the list must be a node type of the notation.
- One type may be a detail type of several types.
- A type may be detailed by itself, for sub-processes or work packages. Any longer cycle is an error: no type could then stand at the top level.
- With
extends, the list adds to what the built-in notation already says for that type. Detailings cannot be removed, so no document that relied on one becomes invalid. A saved file writes back only the ones thevnotationadded. - A name cannot be both a node type and a group type, since
group x: Namewould not say which it is.
The quality report then warns, for any notation with detailings, about a node inside a detailed node that its type is not detailed by, and about a detail type at the top level unless it details itself. Plain groups in between do not count.
A complete example
vnotation RiskMap {
layout: topToBottom
icon risk [viewBox: "0 0 24 24", path: "M12 2 22.5 21h-21zM11 9v6h2V9zm0 8v2h2v-2z"]
icon shield [viewBox: "0 0 24 24", path: "M12 1 3 5v6c0 5.5 3.8 10.7 9 12 5.2-1.3 9-6.5 9-12V5z"]
node type: Risk [nodeStyle: iconWithText, backgroundColor: "#cc3333", icon: "risk"]
node type: Control [nodeStyle: iconWithText, backgroundColor: "#339933", icon: "shield"]
node type: Owner [nodeStyle: circle, backgroundColor: "#3366cc"]
edge type: risk_has_control from: Risk to: Control
edge type: control_owned_by from: Control to: Owner
}
vgraph rm1: RiskMap "Project Risk Map" {
node r1: Risk "Schedule overrun"
node c1: Control "Weekly reviews"
node o1: Owner "PM"
edge r1 -> c1
edge c1 -> o1
}
A vnotation can take extensions like any other notation:
vgraph sm1: SimpleMap, Annotation "Annotated Map" { … }.
Home