Skip to main content
Glama
README.md
# nyyon-figures

![Nyyon Figures — editorial diagrams and real charts, drawn as code](assets/cover.png)

A **local MCP server** that renders editorial diagrams and featured covers from a spec — for *any* brand, not just nyyon. No network, no model, nothing leaves the machine — the calling assistant does the thinking, this tool does the drawing.

It ships three things:

- **Templates** — 37 parametric, content-agnostic shapes: 17 diagram templates (story shapes) + 20 data-chart templates (`chart_*`, real numbers on real scales) + a 1200×630 featured cover, drawn as code (SVG → PNG via resvg at 2×, or **animated SVG**).
- **Settings** — a brand-themeable paper/ink theme with a single accent. Colors, accent, wordmark and URL are all overridable (file or env); it ships with nyyon's look (`#6C5CE7`, Inter + JetBrains Mono) as the default.
- **Reasoning prompt** — how to map an article to a *set* of figures (which shape per idea, anchored to the sentence it illustrates, varied across the piece) + a cover, including a chart-selection guide (pick by goal, the Datawrapper method).

## The 17 diagram templates

`contrast` · `layers` · `cycle` · `fanout` · `columns` · `grid` · `funnel` · `timeline` · `quadrant` · `pyramid` · `venn` · `venn3` · `table` · `pipeline` · `radial` · `bigstat` · `progression`

Each uses the accent as a *signal*: the `FIG.` mark, the primary arrowheads, and the single focal "point" of the diagram (the goal node, the source, the winning quadrant, the apex…).

## The 20 data-chart templates

For when the idea is backed by **real numbers**. Organized by goal, following [Datawrapper's chart-types guide](https://www.datawrapper.de/blog/chart-types-guide):

| goal | templates |
|------|-----------|
| change over time | `chart_line` · `chart_multiples` · `chart_area` (stacked/share/stream) · `chart_column` · `chart_slope` · `chart_arrow` |
| shares of a whole | `chart_bar` · `chart_pie` (pie/donut) · `chart_parliament` · `chart_waffle` · `chart_treemap` · `chart_marimekko` · `chart_bar_stacked` |
| amounts | `chart_bar` · `chart_bar_grouped` · `chart_bar_split` (incl. population pyramids) · `chart_dot` · `chart_prop_area` |
| relationships | `chart_scatter` (bubble via `size`) · `chart_heatmap` |
| flows | `chart_sankey` |

Chart craft is enforced in the renderers, not requested of the caller: bars, columns, areas and waffles always start at zero; line ends and bar ends are labeled directly instead of via legends; bubbles and proportional shapes scale by **area**, never radius; small multiples share one scale; empty or flat data renders a clean labeled frame, never a NaN SVG. Geo maps are deliberately absent (an offline renderer has no shape data): reach for `chart_bar` or `chart_heatmap` by region instead.

## Showcase — every template

One render of each shape, so you can pick by eye. All drawn by this tool, default theme.

### Diagrams

| | |
|---|---|
| ![contrast](docs/showcase/contrast.png) | ![layers](docs/showcase/layers.png) |
| ![cycle](docs/showcase/cycle.png) | ![fanout](docs/showcase/fanout.png) |
| ![columns](docs/showcase/columns.png) | ![grid](docs/showcase/grid.png) |
| ![funnel](docs/showcase/funnel.png) | ![timeline](docs/showcase/timeline.png) |
| ![quadrant](docs/showcase/quadrant.png) | ![pyramid](docs/showcase/pyramid.png) |
| ![venn](docs/showcase/venn.png) | ![venn3](docs/showcase/venn3.png) |
| ![table](docs/showcase/table.png) | ![pipeline](docs/showcase/pipeline.png) |
| ![radial](docs/showcase/radial.png) | ![bigstat](docs/showcase/bigstat.png) |
| ![progression](docs/showcase/progression.png) | |

### Data charts

| | |
|---|---|
| ![line](docs/showcase/chart_line.png) | ![multiples](docs/showcase/chart_multiples.png) |
| ![area](docs/showcase/chart_area.png) | ![column](docs/showcase/chart_column.png) |
| ![slope](docs/showcase/chart_slope.png) | ![arrow](docs/showcase/chart_arrow.png) |
| ![bar](docs/showcase/chart_bar.png) | ![bar stacked](docs/showcase/chart_bar_stacked.png) |
| ![bar grouped](docs/showcase/chart_bar_grouped.png) | ![bar split](docs/showcase/chart_bar_split.png) |
| ![dot](docs/showcase/chart_dot.png) | ![pie](docs/showcase/chart_pie.png) |
| ![parliament](docs/showcase/chart_parliament.png) | ![waffle](docs/showcase/chart_waffle.png) |
| ![treemap](docs/showcase/chart_treemap.png) | ![marimekko](docs/showcase/chart_marimekko.png) |
| ![scatter](docs/showcase/chart_scatter.png) | ![heatmap](docs/showcase/chart_heatmap.png) |
| ![sankey](docs/showcase/chart_sankey.png) | ![prop area](docs/showcase/chart_prop_area.png) |

## Animation

Pass `format: "svg"` + `animate: true` to `render_figure` / `render_set` and you get a **self-animating SVG** instead of a flat PNG: every element fades in on a staggered entrance, holds, then exits — one smooth 8s loop, forever. The "traveling" shapes (`timeline`, `cycle`, `radial`) also get an accent dot gliding their path. Pure SVG — SMIL `<animateMotion>` + CSS `@keyframes`, **no JS, no dependencies**, and it honors `prefers-reduced-motion`. Use it for the web/inline; keep PNG for og:images, email, and link previews (animation doesn't survive those, and a rasterized SVG is just its first frame).

## Tools

| tool | what it does |
|------|--------------|
| `figures_for_article` | **Start here.** Article + a `design` (`auto` / `all` / `cover` / a template name) → a short brief telling you exactly what to produce, then render. Token-lean: a specific design returns only that template's schema. |
| `list_templates` | List all templates + the cover with their slot schemas. |
| `get_settings` | The active theme — colors, fonts, sizes, brand (reflects runtime changes). |
| `set_theme` | Adjust the global look — colors / fonts / brand — for all later renders. |
| `render_figure` | `{ template, slots, format?, animate? }` → a diagram PNG (or animated SVG). Returns the file path. |
| `render_cover` | `{ title, kicker?, highlight?, sub?, style? }` → the 1200×630 cover PNG. |
| `render_set` | A whole article set (`figures[]` + optional `cover`) in one call; `format`/`animate` apply to the figures. |

## Two ways to use it

**Article → figures:**
1. `figures_for_article` with the article + `design` → follow the returned brief to produce the spec.
2. `render_set` (or `render_cover`) → PNGs written locally; embed them, use the cover as featured/OG. Show the renders.

**Ad-hoc one-off** — just call `render_figure` directly, e.g. *"a venn of X and Y overlapping Z"* → `{ template: "venn", slots: { left_label: "X", right_label: "Y", overlap_label: "Z" } }`. No article needed.

Re-theme anytime with `set_theme` (or env / `src/settings.js`).

## Install (Claude / MCP)

```bash
npm install
```

Then add to your MCP client config:

```json
{
  "mcpServers": {
    "nyyon-figures": { "command": "node", "args": ["/ABSOLUTE/PATH/nyyon-figures/src/index.js"] }
  }
}
```

Or with the CLI: `claude mcp add nyyon-figures -- node /ABSOLUTE/PATH/nyyon-figures/src/index.js`

## Settings & overrides

Edit `src/settings.js`, or override at runtime via env:

- `NYYON_FIGURES_ACCENT` — accent hex (default `#6C5CE7`)
- `NYYON_FIGURES_PAPER` / `NYYON_FIGURES_INK` — background / foreground
- `NYYON_FIGURES_BRAND_NAME` — wordmark text on the cover (default `nyyon`)
- `NYYON_FIGURES_BRAND_URL` — URL printed on the cover (default `nyyon.com`)
- `NYYON_FIGURES_BRAND_MARK` — SVG path (~64×70 box) for the logo mark; `""` = text-only wordmark + plain accent hub
- `NYYON_FIGURES_OUT` — directory for rendered PNGs (default `$TMPDIR/nyyon-figures`)

So a different brand is one line: `NYYON_FIGURES_BRAND_NAME='Acme' NYYON_FIGURES_BRAND_URL='acme.io' NYYON_FIGURES_BRAND_MARK='' NYYON_FIGURES_ACCENT='#0EA5E9'`.

## Test

```bash
npm test   # renders one of every template + the cover into tmp-smoke/
```

TDQS

A3.8/5.0

Scored across 6 tools

Disambiguation5/5

Each tool has a distinct purpose: reasoning prompt, settings, template listing, and three rendering variants. No overlap in functionality, so an agent can clearly distinguish them.

Naming Consistency5/5

All tool names follow a consistent verb_noun snake_case pattern (get_, list_, render_). This predictability aids agent selection and code generation.

Tool Count5/5

With 6 tools covering the core workflow (prompt, settings, templates, rendering), the count is well-scoped for figure generation without being too few or excessive.

Completeness4/5

The tool surface covers the essential workflow: obtaining a prompt, checking settings, listing templates, and rendering figures/covers. A minor gap is the lack of a tool to retrieve or delete rendered files, but this is not critical for typical usage.

Maintenance

ActivitySlowing
ResponsivenessNo issues