From agent-skills
Generates interactive two-way flow diagrams as self-contained HTML+SVG pages with zoom/pan, traveling dots, and explainer cards. Ideal for system architectures and request/response flows when Mermaid is too rigid.
How this skill is triggered — by the user, by Claude, or both
Slash command
/agent-skills:flow-diagramThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Output: **one self-contained `.html` file** (no dependencies, opens directly in a browser), laid out as a **2-pane app filling the viewport**: a title row + light/dark toggle (thin-line SVG icon that recolors with the theme — see "Theme icon button") → flow-select chips → **left: diagram, default FIT TO VIEW** — the reader sees the whole system at once, no scrolling — with a zoom bar (+/− butto...
Output: one self-contained .html file (no dependencies, opens directly in a browser), laid out as a 2-pane app filling the viewport: a title row + light/dark toggle (thin-line SVG icon that recolors with the theme — see "Theme icon button") → flow-select chips → left: diagram, default FIT TO VIEW — the reader sees the whole system at once, no scrolling — with a zoom bar (+/− buttons, ⤢ fit-to-view, scroll-to-zoom at the cursor, drag to pan) → right: sidebar of explainer cards. The reader clicks a flow (a chip, a line, or a step badge) → that flow keeps its color and gets a small dot traveling along the line in its direction (see "Traveling dots"), everything else dims to ~10%, the sidebar shrinks to just that flow's card; clicking a step badge highlights the matching line in that card. That's how a non-technical reader answers "where does this flow go, start to finish?" without reading the whole diagram. A fully worked, machine-checked example: references/flow-diagram-example.html. Not sure which layout to use (linear? convergent? hub? branching?) → read references/layout-patterns-guide.html first — a guide to 4 common topologies, each with a "why this layout" section explaining the reasoning, not just numbers to copy.
Hard-won lesson behind this skill: writing SVG means placing coordinates blind — nobody sees the result while typing numbers, and the human eye (even a shrunk screenshot) misses collisions that are only a few pixels off. So the process revolves around a machine-measured loop: draw → check → fix coordinates → check again, until 0 errors. Don't trust the feeling of "that's probably not overlapping."
data-flow code), and for each flow — both the outbound and the return direction. If the user only describes the outbound leg, ask about the return leg (real-world lesson: users almost always want to see how data comes back, not just how it goes out). Any flow's routing that's unclear → ask a multiple-choice question, don't guess. Before placing any coordinates, work out which layout pattern the content matches in references/layout-patterns-guide.html (linear multi-phase / convergent multi-source / central hub / conditional branch) — real diagrams often NEST several patterns (e.g. two sources converging, then branching on pass/fail) — identify each piece and combine them rather than inventing a new layout from scratch.<!-- LAYOUT PLAN: ... --> right after the <svg> tag — the next editing pass will then know which lane already has an owner. 10 minutes of planning saves 5 rounds of untangling overlaps.data-flow; box → data-flows). Keep the SVG's layer order as specified.elementsFromPoint is blind outside the visible area; if you'd zoomed in, click ⤢ before checking or you'll get a false "0 errors". The script reports errors in viewBox coordinates (fix the numbers in the file directly) and draws red/yellow outline boxes on the page. Fix → re-check, usually 1–3 rounds. Only stop once: 0 errors, and any remaining warnings can be justified out loud (more than 5 warnings means the layout is genuinely cluttered — rearrange the boxes instead of arguing with the checker).
Can't connect to the browser (extension broken/unresponsive) → fall back immediately to the offline checker assets/check-svg.js (node assets/check-svg.js <file.html>, no browser permission needed): computes box-overlaps-box, arrow-too-close-to-box, floating-arrow (an arrowhead that touches no box), viewBox overflow, and box-too-close-to-region-border exactly from the real numeric coordinates — only the text-overlap check is an estimate of font width (reported as a warning, not a hard error, and needs a follow-up eyeball check). Never "check" by mentally estimating coordinates — past 10 arrows, doing it by hand reliably both misses real errors and invents false ones (this actually happened once: a by-hand pass "found" a floating line that didn't exist in the file at all). If neither checking path works, stop and ask the user rather than guessing blind.flow-<topic>_YYYY-MM-DD_v1.0.html). A substantial content change → bump the version, keep the old file."Big Tech docs" style: system sans-serif type (NEVER a monospace font for the whole page), restrained color, the diagram sits on a rounded card. Goal: the reader sees a formal enterprise document, not an "AI product."
What makes it read as hand-drawn (learned from real hand-crafted architecture diagrams — the progcoder/AWS-docs school):
<symbol> elements from Simple Icons (CC0 — MongoDB, PostgreSQL, Odoo, n8n, Claude, Gemini, FastAPI, Messenger, Zalo, Discord, Telegram, Facebook, Sheets, Airflow, Grafana, Docker, Redis…). Copy the symbol you need into <defs>, place it inside the box's <g>: <use href="#ic-mongodb" x="boxX+12" y="boxY+(h−16)/2" width="16" height="16"/> (a second logo sits 20px further along). Missing a logo: curl -s https://cdn.simpleicons.org/<slug> then add a symbol following the pattern; a near-black logo should get its fill changed to #1f2937 so it recolors with the theme. Logos let the reader recognize a technology without reading text — the single strongest "hand-drawn" signal.Light/dark theme: every color is declared via light-dark() inside :root (already in the template), defaults to the OS setting, the toggle button overrides it and persists to localStorage. Golden rule when writing SVG: only write LIGHT-palette hex inside an attribute (stroke="#2563eb", fill="#ffffff"…) — the "color mapping" CSS block in the template remaps them per theme automatically (CSS always wins over a presentation attribute). Never write var() inside an attribute, never invent a new hex outside the table — an unlisted color won't follow the theme and will be immediately obvious in dark mode.
| Variable | Light hex (use in SVG) | Meaning | Stroke |
|---|---|---|---|
--di | blue #2563eb | OUT direction (request) | solid, width 1.8 |
--ve | emerald #059669 | RETURN direction (response) | dashed 6 4, width 1.6 |
--sec | red #dc2626 | auth checkpoint / security | solid |
--script | violet #7c3aed | scheduled / cron / batch flow | solid (secondary branch: dashed 5 4) |
--pipe | amber #d97706 | data pipeline (ETL/sync) | dashed 7 5 for async |
Secondary colors for system groups: --sky #0284c7 (data store/API), --fx #c026d3 (content generation). In HTML (chips, card dots) use var(--sky)/var(--fx); in SVG use the hex. Every flow color has its own marker (m-di, m-ve, m-sec, m-sc, m-pi) — an arrow always uses the marker matching its own color.
qa, s, c, d, m…). Give data-flow="<code>" to EVERY line, badge (wrapped in <g data-flow data-step="...">), and label of that flow; give data-flows="<code1> <code2>" to the <g> wrapping each box — list every flow that actually passes through it (missing one dims the box by mistake when that flow is selected; an extra one lights it up for no reason).style="color: <flow color>" — the chips double as the color legend (replacing an in-SVG legend) and as select buttons. Include a hint like "Click a flow to see it run end to end".data-step must match the text inside a span.n1–n5 in its card so clicking the badge highlights the right line — the template's matcher understands both ranges (5→7 = steps 5, 6, 7) and merged codes (3·11), so just write the spans in the same order the story is told..board > .zoombar + .canvas > svg structure — no extra logic needed..dim, .flowing, sidebar, zoom, Esc) — just set the right data-attributes.defs → arrows → regions → boxes → badges + labels. Arrows are drawn first so a box's solid white fill (drawn later) covers the overrun at both ends; a dashed region sits below the boxes but above any long arrow that cuts through the region. Text is drawn last because the template wraps a background-colored halo around every glyph (stroke = var(--panel), recolors with the theme) — a line forced to run near text still leaves it readable. The halo is a safety net, not a license to drop text straight onto a line. There's no in-SVG legend anymore — the chips handle that.
rx=10; name 11–13px weight 650–700 in --text, a secondary caption at 9px --muted underneath.#ffffff: usually border #d1d5db · security border --sec · data store border #0284c7 · secondary component border #e5e7eb with dimmer text. Only the one focal/orchestrator box gets a tinted fill #eff6ff with a --di 1.7 border.marker-end is) must sit ~8px from the destination box's edge (6–10px is acceptable), NEVER ending right at the edge (0–4px). Reason: the default marker scales with stroke-width (a 1.8 stroke → an arrowhead ~16px in real size); ending 2px away makes the arrowhead glue itself to / overlap the box border, which looks cramped. Quick conversion when placing coordinates: an arrow pointing into a box's top edge y_box → end at y_box − 8; bottom edge → y_box + 8 (remember a box below has a LARGER y); left edge → x_box − 8; right edge → x_box + 8. The START point doesn't matter (the box's solid fill, drawn later, covers the overrun) — only the ARROWHEAD needs breathing room. The check-collisions.js/check-svg.js checkers now catch this automatically ("ARROWHEAD TOO CLOSE TO BOX").node assets/fix-arrow-gaps.js <file.html>) — automatically pulls every arrowhead currently under 6px out to ~8px, preserving direction (slides along the exact vector of the final segment, including diagonals), without touching any middle waypoints. On a diagonal line the result can sometimes fall a hair short from rounding — run it twice to be safe, and stop once check-svg.js reports 0 errors. Run this script BEFORE add-flow-dots.js/add-flow-ping.js (those two read the arrows' current coordinates to generate the dots/pings — running them first would generate against the wrong coordinates).r=9 for 1–2 characters, a rounded rect 26×17 rx=8.5 for a 2-character group code (S1, C5); a merged code like 3·11 gets a wider 40×17. Badge background is white, border + text share the flow's color. Center the badge exactly on its line (the solid fill covers the line under it) — a badge floating next to a line instead of centered on it reads as belonging to a different line.1→n; other groups get a letter prefix (S = scheduled, C = API gateway, D = data warehouse, M = media…). If the primary flow passes through the same box pair twice, merge the badges (3·11) instead of drawing 4 lines.transform="rotate(-90 x,y)".When the reader clicks a flow, the "this is flowing" signal is a small dot traveling along the line — NOT a fake "marching ants" dashed animation. This is the convention used by large infrastructure monitoring tools (Kiali/Istio service mesh, Datadog network maps…): the line keeps its stroke/color, only getting selected-state emphasis via dimming everything else; the small dots running along the exact path are what signal direction and speed — a human reads "a dot is moving from A to B" far more intuitively than "a line is twitching."
svg .flow-dot { opacity: 0; transition: opacity .25s; } svg .flow-dot.flowing { opacity: 1; } (dots hidden by default, only shown once their flow is selected) · add @media (prefers-reduced-motion: reduce) { svg .flow-dot { display: none; } }. Don't use stroke-width to "bolden" a selected line (tried it, removed it — users read it as the diagram "zooming in," more distracting than clarifying); the "this flow is selected" signal relies on exactly two things: everything else dims (.dim) and the dots/ping appear — that's clear enough without also changing line thickness.marker-end is immediately followed by 1 <g class="flow-dot" data-flow="..."> containing 2 <circle> (r≈3.4, fill = the same hex as the line's stroke), each carrying an <animateMotion repeatCount="indefinite" path="..."> — path = "M x1,y1 L x2,y2" for a <line>, or copy the d attribute verbatim for a <path>. The 2 dots are phase-offset (begin="0s" and begin="{dur/2}s") so the flow feels continuous, with no gap between loops.dur (seconds) is computed from the line's length: clamp(length/130, 1.2, 3.5) (~130px/s — already slowed down once based on real feedback; the earlier ~260px/s speed was called "too fast to track") — short and long lines both look like the dot moves at the same speed..flowing toggle condition to also catch the dot group (and the ping, see below), not just line/path: if (e.matches('line, path') || e.classList.contains('flow-dot') || e.classList.contains('flow-ping')) e.classList.toggle('flowing', !!f && mine);node assets/add-flow-dots.js <file.html>, overwrites in place, idempotent — it strips any existing dots before regenerating, so re-running it any number of times is safe) — it walks every <line>/<path> with data-flow + marker-end in the file, generates a <g class="flow-dot"> block matching its exact coordinates, and inserts it right after that arrow. Full example: assets/template.html (its 3 sample arrows already have dots).dur/begin from the dot's speed, peaking at 0.8 opacity with a linear 12px swell — it repeated too fast (sometimes under 1s per cycle) and felt jerky; a real user called it "tiring to look at for a while." The current version: one SHARED CSS @keyframes for every ring (no more per-arrow timing) — transform: scale(1→1.05) (a ratio of the box's own size, not a fixed pixel amount, so small and large boxes swell proportionally the same), peak opacity only 0.35, a slow 2.6s cycle with ease-out (decelerating, not linear) and a rest period (opacity stays at 0% from 65%→100% of the cycle) — it reads like an "alive" indicator light, not an alert. CSS: svg .flow-ping-ring { transform-box: fill-box; transform-origin: center; animation: flow-ping 2.6s ease-out infinite; }.node assets/add-flow-ping.js <file.html>, idempotent) to generate the markup — it finds the box nearest each arrow's END point (~14-unit threshold), reads that box's own rect stroke, and inserts <g class="flow-ping" data-flow="..."><rect class="flow-ping-ring" stroke="{box border color}" .../></g> as a child of that box's own <g data-flows> (not a free-floating element — the animation lives entirely in the shared CSS @keyframes, no per-arrow dur to compute). Placing it inside the box is deliberate: when the box gets dragged (see "Drag to rearrange"), the ring follows the box's transform automatically.@media print): hide both the dots and the ping (svg .flow-dot, svg .flow-ping { display: none; }), lines return to a plain static stroke — animation is an interactive layer, not a requirement for reading the diagram on paper.When the user needs to adjust the layout themselves without asking for coordinate edits, add the "✥ Rearrange" mode (a dedicated button next to the theme toggle, id="edit-toggle") — turning it on is what makes boxes draggable; turning it off restores normal behavior (click to select a flow). Run assets/add-drag-to-rearrange.js (node assets/add-drag-to-rearrange.js <file.html>, idempotent — does nothing if it's already present) to insert the CSS+button+JS into a file already built from the template.
x=25 in the example).A8,8 0 0 1, curving to the left uses A8,8 0 0 0 (both bulge upward). Only hop across a straight horizontal/vertical segment, never across a diagonal one. Mention "a small arc = two lines passing over each other" in the subtitle.rect with dashes 7 5, opacity 0.55, a bold 11px label, its own color per region. Keep boxes ≥ 20px from the region's border.data-flow matching its code, a dot in the flow's color, and every step number inside the text colored correctly (.n1–.n5). The last card is usually "Principles" summarizing the locked-in architectural decisions (no data-flow needed on it).check-collisions.js (browser) or check-svg.js (offline) report 0 errors? ≤ 5 warnings and each one explainable?data-flows is complete), the sidebar shrinks to that flow's card, clicking a badge highlights the right line, Esc clears it? Do the traveling dots clearly run along the right line in the right direction, and does the destination box ping in sync with the dots arriving?npx claudepluginhub unclecatvn/agent-skillsGenerates interactive click-through architecture diagrams as self-contained HTML files with animated data flows, mode toggles, and dark/light themes. Use when you need to visualize system design, service maps, data flows, or pipelines for workshops, onboarding, or planning.
Generates professional diagrams (flowcharts, architecture, comparisons, timelines, sequence diagrams, etc.) as draw.io XML. Useful for visualizing processes, structures, and documentation.
Creates technical and product diagrams (architecture, flowchart, sequence, ER, etc.) as standalone HTML files with inline SVG. Includes a customizable style guide and first-run gate.