YAML Specification
The CnD layout specification describes how diagrams are laid out as a YAML document. A spec has four top-level sections, all optional:
constraints:
- # ... constraint definitions
directives:
- # ... directive definitions
projections:
- # ... projection definitions
temporal:
policy: # ... sequence policyAn empty specification is valid.
constraints— structural layout of nodes and their spatial relationships. Reference below.directives— visual styling and presentation (no effect on layout structure). Reference below.projections— slice the instance along a sig axis and render multiple panes. See Projections.temporal— sequence policy for navigating traces fromforge/temporalmodels. See Temporal Mode.
Constraints
Orientation
Specifies the relative positioning of elements selected by a binary/n-ary selector.
- orientation:
selector: <binary-selector> # Required: selector returning (x, y) pairs
directions: [<direction>, ...] # Required: array of positioning directions| Field | Required | Type | Description |
|---|---|---|---|
selector | yes | string | Binary selector (e.g., parent, Node->Node) |
directions | yes | array | One or more positioning directions |
Available directions:
For each selected (x, y) tuple, the direction describes where x appears relative to y.
above—xis abovey(with flexibility)below—xis belowy(with flexibility)left—xis left ofy(with flexibility)right—xis right ofy(with flexibility)directlyAbove—xis directly abovey(strict vertical alignment)directlyBelow—xis directly belowy(strict vertical alignment)directlyLeft—xis directly left ofy(strict horizontal alignment)directlyRight—xis directly right ofy(strict horizontal alignment)
Examples:
# Parent nodes appear above child nodes
- orientation:
selector: parent
directions: [above]
# Nodes flow left to right with strict horizontal alignment
- orientation:
selector: next
directions: [directlyLeft]
# Multiple directions: x is above and to the left of y
- orientation:
selector: precedes
directions: [above, left]Restrictions:
- Cannot combine
abovewithbelow - Cannot combine
leftwithright directly*variants can only combine with their non-direct counterpart (e.g.,directlyAbovewithabove)
Cyclic
Arranges elements along the perimeter of a circle based on selector order.
- cyclic:
selector: <binary-selector> # Required: selector defining circular ordering
direction: <rotation> # Optional: rotation direction (default: clockwise)| Field | Required | Type | Default | Description |
|---|---|---|---|---|
selector | yes | string | — | Binary selector defining the cycle order |
direction | no | string | clockwise | clockwise or counterclockwise |
Examples:
# Arrange states in a clockwise cycle
- cyclic:
selector: nextState
direction: clockwise
# Counter-clockwise arrangement
- cyclic:
selector: follows
direction: counterclockwiseAlign
Ensures elements are aligned horizontally or vertically.
- align:
selector: <n-ary-selector> # Required: selector returning elements to align
direction: <alignment> # Required: horizontal or vertical| Field | Required | Type | Description |
|---|---|---|---|
selector | yes | string | Selector returning atoms to align |
direction | yes | string | horizontal or vertical |
Examples:
# Align all Person nodes horizontally (same Y coordinate)
- align:
selector: Person
direction: horizontal
# Align selected nodes vertically (same X coordinate)
- align:
selector: Node.selected
direction: verticalGroup (by Selector)
Groups elements based on a selector expression.
- group:
selector: <n-ary-selector> # Required: selector returning elements to group
name: <group-name> # Required: display name for the group
addEdge: <boolean> # Optional: add visual edge to group members| Field | Required | Type | Default | Description |
|---|---|---|---|---|
selector | yes | string | — | Selector returning atoms to include in group |
name | yes | string | — | Display name shown on the group box |
addEdge | no | boolean | false | Whether to add visual edges between group members |
Examples:
# Group all Team members together
- group:
selector: Team.members
name: "Team Members"
# Group with connecting edges
- group:
selector: Department.employees
name: "Department"
addEdge: trueGroup (by Field)
Groups elements based on a relational field (tuple-based grouping).
- group:
field: <field-name> # Required: relation field name
groupOn: <index> # Required: tuple index for the group key (0-based)
addToGroup: <index> # Required: tuple index for grouped element (0-based)
selector: <unary-selector> # Optional: filter which source atoms apply| Field | Required | Type | Description |
|---|---|---|---|
field | yes | string | Name of the relation/field |
groupOn | yes | integer | Index of the tuple element to use as group key |
addToGroup | yes | integer | Index of the tuple element to add to the group |
selector | no | string | Unary selector to filter which atoms this applies to |
Examples:
# Group employees by their department
# For relation: worksIn: Employee -> Department
- group:
field: worksIn
groupOn: 1 # Department is the group key
addToGroup: 0 # Employee gets added to the group
# Group with selector filter
- group:
field: owns
groupOn: 0
addToGroup: 1
selector: PersonNegation (hold: never)
Any constraint can be negated by adding hold: never. By default, all constraints implicitly have hold: always. A negated constraint asserts that the relationship must never hold.
- orientation:
selector: <binary-selector>
directions: [<direction>, ...]
hold: never
- align:
selector: <binary-selector>
direction: <alignment>
hold: never
- cyclic:
selector: <binary-selector>
direction: <rotation>
hold: never
- group:
selector: <n-ary-selector> # name is optional for hold: never
hold: never| Field | Required | Type | Default | Description |
|---|---|---|---|---|
hold | no | string | always | always (constraint must hold) or never (constraint must not hold) |
Semantics:
| Positive | hold: never meaning |
|---|---|
above | x is at the same level as or below y |
below | x is at the same level as or above y |
left | x is at the same position as or right of y |
right | x is at the same position as or left of y |
align horizontal | Must have different Y coordinates (disjunction: one above the other) |
align vertical | Must have different X coordinates (disjunction: one left of the other) |
cyclic clockwise | No valid clockwise rotation holds (De Morgan over rotational alternatives) |
group | No clean bounding rectangle can contain exactly these members |
For groups, hold: never asserts that no axis-aligned rectangle can contain exactly the group's members without also containing a non-member. No visual rectangle is drawn. The name field is optional (auto-generated if omitted).
Examples:
# Ensure children NEVER appear above parents
- orientation:
selector: parent
directions: [above]
hold: never
# Nodes must NEVER be horizontally aligned
- align:
selector: A->B
direction: horizontal
hold: never
# Do NOT arrange states clockwise
- cyclic:
selector: nextState
direction: clockwise
hold: never
# No clean rectangle can contain just these nodes
- group:
selector: Alpha
hold: neverRestrictions: double negation is not supported.
Size
Sets the width and height of nodes matching a selector. (Can also be used as a directive.)
- size:
selector: <unary-selector> # Required: selector for nodes to resize
width: <number> # Optional: width in pixels
height: <number> # Optional: height in pixels| Field | Required | Type | Default | Description |
|---|---|---|---|---|
selector | yes | string | — | Unary selector for target nodes |
width | no | number | 100 | Width in pixels (must be > 0) |
height | no | number | 60 | Height in pixels (must be > 0) |
- size:
selector: ImportantNode
width: 150
height: 80Hide Atom
Hides atoms matching a selector from the visualization. (Can also be used as a directive.)
- hideAtom:
selector: <unary-selector> # Required: selector for atoms to hide- hideAtom:
selector: InternalNodeDirectives
Atom Style (atomStyle)
Customizes the shape, fill, border, and label of atoms matching a selector.
- atomStyle:
selector: <unary-selector> # Optional: defaults to all atoms
shape: <shape> # Optional
fillStyle: # Optional
color: <color>
borderStyle: # Optional
color: <color>
width: <number>
textStyle: # Optional
color: <color>- atomStyle:
selector: Person
fillStyle:
color: "#ff5733"
borderStyle:
color: steelblue
width: 2
- atomStyle:
selector: Error
borderStyle:
color: redThe legacy atomColor: { selector, value } form is still parsed for backward compatibility, but new specs should use atomStyle.
Edge Style (edgeStyle)
Customizes the appearance of edges for a specific field/relation.
- edgeStyle:
field: <field-name> # Required: relation/field name
selector: <unary-selector> # Optional: filter by source atom
filter: <n-ary-selector> # Optional: filter which tuples apply
lineStyle: # Optional
color: <color>
pattern: <line-style>
weight: <number>
highlight: <color>
textStyle: # Optional: edge-label styling
color: <color>
showLabel: <boolean> # Optional: show edge label
hidden: <boolean> # Optional: hide the edge entirely| Field | Required | Type | Default | Description |
|---|---|---|---|---|
field | yes | string | — | Name of the relation |
selector | no | string | — | Unary selector to filter source atoms |
filter | no | string | — | N-ary selector to filter specific tuples |
lineStyle | no | object | — | Edge color, pattern, weight, and highlight |
textStyle | no | object | — | Edge-label styling |
showLabel | no | boolean | true | Whether to display the edge label |
hidden | no | boolean | false | Hide the edge from display |
# Color all 'parent' edges blue
- edgeStyle:
field: parent
lineStyle:
color: blue
# Dashed red edges for specific source type
- edgeStyle:
field: references
selector: Document
lineStyle:
color: red
pattern: dashed
weight: 2
# Keep an edge but omit its redundant label
- edgeStyle:
field: next
showLabel: falseThe legacy edgeColor: { field, value, style, weight } form is still parsed for backward compatibility, but new specs should use edgeStyle.
Icon
Assigns an icon to atoms matching a selector.
- icon:
selector: <unary-selector> # Required
path: <icon-path> # Required: path or name of the icon
showLabels: <boolean> # Optional: show text labels alongside icon- icon:
selector: Person
path: "user"
showLabels: true
- icon:
selector: File
path: "/icons/file.svg"Attribute
Converts edge relationships into node attributes (displayed as key-value pairs on nodes).
- attribute:
field: <field-name> # Required
selector: <unary-selector> # Optional: filter which source atoms apply
filter: <n-ary-selector> # Optional: filter which tuples to includeBehavior: removes the edge from the graph; displays the target value as an attribute on the source node. Multiple targets become a list.
# Show 'age' as an attribute instead of an edge
- attribute:
field: age
# Only for Person nodes
- attribute:
field: name
selector: Person
# Filter to only show active relationships
- attribute:
field: status
filter: 'status & (univ -> Active)'Tag
Adds computed attributes to nodes based on selector evaluation. Unlike attribute, this doesn't remove edges.
- tag:
toTag: <unary-selector> # Required: atoms to receive the tag
name: <attribute-name> # Required: attribute name to display
value: <n-ary-selector> # Required: selector whose result becomes the valueBehavior: for binary results displays as name: value; for n-ary results displays as name[key1][key2]: value.
# Simple binary tag
- tag:
toTag: Person
name: age
value: age
# Ternary selector — shows as score[Math]: 95, score[English]: 87
- tag:
toTag: Student
name: score
value: gradesHide Field
Hides edges for a specific field/relation.
- hideField:
field: <field-name> # Required
selector: <unary-selector> # Optional: filter by source atom
filter: <n-ary-selector> # Optional: filter which tuples to hide# Hide all 'internal' edges
- hideField:
field: internal
# Hide only from certain source types
- hideField:
field: debug
selector: ProductionHide Atom
Hides atoms matching a selector.
- hideAtom:
selector: HelperNodeInferred Edge
Creates visual edges based on a selector expression (edges that don't exist in the data).
- inferredEdge:
name: <edge-label> # Required
selector: <binary-selector> # Required: pairs to connect
color: <color> # Optional
style: <line-style> # Optional
weight: <number> # Optional| Field | Required | Type | Default | Description |
|---|---|---|---|---|
name | yes | string | — | Label displayed on the edge |
selector | yes | string | — | Binary selector returning (source, target) pairs |
color | no | string | #000000 | CSS color value |
style | no | string | solid | solid, dashed, or dotted |
weight | no | number | — | Line thickness in pixels |
# Show transitive closure as inferred edges
- inferredEdge:
name: "reachable"
selector: "^parent"
color: gray
style: dotted
# Highlight computed relationships
- inferredEdge:
name: "sibling"
selector: "~parent.parent - iden"
color: purple
style: dashed
weight: 2Flag
Sets global visualization flags.
- flag: <flag-name>| Flag | Description |
|---|---|
hideDisconnected | Hide all nodes with no edges |
hideDisconnectedBuiltIns | Hide built-in type nodes (Int, String, etc.) with no edges |
- flag: hideDisconnected
- flag: hideDisconnectedBuiltInsSelector Syntax
Selectors are expressions that identify atoms or tuples. The syntax depends on your data format (Forge, Alloy, etc.); common patterns:
| Pattern | Description | Example |
|---|---|---|
TypeName | All atoms of a type | Person |
fieldName | All tuples in a relation | parent |
Type.field | Field access | Person.age |
selector1 + selector2 | Union | Student + Teacher |
selector1 & selector2 | Intersection | Person & Employee |
selector1 - selector2 | Difference | Person - Manager |
~selector | Transpose | ~parent (child relation) |
^selector | Transitive closure | ^parent (all ancestors) |
*selector | Reflexive transitive closure | *parent |
selector1 -> selector2 | Product | Person -> Int |
selector1.selector2 | Join | Person.parent |
See Selectors for the full operator set.
Complete Example
constraints:
# Layout structure
- orientation:
selector: parent
directions: [above]
- align:
selector: siblings
direction: horizontal
# Grouping
- group:
selector: Team.members
name: "Team"
# Circular layout for a state machine
- cyclic:
selector: nextState
direction: clockwise
# Negation: siblings must NEVER be vertically stacked
- orientation:
selector: siblings
directions: [above]
hold: never
directives:
# Visual styling
- atomStyle:
selector: Person
borderStyle:
color: "#4a90d9"
- atomStyle:
selector: Error
borderStyle:
color: red
- icon:
selector: File
path: "file-icon"
showLabels: true
# Edge styling
- edgeStyle:
field: error
lineStyle:
color: red
pattern: dashed
weight: 2
# Convert to attributes
- attribute:
field: age
selector: Person
- tag:
toTag: Student
name: grade
value: currentGrade
# Hide clutter
- hideField:
field: internal
- hideAtom:
selector: HelperNode
- flag: hideDisconnectedBuiltIns
# Show computed relationships
- inferredEdge:
name: "ancestor"
selector: "^parent"
color: gray
style: dotted