| name | built-in-shapes |
| version | 0.22.0 |
| description | Use when a report needs rich visual elements — bar charts, stacked/proportional bars, alert boxes, tree hierarchies, term/definition glossaries, or code blocks — instead of hand-drawn ASCII or manual Markdown. Markout ships these as data types (Metric, Breakdown/Slice, Callout, TreeNode, Description, CodeSection) you attach as model properties. Requires the base `markout` pattern. Don't decompile the assembly or web-search the API — the shape types are here. |
Built-in shapes — declare the meaning, get the visual
Attach these types as properties; the formatter draws the right visual. The anti-pattern is
building bars/trees by hand (new string('█', n), indented dashes). Say what the data is — a
measurement, a breakdown, an alert — not how to draw it.
The shapes
[MarkoutSerializable(TitleProperty = nameof(Title))]
public class Dashboard
{
public string Title { get; set; } = "";
[MarkoutSection(Name = "Timings"), MarkoutIgnoreInTable]
public List<Metric>? Timings { get; set; }
[MarkoutSection(Name = "Severity"), MarkoutIgnoreInTable]
public List<Breakdown>? Severity { get; set; }
[MarkoutIgnoreInTable, MarkoutSkipDefault]
public Callout Warning { get; set; }
[MarkoutIgnoreInTable]
public List<TreeNode>? Deps { get; set; }
[MarkoutSection(Name = "Glossary"), MarkoutIgnoreInTable]
public List<Description>? Glossary { get; set; }
[MarkoutIgnoreInTable]
public CodeSection? Snippet { get; set; }
}
Critical guardrails
[MarkoutIgnoreInTable] on every shape list/property. Without it, List<Metric> etc. get
mistreated as a table of columns instead of rendering as the shape. This is the #1 shapes mistake.
- A single
Breakdown property (not a list) renders as ONE labeled proportional bar — use it for a
covered-vs-uncovered coverage bar rather than a List<Breakdown>:
[MarkoutIgnoreInTable] public Breakdown Coverage { get; set; } with
new Breakdown("Coverage", [new Slice("Covered", 82), new Slice("Uncovered", 18)]). Under a Unicode/
terminal formatter this shows the group label + █ bar, not per-slice table rows.
- Children go in a collection expression, never as trailing constructor arguments:
new TreeNode("root", [new TreeNode("leaf")]). Badge is an optional object-initializer property.
Callout is a value type — pair it with [MarkoutSkipDefault] so an unset callout disappears.
- Do not hand-draw bars/trees; if you're building glyphs by hand you're using the wrong tool.
Shape cheat-sheet
| Type | Meaning | Construct |
|---|
Metric | one measured value (bar) | new Metric("Build", 4.2) |
Breakdown + Slice | proportional composition | new Breakdown("By type", [new Slice("A", 3)]) |
Callout | alert/severity box | new Callout(CalloutSeverity.Warning, "…") |
TreeNode | hierarchy | new TreeNode("root", [children]) { Badge = "📁" } |
Description | term + text | new Description("API", "…") |
CodeSection | fenced code block | new CodeSection("csharp", "…") |