Skip to content
ConsoleMonster

Diagrams, zero to hero

Draw terminal diagrams in C#, fluent C# or PowerShell, one idea at a time, from three boxes to live values, request walkthroughs and hierarchies.

A diagram should take a minute to type. Each step below adds one idea to the last, and each frame is what the program beside it prints, in C#, with the fluent builder or in PowerShell. The core package draws every diagram as a tree and needs nothing else; with ConsoleMonster.Graphics registered, as here, you get boxes, routed connections and groups, laid out by ChartForgeX.

The PowerShell commands follow PSWriteHTML's diagrams: New-ConsoleDiagramNode -Label 'A' -To 'B' is the whole first lesson, and New-ConsoleDiagramLink and New-ConsoleDiagramGroup come when you need them.

1. Three boxes, two arrows

A node can point at other nodes with To.

Install-Module ConsoleMonster -Scope CurrentUser
PowerShelldiagram-1.ps1
# A node can point at other nodes with -To.
New-ConsoleDiagram {
    New-ConsoleDiagramNode 'Laptop' -To 'Router'
    New-ConsoleDiagramNode 'Router' -To 'Internet'
    New-ConsoleDiagramNode 'Internet'
} | Show-Console
Full program
Import-Module ConsoleMonster

# A node can point at other nodes with -To.
New-ConsoleDiagram {
    New-ConsoleDiagramNode 'Laptop' -To 'Router'
    New-ConsoleDiagramNode 'Router' -To 'Internet'
    New-ConsoleDiagramNode 'Internet'
} | Show-Console

Run: ./diagram-1.ps1

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C#Program.cs
DiagramRendererProvider.Register();

// A node can point at other nodes with To.
var diagram = new Diagram {
    Nodes = {
        new DiagramNode("Laptop") { To = { "Router" } },
        new DiagramNode("Router") { To = { "Internet" } },
        new DiagramNode("Internet")
    }
};
Terminal.Write(diagram);
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// A node can point at other nodes with To.
var diagram = new Diagram {
    Nodes = {
        new DiagramNode("Laptop") { To = { "Router" } },
        new DiagramNode("Router") { To = { "Internet" } },
        new DiagramNode("Internet")
    }
};
Terminal.Write(diagram);

Run: dotnet run

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C# fluentProgram.cs
DiagramRendererProvider.Register();

// A node can point at other nodes with To.
var diagram = Ui.Diagram()
    .AddNode(new DiagramNode("Laptop") { To = { "Router" } })
    .AddNode(new DiagramNode("Router") { To = { "Internet" } })
    .AddNode(new DiagramNode("Internet"));
diagram.Show();
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// A node can point at other nodes with To.
var diagram = Ui.Diagram()
    .AddNode(new DiagramNode("Laptop") { To = { "Router" } })
    .AddNode(new DiagramNode("Router") { To = { "Internet" } })
    .AddNode(new DiagramNode("Internet"));
diagram.Show();

Run: dotnet run

Three boxes, two arrows 120×524-bitFull

2. Kinds and labels

Kind says what a node is (and picks its icon in images and HTML). A link of its own, New-ConsoleDiagramLink or DiagramLink, can carry a label.

Install-Module ConsoleMonster -Scope CurrentUser
PowerShelldiagram-2.ps1
# -Kind says what a node is; a link of its own can carry a label.
New-ConsoleDiagram -Title 'Home network' {
    New-ConsoleDiagramNode 'Laptop' -Kind Workstation -Subtitle 'Wi-Fi'
    New-ConsoleDiagramNode 'TV' -Kind Workstation -Subtitle 'Ethernet'
    New-ConsoleDiagramNode 'NAS' -Kind Storage -Subtitle 'Photos, backups'
    New-ConsoleDiagramNode 'Router' -Kind Gateway -Subtitle '192.168.1.1'
    New-ConsoleDiagramNode 'Internet' -Kind Cloud -Subtitle 'Fibre 1 Gb'
    New-ConsoleDiagramLink 'Laptop' 'Router' -Label 'Wi-Fi'
    New-ConsoleDiagramLink 'TV' 'Router' -Label '1 Gb'
    New-ConsoleDiagramLink 'NAS' 'Router' -Label '1 Gb'
    New-ConsoleDiagramLink 'Router' 'Internet' -Label 'WAN'
} | Show-Console
Full program
Import-Module ConsoleMonster

# -Kind says what a node is; a link of its own can carry a label.
New-ConsoleDiagram -Title 'Home network' {
    New-ConsoleDiagramNode 'Laptop' -Kind Workstation -Subtitle 'Wi-Fi'
    New-ConsoleDiagramNode 'TV' -Kind Workstation -Subtitle 'Ethernet'
    New-ConsoleDiagramNode 'NAS' -Kind Storage -Subtitle 'Photos, backups'
    New-ConsoleDiagramNode 'Router' -Kind Gateway -Subtitle '192.168.1.1'
    New-ConsoleDiagramNode 'Internet' -Kind Cloud -Subtitle 'Fibre 1 Gb'
    New-ConsoleDiagramLink 'Laptop' 'Router' -Label 'Wi-Fi'
    New-ConsoleDiagramLink 'TV' 'Router' -Label '1 Gb'
    New-ConsoleDiagramLink 'NAS' 'Router' -Label '1 Gb'
    New-ConsoleDiagramLink 'Router' 'Internet' -Label 'WAN'
} | Show-Console

Run: ./diagram-2.ps1

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C#Program.cs
DiagramRendererProvider.Register();

// Kind says what a node is; a link of its own can carry a label.
var diagram = new Diagram("Home network") {
    Nodes = {
        new DiagramNode("Laptop") { Kind = DiagramNodeKind.Workstation, Subtitle = "Wi-Fi" },
        new DiagramNode("TV") { Kind = DiagramNodeKind.Workstation, Subtitle = "Ethernet" },
        new DiagramNode("NAS") { Kind = DiagramNodeKind.Storage, Subtitle = "Photos, backups" },
        new DiagramNode("Router") { Kind = DiagramNodeKind.Gateway, Subtitle = "192.168.1.1" },
        new DiagramNode("Internet") { Kind = DiagramNodeKind.Cloud, Subtitle = "Fibre 1 Gb" }
    },
    Links = {
        new DiagramLink("Laptop", "Router") { Label = "Wi-Fi" },
        new DiagramLink("TV", "Router") { Label = "1 Gb" },
        new DiagramLink("NAS", "Router") { Label = "1 Gb" },
        new DiagramLink("Router", "Internet") { Label = "WAN" }
    }
};
Terminal.Write(diagram);
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// Kind says what a node is; a link of its own can carry a label.
var diagram = new Diagram("Home network") {
    Nodes = {
        new DiagramNode("Laptop") { Kind = DiagramNodeKind.Workstation, Subtitle = "Wi-Fi" },
        new DiagramNode("TV") { Kind = DiagramNodeKind.Workstation, Subtitle = "Ethernet" },
        new DiagramNode("NAS") { Kind = DiagramNodeKind.Storage, Subtitle = "Photos, backups" },
        new DiagramNode("Router") { Kind = DiagramNodeKind.Gateway, Subtitle = "192.168.1.1" },
        new DiagramNode("Internet") { Kind = DiagramNodeKind.Cloud, Subtitle = "Fibre 1 Gb" }
    },
    Links = {
        new DiagramLink("Laptop", "Router") { Label = "Wi-Fi" },
        new DiagramLink("TV", "Router") { Label = "1 Gb" },
        new DiagramLink("NAS", "Router") { Label = "1 Gb" },
        new DiagramLink("Router", "Internet") { Label = "WAN" }
    }
};
Terminal.Write(diagram);

Run: dotnet run

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C# fluentProgram.cs
DiagramRendererProvider.Register();

// Kind says what a node is; a link of its own can carry a label.
var diagram = Ui.Diagram()
    .Title("Home network")
    .AddNode(new DiagramNode("Laptop").Kind(DiagramNodeKind.Workstation).Subtitle("Wi-Fi"))
    .AddNode(new DiagramNode("TV").Kind(DiagramNodeKind.Workstation).Subtitle("Ethernet"))
    .AddNode(new DiagramNode("NAS").Kind(DiagramNodeKind.Storage).Subtitle("Photos, backups"))
    .AddNode(new DiagramNode("Router").Kind(DiagramNodeKind.Gateway).Subtitle("192.168.1.1"))
    .AddNode(new DiagramNode("Internet").Kind(DiagramNodeKind.Cloud).Subtitle("Fibre 1 Gb"))
    .AddLink(new DiagramLink("Laptop", "Router").Label("Wi-Fi"))
    .AddLink(new DiagramLink("TV", "Router").Label("1 Gb"))
    .AddLink(new DiagramLink("NAS", "Router").Label("1 Gb"))
    .AddLink(new DiagramLink("Router", "Internet").Label("WAN"));
diagram.Show();
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// Kind says what a node is; a link of its own can carry a label.
var diagram = Ui.Diagram()
    .Title("Home network")
    .AddNode(new DiagramNode("Laptop").Kind(DiagramNodeKind.Workstation).Subtitle("Wi-Fi"))
    .AddNode(new DiagramNode("TV").Kind(DiagramNodeKind.Workstation).Subtitle("Ethernet"))
    .AddNode(new DiagramNode("NAS").Kind(DiagramNodeKind.Storage).Subtitle("Photos, backups"))
    .AddNode(new DiagramNode("Router").Kind(DiagramNodeKind.Gateway).Subtitle("192.168.1.1"))
    .AddNode(new DiagramNode("Internet").Kind(DiagramNodeKind.Cloud).Subtitle("Fibre 1 Gb"))
    .AddLink(new DiagramLink("Laptop", "Router").Label("Wi-Fi"))
    .AddLink(new DiagramLink("TV", "Router").Label("1 Gb"))
    .AddLink(new DiagramLink("NAS", "Router").Label("1 Gb"))
    .AddLink(new DiagramLink("Router", "Internet").Label("WAN"));
diagram.Show();

Run: dotnet run

Kinds and labels 120×1524-bitFull

3. Groups

A group is a block around its nodes, the way a panel wraps content. Groups can nest.

Install-Module ConsoleMonster -Scope CurrentUser
PowerShelldiagram-3.ps1
# A group is a block around its nodes.
New-ConsoleDiagram -Title 'Small office' {
    New-ConsoleDiagramGroup 'Office LAN' {
        New-ConsoleDiagramNode '12 PCs' -Kind Workstation -To 'Firewall'
        New-ConsoleDiagramNode 'File server' -Kind Storage -Subtitle 'FS01'
        New-ConsoleDiagramNode 'Printer' -Kind Device
    }
    New-ConsoleDiagramGroup 'DMZ' {
        New-ConsoleDiagramNode 'Web server' -Kind Server -Subtitle 'WEB01'
    }
    New-ConsoleDiagramGroup 'Cloud' {
        New-ConsoleDiagramNode 'Microsoft 365' -Kind Cloud
        New-ConsoleDiagramNode 'Backup' -Kind Storage -Subtitle 'Offsite'
    }
    New-ConsoleDiagramNode 'Firewall' -Kind Gateway -To 'Web server', 'Microsoft 365'
    New-ConsoleDiagramLink 'File server' 'Backup' -Label 'nightly'
} | Show-Console
Full program
Import-Module ConsoleMonster

# A group is a block around its nodes.
New-ConsoleDiagram -Title 'Small office' {
    New-ConsoleDiagramGroup 'Office LAN' {
        New-ConsoleDiagramNode '12 PCs' -Kind Workstation -To 'Firewall'
        New-ConsoleDiagramNode 'File server' -Kind Storage -Subtitle 'FS01'
        New-ConsoleDiagramNode 'Printer' -Kind Device
    }
    New-ConsoleDiagramGroup 'DMZ' {
        New-ConsoleDiagramNode 'Web server' -Kind Server -Subtitle 'WEB01'
    }
    New-ConsoleDiagramGroup 'Cloud' {
        New-ConsoleDiagramNode 'Microsoft 365' -Kind Cloud
        New-ConsoleDiagramNode 'Backup' -Kind Storage -Subtitle 'Offsite'
    }
    New-ConsoleDiagramNode 'Firewall' -Kind Gateway -To 'Web server', 'Microsoft 365'
    New-ConsoleDiagramLink 'File server' 'Backup' -Label 'nightly'
} | Show-Console

Run: ./diagram-3.ps1

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C#Program.cs
DiagramRendererProvider.Register();

// A group is a block around its nodes.
var diagram = new Diagram("Small office") {
    Groups = {
        new DiagramGroup("Office LAN") {
            Nodes = {
                new DiagramNode("12 PCs") {
                    Kind = DiagramNodeKind.Workstation,
                    To = { "Firewall" }
                },
                new DiagramNode("File server") {
                    Kind = DiagramNodeKind.Storage,
                    Subtitle = "FS01"
                },
                new DiagramNode("Printer") { Kind = DiagramNodeKind.Device }
            }
        },
        new DiagramGroup("DMZ") {
            Nodes = {
                new DiagramNode("Web server") {
                    Kind = DiagramNodeKind.Server,
                    Subtitle = "WEB01"
                }
            }
        },
        new DiagramGroup("Cloud") {
            Nodes = {
                new DiagramNode("Microsoft 365") { Kind = DiagramNodeKind.Cloud },
                new DiagramNode("Backup") {
                    Kind = DiagramNodeKind.Storage,
                    Subtitle = "Offsite"
                }
            }
        }
    },
    Nodes = {
        new DiagramNode("Firewall") {
            Kind = DiagramNodeKind.Gateway,
            To = { "Web server", "Microsoft 365" }
        }
    },
    Links = {
        new DiagramLink("File server", "Backup") { Label = "nightly" }
    }
};
Terminal.Write(diagram);
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// A group is a block around its nodes.
var diagram = new Diagram("Small office") {
    Groups = {
        new DiagramGroup("Office LAN") {
            Nodes = {
                new DiagramNode("12 PCs") {
                    Kind = DiagramNodeKind.Workstation,
                    To = { "Firewall" }
                },
                new DiagramNode("File server") {
                    Kind = DiagramNodeKind.Storage,
                    Subtitle = "FS01"
                },
                new DiagramNode("Printer") { Kind = DiagramNodeKind.Device }
            }
        },
        new DiagramGroup("DMZ") {
            Nodes = {
                new DiagramNode("Web server") {
                    Kind = DiagramNodeKind.Server,
                    Subtitle = "WEB01"
                }
            }
        },
        new DiagramGroup("Cloud") {
            Nodes = {
                new DiagramNode("Microsoft 365") { Kind = DiagramNodeKind.Cloud },
                new DiagramNode("Backup") {
                    Kind = DiagramNodeKind.Storage,
                    Subtitle = "Offsite"
                }
            }
        }
    },
    Nodes = {
        new DiagramNode("Firewall") {
            Kind = DiagramNodeKind.Gateway,
            To = { "Web server", "Microsoft 365" }
        }
    },
    Links = {
        new DiagramLink("File server", "Backup") { Label = "nightly" }
    }
};
Terminal.Write(diagram);

Run: dotnet run

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C# fluentProgram.cs
DiagramRendererProvider.Register();

// A group is a block around its nodes.
var diagram = Ui.Diagram()
    .Title("Small office")
    .AddGroup(new DiagramGroup("Office LAN") { Nodes =
    {
        new DiagramNode("12 PCs") { Kind = DiagramNodeKind.Workstation, To = { "Firewall" } },
        new DiagramNode("File server").Kind(DiagramNodeKind.Storage).Subtitle("FS01"),
        new DiagramNode("Printer").Kind(DiagramNodeKind.Device)
    } })
    .AddGroup(new DiagramGroup("DMZ") { Nodes = { new DiagramNode("Web server")
        .Kind(DiagramNodeKind.Server)
        .Subtitle("WEB01") } })
    .AddGroup(new DiagramGroup("Cloud") { Nodes =
    {
        new DiagramNode("Microsoft 365").Kind(DiagramNodeKind.Cloud),
        new DiagramNode("Backup").Kind(DiagramNodeKind.Storage).Subtitle("Offsite")
    } })
    .AddNode(new DiagramNode("Firewall")
    {
        Kind = DiagramNodeKind.Gateway,
        To = { "Web server", "Microsoft 365" }
    })
    .AddLink(new DiagramLink("File server", "Backup").Label("nightly"));
diagram.Show();
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// A group is a block around its nodes.
var diagram = Ui.Diagram()
    .Title("Small office")
    .AddGroup(new DiagramGroup("Office LAN") { Nodes =
    {
        new DiagramNode("12 PCs") { Kind = DiagramNodeKind.Workstation, To = { "Firewall" } },
        new DiagramNode("File server").Kind(DiagramNodeKind.Storage).Subtitle("FS01"),
        new DiagramNode("Printer").Kind(DiagramNodeKind.Device)
    } })
    .AddGroup(new DiagramGroup("DMZ") { Nodes = { new DiagramNode("Web server")
        .Kind(DiagramNodeKind.Server)
        .Subtitle("WEB01") } })
    .AddGroup(new DiagramGroup("Cloud") { Nodes =
    {
        new DiagramNode("Microsoft 365").Kind(DiagramNodeKind.Cloud),
        new DiagramNode("Backup").Kind(DiagramNodeKind.Storage).Subtitle("Offsite")
    } })
    .AddNode(new DiagramNode("Firewall")
    {
        Kind = DiagramNodeKind.Gateway,
        To = { "Web server", "Microsoft 365" }
    })
    .AddLink(new DiagramLink("File server", "Backup").Label("nightly"));
diagram.Show();

Run: dotnet run

Groups 120×3024-bitFull

4. Status

Status uses the same words as every other widget: Pass, Warn, Fail, Info and Pending. Put what is wrong in Value. A node without a status shows no mark, the legend appears only when something isn't fine, and Needs attention under the diagram lists every node and link that isn't, with its full text.

Install-Module ConsoleMonster -Scope CurrentUser
PowerShelldiagram-4.ps1
# Status uses the same words as every widget; -Value says what is wrong.
New-ConsoleDiagram -Title 'Small office · Monday 08:10' {
    New-ConsoleDiagramGroup 'Office LAN' {
        New-ConsoleDiagramNode '12 PCs' -Kind Workstation -To 'Firewall'
        New-ConsoleDiagramNode 'File server' -Kind Storage -Status Warn -Value 'disk 91%'
        New-ConsoleDiagramNode 'Printer' -Kind Device -Status Fail -Value 'offline'
    }
    New-ConsoleDiagramGroup 'Cloud' {
        New-ConsoleDiagramNode 'Microsoft 365' -Kind Cloud
        New-ConsoleDiagramNode 'Backup' -Kind Storage -Status Fail -Value 'last success 2 days ago'
    }
    New-ConsoleDiagramNode 'Firewall' -Kind Gateway -To 'Microsoft 365'
    New-ConsoleDiagramLink 'File server' 'Backup' -Label 'failed 2 nights' -Status Fail
} | Show-Console
Full program
Import-Module ConsoleMonster

# Status uses the same words as every widget; -Value says what is wrong.
New-ConsoleDiagram -Title 'Small office · Monday 08:10' {
    New-ConsoleDiagramGroup 'Office LAN' {
        New-ConsoleDiagramNode '12 PCs' -Kind Workstation -To 'Firewall'
        New-ConsoleDiagramNode 'File server' -Kind Storage -Status Warn -Value 'disk 91%'
        New-ConsoleDiagramNode 'Printer' -Kind Device -Status Fail -Value 'offline'
    }
    New-ConsoleDiagramGroup 'Cloud' {
        New-ConsoleDiagramNode 'Microsoft 365' -Kind Cloud
        New-ConsoleDiagramNode 'Backup' -Kind Storage -Status Fail -Value 'last success 2 days ago'
    }
    New-ConsoleDiagramNode 'Firewall' -Kind Gateway -To 'Microsoft 365'
    New-ConsoleDiagramLink 'File server' 'Backup' -Label 'failed 2 nights' -Status Fail
} | Show-Console

Run: ./diagram-4.ps1

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C#Program.cs
DiagramRendererProvider.Register();

// Status uses the same words as every widget; Value says what is wrong.
var diagram = new Diagram("Small office · Monday 08:10") {
    Groups = {
        new DiagramGroup("Office LAN") {
            Nodes = {
                new DiagramNode("12 PCs") {
                    Kind = DiagramNodeKind.Workstation,
                    To = { "Firewall" }
                },
                new DiagramNode("File server") {
                    Kind = DiagramNodeKind.Storage,
                    Status = StatusKind.Warn,
                    Value = "disk 91%"
                },
                new DiagramNode("Printer") {
                    Kind = DiagramNodeKind.Device,
                    Status = StatusKind.Fail,
                    Value = "offline"
                }
            }
        },
        new DiagramGroup("Cloud") {
            Nodes = {
                new DiagramNode("Microsoft 365") { Kind = DiagramNodeKind.Cloud },
                new DiagramNode("Backup") {
                    Kind = DiagramNodeKind.Storage,
                    Status = StatusKind.Fail,
                    Value = "last success 2 days ago"
                }
            }
        }
    },
    Nodes = {
        new DiagramNode("Firewall") {
            Kind = DiagramNodeKind.Gateway,
            To = { "Microsoft 365" }
        }
    },
    Links = {
        new DiagramLink("File server", "Backup") {
            Label = "failed 2 nights",
            Status = StatusKind.Fail
        }
    }
};
Terminal.Write(diagram);
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Styling;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// Status uses the same words as every widget; Value says what is wrong.
var diagram = new Diagram("Small office · Monday 08:10") {
    Groups = {
        new DiagramGroup("Office LAN") {
            Nodes = {
                new DiagramNode("12 PCs") {
                    Kind = DiagramNodeKind.Workstation,
                    To = { "Firewall" }
                },
                new DiagramNode("File server") {
                    Kind = DiagramNodeKind.Storage,
                    Status = StatusKind.Warn,
                    Value = "disk 91%"
                },
                new DiagramNode("Printer") {
                    Kind = DiagramNodeKind.Device,
                    Status = StatusKind.Fail,
                    Value = "offline"
                }
            }
        },
        new DiagramGroup("Cloud") {
            Nodes = {
                new DiagramNode("Microsoft 365") { Kind = DiagramNodeKind.Cloud },
                new DiagramNode("Backup") {
                    Kind = DiagramNodeKind.Storage,
                    Status = StatusKind.Fail,
                    Value = "last success 2 days ago"
                }
            }
        }
    },
    Nodes = {
        new DiagramNode("Firewall") {
            Kind = DiagramNodeKind.Gateway,
            To = { "Microsoft 365" }
        }
    },
    Links = {
        new DiagramLink("File server", "Backup") {
            Label = "failed 2 nights",
            Status = StatusKind.Fail
        }
    }
};
Terminal.Write(diagram);

Run: dotnet run

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C# fluentProgram.cs
DiagramRendererProvider.Register();

// Status uses the same words as every widget; Value says what is wrong.
var diagram = Ui.Diagram()
    .Title("Small office · Monday 08:10")
    .AddGroup(new DiagramGroup("Office LAN") { Nodes =
    {
        new DiagramNode("12 PCs") { Kind = DiagramNodeKind.Workstation, To = { "Firewall" } },
        new DiagramNode("File server")
            .Kind(DiagramNodeKind.Storage)
            .Status(StatusKind.Warn)
            .Value("disk 91%"),
        new DiagramNode("Printer")
            .Kind(DiagramNodeKind.Device)
            .Status(StatusKind.Fail)
            .Value("offline")
    } })
    .AddGroup(new DiagramGroup("Cloud") { Nodes =
    {
        new DiagramNode("Microsoft 365").Kind(DiagramNodeKind.Cloud),
        new DiagramNode("Backup")
            .Kind(DiagramNodeKind.Storage)
            .Status(StatusKind.Fail)
            .Value("last success 2 days ago")
    } })
    .AddNode(new DiagramNode("Firewall")
    {
        Kind = DiagramNodeKind.Gateway,
        To = { "Microsoft 365" }
    })
    .AddLink(new DiagramLink("File server", "Backup")
        .Label("failed 2 nights")
        .Status(StatusKind.Fail));
diagram.Show();
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Styling;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// Status uses the same words as every widget; Value says what is wrong.
var diagram = Ui.Diagram()
    .Title("Small office · Monday 08:10")
    .AddGroup(new DiagramGroup("Office LAN") { Nodes =
    {
        new DiagramNode("12 PCs") { Kind = DiagramNodeKind.Workstation, To = { "Firewall" } },
        new DiagramNode("File server")
            .Kind(DiagramNodeKind.Storage)
            .Status(StatusKind.Warn)
            .Value("disk 91%"),
        new DiagramNode("Printer")
            .Kind(DiagramNodeKind.Device)
            .Status(StatusKind.Fail)
            .Value("offline")
    } })
    .AddGroup(new DiagramGroup("Cloud") { Nodes =
    {
        new DiagramNode("Microsoft 365").Kind(DiagramNodeKind.Cloud),
        new DiagramNode("Backup")
            .Kind(DiagramNodeKind.Storage)
            .Status(StatusKind.Fail)
            .Value("last success 2 days ago")
    } })
    .AddNode(new DiagramNode("Firewall")
    {
        Kind = DiagramNodeKind.Gateway,
        To = { "Microsoft 365" }
    })
    .AddLink(new DiagramLink("File server", "Backup")
        .Label("failed 2 nights")
        .Status(StatusKind.Fail));
diagram.Show();

Run: dotnet run

Status 120×3024-bitFull

5. From a list

You rarely type every link. Nodes you never declared are created from the links, so a list of rows is enough: Diagram.FromLinks in C#, and in PowerShell a hashtable per row splatted into New-ConsoleDiagramLink. Rows with From, To, Label, Status and Group columns can also be piped straight into Show-ConsoleDiagram, for example from Import-Csv.

Install-Module ConsoleMonster -Scope CurrentUser
PowerShelldiagram-5.ps1
# Rows you already have; nodes are created from the links.
$links = @(
    @{ From = 'Browser'; To = 'CDN' }
    @{ From = 'CDN'; To = 'Web' }
    @{ From = 'Web'; To = 'Orders API' }
    @{ From = 'Orders API'; To = 'SQL' }
    @{ From = 'Web'; To = 'Redis' }
    @{ From = 'Orders API'; To = 'Queue' }
    @{ From = 'Queue'; To = 'Worker' }
)
New-ConsoleDiagram -Title 'Shop · production' {
    foreach ($link in $links) { New-ConsoleDiagramLink @link }
} | Show-Console
Full program
Import-Module ConsoleMonster

# Rows you already have; nodes are created from the links.
$links = @(
    @{ From = 'Browser'; To = 'CDN' }
    @{ From = 'CDN'; To = 'Web' }
    @{ From = 'Web'; To = 'Orders API' }
    @{ From = 'Orders API'; To = 'SQL' }
    @{ From = 'Web'; To = 'Redis' }
    @{ From = 'Orders API'; To = 'Queue' }
    @{ From = 'Queue'; To = 'Worker' }
)
New-ConsoleDiagram -Title 'Shop · production' {
    foreach ($link in $links) { New-ConsoleDiagramLink @link }
} | Show-Console

Run: ./diagram-5.ps1

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C#Program.cs
DiagramRendererProvider.Register();

// Rows you already have; nodes are created from the links.
Link[] links = {
    new("Browser", "CDN"),
    new("CDN", "Web"),
    new("Web", "Orders API"),
    new("Orders API", "SQL"),
    new("Web", "Redis"),
    new("Orders API", "Queue"),
    new("Queue", "Worker")
};
Diagram diagram = Diagram.FromLinks(links, link => link.From, link => link.To);
diagram.Title = "Shop · production";
Terminal.Write(diagram);

record Link(string From, string To);
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// Rows you already have; nodes are created from the links.
Link[] links = {
    new("Browser", "CDN"),
    new("CDN", "Web"),
    new("Web", "Orders API"),
    new("Orders API", "SQL"),
    new("Web", "Redis"),
    new("Orders API", "Queue"),
    new("Queue", "Worker")
};
Diagram diagram = Diagram.FromLinks(links, link => link.From, link => link.To);
diagram.Title = "Shop · production";
Terminal.Write(diagram);

record Link(string From, string To);

Run: dotnet run

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C# fluentProgram.cs
DiagramRendererProvider.Register();

// Rows you already have; nodes are created from the links.
Link[] links =
{
    new("Browser", "CDN"),
    new("CDN", "Web"),
    new("Web", "Orders API"),
    new("Orders API", "SQL"),
    new("Web", "Redis"),
    new("Orders API", "Queue"),
    new("Queue", "Worker")
};
Diagram diagram = Diagram.FromLinks(links, link => link.From, link => link.To)
    .Title("Shop · production");
diagram.Show();

record Link(string From, string To);
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// Rows you already have; nodes are created from the links.
Link[] links =
{
    new("Browser", "CDN"),
    new("CDN", "Web"),
    new("Web", "Orders API"),
    new("Orders API", "SQL"),
    new("Web", "Redis"),
    new("Orders API", "Queue"),
    new("Queue", "Worker")
};
Diagram diagram = Diagram.FromLinks(links, link => link.From, link => link.To)
    .Title("Shop · production");
diagram.Show();

record Link(string From, string To);

Run: dotnet run

From a list 120×1324-bitFull

6. Live values

Give the diagram a widget id and update it while it shows; values and statuses change, the layout stays put. This frame is one moment of a ping monitor. The live version wraps the same diagram in a dashboard:

$diagram = New-ConsoleDiagram -WidgetId ping -Title 'Ping monitor · every 5 s' { <# the nodes above #> }
Invoke-ConsoleDashboard $diagram {
    while ($true) {
        foreach ($name in 'Router', 'DNS', 'VPN', 'contoso.com') {
            $ping = Test-Connection $name -Count 1 -TimeoutSeconds 1 -ErrorAction Ignore
            $status = if (-not $ping) { 'Fail' } elseif ($ping.Latency -gt 100) { 'Warn' } else { 'Pass' }
            $value = if ($ping) { "$($ping.Latency) ms" } else { 'timeout' }
            Update-Console ping -Key $name -Value $value -Status $status
        }
        Start-Sleep -Seconds 5
    }
}
Install-Module ConsoleMonster -Scope CurrentUser
PowerShelldiagram-6.ps1
# The values a live session would keep updating; the layout never moves.
New-ConsoleDiagram -Title 'Ping monitor · every 5 s' {
    New-ConsoleDiagramNode 'This PC' -Kind Workstation -To 'Router'
    New-ConsoleDiagramNode 'Router' -Kind Gateway -Value '1 ms' -To 'DNS', 'VPN', 'contoso.com'
    New-ConsoleDiagramNode 'DNS' -Kind Server -Subtitle '1.1.1.1' -Value '12 ms'
    New-ConsoleDiagramNode 'VPN' -Kind Server -Subtitle '10.8.0.1' -Status Warn -Value '180 ms'
    New-ConsoleDiagramNode 'contoso.com' -Kind Cloud -Status Fail -Value 'timeout'
} | Show-Console
Full program
Import-Module ConsoleMonster

# The values a live session would keep updating; the layout never moves.
New-ConsoleDiagram -Title 'Ping monitor · every 5 s' {
    New-ConsoleDiagramNode 'This PC' -Kind Workstation -To 'Router'
    New-ConsoleDiagramNode 'Router' -Kind Gateway -Value '1 ms' -To 'DNS', 'VPN', 'contoso.com'
    New-ConsoleDiagramNode 'DNS' -Kind Server -Subtitle '1.1.1.1' -Value '12 ms'
    New-ConsoleDiagramNode 'VPN' -Kind Server -Subtitle '10.8.0.1' -Status Warn -Value '180 ms'
    New-ConsoleDiagramNode 'contoso.com' -Kind Cloud -Status Fail -Value 'timeout'
} | Show-Console

Run: ./diagram-6.ps1

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C#Program.cs
DiagramRendererProvider.Register();

// The values a live session would keep updating; the layout never moves.
var diagram = new Diagram("Ping monitor · every 5 s") {
    Nodes = {
        new DiagramNode("This PC") {
            Kind = DiagramNodeKind.Workstation,
            To = { "Router" }
        },
        new DiagramNode("Router") {
            Kind = DiagramNodeKind.Gateway,
            Value = "1 ms",
            To = { "DNS", "VPN", "contoso.com" }
        },
        new DiagramNode("DNS") {
            Kind = DiagramNodeKind.Server,
            Subtitle = "1.1.1.1",
            Value = "12 ms"
        },
        new DiagramNode("VPN") {
            Kind = DiagramNodeKind.Server,
            Subtitle = "10.8.0.1",
            Status = StatusKind.Warn,
            Value = "180 ms"
        },
        new DiagramNode("contoso.com") {
            Kind = DiagramNodeKind.Cloud,
            Status = StatusKind.Fail,
            Value = "timeout"
        }
    }
};
Terminal.Write(diagram);
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Styling;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// The values a live session would keep updating; the layout never moves.
var diagram = new Diagram("Ping monitor · every 5 s") {
    Nodes = {
        new DiagramNode("This PC") {
            Kind = DiagramNodeKind.Workstation,
            To = { "Router" }
        },
        new DiagramNode("Router") {
            Kind = DiagramNodeKind.Gateway,
            Value = "1 ms",
            To = { "DNS", "VPN", "contoso.com" }
        },
        new DiagramNode("DNS") {
            Kind = DiagramNodeKind.Server,
            Subtitle = "1.1.1.1",
            Value = "12 ms"
        },
        new DiagramNode("VPN") {
            Kind = DiagramNodeKind.Server,
            Subtitle = "10.8.0.1",
            Status = StatusKind.Warn,
            Value = "180 ms"
        },
        new DiagramNode("contoso.com") {
            Kind = DiagramNodeKind.Cloud,
            Status = StatusKind.Fail,
            Value = "timeout"
        }
    }
};
Terminal.Write(diagram);

Run: dotnet run

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C# fluentProgram.cs
DiagramRendererProvider.Register();

// The values a live session would keep updating; the layout never moves.
var diagram = Ui.Diagram()
    .Title("Ping monitor · every 5 s")
    .AddNode(new DiagramNode("This PC") { Kind = DiagramNodeKind.Workstation, To = { "Router" } })
    .AddNode(new DiagramNode("Router")
    {
        Kind = DiagramNodeKind.Gateway,
        Value = "1 ms",
        To = { "DNS", "VPN", "contoso.com" }
    })
    .AddNode(new DiagramNode("DNS").Kind(DiagramNodeKind.Server).Subtitle("1.1.1.1").Value("12 ms"))
    .AddNode(new DiagramNode("VPN")
        .Kind(DiagramNodeKind.Server)
        .Subtitle("10.8.0.1")
        .Status(StatusKind.Warn)
        .Value("180 ms"))
    .AddNode(new DiagramNode("contoso.com")
        .Kind(DiagramNodeKind.Cloud)
        .Status(StatusKind.Fail)
        .Value("timeout"));
diagram.Show();
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Styling;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// The values a live session would keep updating; the layout never moves.
var diagram = Ui.Diagram()
    .Title("Ping monitor · every 5 s")
    .AddNode(new DiagramNode("This PC") { Kind = DiagramNodeKind.Workstation, To = { "Router" } })
    .AddNode(new DiagramNode("Router")
    {
        Kind = DiagramNodeKind.Gateway,
        Value = "1 ms",
        To = { "DNS", "VPN", "contoso.com" }
    })
    .AddNode(new DiagramNode("DNS").Kind(DiagramNodeKind.Server).Subtitle("1.1.1.1").Value("12 ms"))
    .AddNode(new DiagramNode("VPN")
        .Kind(DiagramNodeKind.Server)
        .Subtitle("10.8.0.1")
        .Status(StatusKind.Warn)
        .Value("180 ms"))
    .AddNode(new DiagramNode("contoso.com")
        .Kind(DiagramNodeKind.Cloud)
        .Status(StatusKind.Fail)
        .Value("timeout"));
diagram.Show();

Run: dotnet run

Live values 120×2024-bitFull

7. A request walkthrough

A use case walks a request through the diagram, step by step: requests, replies, messages nobody waits for and calls that fail. The active step lights up and the panel underneath lists the steps. In an interactive console, Show-ConsoleDiagram or diagram.Run() lets Space play it and the arrow keys step through it.

Install-Module ConsoleMonster -Scope CurrentUser
PowerShelldiagram-7.ps1
# A use case walks a request through the diagram; this shows its third step.
Show-ConsoleDiagram -Title 'Checkout' -Step 3 -StaticSnapshot {
    New-ConsoleDiagramNode 'Shopper' -Kind User -To 'Web'
    New-ConsoleDiagramNode 'Web' -Kind Service -To 'Orders API'
    New-ConsoleDiagramNode 'Orders API' -Kind Service -To 'Payments', 'SQL'
    New-ConsoleDiagramNode 'Payments' -Kind External -Subtitle 'Stripe'
    New-ConsoleDiagramNode 'SQL' -Kind Database
    New-ConsoleDiagramUseCase 'Place an order' {
        New-ConsoleDiagramStep 'Shopper' 'Web' 'POST /checkout'
        New-ConsoleDiagramStep 'Web' 'Orders API' 'create order'
        New-ConsoleDiagramStep 'Orders API' 'Payments' 'charge 24.00 EUR'
        New-ConsoleDiagramStep 'Payments' 'Orders API' 'approved' -Reply
        New-ConsoleDiagramStep 'Orders API' 'SQL' 'INSERT order'
        New-ConsoleDiagramStep 'Orders API' 'Web' '201 order 1042' -Reply
        New-ConsoleDiagramStep 'Web' 'Shopper' 'Thank you page' -Reply
    }
}
Full program
Import-Module ConsoleMonster

# A use case walks a request through the diagram; this shows its third step.
Show-ConsoleDiagram -Title 'Checkout' -Step 3 -StaticSnapshot {
    New-ConsoleDiagramNode 'Shopper' -Kind User -To 'Web'
    New-ConsoleDiagramNode 'Web' -Kind Service -To 'Orders API'
    New-ConsoleDiagramNode 'Orders API' -Kind Service -To 'Payments', 'SQL'
    New-ConsoleDiagramNode 'Payments' -Kind External -Subtitle 'Stripe'
    New-ConsoleDiagramNode 'SQL' -Kind Database
    New-ConsoleDiagramUseCase 'Place an order' {
        New-ConsoleDiagramStep 'Shopper' 'Web' 'POST /checkout'
        New-ConsoleDiagramStep 'Web' 'Orders API' 'create order'
        New-ConsoleDiagramStep 'Orders API' 'Payments' 'charge 24.00 EUR'
        New-ConsoleDiagramStep 'Payments' 'Orders API' 'approved' -Reply
        New-ConsoleDiagramStep 'Orders API' 'SQL' 'INSERT order'
        New-ConsoleDiagramStep 'Orders API' 'Web' '201 order 1042' -Reply
        New-ConsoleDiagramStep 'Web' 'Shopper' 'Thank you page' -Reply
    }
}

Run: ./diagram-7.ps1

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C#Program.cs
DiagramRendererProvider.Register();

// A use case walks a request through the diagram; this shows its third step.
var diagram = new Diagram("Checkout") {
    Nodes = {
        new DiagramNode("Shopper") { Kind = DiagramNodeKind.User, To = { "Web" } },
        new DiagramNode("Web") { Kind = DiagramNodeKind.Service, To = { "Orders API" } },
        new DiagramNode("Orders API") {
            Kind = DiagramNodeKind.Service,
            To = { "Payments", "SQL" }
        },
        new DiagramNode("Payments") {
            Kind = DiagramNodeKind.External,
            Subtitle = "Stripe"
        },
        new DiagramNode("SQL") { Kind = DiagramNodeKind.Database }
    },
    UseCases = {
        new DiagramUseCase("Place an order") {
            Steps = {
                new DiagramStep("Shopper", "Web", "POST /checkout"),
                new DiagramStep("Web", "Orders API", "create order"),
                new DiagramStep("Orders API", "Payments", "charge 24.00 EUR"),
                new DiagramStep("Payments", "Orders API", "approved") {
                    Kind = DiagramStepKind.Reply
                },
                new DiagramStep("Orders API", "SQL", "INSERT order"),
                new DiagramStep("Orders API", "Web", "201 order 1042") {
                    Kind = DiagramStepKind.Reply
                },
                new DiagramStep("Web", "Shopper", "Thank you page") {
                    Kind = DiagramStepKind.Reply
                }
            }
        }
    }
};
diagram.Step(2);
Terminal.Write(diagram);
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// A use case walks a request through the diagram; this shows its third step.
var diagram = new Diagram("Checkout") {
    Nodes = {
        new DiagramNode("Shopper") { Kind = DiagramNodeKind.User, To = { "Web" } },
        new DiagramNode("Web") { Kind = DiagramNodeKind.Service, To = { "Orders API" } },
        new DiagramNode("Orders API") {
            Kind = DiagramNodeKind.Service,
            To = { "Payments", "SQL" }
        },
        new DiagramNode("Payments") {
            Kind = DiagramNodeKind.External,
            Subtitle = "Stripe"
        },
        new DiagramNode("SQL") { Kind = DiagramNodeKind.Database }
    },
    UseCases = {
        new DiagramUseCase("Place an order") {
            Steps = {
                new DiagramStep("Shopper", "Web", "POST /checkout"),
                new DiagramStep("Web", "Orders API", "create order"),
                new DiagramStep("Orders API", "Payments", "charge 24.00 EUR"),
                new DiagramStep("Payments", "Orders API", "approved") {
                    Kind = DiagramStepKind.Reply
                },
                new DiagramStep("Orders API", "SQL", "INSERT order"),
                new DiagramStep("Orders API", "Web", "201 order 1042") {
                    Kind = DiagramStepKind.Reply
                },
                new DiagramStep("Web", "Shopper", "Thank you page") {
                    Kind = DiagramStepKind.Reply
                }
            }
        }
    }
};
diagram.Step(2);
Terminal.Write(diagram);

Run: dotnet run

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C# fluentProgram.cs
DiagramRendererProvider.Register();

// A use case walks a request through the diagram; this shows its third step.
var diagram = Ui.Diagram()
    .Title("Checkout")
    .AddNode(new DiagramNode("Shopper") { Kind = DiagramNodeKind.User, To = { "Web" } })
    .AddNode(new DiagramNode("Web") { Kind = DiagramNodeKind.Service, To = { "Orders API" } })
    .AddNode(new DiagramNode("Orders API")
    {
        Kind = DiagramNodeKind.Service,
        To = { "Payments", "SQL" }
    })
    .AddNode(new DiagramNode("Payments").Kind(DiagramNodeKind.External).Subtitle("Stripe"))
    .AddNode(new DiagramNode("SQL").Kind(DiagramNodeKind.Database))
    .AddUseCase(new DiagramUseCase("Place an order") { Steps =
    {
        new DiagramStep("Shopper", "Web", "POST /checkout"),
        new DiagramStep("Web", "Orders API", "create order"),
        new DiagramStep("Orders API", "Payments", "charge 24.00 EUR"),
        new DiagramStep("Payments", "Orders API", "approved").Kind(DiagramStepKind.Reply),
        new DiagramStep("Orders API", "SQL", "INSERT order"),
        new DiagramStep("Orders API", "Web", "201 order 1042").Kind(DiagramStepKind.Reply),
        new DiagramStep("Web", "Shopper", "Thank you page").Kind(DiagramStepKind.Reply)
    } });
diagram.Step(2);
diagram.Show();
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// A use case walks a request through the diagram; this shows its third step.
var diagram = Ui.Diagram()
    .Title("Checkout")
    .AddNode(new DiagramNode("Shopper") { Kind = DiagramNodeKind.User, To = { "Web" } })
    .AddNode(new DiagramNode("Web") { Kind = DiagramNodeKind.Service, To = { "Orders API" } })
    .AddNode(new DiagramNode("Orders API")
    {
        Kind = DiagramNodeKind.Service,
        To = { "Payments", "SQL" }
    })
    .AddNode(new DiagramNode("Payments").Kind(DiagramNodeKind.External).Subtitle("Stripe"))
    .AddNode(new DiagramNode("SQL").Kind(DiagramNodeKind.Database))
    .AddUseCase(new DiagramUseCase("Place an order") { Steps =
    {
        new DiagramStep("Shopper", "Web", "POST /checkout"),
        new DiagramStep("Web", "Orders API", "create order"),
        new DiagramStep("Orders API", "Payments", "charge 24.00 EUR"),
        new DiagramStep("Payments", "Orders API", "approved").Kind(DiagramStepKind.Reply),
        new DiagramStep("Orders API", "SQL", "INSERT order"),
        new DiagramStep("Orders API", "Web", "201 order 1042").Kind(DiagramStepKind.Reply),
        new DiagramStep("Web", "Shopper", "Thank you page").Kind(DiagramStepKind.Reply)
    } });
diagram.Step(2);
diagram.Show();

Run: dotnet run

A request walkthrough 120×2424-bitFull

8. Hierarchy

Links that form a tree are a hierarchy: an org chart, a folder tree, a dependency tree. Direction = Down lays it out top to bottom.

Install-Module ConsoleMonster -Scope CurrentUser
PowerShelldiagram-8.ps1
# Links that form a tree become a hierarchy, laid out top to bottom.
New-ConsoleDiagram -Title 'IT team' -Direction Down {
    New-ConsoleDiagramNode 'Anna' -Kind Person -Subtitle 'CIO' -To 'Marek', 'Julia'
    New-ConsoleDiagramNode 'Marek' -Kind Person -Subtitle 'Operations' -To 'Tom', 'Ola'
    New-ConsoleDiagramNode 'Julia' -Kind Person -Subtitle 'Development' -To 'Ben'
    New-ConsoleDiagramNode 'Tom' -Kind Person -Subtitle 'Service desk'
    New-ConsoleDiagramNode 'Ola' -Kind Person -Subtitle 'Network'
    New-ConsoleDiagramNode 'Ben' -Kind Person -Subtitle 'Apps'
} | Show-Console
Full program
Import-Module ConsoleMonster

# Links that form a tree become a hierarchy, laid out top to bottom.
New-ConsoleDiagram -Title 'IT team' -Direction Down {
    New-ConsoleDiagramNode 'Anna' -Kind Person -Subtitle 'CIO' -To 'Marek', 'Julia'
    New-ConsoleDiagramNode 'Marek' -Kind Person -Subtitle 'Operations' -To 'Tom', 'Ola'
    New-ConsoleDiagramNode 'Julia' -Kind Person -Subtitle 'Development' -To 'Ben'
    New-ConsoleDiagramNode 'Tom' -Kind Person -Subtitle 'Service desk'
    New-ConsoleDiagramNode 'Ola' -Kind Person -Subtitle 'Network'
    New-ConsoleDiagramNode 'Ben' -Kind Person -Subtitle 'Apps'
} | Show-Console

Run: ./diagram-8.ps1

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C#Program.cs
DiagramRendererProvider.Register();

// Links that form a tree become a hierarchy, laid out top to bottom.
var diagram = new Diagram("IT team") {
    Direction = DiagramDirection.Down,
    Nodes = {
        new DiagramNode("Anna") {
            Kind = DiagramNodeKind.Person,
            Subtitle = "CIO",
            To = { "Marek", "Julia" }
        },
        new DiagramNode("Marek") {
            Kind = DiagramNodeKind.Person,
            Subtitle = "Operations",
            To = { "Tom", "Ola" }
        },
        new DiagramNode("Julia") {
            Kind = DiagramNodeKind.Person,
            Subtitle = "Development",
            To = { "Ben" }
        },
        new DiagramNode("Tom") { Kind = DiagramNodeKind.Person, Subtitle = "Service desk" },
        new DiagramNode("Ola") { Kind = DiagramNodeKind.Person, Subtitle = "Network" },
        new DiagramNode("Ben") { Kind = DiagramNodeKind.Person, Subtitle = "Apps" }
    }
};
Terminal.Write(diagram);
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// Links that form a tree become a hierarchy, laid out top to bottom.
var diagram = new Diagram("IT team") {
    Direction = DiagramDirection.Down,
    Nodes = {
        new DiagramNode("Anna") {
            Kind = DiagramNodeKind.Person,
            Subtitle = "CIO",
            To = { "Marek", "Julia" }
        },
        new DiagramNode("Marek") {
            Kind = DiagramNodeKind.Person,
            Subtitle = "Operations",
            To = { "Tom", "Ola" }
        },
        new DiagramNode("Julia") {
            Kind = DiagramNodeKind.Person,
            Subtitle = "Development",
            To = { "Ben" }
        },
        new DiagramNode("Tom") { Kind = DiagramNodeKind.Person, Subtitle = "Service desk" },
        new DiagramNode("Ola") { Kind = DiagramNodeKind.Person, Subtitle = "Network" },
        new DiagramNode("Ben") { Kind = DiagramNodeKind.Person, Subtitle = "Apps" }
    }
};
Terminal.Write(diagram);

Run: dotnet run

Terminal
dotnet new console -n Diagrams
cd Diagrams
dotnet add package ConsoleMonster
dotnet add package ConsoleMonster.Graphics
C# fluentProgram.cs
DiagramRendererProvider.Register();

// Links that form a tree become a hierarchy, laid out top to bottom.
var diagram = Ui.Diagram()
    .Title("IT team")
    .Direction(DiagramDirection.Down)
    .AddNode(new DiagramNode("Anna")
    {
        Kind = DiagramNodeKind.Person,
        Subtitle = "CIO",
        To = { "Marek", "Julia" }
    })
    .AddNode(new DiagramNode("Marek")
    {
        Kind = DiagramNodeKind.Person,
        Subtitle = "Operations",
        To = { "Tom", "Ola" }
    })
    .AddNode(new DiagramNode("Julia")
    {
        Kind = DiagramNodeKind.Person,
        Subtitle = "Development",
        To = { "Ben" }
    })
    .AddNode(new DiagramNode("Tom").Kind(DiagramNodeKind.Person).Subtitle("Service desk"))
    .AddNode(new DiagramNode("Ola").Kind(DiagramNodeKind.Person).Subtitle("Network"))
    .AddNode(new DiagramNode("Ben").Kind(DiagramNodeKind.Person).Subtitle("Apps"));
diagram.Show();
Full program
using ConsoleMonster;
using ConsoleMonster.Graphics;
using ConsoleMonster.Widgets;

DiagramRendererProvider.Register();

// Links that form a tree become a hierarchy, laid out top to bottom.
var diagram = Ui.Diagram()
    .Title("IT team")
    .Direction(DiagramDirection.Down)
    .AddNode(new DiagramNode("Anna")
    {
        Kind = DiagramNodeKind.Person,
        Subtitle = "CIO",
        To = { "Marek", "Julia" }
    })
    .AddNode(new DiagramNode("Marek")
    {
        Kind = DiagramNodeKind.Person,
        Subtitle = "Operations",
        To = { "Tom", "Ola" }
    })
    .AddNode(new DiagramNode("Julia")
    {
        Kind = DiagramNodeKind.Person,
        Subtitle = "Development",
        To = { "Ben" }
    })
    .AddNode(new DiagramNode("Tom").Kind(DiagramNodeKind.Person).Subtitle("Service desk"))
    .AddNode(new DiagramNode("Ola").Kind(DiagramNodeKind.Person).Subtitle("Network"))
    .AddNode(new DiagramNode("Ben").Kind(DiagramNodeKind.Person).Subtitle("Apps"));
diagram.Show();

Run: dotnet run

Hierarchy 120×2224-bitFull

Next

Architecture diagrams loads ChartForgeX architecture files and plays their use cases, and live dashboards shows how a diagram becomes part of a running dashboard.

Edit this page on GitHub