Visualization

Mechanoid emits Mermaid (and GraphViz) from the same Machine you run. This site feeds that source into mermoid so the published picture fails CI if the Mermaid cannot parse.

State diagram

MermaidVisualizer.stateDiagram(machine, Some(Created)) (also machine.toMermaidStateDiagram(Some(Created))):

{
  enum OrderState derives Finite:
    case Created, Processing, Completed

  enum OrderEvent derives Finite:
    case Start, Finish

  import OrderState.*, OrderEvent.*

  val machine = Machine(
    assembly[OrderState, OrderEvent](
      Created via Start to Processing,
      Processing via Finish to Completed,
    )
  )

  Mermoid.diagram(
    MermaidVisualizer.stateDiagram(machine, Some(Created)),
    Mermoid.chalkboard,
  )
}
StartFinish

Flowchart

MermaidVisualizer.flowchart(machine) is often clearer for dense graphs (Domain pages use it):

{
  enum OrderState derives Finite:
    case Created, Processing, Completed

  enum OrderEvent derives Finite:
    case Start, Finish

  import OrderState.*, OrderEvent.*

  val machine = Machine(
    assembly[OrderState, OrderEvent](
      Created via Start to Processing,
      Processing via Finish to Completed,
    )
  )

  Mermoid.diagram(
    MermaidVisualizer.flowchart(machine),
    Mermoid.chalkboard,
  )
}
StartFinish

Query the graph

MachineGraph reads the same assembly edges Mermaid walks. hasEdge is the declared transition, not reducer success. destLeaf is the Goto leaf name, or the current leaf for Stay / Stop (None when there is no edge). Call sites do not hash Finite cases.

{
  enum OrderState derives Finite:
    case Created, Processing, Completed

  enum OrderEvent derives Finite:
    case Start, Finish

  import OrderState.*, OrderEvent.*

  val machine = Machine(
    assembly[OrderState, OrderEvent](
      Created via Start to Processing,
      Processing via Finish to Completed,
      Processing via Start to stay,
    )
  )

  Mermoid.diagram(
    MermaidVisualizer.stateDiagram(machine, Some(Created)),
    Mermoid.chalkboard,
  )
}
StartFinishStart
{
  enum OrderState derives Finite:
    case Created, Processing, Completed

  enum OrderEvent derives Finite:
    case Start, Finish

  import OrderState.*, OrderEvent.*

  val machine = Machine(
    assembly[OrderState, OrderEvent](
      Created via Start to Processing,
      Processing via Finish to Completed,
      Processing via Start to stay,
    )
  )

  val startEdge  = MachineGraph.hasEdge(machine, Created, Start)
  val startDest  = MachineGraph.destLeaf(machine, Created, Start)
  val finishEdge = MachineGraph.hasEdge(machine, Created, Finish)
  val finishDest = MachineGraph.destLeaf(machine, Created, Finish)
  val stayDest   = MachineGraph.destLeaf(machine, Processing, Start)
  ZIO.succeed(
    List(
      s"hasEdge(Created, Start) = $startEdge",
      s"destLeaf(Created, Start) = $startDest",
      s"hasEdge(Created, Finish) = $finishEdge",
      s"destLeaf(Created, Finish) = $finishDest",
      s"destLeaf(Processing, Start) = $stayDest",
    ).mkString("\n")
  )
}
hasEdge(Created, Start) = true
destLeaf(Created, Start) = Some(Processing)
hasEdge(Created, Finish) = false
destLeaf(Created, Finish) = None
destLeaf(Processing, Start) = Some(Processing)

Traces and GraphViz

Also available:

  • toMermaidFlowchartWithTrace(trace) / trace.toMermaidSequenceDiagram

  • toGraphViz(...) / toGraphVizWithTrace(...) / trace.toGraphVizTimeline

Mark sensitive fields with @sensitive when exporting. Feed Mermaid strings into Mermoid.diagram(...) or a fenced mermaid block.

Next: Reference.