Skip to content

Control layout

Kekonic Diagrams owns coordinates, but you own visual structure. Give the engine a reading direction, meaningful boundaries, and a small number of constraints. Tune the result only after the model is clear.

Work down this list. Stop as soon as the diagram reads well.

  1. Set direction.
  2. Reorder declarations to match the story.
  3. Add meaningful groups.
  4. Change density or crossing treatment.
  5. Arrange regions into rows, stacks, or a grid.
  6. Split the diagram.

The last option is often better than adding more configuration.

diagram.kdiagram
direction LR // left to right
direction TD // top to bottom
direction RL // right to left
direction BT // bottom to top

Architecture and data flow usually read well as LR. Workflows usually read well as TD. Choose the direction that matches the story, not the available page shape.

Kekonic Diagrams lays out the contents of a group and the relationships between groups. That makes a group stronger than a decorative enclosure:

diagram.kdiagram
group application "Application" {
arrange: stack
api: gateway "API"
checkout: service "Checkout"
}
group data "Data" {
arrange: stack
database: database "Postgres"
events: broker "Kafka"
}

Use arrange: pack for a compact cluster, stack for horizontal bands in a top-down diagram or vertical members in a left-to-right one, and row for the opposite axis.

When the regions themselves have a stable order, wrap them in a parent and arrange the children:

diagram.kdiagram
group platform {
chrome: false
arrange: row
align: stretch
group edge "Edge" { /* … */ }
group core "Core" { /* … */ }
group data "Data" { /* … */ }
}

Visible groups are a dashed outline without a fill — nested boxes would otherwise stack translucent washes on the canvas. chrome: false makes the parent structural without painting another visible box. align: stretch asks sibling regions to share the available cross-axis size.

For ports-and-adapters or onion-style views, nest a hub group and put satellite nodes as siblings with arrange: surround. Optional shape: hexagon or shape: circle paints that chrome silhouette. Nest surround groups to build rings (adapters outside, ports inside):

diagram.kdiagram
group service "Order service" {
shape: hexagon
arrange: surround
group core "Domain" {
arrange: stack
app: component "Handler"
}
api: component "API adapter" { side: west }
store: component "Store adapter" { side: east }
}

Satellite nodes sit in the annulus inside the parent chrome and outside the hub. Depth is unlimited: the hub may itself use arrange: surround. Kekonic Diagrams does not attach ports to hex faces.

For a whole-diagram staged composition, put arrange in the layout block. Ungrouped nodes and top-level regions share the tracks in declaration order, so an actor, service boundary, adapter, and external system can form one predictable progression without layout-only wrapper groups:

diagram.kdiagram
layout { arrange: row }
client: application "Client"
group service "Service" { /* ports and core */ }
repository: component "Repository Adapter"
database: database "Database"

A grid is appropriate when both rows and columns have meaning—platform zones by concern and runtime, for example:

diagram.kdiagram
group platform {
arrange: grid
columns: [edge, core, data]
rows: 2
group gatewayPlane "Edge" { column: edge }
group services "Core" { column: core; rowSpan: 2 }
group stores "Data" { column: data }
group operations "Operations" { column: edge; row: 2 }
}

Use named columns when names make the source easier to review. rowSpan and colSpan let a region occupy more than one track. A grid is not a pixel canvas; it declares relationships between regions.

Edit source — diagram updates live
Source

Put diagram-wide policy in blocks:

diagram.kdiagram
layout {
density: normal
spacingScale: 1.1
groupLayout: compound
considerModelOrder: true
}
edges {
route: metro
crossings: smart
}

density is the first spacing control. spacingScale is a multiplier for finer adjustment. considerModelOrder asks the layout engine to respect declaration order where it can; it is a preference, not a guarantee.

Routes:

  • metro (default) and rounded — orthogonal corridors with eased ports and curved avoidance (not sharp 90° stairs)
  • orthogonal — the same corridors with sharp corners
  • straight — a true port-to-port chord when that line misses other nodes; otherwise a short dogleg that follows the existing corridor
  • bezier — a smoother cubic along that corridor, using port exit/entry directions and splitting around nodes instead of drawing a naive center-to-center S-curve

Crossing treatment can be none, gaps, jumps, or smart. Layout still owns the channel; metro, rounded, bezier, and straight refine it rather than inventing a second router.

swimlane groups are horizontal responsibility bands with a shared left-to-right process timeline and a left header. Adjacent lanes share a hairline, not a dashed box around each band. Top-level swimlanes infer groupLayout: swimlane and direction: LR. See Expense approval.

arrange: row (or stacked groups inside a row) is the right tool for owner columns — architecture or workflow bands that do not share a process axis. See Customer refund request. Do not force a column composition into swimlane just because the groups are named after teams.

Diagnose structure before spacing:

  • No obvious entry point: the graph may have several stories; split it or raise one path’s priority.
  • Groups create huge empty areas: remove weak boundaries or avoid deeply nested compound groups.
  • Too many crossings: reduce edges, group related endpoints, or split views before increasing spacing.
  • Labels fight the lines: shorten them and put detail in surrounding prose.
  • One node dominates: shorten its label or use minWidth/maxWidth intentionally.

Kekonic Diagrams does not expose arbitrary coordinates. If the exact position of an individual shape is a hard requirement, use a drawing tool.