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:
%%{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). 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) — 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"
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:
<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:
- All
<style> and <link> tags first
- HTML structure
<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):
.element { transition: all 0.3s ease; }
.element:hover { transform: scale(1.05); opacity: 0.8; }
CSS Animation (keyframes):
@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
1---2name: jaw-diagram3description: SVG diagrams, charts, and interactive visualizations for chat UI4---56# Diagram Visualization Skill78## Design Principles910- **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.11- **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`.12- **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`.13- **Flat**: No gradients, shadows, blur, glow, or decorative effects. Clean flat surfaces only.14- **Compact**: Show the essential inline. Explain the rest in response text.15- **Theme-aware**: Every color must work in both light and dark mode. Use CSS classes for SVG, `window.__jawTokens` for canvas/JS.16- **Text in response, visuals in tool**: All explanatory prose goes outside the diagram. Never put paragraphs of explanation inside the SVG or widget HTML.1718## Complexity Budget — Hard Limits1920- Box subtitles: **≤5 words**. Detail goes in `sendPrompt()` or prose — not the box.21- Colors: **≤2 ramps** per diagram. More = visual noise.22- Horizontal row: **≤4 boxes** at 680px width. 5+ boxes → shrink or wrap to 2 rows.23- 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.24- **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.2526## Diagram Type Selection2728Route 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.2930| User says / intent | Type | Output |31|---|---|---|32| "how does X work" | Illustrative SVG | Spatial metaphor, cross-section, physical layout |33| "architecture of X" (system context) | Structural SVG | Containers, regions, nesting |34| "steps of X" (generic process) | Flowchart SVG or Mermaid `flowchart` | Top-down boxes + arrows |35| "compare A vs B" | Comparison SVG | Side-by-side columns |36| "DB schema / entity relationship" | Mermaid | ` ```mermaid ` `erDiagram` |37| "class diagram / OOP structure" | Mermaid | ` ```mermaid ` `classDiagram` |38| "state machine / lifecycle" | Mermaid | ` ```mermaid ` `stateDiagram-v2` |39| "sequence / call order / API flow" | Mermaid | ` ```mermaid ` `sequenceDiagram` |40| "timeline / roadmap / history" | Mermaid | ` ```mermaid ` `timeline` |41| "mind map / brainstorm / outline" | Mermaid | ` ```mermaid ` `mindmap` |42| "git branching / release history" | Mermaid | ` ```mermaid ` `gitGraph` |43| "2×2 matrix / priority quadrant" | Mermaid | ` ```mermaid ` `quadrantChart` |44| "radar / spider / skill profile" | Mermaid v11.6+ (beta) | ` ```mermaid ` `radar-beta` |45| "gantt / project schedule" | Mermaid | ` ```mermaid ` `gantt` |46| "user journey map" | Mermaid | ` ```mermaid ` `journey` |47| "pie breakdown (simple)" | Mermaid | ` ```mermaid ` `pie` |48| "kanban board" | Mermaid v11.12+ (beta, test before use) | ` ```mermaid ` `kanban` |49| "cloud/infra architecture" | Mermaid (beta) | ` ```mermaid ` `architecture-beta` |50| "hierarchy / proportional size" | Mermaid (beta) | ` ```mermaid ` `treemap-beta` |51| "free-form block layout" | Mermaid | ` ```mermaid ` `block` |52| "packet / network frame" | Mermaid | ` ```mermaid ` `packet` |53| "ishikawa / fishbone / cause-effect" | Mermaid | ` ```mermaid ` `ishikawa` |54| "swimlane / lane-based workflow" | Mermaid | ` ```mermaid ` `swimlane-beta` |55| "requirement / traceability" | Mermaid | ` ```mermaid ` `requirementDiagram` |56| "sankey / flow quantity" | Mermaid | ` ```mermaid ` `sankey` |57| "XY chart / scatter / line" | Mermaid | ` ```mermaid ` `xychart` |58| "venn / overlap / set intersection" | Mermaid (beta) | ` ```mermaid ` `venn-beta` |59| "show sources / search results / citations" | `structured-renderers` skill | Non-diagram native card: load `structured-renderers` for `search-results` schema |60| "write / draft / compose email, message, document" | `structured-renderers` skill | Non-diagram native card: load `structured-renderers` for `compose-block` schema |61| "table / rows / sortable data / filterable data" | `structured-renderers` skill | Non-diagram native card: load `structured-renderers` for `dataframe` schema |62| "patch / diff / unified diff" | `structured-renderers` skill | Non-diagram native display: load `structured-renderers` for `diff` routing |63| "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 |64| "simulate / interactive" | diagram-file | File-backed Matter.js / Canvas / sliders widget |65| "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 |66| "interactive map (with pan/zoom/markers)" | diagram-file | File-backed Leaflet iframe widget — see `reference/module-map.md` |67| "static country/state choropleth" | diagram-file | File-backed D3 + TopoJSON widget — see `reference/module-chart.md` |6869Default 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.7071`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.7273### Native Web UI renderer boundary7475Before producing a `diagram-file` HTML widget, check whether a native renderer is a better fit:7677- Load `structured-renderers` for `search-results`, `compose-block`, `dataframe`, `chart-json`, and `diff` schemas.78- Use `chart-json` for simple single-series bar/line/pie charts.79- Stay in `diagram` and use `diagram-file` for maps, multi-series charts, advanced chart types, custom JavaScript, external libraries, or richer interaction.8081These 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.8283### OfficeCLI raster CJK rule8485When OfficeCLI rasterizes Mermaid to PNG and the diagram contains Korean/CJK text,86prepend this directive to the Mermaid source before rendering:87```mermaid88%%{init: {"themeVariables":{"fontFamily":"Noto Sans KR, Apple SD Gothic Neo, NanumGothic, Malgun Gothic, sans-serif"}}}%%89```90After export, open and inspect the PNG. Confirm that Korean glyphs are not tofu91boxes, labels are not clipped, and the fallback font did not change node metrics.92Rendering or a successful OfficeCLI exit code is not visual verification.9394### Mermaid gotchas (read before using beta/experimental types)9596- **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:97 - **C4 System Context** → Structural SVG (custom) OR Mermaid `flowchart` with subgraphs98 - **C4 Container** → Mermaid `architecture-beta` (cloud/infra layout)99 - **C4 Component** → Mermaid `flowchart` with `subgraph` grouping100 - **C4 Dynamic** → Mermaid `sequenceDiagram`101 - **C4 Deployment** → Mermaid `architecture-beta`102- **`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.103- **Now stable (no suffix needed):** `block`, `packet`, `kanban`, `sankey`, `xychart`, `ishikawa`.104- **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.105- **`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.106- **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.107108## When to Use109110### 1. Explicit request (명시적 요청)111112한국어: "그려줘", "시각화", "다이어그램", "차트로", "도표로", "비교표", "플로우차트"113영어: "draw", "visualize", "diagram", "chart", "graph", "illustrate", "show me"114115### 2. Proactive generation (에이전트 판단)116117다음 상황에서 텍스트만으로는 전달이 부족할 때 자동 생성:118- 시스템/프로세스 아키텍처 설명 (3+ 컴포넌트)119- 데이터 3항목 이상 비교120- 프로세스 5단계 이상 설명121- 계층 구조 (트리 2+ 레벨)122- 타임라인/히스토리 (4+ 이벤트)123- 수학적 관계 시각화124125이 개수 조건은 그릴지 **검토할** 신호이지 그리라는 지시가 아니다 (DIAGRAM-SCOPE-01). 항목 사이에126관계가 없으면 그것은 목록이다. 주장 한 줄을 먼저 쓰고, 그 주장이 그림에서 보일 때만 그린다.127128A report or explainer around the diagram follows `jaw-dev/references/reader-documents.md`.129The figure itself follows `reference/visual-story.md`: claim, evidence class, sequencing, handoff.130Rendering, formats and security stay owned here.131132### 3. Specification (명사구 스펙)133134사용자가 시각물의 구조를 명사구로 기술:135- "X vs Y 비교" → comparison layout136- "X 구조" / "X 아키텍처" → architecture diagram137- "X 플로우" → flowchart138- "X 타임라인" → timeline139140### 4. When NOT to use141142- 단순 질의응답 (팩트 한 줄이면 충분)143- 코드 리뷰/디버깅 (코드가 더 명확)144- 이미 diagram-html 내에서 동작 중인 위젯 재생성145- 사용자가 "간단히 설명해줘"라고 한 경우146147## Delivery Mechanism (read before producing anything)148149All 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.150151### File-backed widgets (`diagram-file`)152153Use ` ```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.154155The 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.156157Determine 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.158159| ❌ Don't | ✅ Do |160|---|---|161| Save SVG/Mermaid outputs to `.svg` / `.png` files unless explicitly asked | Paste SVG/Mermaid blocks directly into your reply |162| Wrap `diagram-html` in your own `<iframe>` / `<html>` / `<body>` / `<head>` | Start at `<div>` / `<canvas>` / `<style>` — host injects the shell |163| Send via `/api/channel/send` or Telegram/Discord — it is NOT an attachment | Let the renderer handle it; diagrams are response text |164| Reference an external image URL and call it a diagram | Output the SVG/widget code itself |165166If 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).167168## Output Formats169170### 1. Inline SVG (static diagrams)171Output raw `<svg>` markup directly in the response. The chat UI renders it inline.172173```174<svg viewBox="0 0 680 {height}" xmlns="http://www.w3.org/2000/svg"175 role="img" aria-labelledby="title-id desc-id">176 <title id="title-id">Retries are the only path that writes twice</title>177 <desc id="desc-id">Request flow from client to queue, with the retry branch rejoining after the write step</desc>178 <!-- shapes, text, paths -->179</svg>180```181182Rules:183- viewBox width MUST be 680 (matches container width — do NOT change)184- Height varies by content: last element bottom + 40px padding185- 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`).186- 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`.187- 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 class188- Colors: use CSS classes, not inline fill/stroke colors189- 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.190191### 2. Mermaid (simple flowcharts, ERDs)192Use standard ` ```mermaid ` code blocks. The existing renderer handles these.193194### 3. Interactive HTML Widget (fallback form: charts, controls, simulations)195Use ` ```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.196197```198` ` `diagram-html199<div id="chart-wrapper" style="position: relative; width: 100%; height: 300px;">200 <canvas id="myChart" role="img"201 aria-label="Signups doubled after the March pricing change">202 Fallback text stating the same takeaway203 </canvas>204</div>205<script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"206 onerror="document.body.innerHTML='<p>Chart library failed to load.</p>'">207</script>208<script>209 const isDark = window.__jawTheme?.isDark ?? true;210 // ... Chart.js code211</script>212` ` `213```214215## SVG Design System216217### Design Forbidden List218These are design quality rules (separate from security restrictions below):219- No gradients, drop shadows, blur, glow, or neon effects220- No emoji — use CSS shapes or SVG paths221- No decorative step numbers or oversized headings222- No icons or illustrations inside flowchart boxes — text only223- No rotated text224- No dark/colored backgrounds on outer containers (transparent only — host provides bg)225- Stroke width: **0.5px** for borders and edges (not 1px or 2px)226- Font weights: **400** (regular) and **500** (bold) only. Never 600 or 700.227- Font sizes in SVG: **14px** (node labels) and **12px** (subtitles/arrow labels) only228- **Sentence case** always. Never Title Case or ALL CAPS.229230### `<style>` in Inline SVG231232`<style>` tags inside inline SVG ARE preserved. Custom CSS classes work:233234```xml235<svg viewBox="0 0 100 100">236 <style>237 .highlight { fill: #e94560; }238 .dim { fill: #94a3b8; }239 </style>240 <rect class="highlight" width="50" height="50"/>241</svg>242```243244**Security filters applied automatically:**245- `@import` rules → stripped246- `@font-face` blocks → stripped247- External `url()` → replaced with `none` (internal `url(#ref)` preserved)248249**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.250251### Forbidden in Inline SVG (Security)252These are stripped by DOMPurify — NEVER use in inline `<svg>`:253- `<foreignObject>` — embeds HTML in SVG (XSS vector)254- `<animate>`, `<set>`, `<animateTransform>`, `<animateMotion>` — animation XSS vectors255- Nested `<svg>` — use `<g>` groups instead256257### Forbidden Attributes in Inline SVG258- `xlink:href` — use `href="#fragment"` on `<use>` only (no external URLs)259- All `on*` event handlers (onclick, onerror, etc.) — stripped by DOMPurify260261> **Note**: `diagram-file` and fallback `diagram-html` content run inside a sandboxed iframe where262> `<script>`, `on*` handlers, and CDN imports ARE allowed. The restrictions263> above apply only to inline SVG rendered in the main document.264265### Color Ramps (9 semantic colors)266Each ramp has 3 shades: fill (bg), stroke (border), text (label).267Use CSS class names — see `reference/color-palette.md`:268269| Ramp | Class prefix | Preferred use |270|---|---|---|271| cyan | `.c-cyan` | General categories (preferred for neutral info) |272| pink | `.c-pink` | General categories, highlights |273| purple | `.c-purple` | General categories, grouping |274| orange | `.c-orange` | General categories, accent |275| slate | `.c-slate` | Neutral, disabled, structural (start/end nodes) |276| blue | `.c-blue` | Informational (semantic — use only when meaning is "info") |277| green | `.c-green` | Success, positive (semantic) |278| amber | `.c-amber` | Warning, attention (semantic) |279| red | `.c-red` | Error, negative (semantic) |280281**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.282283### Layout Patterns284- Flowchart: top-to-bottom, 680×auto285- Comparison: side-by-side columns286- Timeline: horizontal with markers287- Org chart: hierarchical tree288- See `reference/svg-components.md` for templates and detailed SVG rules.289290### Style-First, Script-Last291For `diagram-file` widgets and fallback `diagram-html` widgets:2921. All `<style>` and `<link>` tags first2932. HTML structure2943. `<script>` tags last295296This ensures visual content appears before scripts execute (important during streaming).297298## Theme Integration299300### CSS Variable Mapping (cli-jaw)301| Variable | Use |302|---|---|303| `--bg` | Page background |304| `--surface` | Card/surface background |305| `--text` | Primary text |306| `--text-dim` | Muted/secondary text |307| `--border` | Default border |308| `--accent` | Accent color |309| `--font-ui` | UI font family |310| `--font-mono` | Code font family |311| `--radius-md` | 8px border radius |312| `--radius-lg` | 12px border radius |313314### By format315- **Inline SVG**: CSS classes adapt to host theme automatically316- **iframe widgets**: use `window.__jawTheme.isDark` (boolean) for JS-side theme detection317- **iframe widgets**: use `window.__jawTokens['--bg']` etc. for computed host CSS values318- Do NOT use `matchMedia('prefers-color-scheme')` — the host controls theme319320## SVG Mobile Notes321322- viewBox 680px 기준은 유지하되, 텍스트는 최소 14px (모바일 축소 후 ~9px)323- CJK 텍스트: 최소 16px (축소 후 ~10px)324- 터치 가능한 SVG 요소: 최소 44×44 hit area325326## Animation Rules327328### Inline SVG (DOMPurify sanitized)329- SMIL tags (`<animate>`, `<set>`, `<animateMotion>`) are stripped — do not use330- Inline SVG is static only — no animation331332### diagram-file and diagram-html (sandboxed iframe)333All CSS/JS animation is available:334335**CSS Transition** (preferred for hover/state changes):336```css337.element { transition: all 0.3s ease; }338.element:hover { transform: scale(1.05); opacity: 0.8; }339```340341**CSS Animation** (keyframes):342```css343@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }344.element { animation: fadeIn 0.5s ease-out; }345```346347**JS requestAnimationFrame**: already documented in module-widget.md (Matter.js, Three.js, p5.js)348349### Performance350- Animate only `transform` and `opacity` (GPU-accelerated)351- Avoid animating `width`, `height`, `top`, `left` (layout thrashing)352- Always call `cancelAnimationFrame` on cleanup353354## Reference Files355For detailed patterns, see:356- `reference/visual-story.md` — **read first**: claim, evidence classes, one-takeaway sequencing, prose handoff, compositions to avoid, fresh-reader check357- `reference/svg-components.md` — SVG primitives, viewBox checklist, layout templates358- `reference/color-palette.md` — Full color values (light + dark), assignment rules359- `reference/module-chart.md` — Chart.js + D3 + ECharts 6 integration (bar/line/pie/choropleth + heatmap/sankey/radar/treemap/gauge/funnel/candlestick/chord)360- `reference/module-widget.md` — Physics (Matter.js), math graphs (Math.js), 3D (Three.js), creative coding (p5.js), audio (Tone.js), mini-games361- `reference/module-interactive.md` — Sliders, selects, segmented buttons, toggles, play/pause/reset, debouncing, sendPrompt, keyboard accessibility, control layout pattern362- `reference/module-map.md` — Leaflet interactive maps (OpenStreetMap tiles, markers, popups, dark mode)363- `reference/module-mockup.md` — UI mockup patterns364- `reference/module-art.md` — Decorative SVG patterns365- `reference/module-domain-cards.md` — Domain card templates (weather, finance, sports, product) + real-time data pipeline366- `reference/structured-renderers.md` — native renderer delegation notes