Visual Explaining
Markdown--- name: visual-explaining description: Converts messy terminal output (architecture notes, diffs, plans, comparisons, recaps, fact checks) into polished, self-contained HTML pages with Mermaid diagrams, responsive tables, and dark/light themes. Use when output is hard to read as raw text, when presenting technical content to stakeholders, or when explicitly asked to visualize, diagram, or generate a slide deck from terminal/agent output. --- # Visual Explaining Turns raw text (architecture notes, git diffs, plans, comparisons, recaps, fact checks) into self-contained HTML pages that open automatically in the browser. No build step, no server — one HTML file with inline CSS/JS, CDN-loaded Mermaid.js, and native dark/light theming.
Bash# From anywhere in a coding agent session: "Generate a diagram of this architecture" → diagram command "Turn this plan into a visual page" → plan command "Make slides out of this recap" → slides command "Review this diff visually" → diff-review command "Visualize this fact check" → fact-check command
Each command produces one file in ~/.agent/diagrams/<slug>.html and opens it via the OS default-browser command. No arguments needed beyond "here's the content" — infer the slug from context (project name + content type + date if colliding).
Bashmkdir -p ~/.agent/diagrams # macOS open ~/.agent/diagrams/<slug>.html # Linux xdg-open ~/.agent/diagrams/<slug>.html # Windows / WSL start ~/.agent/diagrams/<slug>.html # or: cmd.exe /c start "" "<path>"
Detect OS first (uname / $OSTYPE / presence of wslpath) and pick the right opener. Never fail silently — if no opener works, print the file path so the user can open it manually.
| Command | Trigger phrases | Template |
|---|---|---|
diagram | "diagram this", "visualize the architecture", "draw the flow" | architecture.html |
plan | "visual plan", "show me the implementation plan" | plan.html |
slides | "make slides", "slide deck of this", "present this" | slides.html |
diff-review | "review this diff visually", "show the diff nicely" | diff.html |
plan-review | "audit this plan", "compare requirements vs plan" | comparison.html |
recap | "project recap", "summarize what we did" | recap.html |
fact-check | "fact check this", "verify these claims" | factcheck.html |
All templates share one base shell (theme toggle, typography, container, print styles). Only the content-injection region differs.
Progress:
- 1. Analyze raw input, identify content type if not explicit
- 2. Route to template + pick visualization strategy per section (Mermaid vs table vs card grid vs chart)
- 3. Transform content into target syntax (Mermaid graph, HTML table rows, diff spans, slide sections)
- 4. Inject into base HTML template
- 5. Write file to
~/.agent/diagrams/<slug>.html - 6. Open in browser via OS command
- 7. Print the file path in chat as a fallback link
Step 1: Analyze and Route
Classify each logical chunk of the input independently — a single input may need multiple visualization strategies:
- Sequential process / pipeline / call flow → Mermaid
sequenceDiagramorflowchart TD - System components & relationships → Mermaid
flowchart(subgraphs) or CSS Grid architecture cards - Before/after, requirement vs implementation, claim vs evidence → two/three-column comparison table
- Git diff → side-by-side or unified diff view with add/remove coloring
- Timeline / recap of work done → vertical timeline component
- Numeric/status data (pass/fail counts, coverage %) → simple Chart.js bar/donut
- Everything else (prose explanations) → styled prose card with pull-quotes for key points
Default to Mermaid flowchart TD for anything resembling steps or dependencies — it's the highest-leverage conversion.
Step 2: Transform Content
Mermaid conversion rules:
- Sanitize node labels: strip characters that break Mermaid (
[]{}()"inside labels → wrap in quotes or replace) - Keep node IDs short/alphanumeric (
A,B1,ocr_step), put readable text in the label - Use
subgraphfor architecture boundaries (e.g. "Client", "API Layer", "Data Layer") - For async/pipeline flows, prefer
sequenceDiagramwithparticipantper service and->>/-->>for async calls - Add
classDefstyles for status coloring (green=done, yellow=in-progress, red=blocked)
Diff conversion rules:
- Parse unified diff (
@@ ... @@,+,-,prefixes) - Render as two-pane side-by-side on wide screens, unified stacked on mobile
- Color: additions
--diff-add-bg, deletions--diff-del-bg, context muted - Collapse unchanged hunks >20 lines behind a
<details>toggle
Table conversion rules:
- Never dump ASCII tables raw — parse columns by whitespace/pipe delimiters into a real
<table> - Add
<thead>with sticky positioning for tables >10 rows - Right-align numeric columns automatically (detect via regex on cell content)
- For pass/fail/status columns, render as colored pill badges, not plain text
Slide mode rules:
- Split content into one
<section class="slide">per logical unit (one diagram, one table, one key point per slide — don't overload) - Title slide first, summary/next-steps slide last
- Keyboard nav (arrow keys,
ffullscreen,Escoverview grid) via vanilla JS, no framework
Step 3: Inject into Template
Use the base shell below for every page. Replace {{TITLE}}, {{CONTENT}}, {{MERMAID_INIT}} placeholders.
HTML<!DOCTYPE html> <html lang="en" data-theme="dark"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{TITLE}}</title> <script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script> <style> :root { --bg: #ffffff; --fg: #1a1a1a; --muted: #6b7280; --border: #e5e7eb; --card-bg: #f9fafb; --accent: #2563eb; --diff-add-bg: #dcfce7; --diff-add-fg: #166534; --diff-del-bg: #fee2e2; --diff-del-fg: #991b1b; --code-bg: #f3f4f6; } [data-theme="dark"] { --bg: #0f1115; --fg: #e5e7eb; --muted: #9ca3af; --border: #2a2e37; --card-bg: #171a21; --accent: #60a5fa; --diff-add-bg: #052e16; --diff-add-fg: #4ade80; --diff-del-bg: #450a0a; --diff-del-fg: #f87171; --code-bg: #1a1d24; } * { box-sizing: border-box; } body { margin: 0; background: var(--bg); color: var(--fg); font: 16px/1.6 -apple-system, "Segoe UI", Inter, sans-serif; transition: background .2s, color .2s; } .container { max-width: 1100px; margin: 0 auto; padding: 2rem 1.5rem 5rem; } h1, h2, h3 { line-height: 1.25; } .theme-toggle { position: fixed; top: 1rem; right: 1rem; z-index: 50; background: var(--card-bg); border: 1px solid var(--border); border-radius: 999px; padding: .5rem .9rem; cursor: pointer; color: var(--fg); } table { width: 100%; border-collapse: collapse; margin: 1.5rem 0; } th, td { padding: .6rem .8rem; border-bottom: 1px solid var(--border); text-align: left; } th { position: sticky; top: 0; background: var(--card-bg); } td.num { text-align: right; font-variant-numeric: tabular-nums; } .badge { padding: .15rem .6rem; border-radius: 999px; font-size: .8rem; font-weight: 600; } .badge.pass { background: var(--diff-add-bg); color: var(--diff-add-fg); } .badge.fail { background: var(--diff-del-bg); color: var(--diff-del-fg); } .card { background: var(--card-bg); border: 1px solid var(--border); border-radius: .75rem; padding: 1.25rem; margin: 1rem 0; } .grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); } .diff-line.add { background: var(--diff-add-bg); color: var(--diff-add-fg); } .diff-line.del { background: var(--diff-del-bg); color: var(--diff-del-fg); } .diff-line { display: block; padding: 0 .5rem; font-family: ui-monospace, monospace; white-space: pre-wrap; } .mermaid { background: var(--card-bg); border-radius: .75rem; padding: 1rem; overflow-x: auto; } @media (max-width: 640px) { .container { padding: 1rem; } } @media print { .theme-toggle { display: none; } } </style> </head> <body> <button class="theme-toggle" onclick="toggleTheme()">🌓 Theme</button> <div class="container"> {{CONTENT}} </div> <script> function toggleTheme() { const html = document.documentElement; const next = html.dataset.theme === 'dark' ? 'light' : 'dark'; html.dataset.theme = next; localStorage.setItem('vx-theme', next); } document.documentElement.dataset.theme = localStorage.getItem('vx-theme') || 'dark'; mermaid.initialize({ startOnLoad: true, theme: document.documentElement.dataset.theme === 'dark' ? 'dark' : 'default' }); </script> </body> </html>
For slide mode, wrap each unit in <section class="slide"> inside a #deck container and append the slide-engine script (see slides.html reference below) instead of the plain .container flow.
Step 4: Save and Render
Bashmkdir -p ~/.agent/diagrams cat > ~/.agent/diagrams/<slug>.html <<'EOF' <compiled HTML> EOF open ~/.agent/diagrams/<slug>.html 2>/dev/null || xdg-open ~/.agent/diagrams/<slug>.html 2>/dev/null || echo "Open manually: ~/.agent/diagrams/<slug>.html"
Slug format: <project-or-topic>-<type> (e.g. eduverify-architecture, auth-refactor-diff, q3-recap). If a file with that slug exists, append -2, -3, etc. rather than overw