Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions .claude/skills/add-playground-example/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
---
name: add-playground-example
description: Add a new example diagram (or a whole new diagram-type group) to the Beck docs playground picker at docs/Beck.Docs. Use when asked to "add X to the playground", "put a flowchart/sequence/etc. example in the playground", "add a new example to the playground dropdown", or to wire up a new diagram type in the playground's Examples menu. Covers authoring the example YAML, registering it in the picker, and adding the type pill colour.
---

# Add a playground example

The `/playground` page (docs site) has an **Examples** dropdown grouped by diagram type. Each entry
loads a YAML file over HTTP and renders it live. Adding one means three things at most:

1. **Author** the example YAML (always).
2. **Register** it in the picker's `ExampleGroups` (always).
3. **Add a type pill colour** in `BrandStyling.cs` — **only when introducing a new diagram type**.

Then verify it renders. Details below.

## The three files

| Concern | File |
| --- | --- |
| Example YAML | `docs/Beck.Docs/wwwroot/examples/<name>.beck.yaml` |
| Picker registration | `docs/Beck.Docs.Client/PlaygroundIsland.razor` → `ExampleGroups` array |
| Type pill colour (new type only) | `docs/Beck.Docs/BrandStyling.cs` → `.pg-pill[data-type="…"]` rules |

> **Location matters.** Playground examples live at the **root** of `wwwroot/examples/`. The
> `wwwroot/examples/guides/`, `/reference/`, `/styles/` subfolders belong to the docs *pages* (loaded
> by `` ```beck:symbol `` fences) — putting a playground example there means the picker's `Src` path
> (`/examples/<name>.beck.yaml`) won't resolve.

## 1. Author the example YAML

Write `docs/Beck.Docs/wwwroot/examples/<name>.beck.yaml`. Match the house style of the existing
examples (read a couple first, e.g. `webhook-retry.beck.yaml`, `order-lifecycle.beck.yaml`):

- Lead with `type:` (`architecture` | `sequence` | `state` | `class` | `flowchart` | `mindmap`).
- `meta:` with a `title`, an optional one-line `subtitle`, and a `direction` (`TB`/`LR`).
- A **recognisable real-world scenario**, kept small — roughly 4–7 nodes reads best in the pane.
- **Accent tokens, never hex**: `primary` `success` `warn` `danger` `info` `neutral`. Colours are
CSS tokens so the diagram adopts the site palette and the playground colour-scheme picker.
- Add a `note:` to a few edges / links / transitions — the engine derives a flow from these and
narrates them in the caption bar (no `flow:` block needed for a nice default animation).
- Keep it deterministic: no counters, timestamps, or RNG anywhere.

Schema references: `docs/Beck.Docs/Content/docs/reference/yaml.md`, and the per-type model builders
in `src/Beck/Model/*Builder.cs` (they list every field and the exact tokens).

## 2. Register it in the picker

In `docs/Beck.Docs.Client/PlaygroundIsland.razor`, find the `ExampleGroups` static array.

**Adding to an existing type** — append an `Ex` to that group's `Items`:

```csharp
new Ex("Deploy gate", "Build, gate on green, deploy, then smoke-test with a rollback loop", "/examples/flowchart-deploy.beck.yaml"),
```

`Ex(Label, Desc, Src)` — `Label` is the bold title, `Desc` the one-line grey blurb, `Src` the site
path `/examples/<name>.beck.yaml` (leading slash; fetched relative to the app base). Two examples per
type is the established cadence for the smaller types.

**Adding a new diagram type** — add a new `ExGroup`:

```csharp
new("flowchart", "Flowchart", "◇", "flow", [
new Ex("Deploy gate", "Build, gate on green, deploy, then smoke-test with a rollback loop", "/examples/flowchart-deploy.beck.yaml"),
new Ex("Ticket triage", "An inbound support ticket routed by urgency and prior art", "/examples/flowchart-triage.beck.yaml")
]),
```

`ExGroup(Type, Label, Glyph, Short, Items)`:
- **`Type`** must equal the diagram's `type:` — it drives the pill's `data-type` (step 3).
- **`Glyph` + `Short`** are the pill's icon and 3–5 char tag. Pick a distinct unicode glyph.
Existing: `⬡ arch` · `▷ seq` · `◈ state` · `▤ class` · `◇ flow` · `❋ map`.

## 3. Add the type pill colour (new type only)

Skip this if you reused an existing type. For a new `Type`, add a light **and** a `.dark` rule in
`docs/Beck.Docs/BrandStyling.cs`, next to the other `.pg-pill[data-type="…"]` rules. Pick a hue
distinct from the ones already in use (emerald / sky / amber / violet / teal / rose):

```css
.pg-pill[data-type="flowchart"] { color: #0f766e; background: color-mix(in srgb, #14b8a6 15%, transparent); border-color: color-mix(in srgb, #14b8a6 30%, transparent); }
.dark .pg-pill[data-type="flowchart"] { color: #5eead4; }
```

Keep the `color-mix(...)` + literal-fallback shape of the neighbours (don't resolve to a flat hex).

## 4. Verify it renders

The picker loads examples at **runtime over HTTP**, so a docs build will *not* catch a malformed
YAML. Verify one of these ways:

- **Quick engine check (preferred).** Drop a temporary `[Theory]` into `tests/Beck.Tests` that reads
each new file and renders it, then delete it after:

```csharp
[Theory]
[InlineData("flowchart-deploy")]
public void PlaygroundExampleRenders(string name)
{
var font = TestFonts.Spec();
using var measurer = new SkiaTextMeasurer(font);
var path = Path.Combine(/* repo root */, "docs", "Beck.Docs", "wwwroot", "examples", name + ".beck.yaml");
var info = BeckSvg.RenderWithInfo(File.ReadAllText(path), new SvgRenderOptions { Measurer = measurer, Font = font });
Assert.StartsWith("<svg", info.Svg);
}
```

Run: `dotnet test tests/Beck.Tests/Beck.Tests.csproj --filter "FullyQualifiedName~PlaygroundExampleRenders"`.
Dump `info.Svg` to a file and confirm the **viewBox starts at `0 0`** and there are **no negative
path coordinates** — off-canvas routes are the signature of a routing regression.

- **Full visual check.** `dotnet run --project docs/Beck.Docs`, open `/playground`, pick the new
entry from the Examples dropdown, and confirm it loads, animates, and the type pill shows the right
colour. (A screenshot harness works too: render the YAML to SVG, embed it in an HTML page served
over `http://` — `file://` is blocked in the browser tools — and screenshot it.)

Remove any temporary test/scratch files before finishing.

## What NOT to touch

- **Don't** register the example anywhere else — there's no manifest; `ExampleGroups` is the single
source of truth for the picker.
- **Don't** add the file under `wwwroot/examples/guides|reference|styles/` (those are for docs pages).
- **Don't** hardcode colours in the YAML or resolve `--beck-*`/`--color-*` tokens to literals.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
bin/
obj/
*.nupkg
*.snupkg

# Local pack output
/dist/

# Local dogfooding / verification scratch (not product code)
/scratch/
Expand All @@ -20,3 +24,4 @@ docs/Beck.Docs/output/
# IDE
.idea/
.vs/
*.user
16 changes: 16 additions & 0 deletions docs/Beck.Docs.Client/PlaygroundIsland.razor
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,22 @@
new("class", "Class", "▤", "class", [
new Ex("Domain model", "Entities and relations in an order domain", "/examples/domain-model.beck.yaml"),
new Ex("Payment gateways", "A gateway interface with provider implementations", "/examples/payment-gateways.beck.yaml")
]),
new("flowchart", "Flowchart", "◇", "flow", [
new Ex("Deploy gate", "Build, gate on green, deploy, then smoke-test with a rollback loop", "/examples/flowchart-deploy.beck.yaml"),
new Ex("Ticket triage", "An inbound support ticket routed by urgency and prior art", "/examples/flowchart-triage.beck.yaml")
]),
new("mindmap", "Mindmap", "❋", "map", [
new Ex("Product roadmap", "Branch statuses and a ghosted future launch", "/examples/mindmap-roadmap.beck.yaml"),
new Ex("How Beck works", "The engine as a topic tree, with items and body copy", "/examples/mindmap-beck.beck.yaml"),
new Ex("Frontend roadmap", "A wide learning path across the accent cycle", "/examples/mindmap-skills.beck.yaml")
]),
new("chart", "Charts", "▦", "chart", [
new Ex("Revenue by region", "A bar chart with an analogous palette derived from the primary", "/examples/chart-bar.beck.yaml"),
new Ex("This year vs last", "Two lines in complementary hues — a two-way comparison", "/examples/chart-line.beck.yaml"),
new Ex("Storage by tier", "A pie chart in monochromatic tints of one hue", "/examples/chart-pie.beck.yaml"),
new Ex("Requests by service", "A donut with a centre total and values in the legend", "/examples/chart-donut.beck.yaml"),
new Ex("Latency vs throughput", "A scatter plot on a sequential primary-to-neutral ramp", "/examples/chart-scatter.beck.yaml")
])
];

Expand Down
6 changes: 6 additions & 0 deletions docs/Beck.Docs/BrandStyling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,16 @@ items and several are toggled from JS (is-open / is-active). */
.pg-pill[data-type="sequence"] { color: var(--color-sky-700, #0369a1); background: color-mix(in srgb, var(--color-sky-500, #0ea5e9) 14%, transparent); border-color: color-mix(in srgb, var(--color-sky-500, #0ea5e9) 30%, transparent); }
.pg-pill[data-type="state"] { color: #b45309; background: color-mix(in srgb, #f59e0b 16%, transparent); border-color: color-mix(in srgb, #f59e0b 32%, transparent); }
.pg-pill[data-type="class"] { color: #6d28d9; background: color-mix(in srgb, #8b5cf6 16%, transparent); border-color: color-mix(in srgb, #8b5cf6 32%, transparent); }
.pg-pill[data-type="flowchart"] { color: #0f766e; background: color-mix(in srgb, #14b8a6 15%, transparent); border-color: color-mix(in srgb, #14b8a6 30%, transparent); }
.pg-pill[data-type="mindmap"] { color: #be123c; background: color-mix(in srgb, #f43f5e 14%, transparent); border-color: color-mix(in srgb, #f43f5e 30%, transparent); }
.pg-pill[data-type="chart"] { color: #0e7490; background: color-mix(in srgb, #06b6d4 15%, transparent); border-color: color-mix(in srgb, #06b6d4 30%, transparent); }
.dark .pg-pill[data-type="architecture"] { color: var(--color-emerald-300, #6ee7b7); }
.dark .pg-pill[data-type="sequence"] { color: var(--color-sky-300, #7dd3fc); }
.dark .pg-pill[data-type="state"] { color: #fcd34d; }
.dark .pg-pill[data-type="class"] { color: #c4b5fd; }
.dark .pg-pill[data-type="flowchart"] { color: #5eead4; }
.dark .pg-pill[data-type="mindmap"] { color: #fda4af; }
.dark .pg-pill[data-type="chart"] { color: #67e8f9; }

/* Colour-scheme swatch: a two-tone chip previewing each palette's signature. */
.pg-swatch { flex: none; width: 15px; height: 15px; border-radius: 4px; border: 1px solid rgb(0 0 0 / .18); }
Expand Down
123 changes: 123 additions & 0 deletions docs/Beck.Docs/Content/docs/guides/chart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
title: Draw a data chart
description: Bar, line, pie, donut, and scatter charts whose whole colour set is derived from one primary token — re-tinting with your palette and flipping light and dark.
order: 31
sectionLabel: Other diagram types
uid: docs.guide.chart
---

A `type: chart` document draws a small data chart — a **bar**, **line**, **pie**, **donut**, or
**scatter** — to round out a diagram with the numbers behind it. Charts are deliberately simple: no
axes to configure, no data toolkit, and no animation. What they *do* carry is Beck's colour idea taken
to its conclusion — **every series colour is derived from `--beck-primary`** by a pure
`color-mix`/relative-colour expression, so the whole set re-tints with your palette and flips light↔dark
on the same switch as the rest of the page. Swap the primary and every bar, line, slice, and dot
follows.

## The shape: chart kind and series

Set the `chart` kind, then list a `series`. What each series carries depends on the kind: a single
`value` for a bar or a pie/donut slice, a list of `values` for a line, or a list of `[x, y]` `points`
for a scatter. That's the whole schema — colours, spacing, and the legend are derived for you.

```yaml:symbol
wwwroot/examples/guides/chart-01.beck.yaml
```

```beck:symbol,static
wwwroot/examples/guides/chart-01.beck.yaml
```

A bar chart colours each bar from the palette and prints its value above it; the legend maps the
colours back to labels. Any series can pin its own colour with `color:` (a token like `info` or a raw
CSS colour) to break out of the derived set.

## Colour palettes

`palette:` picks how the colours beyond the first are generated from `--beck-primary`. Each is a pure
function of that one token, so a chart needs no colour list of its own:

| palette | how it derives | best for |
|---|---|---|
| `analogous` *(default)* | small hue steps either side of the primary | categorical series — distinct yet harmonious |
| `monochromatic` | tints of the primary, mixed toward the surface | an ordered magnitude, single-hue |
| `complementary` | the primary alternating with its opposite, lightening per pair | a two-way comparison |
| `sequential` | the primary fading toward neutral | one continuous scale — density or heat |

Because the colours are expressions over the tokens rather than baked hex, they re-tint with the host
palette and adapt to dark mode automatically — see [Match your theme and
colours](/docs/guides/theme). Here `complementary` sets two lines against each other:

```yaml:symbol
wwwroot/examples/guides/chart-02.beck.yaml
```

```beck:symbol,static
wwwroot/examples/guides/chart-02.beck.yaml
```

## Lines, scatters, and centred donuts

A **line** series is a list of `values`, one per x-step; lines share a light gridline backdrop and a
dot on the latest point. A **scatter** series is a list of `[x, y]` `points`, one colour per series
(cluster). A **pie** is a filled wedge per slice; a **donut** is the same with a hole, and it can carry
a `center` headline and a `centerLabel` sub-caption:

```yaml:symbol
wwwroot/examples/guides/chart-04.beck.yaml
```

```beck:symbol,static
wwwroot/examples/guides/chart-04.beck.yaml
```

```yaml:symbol
wwwroot/examples/guides/chart-03.beck.yaml
```

```beck:symbol,static
wwwroot/examples/guides/chart-03.beck.yaml
```

## The legend

`legend:` places the key `right` (the default), `top`, `bottom`, or `none`. A right-hand legend is a
column; top and bottom are centered rows that wrap. For a single-magnitude chart (bar, pie, donut) add
`legendValues: true` to print each value alongside its label in a right-hand column — as in the donut
above. A single-series chart, or one whose bars already label themselves, reads fine with `legend:
none`.

## Generate it from your C#

`ChartDiagramBuilder` emits the same schema from code — fix the kind at construction, then add one
`Series` per bar, line, or cluster:

```csharp
using Beck.Authoring;

string fence = new ChartDiagramBuilder(ChartKind.Donut, "Cloud spend by service")
.Palette(ChartPalette.Analogous)
.Legend(LegendPlacement.Right, values: true)
.Center("$128k", "total")
.Series("Compute", 52)
.Series("Storage", 34)
.Series("Network", 22)
.ToFence(); // ```beck … ``` — drop it into any Markdown page
```

The `Series` overloads follow the data shapes — a single value for bar/pie/donut, several for a line,
`(x, y)` tuples for a scatter:

```csharp
new ChartDiagramBuilder(ChartKind.Line)
.Series("This quarter", 2.4, 2.7, 3.1, 3.6) // a value per x-step
.Series("Last quarter", 1.9, 2.1, 2.3, 2.8);

new ChartDiagramBuilder(ChartKind.Scatter)
.Series("v3.4", (74, 88), (80, 95), (77, 84)); // (x, y) points
```

---

Full field tables: [chart series in the YAML schema](/docs/reference/yaml#chart-series-type-chart).
Generating one from C#: [`ChartDiagramBuilder`](/docs/guides/generate).
2 changes: 1 addition & 1 deletion docs/Beck.Docs/Content/docs/guides/custom-styles.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Author a custom style
description: Derive a BeckStyle from a built-in with a with-expression, register it, and drive it from meta.style — retinting tokens, choosing a metrics font, and composing an artwork.
order: 33
order: 36
sectionLabel: Cross-cutting
uid: docs.guide.custom-styles
---
Expand Down
2 changes: 1 addition & 1 deletion docs/Beck.Docs/Content/docs/guides/flow.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Animate the flow
description: Script packets, bursts, status pills, and effects to tell a story with motion.
order: 30
order: 33
sectionLabel: Cross-cutting
uid: docs.guide.flow
---
Expand Down
Loading
Loading