Pugflow

Complete offline reference for building, styling, editing, and exporting source-first diagrams.

Getting started

A project needs one Pug file and may have one companion CSS file. Pug describes structure and local overrides; CSS holds reusable node, flow, and annotation types. The smallest diagram is:

graph
  .node
    .id start
    .right-ports distributed
    .label Start

Indentation defines ownership. Use two spaces consistently. Blank lines and lines beginning with // are ignored. Save Pug and CSS to keep the project editable; SVG and PNG are export formats.

Canvas and graphs

The canvas is always implied, so an empty file is a valid empty canvas. Put canvas defaults, one or more sibling graph blocks, and cross-graph flows directly at the source root. Graphs never nest. Declare every node directly inside its graph and put a flow inside that graph when both endpoints belong to it. Legacy #canvas and #diagram roots still parse, but new source never needs or emits them.

.background #ffffff
graph
  .id main
  .label Main process
  .label-position outside
  .align center
  .font-size 16
  .font-weight bold
  .node
    .id root
    .label Root
graph
  .id separate
  .layer 1
  .offset (0, 40)
  .node
    .label Independent graph

Graph titles support .label-position inside|outside, horizontal .align left|center|right, vertical .vertical-align top|middle|bottom, .label-offset (x, y), .color, and all font options. Titles default to top-center inside the graph. Drag a graph title to set its label offset. Use .placement above|below|left|right with .relative-to graph-id to position a graph relative to another graph. Without these fields, each graph is placed below the previous graph. Use .x-spacing and .y-spacing to tune layout within a graph. Frames are automatically packed without overlap by default. Explicit offsets may overlap frames. Clean Up removes small accidental flow kinks within and between graphs while preserving deliberate bends; cross-graph corrections move whole graphs rather than altering their internal layouts. Higher layers render in front; equal layers retain source order. The right-side Objects panel combines collapsible graph ordering with a graph picker and clickable node/flow lists. A flow renders at the higher layer of its endpoint graphs.

Nodes

A node always starts with .node; nest a reusable @node class such as .card directly beneath it to apply that type, exactly as flows nest their class inside .flow. Declaring the class itself as the keyword still works for older documents. Keep identity, label, layout, and appearance fields together beneath it. Declaration order initially controls stacking within the graph, with later nodes in front. Reordering nodes adds integer .layer overrides to the source.

.node
  .id service
  .layer 1
  .label
    | Service name
    | Multiline description
  .shape rounded
  .width 220
  .height auto
  .fill #ffffff
  .color #111827
  .outline #94a3b8
  .outline-style dashed
  .outline-width 2
  .align left
  .vertical-align middle

Nodes do not nest. Give connected nodes IDs and declare their relationships as sibling .flow blocks in the graph.

Flows

Every flow explicitly identifies its source and target node. Branching and merging are inferred when several flows share a source or target.

graph
  .node
    .id start
    .label Start
  .node
    .id validate
    .label Validate
  .node
    .id publish
    .label Publish
  .flow
    .from start
    .to validate
    .direction right
  .flow
    .from validate
    .to publish

Directions are right, left, up, and down. Every node face has its own port setting: top-ports, right-ports, bottom-ports, and left-ports. Each is shared by default or may be distributed. Multiple outgoing flows are rendered as branches; multiple incoming flows are rendered as a merge. No separate branch, merge, or connection keyword is needed.

A flow may also connect any two nodes by ID, regardless of their order in the source. This supports convergence, feedback, cross-graph connections, and targets declared later:

.flow
  .from archived
  .to active
  .from-direction up
  .to-direction left
  .feedback_flow
  .label feedback

.from-direction controls the side used to leave the source; .to-direction independently controls the side used to enter the target.

Flows may contain any number of direct annotations. They appear above the route by default and may be dragged to write an .offset:

.flow
  .from validate
  .to publish
  .annotation
    | first note
  .annotation
    .color #dc2626
    | second note

Set .arrow-shape chunky for a filled block arrow. Its .color is the fill, while .outline and .outline-width control the outside border. .arrow-height sets shaft height and .arrow-head-width sets head length.

Reusable CSS

Reusable definitions may be written at the source root in Pug or in the optional CSS tab. CSS uses Pugflow at-rules rather than browser selectors:

@node card {
  shape: rounded;
  fill: #ffffff;
  outline: #94a3b8;
  shadow-color: #000000;
}

@flow warning {
  color: #dc2626;
  stroke-style: dashed;
  arrow-style: both;
}

@annotation note {
  color: #2563eb;
  font-style: italic;
}

Nest .card inside .node, and .warning/.note inside the flow or annotation they decorate. Local fields beneath an item override its reusable type. Names must be unique across all four definition kinds: node, flow, graph, and annotation.

Text and annotations

Graph titles, nodes, annotations, and connection labels support font-family, font-size, font-weight, font-style, text-decoration, text-outline, and text-outline-width. Text outlines are transparent with zero width by default. Nodes additionally support horizontal .align left|center|right and .vertical-align top|middle|bottom. A node may have any number of annotations above or below it. In the node inspector, use + Add Annotation, choose Above or Below as a convenient starting position, then edit, hide, delete, or drag each annotation to set its own offset.

.node
  .label Important
  .font-size 20
  .font-weight bold
  .font-style italic
  .text-decoration underline
  .annotation
    .above
      .font-size 13
      .color #2563eb
      | Annotation above
    .below Annotation below

Use $...$ for inline math and $$...$$ for display math. Pugflow bundles MathJax and renders real TeX as self-contained SVG paths in nodes, node annotations, and flow annotations. Equations are measured during layout and work in offline SVG, PNG, and CLI exports.

Images and shadows

.node
  .label Profile
  .image photos/profile.png
  .image-width 96
  .image-height 96
  .image-fit contain
  .image-opacity 1
  .image-padding 8
  .shadow-color #000000
  .shadow-offset-x 4
  .shadow-offset-y 5
  .shadow-blur 8
  .shadow-opacity 0.3

The node grows to contain the complete image plus padding. Image fit accepts contain, cover, or fill. Drag the image or its resize handles on the canvas to write image geometry and .image-offset.

Hiding items

Add .hidden to a node, annotation, flow, or graph. Hidden nodes remain in layout so before/after versions retain exact placement; their annotations and every touching flow are also hidden. Hidden graphs, nodes, and flows appear struck through in the Objects panel.

Canvas editing

Source editor

The editor provides line numbers, current-line highlighting, syntax color, color pickers beside hex values, completions with Ctrl+Space, Tab/Shift+Tab indentation, and click-to-source navigation. Vim mode is off by default and supports Normal, Insert, and Visual modes, a block cursor, movement/edit/yank/paste/marks, >/< indentation, and Escape/Ctrl+[ /Ctrl+C to return to Normal mode.

Pug and CSS files

The File menu creates or opens Pug and CSS documents. Save writes the active tab directly to its selected system file, while Save As chooses a new location. The CSS file is optional unless custom types are referenced. Each editor tab shows the exact filename being edited. Hide source collapses the source panel and remembers that preference. Pugflow intentionally starts blank or with --demo; it does not restore source text in browser storage.

Command line

pugflow                         # blank GUI
pugflow --demo                  # GUI with feature tour
pugflow --vim                   # GUI with Vim enabled
pugflow --gui diagram.pug --css diagram.css
pugflow diagram.pug
pugflow diagram.pug --css styles.css --output diagram.png --scale 2
pugflow --no-browser --host 127.0.0.1 --port 4173

Direct rendering uses an installed Edge, Chrome, or Chromium browser. Set PUGFLOW_BROWSER if automatic discovery cannot find it.

Property reference

ScopeFields
Canvasbackground, font, nested defaults.node, defaults.flow, defaults.annotation
Graphid, label, label-position, label-offset, align, vertical-align, layer, placement, relative-to, offset, x-spacing, y-spacing, fill, color, font options, text-outline, text-outline-width, outline, outline-style, outline-width, padding, hidden
Nodeid, label, optional layer, top-ports, right-ports, bottom-ports, left-ports, shape, fill, color, outline, outline-style, outline-width, width, height, align, vertical-align, offset, label-offset, font options, text-outline, text-outline-width, image, shadow, hidden
Flowfrom, to, direction, from-direction, to-direction, color (chunky fill), width, outline, outline-width, roundness (corner radius; 0 for sharp bends), stroke-style, arrow-style, arrow-shape, chunky arrow-height and arrow-head-width, source-face, target-face, label, repeated annotation, label-offset, font options, text-outline, text-outline-width, hidden
Annotationcolor, offset, font options, text-outline, text-outline-width, hidden
Font optionsfont-family, font-size, font-weight, font-style, text-decoration, text-outline, text-outline-width
Imageimage, image-width, image-height, image-fit, image-opacity, image-padding, image-offset
Shadowshadow-color, shadow-offset-x, shadow-offset-y, shadow-blur, shadow-opacity