# Jaw Diagram

> SVG diagrams, charts, and interactive visualizations for chat UI

- Skill: `lidge-jun/jaw-diagram` (Agent Skill, multi-file: 14 files)
- Install (CLI): `npx skillmds@latest add lidge-jun/jaw-diagram`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lidge-jun/jaw-diagram/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: lidge-jun (https://skillmd.com/u/lidge-jun)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/lidge-jun/jaw-diagram

---


# Diagram Visualization Skill

## Design Principles

- **Claim first** (DIAGRAM-CLAIM-01): before choosing a type, name the reader, the decision they face, and one claim they could disagree with. That sentence becomes the caption and the `<title>`. If there is no claim, write the sentence and skip the diagram.
- **Shape carries meaning** (DIAGRAM-SCOPE-01): draw when the point is a relation — contains, precedes, causes, branches, outweighs. Definitions, single facts, and values a reader must compare precisely belong in prose or a table. Recipes: `reference/visual-story.md`.
- **Never invent data** (DIAGRAM-EVIDENCE-01): every quantity is observed, user-supplied, assumed, or illustrative, and the figure or caption says which. A chart of numbers you made up is not a placeholder, it is a false claim that renders beautifully. Put units on the axis, and say so when an axis does not start at zero. Classes and worked form: `reference/visual-story.md`.
- **Flat**: No gradients, shadows, blur, glow, or decorative effects. Clean flat surfaces only.
- **Compact**: Show the essential inline. Explain the rest in response text.
- **Theme-aware**: Every color must work in both light and dark mode. Use CSS classes for SVG, `window.__jawTokens` for canvas/JS.
- **Text in response, visuals in tool**: All explanatory prose goes outside the diagram. Never put paragraphs of explanation inside the SVG or widget HTML.

## Complexity Budget — Hard Limits

- Box subtitles: **≤5 words**. Detail goes in `sendPrompt()` or prose — not the box.
- Colors: **≤2 ramps** per diagram. More = visual noise.
- Horizontal row: **≤4 boxes** at 680px width. 5+ boxes → shrink or wrap to 2 rows.
- Nodes: **≤6 per diagram**. 7+ → split into overview + detail diagrams. One takeaway per figure (DIAGRAM-SEQ-01): the overview shows the level where the claim is visible, then a **named** detail figure zooms into one region. Shrinking everything into one frame until labels are unreadable is the failure this budget exists to prevent.
- **Always add prose between diagrams** — never output consecutive SVG blocks or widget blocks without text between them. That prose is claim-shaped (DIAGRAM-HANDOFF-01): it states what to conclude, not "the diagram below shows the architecture". Detail that will not fit a five-word subtitle goes here.

## Diagram Type Selection

Route on the verb, not the noun. Same subject gets different diagrams. Prefer Mermaid when the diagram type maps cleanly to a native Mermaid syntax — it's cheaper than hand-rolling SVG.

| User says / intent | Type | Output |
|---|---|---|
| "how does X work" | Illustrative SVG | Spatial metaphor, cross-section, physical layout |
| "architecture of X" (system context) | Structural SVG | Containers, regions, nesting |
| "steps of X" (generic process) | Flowchart SVG or Mermaid `flowchart` | Top-down boxes + arrows |
| "compare A vs B" | Comparison SVG | Side-by-side columns |
| "DB schema / entity relationship" | Mermaid | ` ```mermaid ` `erDiagram` |
| "class diagram / OOP structure" | Mermaid | ` ```mermaid ` `classDiagram` |
| "state machine / lifecycle" | Mermaid | ` ```mermaid ` `stateDiagram-v2` |
| "sequence / call order / API flow" | Mermaid | ` ```mermaid ` `sequenceDiagram` |
| "timeline / roadmap / history" | Mermaid | ` ```mermaid ` `timeline` |
| "mind map / brainstorm / outline" | Mermaid | ` ```mermaid ` `mindmap` |
| "git branching / release history" | Mermaid | ` ```mermaid ` `gitGraph` |
| "2×2 matrix / priority quadrant" | Mermaid | ` ```mermaid ` `quadrantChart` |
| "radar / spider / skill profile" | Mermaid v11.6+ (beta) | ` ```mermaid ` `radar-beta` |
| "gantt / project schedule" | Mermaid | ` ```mermaid ` `gantt` |
| "user journey map" | Mermaid | ` ```mermaid ` `journey` |
| "pie breakdown (simple)" | Mermaid | ` ```mermaid ` `pie` |
| "kanban board" | Mermaid v11.12+ (beta, test before use) | ` ```mermaid ` `kanban` |
| "cloud/infra architecture" | Mermaid (beta) | ` ```mermaid ` `architecture-beta` |
| "hierarchy / proportional size" | Mermaid (beta) | ` ```mermaid ` `treemap-beta` |
| "free-form block layout" | Mermaid | ` ```mermaid ` `block` |
| "packet / network frame" | Mermaid | ` ```mermaid ` `packet` |
| "ishikawa / fishbone / cause-effect" | Mermaid | ` ```mermaid ` `ishikawa` |
| "swimlane / lane-based workflow" | Mermaid | ` ```mermaid ` `swimlane-beta` |
| "requirement / traceability" | Mermaid | ` ```mermaid ` `requirementDiagram` |
| "sankey / flow quantity" | Mermaid | ` ```mermaid ` `sankey` |
| "XY chart / scatter / line" | Mermaid | ` ```mermaid ` `xychart` |
| "venn / overlap / set intersection" | Mermaid (beta) | ` ```mermaid ` `venn-beta` |
| "show sources / search results / citations" | `structured-renderers` skill | Non-diagram native card: load `structured-renderers` for `search-results` schema |
| "write / draft / compose email, message, document" | `structured-renderers` skill | Non-diagram native card: load `structured-renderers` for `compose-block` schema |
| "table / rows / sortable data / filterable data" | `structured-renderers` skill | Non-diagram native card: load `structured-renderers` for `dataframe` schema |
| "patch / diff / unified diff" | `structured-renderers` skill | Non-diagram native display: load `structured-renderers` for `diff` routing |
| "show data / chart" | `chart-json` for simple bar/line/pie; diagram-file for advanced charts | For `chart-json`, load `structured-renderers`; use file-backed Chart.js / D3 / ECharts iframe widgets when custom JS, maps, advanced chart types, or richer interactivity are required |
| "simulate / interactive" | diagram-file | File-backed Matter.js / Canvas / sliders widget |
| "large widget / iterative widget editing" | diagram-file | Default for all HTML widgets: write the full widget HTML to `~/.cli-jaw/widgets/<chatId>/<widgetId>.html`, then emit an id-only file-backed fence |
| "interactive map (with pan/zoom/markers)" | diagram-file | File-backed Leaflet iframe widget — see `reference/module-map.md` |
| "static country/state choropleth" | diagram-file | File-backed D3 + TopoJSON widget — see `reference/module-chart.md` |

Default to illustrative SVG for "how does X work?" — don't default to flowchart. Default to Mermaid when the type is in the table above — don't hand-roll an SVG when `classDiagram`/`sequenceDiagram`/`stateDiagram` already exists.

`diagram-file` is the default for all HTML widget types. Use `diagram-html` only as a fallback when the chatId cannot be determined or for very small throwaway widgets that do not warrant a file.

### Native Web UI renderer boundary

Before producing a `diagram-file` HTML widget, check whether a native renderer is a better fit:

- Load `structured-renderers` for `search-results`, `compose-block`, `dataframe`, `chart-json`, and `diff` schemas.
- Use `chart-json` for simple single-series bar/line/pie charts.
- Stay in `diagram` and use `diagram-file` for maps, multi-series charts, advanced chart types, custom JavaScript, external libraries, or richer interaction.

These renderers are lighter than HTML widgets, survive sanitizer/hydration, and avoid iframe overhead. They are final-answer-only structured fences; during streaming they remain inert code blocks. Keep JSON complete, compact, and schema-versioned. See the active `structured-renderers` skill for canonical schemas and examples.

### OfficeCLI raster CJK rule

When OfficeCLI rasterizes Mermaid to PNG and the diagram contains Korean/CJK text,
prepend this directive to the Mermaid source before rendering:
```mermaid
%%{init: {"themeVariables":{"fontFamily":"Noto Sans KR, Apple SD Gothic Neo, NanumGothic, Malgun Gothic, sans-serif"}}}%%
```
After export, open and inspect the PNG. Confirm that Korean glyphs are not tofu
boxes, labels are not clipped, and the fallback font did not change node metrics.
Rendering or a successful OfficeCLI exit code is not visual verification.

### Mermaid gotchas (read before using beta/experimental types)

- **Do NOT use C4 diagrams** (`C4Context`, `C4Container`, etc.) — theme tokens are not applied in dark mode, text becomes unreadable ([mermaid #4906](https://github.com/mermaid-js/mermaid/issues/4906)). Substitute routing:
  - **C4 System Context** → Structural SVG (custom) OR Mermaid `flowchart` with subgraphs
  - **C4 Container** → Mermaid `architecture-beta` (cloud/infra layout)
  - **C4 Component** → Mermaid `flowchart` with `subgraph` grouping
  - **C4 Dynamic** → Mermaid `sequenceDiagram`
  - **C4 Deployment** → Mermaid `architecture-beta`
- **`sankey-beta` / `xychart-beta`** — known to break scale-down at narrow chat widths. Prefer `diagram-file` + ECharts sankey for flow diagrams, Chart.js for simple XY.
- **Now stable (no suffix needed):** `block`, `packet`, `kanban`, `sankey`, `xychart`, `ishikawa`.
- **Still beta (suffix required):** `radar-beta`, `architecture-beta`, `treemap-beta`, `venn-beta`, `wardley-beta`, `treeView-beta`, `cynefin-beta`, `swimlane-beta`. Test beta types in the cli-jaw Web UI before finalizing.
- **`sandbox` securityLevel iframe background bug** ([mermaid #5034](https://github.com/mermaid-js/mermaid/issues/5034)) — affects host rendering, not your output. No action needed from the agent.
- **Theme**: all stable Mermaid types pick up the host dark/light theme automatically via cli-jaw's `themeVariables`. Do NOT set explicit colors in `%%{init: ...}%%` unless overriding for semantic reasons.

## When to Use

### 1. Explicit request (명시적 요청)

한국어: "그려줘", "시각화", "다이어그램", "차트로", "도표로", "비교표", "플로우차트"
영어: "draw", "visualize", "diagram", "chart", "graph", "illustrate", "show me"

### 2. Proactive generation (에이전트 판단)

다음 상황에서 텍스트만으로는 전달이 부족할 때 자동 생성:
- 시스템/프로세스 아키텍처 설명 (3+ 컴포넌트)
- 데이터 3항목 이상 비교
- 프로세스 5단계 이상 설명
- 계층 구조 (트리 2+ 레벨)
- 타임라인/히스토리 (4+ 이벤트)
- 수학적 관계 시각화

이 개수 조건은 그릴지 **검토할** 신호이지 그리라는 지시가 아니다 (DIAGRAM-SCOPE-01). 항목 사이에
관계가 없으면 그것은 목록이다. 주장 한 줄을 먼저 쓰고, 그 주장이 그림에서 보일 때만 그린다.

A report or explainer around the diagram follows `jaw-dev/references/reader-documents.md`.
The figure itself follows `reference/visual-story.md`: claim, evidence class, sequencing, handoff.
Rendering, formats and security stay owned here.

### 3. Specification (명사구 스펙)

사용자가 시각물의 구조를 명사구로 기술:
- "X vs Y 비교" → comparison layout
- "X 구조" / "X 아키텍처" → architecture diagram
- "X 플로우" → flowchart
- "X 타임라인" → timeline

### 4. When NOT to use

- 단순 질의응답 (팩트 한 줄이면 충분)
- 코드 리뷰/디버깅 (코드가 더 명확)
- 이미 diagram-html 내에서 동작 중인 위젯 재생성
- 사용자가 "간단히 설명해줘"라고 한 경우

## Delivery Mechanism (read before producing anything)

All four formats — inline SVG, ` ```mermaid `, ` ```diagram-file `, ` ```diagram-html ` — are **rendered inline in the chat response**. The jaw frontend parses your reply text and mounts them automatically. `diagram-file` and `diagram-html` go into sandboxed `<iframe>` elements that the host creates; you do **not** create the iframe.

### File-backed widgets (`diagram-file`)

Use ` ```diagram-file ` as the default for all HTML widget output, including charts, maps, simulations, controls, games, and custom JavaScript widgets. Write the full widget HTML first to `~/.cli-jaw/widgets/<chatId>/<widgetId>.html`, following the same HTML rules as `diagram-html`: the host renders it through the validator and sandboxed iframe, with the same CDN allowlist and theme token expectations.

The fence body is id-only: `{"id": "<widgetId>"}`. A bare widget id string is also accepted. Do not put paths in the fence; the host resolves `<current chatId>/<widgetId>.html` by convention. The file-backed cap is 2 MB, while inline `diagram-html` remains capped at 512 KB. File-backed widgets are mutable: editing the saved HTML updates every message that references the same id. Save under a new id when a frozen version is needed.

Determine the current chatId from runtime context when available. If it is not determinable, use inline `diagram-html` as the fail-safe. `diagram-html` is also acceptable for very small throwaway widgets that do not warrant a file.

| ❌ Don't | ✅ Do |
|---|---|
| Save SVG/Mermaid outputs to `.svg` / `.png` files unless explicitly asked | Paste SVG/Mermaid blocks directly into your reply |
| Wrap `diagram-html` in your own `<iframe>` / `<html>` / `<body>` / `<head>` | Start at `<div>` / `<canvas>` / `<style>` — host injects the shell |
| Send via `/api/channel/send` or Telegram/Discord — it is NOT an attachment | Let the renderer handle it; diagrams are response text |
| Reference an external image URL and call it a diagram | Output the SVG/widget code itself |

If the user says "save this diagram" or "download it", still output it inline first so they see it rendered; only write a file if they explicitly ask for a file on disk (and even then, the inline version is the canonical delivery).

## Output Formats

### 1. Inline SVG (static diagrams)
Output raw `<svg>` markup directly in the response. The chat UI renders it inline.

```
<svg viewBox="0 0 680 {height}" xmlns="http://www.w3.org/2000/svg"
  role="img" aria-labelledby="title-id desc-id">
  <title id="title-id">Retries are the only path that writes twice</title>
  <desc id="desc-id">Request flow from client to queue, with the retry branch rejoining after the write step</desc>
  <!-- shapes, text, paths -->
</svg>
```

Rules:
- viewBox width MUST be 680 (matches container width — do NOT change)
- Height varies by content: last element bottom + 40px padding
- Every SVG MUST have `role="img"` + `<title>` + `<desc>`. The `<title>` states the takeaway, not the subject (DIAGRAM-A11Y-01) — a screen-reader user gets the claim, not the word "Diagram". The same applies to a canvas or widget `aria-label` and its fallback text. Never let a distinction live in color alone: carry it in the label, shape, or position too, so it survives grayscale and color vision deficiency. Widget controls stay keyboard reachable (`reference/module-interactive.md`).
- Look at the rendered figure before delivering (DIAGRAM-RENDER-01): text inside its box, nothing clipped, no overlapping labels, no empty series, and for CJK no tofu or fallback metric shift. Valid syntax is not a rendered result. CJK specifics: `reference/korean-text.md`.
- Use classes from the design system (`.node`, `.connector`, `.label`, `.label-start`, etc.) — `.label` forces `text-anchor: middle` (centered text only); for left-aligned text use `.label-start` or just the color class
- Colors: use CSS classes, not inline fill/stroke colors
- Text: inline SVG inherits `font-family` from the jaw host; do not set explicit fonts there. Exception: OfficeCLI-rasterized Mermaid with Korean/CJK text must use the init directive above because the raster renderer is not the jaw host.

### 2. Mermaid (simple flowcharts, ERDs)
Use standard ` ```mermaid ` code blocks. The existing renderer handles these.

### 3. Interactive HTML Widget (fallback form: charts, controls, simulations)
Use ` ```diagram-file ` by default. Wrap in a ` ```diagram-html ` code block only when the chatId cannot be determined or the widget is a very small throwaway. Rendered inside a sandboxed iframe.

```
` ` `diagram-html
<div id="chart-wrapper" style="position: relative; width: 100%; height: 300px;">
  <canvas id="myChart" role="img"
    aria-label="Signups doubled after the March pricing change">
    Fallback text stating the same takeaway
  </canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"
  onerror="document.body.innerHTML='<p>Chart library failed to load.</p>'">
</script>
<script>
  const isDark = window.__jawTheme?.isDark ?? true;
  // ... Chart.js code
</script>
` ` `
```

## SVG Design System

### Design Forbidden List
These are design quality rules (separate from security restrictions below):
- No gradients, drop shadows, blur, glow, or neon effects
- No emoji — use CSS shapes or SVG paths
- No decorative step numbers or oversized headings
- No icons or illustrations inside flowchart boxes — text only
- No rotated text
- No dark/colored backgrounds on outer containers (transparent only — host provides bg)
- Stroke width: **0.5px** for borders and edges (not 1px or 2px)
- Font weights: **400** (regular) and **500** (bold) only. Never 600 or 700.
- Font sizes in SVG: **14px** (node labels) and **12px** (subtitles/arrow labels) only
- **Sentence case** always. Never Title Case or ALL CAPS.

### `<style>` in Inline SVG

`<style>` tags inside inline SVG ARE preserved. Custom CSS classes work:

```xml
<svg viewBox="0 0 100 100">
  <style>
    .highlight { fill: #e94560; }
    .dim { fill: #94a3b8; }
  </style>
  <rect class="highlight" width="50" height="50"/>
</svg>
```

**Security filters applied automatically:**
- `@import` rules → stripped
- `@font-face` blocks → stripped
- External `url()` → replaced with `none` (internal `url(#ref)` preserved)

**Best practice:** Prefer predefined `.c-*` classes (see `reference/color-palette.md`) for theme-aware colors. Use custom `<style>` when you need colors/patterns not in the design system.

### Forbidden in Inline SVG (Security)
These are stripped by DOMPurify — NEVER use in inline `<svg>`:
- `<foreignObject>` — embeds HTML in SVG (XSS vector)
- `<animate>`, `<set>`, `<animateTransform>`, `<animateMotion>` — animation XSS vectors
- Nested `<svg>` — use `<g>` groups instead

### Forbidden Attributes in Inline SVG
- `xlink:href` — use `href="#fragment"` on `<use>` only (no external URLs)
- All `on*` event handlers (onclick, onerror, etc.) — stripped by DOMPurify

> **Note**: `diagram-file` and fallback `diagram-html` content run inside a sandboxed iframe where
> `<script>`, `on*` handlers, and CDN imports ARE allowed. The restrictions
> above apply only to inline SVG rendered in the main document.

### Color Ramps (9 semantic colors)
Each ramp has 3 shades: fill (bg), stroke (border), text (label).
Use CSS class names — see `reference/color-palette.md`:

| Ramp | Class prefix | Preferred use |
|---|---|---|
| cyan | `.c-cyan` | General categories (preferred for neutral info) |
| pink | `.c-pink` | General categories, highlights |
| purple | `.c-purple` | General categories, grouping |
| orange | `.c-orange` | General categories, accent |
| slate | `.c-slate` | Neutral, disabled, structural (start/end nodes) |
| blue | `.c-blue` | Informational (semantic — use only when meaning is "info") |
| green | `.c-green` | Success, positive (semantic) |
| amber | `.c-amber` | Warning, attention (semantic) |
| red | `.c-red` | Error, negative (semantic) |

**Color assignment**: color encodes **meaning**, not sequence. Don't cycle through colors like a rainbow. Group by category — all nodes of the same type share one color. Prefer cyan/pink/purple/orange for general categories. Reserve blue/green/amber/red for genuinely semantic concepts.

### Layout Patterns
- Flowchart: top-to-bottom, 680×auto
- Comparison: side-by-side columns
- Timeline: horizontal with markers
- Org chart: hierarchical tree
- See `reference/svg-components.md` for templates and detailed SVG rules.

### Style-First, Script-Last
For `diagram-file` widgets and fallback `diagram-html` widgets:
1. All `<style>` and `<link>` tags first
2. HTML structure
3. `<script>` tags last

This ensures visual content appears before scripts execute (important during streaming).

## Theme Integration

### CSS Variable Mapping (cli-jaw)
| Variable | Use |
|---|---|
| `--bg` | Page background |
| `--surface` | Card/surface background |
| `--text` | Primary text |
| `--text-dim` | Muted/secondary text |
| `--border` | Default border |
| `--accent` | Accent color |
| `--font-ui` | UI font family |
| `--font-mono` | Code font family |
| `--radius-md` | 8px border radius |
| `--radius-lg` | 12px border radius |

### By format
- **Inline SVG**: CSS classes adapt to host theme automatically
- **iframe widgets**: use `window.__jawTheme.isDark` (boolean) for JS-side theme detection
- **iframe widgets**: use `window.__jawTokens['--bg']` etc. for computed host CSS values
- Do NOT use `matchMedia('prefers-color-scheme')` — the host controls theme

## SVG Mobile Notes

- viewBox 680px 기준은 유지하되, 텍스트는 최소 14px (모바일 축소 후 ~9px)
- CJK 텍스트: 최소 16px (축소 후 ~10px)
- 터치 가능한 SVG 요소: 최소 44×44 hit area

## Animation Rules

### Inline SVG (DOMPurify sanitized)
- SMIL tags (`<animate>`, `<set>`, `<animateMotion>`) are stripped — do not use
- Inline SVG is static only — no animation

### diagram-file and diagram-html (sandboxed iframe)
All CSS/JS animation is available:

**CSS Transition** (preferred for hover/state changes):
```css
.element { transition: all 0.3s ease; }
.element:hover { transform: scale(1.05); opacity: 0.8; }
```

**CSS Animation** (keyframes):
```css
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.element { animation: fadeIn 0.5s ease-out; }
```

**JS requestAnimationFrame**: already documented in module-widget.md (Matter.js, Three.js, p5.js)

### Performance
- Animate only `transform` and `opacity` (GPU-accelerated)
- Avoid animating `width`, `height`, `top`, `left` (layout thrashing)
- Always call `cancelAnimationFrame` on cleanup

## Reference Files
For detailed patterns, see:
- `reference/visual-story.md` — **read first**: claim, evidence classes, one-takeaway sequencing, prose handoff, compositions to avoid, fresh-reader check
- `reference/svg-components.md` — SVG primitives, viewBox checklist, layout templates
- `reference/color-palette.md` — Full color values (light + dark), assignment rules
- `reference/module-chart.md` — Chart.js + D3 + ECharts 6 integration (bar/line/pie/choropleth + heatmap/sankey/radar/treemap/gauge/funnel/candlestick/chord)
- `reference/module-widget.md` — Physics (Matter.js), math graphs (Math.js), 3D (Three.js), creative coding (p5.js), audio (Tone.js), mini-games
- `reference/module-interactive.md` — Sliders, selects, segmented buttons, toggles, play/pause/reset, debouncing, sendPrompt, keyboard accessibility, control layout pattern
- `reference/module-map.md` — Leaflet interactive maps (OpenStreetMap tiles, markers, popups, dark mode)
- `reference/module-mockup.md` — UI mockup patterns
- `reference/module-art.md` — Decorative SVG patterns
- `reference/module-domain-cards.md` — Domain card templates (weather, finance, sports, product) + real-time data pipeline
- `reference/structured-renderers.md` — native renderer delegation notes

