yf-diagram-authoring

Generate light-mode, white-background diagram PNGs from d2 source, keeping the .d2 source beside every .png render. Stan

Generate light-mode, white-background diagram PNGs from d2 source, keeping the .d2 source beside every .png render. Standardizes d2 (not mermaid) as the single, local, offline diagram engine: write .d2 -> render .png (theme 0, elk) -> verify by Read.

At a glance

  • Category: utility
  • Invocation: /yf-diagram-authoring (user-invocable)
  • Requires tools: d2
  • Source: SKILL.md · README.md

When it fires

the operator asks to author/render/regenerate a diagram, or a content-producing skill (yf-plan, yf-research, yf-skill-authoring) generates a structural diagram for a plan, research report, or skill spec.

When to skip it

non-diagram image work; mermaid-specific workflows; any task that does not produce a d2 diagram. Output locations are caller-supplied (the skill is location-agnostic); consumers set their own convention (plan_dir/diagrams, research_dir/ diagrams, skill spec/ co-resident, project docs/diagrams).


Prerequisites

Tool Version Purpose Install
d2 >= 0.7 Diagram compiler/renderer (.d2.png, theme 0, elk) brew install d2

Mirrors SKILL.md frontmatter depends-on-tool: [d2]. The first PNG render fetches a one-time ~140MB playwright Chromium; that warm-up is owned outside this skill (e.g. a dotfiles bootstrap hook). Preflight only checks that d2 is on PATH — it never probes the Chromium cache.

Usage

User-invocable. Drive d2 through scripts/render.py (run via uv run):

uv run scripts/render.py preflight                 # OS-independent `command -v d2` check
uv run scripts/render.py render <slug>.d2          # one .d2 -> sibling .png (theme 0, elk)
uv run scripts/render.py render-dir <dir>          # (re)render every .d2 under <dir>
uv run scripts/render.py check-dir <dir>           # every .d2 has a .png (+ advisory staleness)
uv run scripts/render.py embed <src.d2> <tgt.md>   # insert source as an inline ```d2 fence
uv run scripts/render.py lift <tgt.md>             # inline ```d2 -> standalone .d2 + .png + link
uv run scripts/render.py inline <tgt.md>           # standalone .png link -> inline ```d2 fence

Write .d2 source into the caller's diagrams location, render, then Read the PNG to verify (white background, legible labels). Reference a render from docs with relative markdown image syntax — ![alt](https://raw.githubusercontent.com/dixson3/yoshiko-flow/main/skills/yf-diagram-authoring/spec/<slug>.png) from a skill README, ![alt](https://raw.githubusercontent.com/dixson3/yoshiko-flow/main/skills/yf-diagram-authoring/docs/diagrams/<slug>.png) from the project README.

Inline source vs standalone render. A diagram can travel inline as a ```d2 fence (rendered at preview/PDF time by yf-markdown-pdf — one file, no committed binary) or as a standalone committed .d2 + .png referenced by an image link (previews anywhere, but adds a binary + a regeneration discipline). embed inserts inline source, lift converts inline → standalone, inline converts standalone → inline; the pair round-trips (source unchanged). See SKILL.md for the full workflow, the trade-off table, location conventions, and d2 authoring notes.

Layout

skills/diagram-authoring/
├── SKILL.md             # the d2 workflow, location conventions, when-to-diagram, d2 authoring notes
├── README.md            # this file
└── scripts/
    ├── render.py        # PEP 723 helper: preflight / render / render-dir / check-dir / embed / lift / inline
    └── test_render.py   # pytest: embed/lift/inline parsing + the round-trip guarantee