Skip to content

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:

yaml
constraints:
  - # ... constraint definitions

directives:
  - # ... directive definitions

projections:
  - # ... projection definitions

temporal:
  policy: # ... sequence policy

An 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 from forge/temporal models. See Temporal Mode.

Constraints ​

Orientation ​

Specifies the relative positioning of elements selected by a binary/n-ary selector.

yaml
- orientation:
    selector: <binary-selector>    # Required: selector returning (x, y) pairs
    directions: [<direction>, ...] # Required: array of positioning directions
FieldRequiredTypeDescription
selectoryesstringBinary selector (e.g., parent, Node->Node)
directionsyesarrayOne or more positioning directions

Available directions:

For each selected (x, y) tuple, the direction describes where x appears relative to y.

  • above — x is above y (with flexibility)
  • below — x is below y (with flexibility)
  • left — x is left of y (with flexibility)
  • right — x is right of y (with flexibility)
  • directlyAbove — x is directly above y (strict vertical alignment)
  • directlyBelow — x is directly below y (strict vertical alignment)
  • directlyLeft — x is directly left of y (strict horizontal alignment)
  • directlyRight — x is directly right of y (strict horizontal alignment)

Examples:

yaml
# 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 above with below
  • Cannot combine left with right
  • directly* variants can only combine with their non-direct counterpart (e.g., directlyAbove with above)

Cyclic ​

Arranges elements along the perimeter of a circle based on selector order.

yaml
- cyclic:
    selector: <binary-selector>  # Required: selector defining circular ordering
    direction: <rotation>        # Optional: rotation direction (default: clockwise)
FieldRequiredTypeDefaultDescription
selectoryesstring—Binary selector defining the cycle order
directionnostringclockwiseclockwise or counterclockwise

Examples:

yaml
# Arrange states in a clockwise cycle
- cyclic:
    selector: nextState
    direction: clockwise

# Counter-clockwise arrangement
- cyclic:
    selector: follows
    direction: counterclockwise

Align ​

Ensures elements are aligned horizontally or vertically.

yaml
- align:
    selector: <n-ary-selector>   # Required: selector returning elements to align
    direction: <alignment>       # Required: horizontal or vertical
FieldRequiredTypeDescription
selectoryesstringSelector returning atoms to align
directionyesstringhorizontal or vertical

Examples:

yaml
# 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: vertical

Group (by Selector) ​

Groups elements based on a selector expression.

yaml
- 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
FieldRequiredTypeDefaultDescription
selectoryesstring—Selector returning atoms to include in group
nameyesstring—Display name shown on the group box
addEdgenobooleanfalseWhether to add visual edges between group members

Examples:

yaml
# Group all Team members together
- group:
    selector: Team.members
    name: "Team Members"

# Group with connecting edges
- group:
    selector: Department.employees
    name: "Department"
    addEdge: true

Group (by Field) — removed ​

The field form of group (field / groupOn / addToGroup) was removed; a spec that still uses it fails to parse. Use a group with a binary selector instead: the first column is the group key, the second the members, and the group needs a name.

yaml
# Before — worksIn: Employee -> Department, grouped by department
- group:
    field: worksIn
    groupOn: 1
    addToGroup: 0

# After — transpose so the department (the key) comes first
- group:
    selector: ~worksIn
    name: "Department"

# Before — owns, grouped by owner, Person owners only
- group:
    field: owns
    groupOn: 0
    addToGroup: 1
    selector: Person

# After — the key is already first; restrict the owners with a product
- group:
    selector: owns & (Person -> univ)
    name: "Owned"

Negation (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.

yaml
- 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
FieldRequiredTypeDefaultDescription
holdnostringalwaysalways (constraint must hold) or never (constraint must not hold)

Semantics:

Positivehold: never meaning
abovex is at the same level as or below y
belowx is at the same level as or above y
leftx is at the same position as or right of y
rightx is at the same position as or left of y
align horizontalMust have different Y coordinates (disjunction: one above the other)
align verticalMust have different X coordinates (disjunction: one left of the other)
cyclic clockwiseNo valid clockwise rotation holds (De Morgan over rotational alternatives)
groupNo 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:

yaml
# 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: never

Restrictions: double negation is not supported.


Size ​

Sets the width and height of nodes matching a selector. (Can also be used as a directive.)

yaml
- size:
    selector: <unary-selector>   # Required: selector for nodes to resize
    width: <number>              # Optional: width in pixels
    height: <number>             # Optional: height in pixels
FieldRequiredTypeDefaultDescription
selectoryesstring—Unary selector for target nodes
widthnonumber100Width in pixels (must be > 0)
heightnonumber60Height in pixels (must be > 0)
yaml
- size:
    selector: ImportantNode
    width: 150
    height: 80

Hide Atom ​

Hides atoms matching a selector from the visualization. (Can also be used as a directive.)

yaml
- hideAtom:
    selector: <unary-selector>   # Required: selector for atoms to hide
yaml
- hideAtom:
    selector: InternalNode

Directives ​

Atom Style (atomStyle) ​

Customizes the shape, fill, border, and label of atoms matching a selector.

yaml
- 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>
yaml
- atomStyle:
    selector: Person
    fillStyle:
      color: "#ff5733"
    borderStyle:
      color: steelblue
      width: 2

- atomStyle:
    selector: Error
    borderStyle:
      color: red

The 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.

yaml
- 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
FieldRequiredTypeDefaultDescription
fieldyesstring—Name of the relation
selectornostring—Unary selector to filter source atoms
filternostring—N-ary selector to filter specific tuples
lineStylenoobject—Edge color, pattern, weight, and highlight
textStylenoobject—Edge-label styling
showLabelnobooleantrueWhether to display the edge label
hiddennobooleanfalseHide the edge from display
yaml
# 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: false

The 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.

yaml
- icon:
    selector: <unary-selector>   # Required
    path: <icon-path>            # Required: path or name of the icon
    showLabels: <boolean>        # Optional: show text labels alongside icon
yaml
- 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).

yaml
- attribute:
    field: <field-name>          # Required
    selector: <unary-selector>   # Optional: filter which source atoms apply
    filter: <n-ary-selector>     # Optional: filter which tuples to include

Behavior: removes the edge from the graph; displays the target value as an attribute on the source node. Multiple targets become a list.

yaml
# 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.

yaml
- 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 value

Behavior: for binary results displays as name: value; for n-ary results displays as name[key1][key2]: value.

yaml
# 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: grades

Hide Field ​

Hides edges for a specific field/relation.

yaml
- hideField:
    field: <field-name>          # Required
    selector: <unary-selector>   # Optional: filter by source atom
    filter: <n-ary-selector>     # Optional: filter which tuples to hide
yaml
# Hide all 'internal' edges
- hideField:
    field: internal

# Hide only from certain source types
- hideField:
    field: debug
    selector: Production

Hide Atom ​

Hides atoms matching a selector.

yaml
- hideAtom:
    selector: HelperNode

Inferred Edge ​

Creates visual edges based on a selector expression (edges that don't exist in the data).

yaml
- inferredEdge:
    name: <edge-label>           # Required
    selector: <binary-selector>  # Required: pairs to connect
    color: <color>               # Optional
    style: <line-style>          # Optional
    weight: <number>             # Optional
FieldRequiredTypeDefaultDescription
nameyesstring—Label displayed on the edge
selectoryesstring—Binary selector returning (source, target) pairs
colornostring#000000CSS color value
stylenostringsolidsolid, dashed, or dotted
weightnonumber—Line thickness in pixels
yaml
# 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: 2

Flag ​

Sets global visualization flags.

yaml
- flag: <flag-name>
FlagDescription
hideDisconnectedHide all nodes with no edges
hideDisconnectedBuiltInsHide built-in type nodes (Int, String, etc.) with no edges
yaml
- flag: hideDisconnected
- flag: hideDisconnectedBuiltIns

Selector Syntax ​

Selectors are expressions that identify atoms or tuples. The syntax depends on your data format (Forge, Alloy, etc.); common patterns:

PatternDescriptionExample
TypeNameAll atoms of a typePerson
fieldNameAll tuples in a relationparent
Type.fieldField accessPerson.age
selector1 + selector2UnionStudent + Teacher
selector1 & selector2IntersectionPerson & Employee
selector1 - selector2DifferencePerson - Manager
~selectorTranspose~parent (child relation)
^selectorTransitive closure^parent (all ancestors)
*selectorReflexive transitive closure*parent
selector1 -> selector2ProductPerson -> Int
selector1.selector2JoinPerson.parent

See Selectors for the full operator set.


Complete Example ​

yaml
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

Released under the MIT License.