Skip to content
Back to skills

Diagrams And Charts

ASecurity

Create blog-quality diagrams and data charts (architecture flows, data structure cards, grouped bar charts) as plain HTML, then export them to PNG with a playwriter-based CLI. Ships two styles: claude-style (Anthropic engineering blog look, light) and nextjs-style (Next.js docs look, dark). Use when the user wants a diagram, chart, figure, infographic or data visualization image for a blog post, docs or social, especially "Anthropic style", "Claude style", "Next.js style" or a dark diagram.

  • 44 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
ai-agentstypescriptgobashnextjsnodeawsgit

Works with

  • cli

Security analysis

A100/100

Pro scans all 12 files and shows the line behind each finding

Scanned November 7, 2026

npx -y skills add remorses/opencode-config --skill diagrams-and-charts --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Diagrams And Charts?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Diagrams And Charts
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/remorses-diagrams-and-charts/badge)](https://www.skillsdirectory.com/skills/remorses-diagrams-and-charts)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: diagrams-and-charts
description: >
  Create blog-quality diagrams and data charts (architecture flows, data structure cards, grouped
  bar charts) as plain HTML, then export them to PNG with a playwriter-based CLI. Ships two
  styles: claude-style (Anthropic engineering blog look, light) and nextjs-style (Next.js docs
  look, dark). Use when the user wants a diagram, chart, figure,
  infographic or data visualization image for a blog post, docs or social, especially "Anthropic
  style", "Claude style", "Next.js style" or a dark diagram.
---

# diagrams-and-charts

Figures are **plain HTML files**: boxes laid out with a css grid, arrows and charts drawn from
data by small TypeScript helpers. `render.ts` exports them through the user's Chrome.

The image is **only the diagram or chart** on its light background, with padding and square
corners. No title, no page frame, no outer card: the blog post or doc supplies those. Put the
title in the surrounding text, not in the image.

```
fig.html ──▶ render.ts: Bun.serve + playwriter tab ──▶ wait network, fonts, helpers ──▶ png
   │ links /skill/<style>/style.css, imports /skill/diagram.ts, /skill/charts.ts
```

## Styles

A style is only fonts and colors: `<style>/style.css` sets tokens and imports the shared
`base.css`. Layout rules live in `claude-style/DESIGN.md` and apply to every style.

| folder          | look                                                        |
| --------------- | ----------------------------------------------------------- |
| `claude-style/` | Anthropic engineering blog: light, warm gray, clay accent   |
| `nextjs-style/` | Next.js docs: dark, gray cards, blue, pink, purple, green, amber |

Switch style by changing one line in the html:

```html
<link rel="stylesheet" href="/skill/nextjs-style/style.css" />
```

Start from the closest example in `examples/` (they link claude-style):

| example                  | use for                                           |
| ------------------------ | ------------------------------------------------- |
| `architecture-flow.html` | services, clients, data flow arrows               |
| `changeset-shape.html`   | struct / record card, storage tiers, derived data |
| `grouped-bar-chart.html` | benchmark comparisons, before vs after            |

## Workflow

1. Read `claude-style/DESIGN.md` (and the chosen style's DESIGN.md). Copy the closest example into a **new file** with a unique
   name, next to where the user wants the image or in `./tmp/<figure-name>/`. Never edit files in
   this skill folder: other agents may render from it at the same time.
2. Replace the content with the user's data. Keep `<div class="canvas" id="diagram">` as root;
   it is exactly what gets exported. Use `.section` + `.section-label` to split one figure into
   regions (e.g. metadata vs storage).
3. Render, then read the png back and fix what looks wrong:

   ```bash
   bun ~/.config/opencode/skills/diagrams-and-charts/render.ts render ./fig.html -o ./fig.png
   ```

Run `render.ts render --help` for options (`--id`, `--scale`, `--width`, `--dark`). Output type
comes from the extension: `.png` / `.jpg` (default scale 2: 2120px wide).

**Light and dark copies for websites and READMEs.** Render the figure twice; `--dark <style>`
keeps the layout and fonts and swaps in that style's colors:

```bash
bun ~/.config/opencode/skills/diagrams-and-charts/render.ts render fig.html -o fig.png
bun ~/.config/opencode/skills/diagrams-and-charts/render.ts render fig.html -o fig-dark.png --dark nextjs-style
```

On GitHub use `<picture>`. In Holocron MDX wrap each `<img>` in a `div`: Holocron's image
wrapper sets an inline `display`, so a `className` on the `<img>` cannot hide it.

```html
<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/fig-dark.png" />
  <img alt="Full description of the flow" src="assets/fig.png" />
</picture>

<div className="dark:hidden"><img src="/assets/fig.png" alt="..." /></div>
<div className="hidden dark:block"><img src="/assets/fig-dark.png" alt="..." /></div>
```

Write a full alt text that describes the flow, agents read it instead of the image.

## Writing figures

- **No coordinates.** Place boxes in a `.flow` grid by cell (`grid-area: row / col`). Give
  boxes that arrows touch an `id`.
- **Arrows** from ids, after the markup:

  ```html
  <script type="module">
    import { connect } from '/skill/diagram.ts'
    connect('dev', 'cache', { color: 'accent', label: 'Trees and file contents' })
    connect('cache', 'server', { from: 'right', to: 'bottom', color: 'accent' })
    connect('server', 'storage', { color: 'purple' })
  </script>
  ```

  Sides are picked from the layout. Force them with `from` / `to` when the route crosses a box.
- **Use the whole palette.** Every style has `blue` plus four category hues: `pink`, `purple`,
  `green`, `amber`. Give each category of boxes one hue (`class="box green"`, also on `.group`
  and `.dashed`) and color the wires of that category the same (`color: 'green'`; the label
  follows). Typical mapping: clients/users green, your system blue, cloud/third party purple,
  devices or targets pink, storage amber. Keep `accent` for the one highlighted path. Bar chart
  series take `colors: ['bar', 'green', ...]`.
- **Charts** from data: `barChart('#diagram', spec)` from `charts.ts`, on an empty canvas. Format value labels yourself;
  values in one chart share one unit.
- `/skill/` maps to this folder, other paths to the html folder. `.ts` files are transpiled on the
  fly, so page scripts can be TypeScript too (`<script type="module" src="./data.ts">`).

## Gotchas

- Concurrent renders are safe: each run uses its own port, tab and playwriter session.
  Only the html and output paths must be unique per figure.
- Needs Chrome with the playwriter extension connected. If connecting fails, ask the user to
  click the extension icon. The CLI opens its own tab in a `diagrams` tab group and closes it.
- Page errors (bad id in `connect`, js exceptions) fail the render with the message. Read it.
- The canvas is 1060px. Keep to about 5 columns and short sub lines; the CLI prints
  `warning: clipped` with the element names when something sticks out. Fix every warning.
- A wire label is centered on its longest segment, so the gap between two boxes must be wider
  than the label. Shorten the label or put it in `sub` (second line) when a gap is narrow.
- Two arrows leaving the same side of one box overlap. Spread them with `fromAt: 0.3` and
  `fromAt: 0.7`, or start one from the enclosing group.
- `--dark` must change only colors: the arrows keep the light render's positions.
- Code that draws asynchronously must register its promise with `track()` from `diagram.ts`,
  otherwise the screenshot can happen before it finishes.
- Use `.box.dashed` (svg outline), not css `border-style: dashed`. Import `diagram.ts` on pages
  with dashed boxes even when there are no arrows.
- Deps come from `~/.config/opencode/node_modules` (goke, playwriter, zod, string-dedent). If
  imports fail, run `bun add goke playwriter zod string-dedent` in `~/.config/opencode`.

## Adding a style

Create `<name>-style/` with `style.css` (fonts `@import`, then `@import url('../base.css')`, then
the `:root` tokens; copy the token list from an existing style), a short `DESIGN.md` with the
palette table, and `references/`. Never hardcode colors in `base.css`, the ts helpers or html:
use tokens, so every figure works in every style.

Files in this skill

  • SKILL.md7.3 KB
  • base.css6.7 KB
  • charts.ts6.6 KB
  • claude-style/DESIGN.md6.7 KB
  • claude-style/style.css823 B
  • diagram.ts9.6 KB
  • examples/architecture-flow.html2.3 KB
  • examples/changeset-shape.html3.9 KB
  • examples/grouped-bar-chart.html2.9 KB
  • nextjs-style/DESIGN.md2.4 KB
  • nextjs-style/style.css971 B
  • render.ts7.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.