diagram-design
Create branded architecture, architecture delta, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, polar chart (polar/radial lollipop), loop/flywheel, nested, tree, org chart, layer stack, exploded axonometric, axonometric plan, Venn, pyramid/funnel, treemap and marimekko, heatmap, bar and dumbbell, waterfall, line (slopegraph, ridgeline, streamgraph, bump), Gantt and scatter charts (bubble, beeswarm, box plot), high-level, process,
Install
npx skills add https://github.com/cathrynlavery/diagram-design --skill diagram-designDP integration
Best for: the integration topology of a data platform — which source systems plug in, which consumer surfaces plug out, and which protocol each one speaks. Hub-and-spoke layout wrapped in an explicit Data platform layer; no time/phase axis.
Use when the question is "what surfaces does this platform expose, and over what wire?" rather than "how does data move through phases?".
This type is parametric — like type-high-level.md, every coord is derived from a small inputs schema. Two generations from the same inputs must produce visually identical SVG.
1. Inputs — the parameter contract
Reserved kind values for platform.rows:
bar— full-zone-width strip. Default height 44 px (focal bars get 56 px). Required fields:name,icon. Optional:subtitle,role,color,focal.row— N nodes evenly spaced across zone width. Required:nodeslist. Each node hasname,icon, optionalrole,subtitle,color,focal.
Source/consumer type values → icon mapping (extends references/primitive-icons.md):
db→ cylinder,sftp→ folder-with-arrow,mail→ envelope,mainframe→ server-with-ventsmonitor→ desktop screen,chart→ bar-chart,globe→ globe,api→ curly braceskey→ key + ring (identity / IDP)- Any explicit icon name in
primitive-icons.mdis also accepted.
Per-component color: "#hex" is optional on any node, bar, or footer entry. See §4.
2. Layout formulas — deterministic geometry
2.1 Row placement (cursor algorithm)
Allocate each platform.rows entry top-to-bottom. The single row (or first row when N>1) anchors to side-column row 2 so its connectors stay horizontal:
This produces the canonical layout for the standard shape (top bar / 3-node row / bottom bar): Trino at y=104 h=56, primary row at y=176 h=72, Airflow at y=324 h=44. Bottom anchor of Airflow at y=368 (40-px clear from zone bottom at y=408). Note: with the canonical layout there's a 76-px gap between the primary row's bottom (y=248) and Airflow's top (y=324). That gap is intentional — Airflow visually sits at the same y-band as source/consumer row 4 (cy=388), so it reads as a sibling of the bottom side-column row.
2.2 Node placement inside a row entry
For the canonical 3-node row: node_w = (696 - 32 - 32) / 3 = 210.67. The shipped example uses fixed node_w=160 with custom x positions (288, 480, 672) chosen so each node's cx aligns to the column for connector convenience: 368, 560, 752. Both layouts are valid; the formula above is the default for new diagrams. Document any deviation in the rendered SVG with a comment.
2.3 Bar (full-zone-width) placement
Bars span the full zone width minus 16-px padding on each side. Bars marked focal: true use bar_h_focal=56 and accent styling (fill rgba(focal_accent, 0.08), stroke focal_accent). Non-focal bars use bar_h_default=44 with muted styling (fill ink @ 0.05, stroke ink @ 0.32).
2.4 Source / consumer placement (side columns)
All side-column nodes use fixed w=160 h=64. Same fill / stroke pattern: fill muted @ 0.06, stroke soft, stroke-width 1.
3. Connector rules (mandatory)
Five styles, bound to topology. Don't let user override style on focal-touching, bar-originating, or Trino → consumer edges — those are fixed by rule.
Defs block (required, six markers — exactly):
3.1 Exit / entry sides (non-negotiable)
3.2 Routing
- Orthogonal elbows with at most two bends; Q-bezier
r=8at every corner. - Fan-out staggering: when one node fans out to N targets on the same side, stagger the exit y by ±4 px per index so arrows don't overlap (e.g., Trino → 4 consumers exits at y=124, 132, 140, 148). The vertical segments run in the corridor between the zone edge and the consumer column, also y-staggered.
- Z-order: all connectors drawn before any rect (so node fills mask the line ends).
- Markers: exactly one
marker-endper<line>/<path>. Nevermarker-start. - Labels: every
primary,secondary,federated,authedge gets a protocol label (thearrow-labelrole at 8 px, paper-filled rect mask with 6–10 px clear gap above the stroke).triggeredges are unlabelled.
3.3 Footer → zone trunk
When N=1 footer: single vertical line at x = zone_cx from footer_y(0) to zone_y + zone_h.
When N≥2 footers: stagger AUTH lines so they don't overlap stacked footers. For footer index k:
Examples:
- N=1 → 560
- N=2 → 544, 576
- N=3 → 528, 560, 592
Each AUTH line goes from (footer_auth_x(k), footer_y(k)) up to (footer_auth_x(k), zone_y + zone_h). AUTH labels sit just above the arrowhead at the zone bottom edge.
3.4 Crossings
Avoid. Re-route via the corridor x positions before accepting a crossing. If unavoidable, the path drawn second carries a 6-px arc hop over the first.
4. Component color override (mirrors type-high-level.md §3.4)
Any source, consumer, platform component (node or bar), or footer node accepts an optional color: "#hex". Mirrors high-level so the rule reads identically across types.
Where the color is applied (C = color):
C_light = the same hex lightened ~15% for dark-mode contrast (e.g., #b85450 → #d97a78).
Rules:
- Never on focal components.
focal_accentalways wins — acoloron a focal component is ignored. - Never on connectors. If you want a colored edge, pick a different
stylefrom §3, not a color override. - Cap at 2 custom-colored components per diagram (in addition to the focal pair).
Semantic palette (use these unless brand demands otherwise):
#b85450rust-red — Security / Identity (AD, Keycloak, Vault)#5a7d9aslate-blue — Observability (Prometheus, Datadog, OpenTelemetry)#7a8c47olive-green — Governance / Lineage (OpenMetadata, DataHub)#8c6d3fwarm-brown — Backup / DR (Velero, Restic)
5. Focal rule
Exactly two focal components. Default: the storage hub (MinIO / S3 / similar) and the federation engine (Trino / Dremio / similar). These two surfaces distinguish a "platform" from a pile of tools. Everything else (NiFi, Jupyter, Airflow, AD, all sources, all consumers) stays ink / muted.
- Mark with
focal: trueon the component entry. - A focal
kind: barusesbar_h_focal=56(taller) and accent styling. - A focal
kind: rownode keepsrow_h=72but uses accent styling. - The Trino → all consumers edges are always
primary(accent), regardless of focal flag on each consumer — this is the serve-flow rule. - If fewer than 2 or more than 2 components are marked
focal: true, halt and ask the user.
6. Dark mode
paper, ink, muted, soft, accent, and link invert with the skin: take their values from the dark column in style-guide.md [blocked]. A role at an opacity needs no dark-mode handling, since ink @ 0.32 resolves against whichever ink is active.
Only these differ between modes:
Unchanged across modes: zone stroke ink @ 0.32, focal stroke accent, and custom component colors (C light → C_light, lightened ~15%).
7. Reproducibility checklist (taste gate)
Before emitting SVG, verify every item:
viewBox = "0 0 1200 {viewBox_h}"whereviewBox_h = max(600, footer_bottom + 84).- Platform zone at
x=260 y=72 w=696 h=col_h. Zone label paper-masked across top border aty=zone_y+3. - Left column at
x=40..200, right column atx=1000..1160— both 160 wide. - Source / consumer rows top at
y=92, stride 88 px. platform.rowsentries stack inside zone via the §2.1 cursor algorithm; total y-span ≤zone_h.- Inside each
kind: row, node x-centers are evenly spaced across zone width (§2.2). - Exactly 2 focal components (
focal: true). - Every edge originating from a
kind: barcomponent usesstyle: trigger(dashed, unlabelled). - Every Trino → consumer edge uses
style: primary(the serve-flow rule). - Footer nodes connect only to the zone bottom edge via
authstyle. No edge from a footer to a specific component. - Custom component colors ≤ 2 (in addition to the focal pair). Connectors never recolored by component
color. - All connectors emitted before any node rect (z-order rule).
8. Sources and consumers — icon library
Define each icon as <g id="ico-…"> in <defs>, drawn at translate(cx, cy) with stroke="currentColor" so it inherits the surrounding text color. Common icons:
ico-db(cylinder) — relational sourcesico-sftp(folder with down arrow) — file dropsico-mail(envelope) — email pullsico-mainframe(server with vents) — legacy systemsico-monitor— desktop analytics toolsico-chart(bars) — BI / report toolsico-globe— public websitesico-api(brackets{}) — gateways and 3rd-party clientsico-key— identity / IDPico-monitoring(chart-line) — observability stack
If you need more icons, browse assets/icons.html and define matching <symbol> blocks.
9. Identity, common services → connect to the layer, not to components
Active Directory (or Keycloak, IAM, OPA, any cross-cutting identity / policy / secrets store) authenticates every component in the platform. Wiring it to one specific tool would understate the trust scope. Connect it instead with a single arrow to the bottom edge of the platform zone, labeled AUTH (§3.3).
The same rule applies to any other layer-wide service: centralized logging, secrets vault, observability stack, audit sink, mTLS root. Each goes in the footer list, each gets its own row, each gets its own AUTH line up to the zone bottom edge (staggered by index per §3.3). The visual reading is "the platform layer delegates to all of these," which is the architectural truth.
10. Budget — this type exceeds the default
This is the one type where the default 9-node / 12-arrow budget is intentionally exceeded. A realistic platform integration shows:
- 4–6 source nodes
- 5 platform components
- 4–6 consumer nodes
- 1–3 footer nodes (identity, observability, backup, …)
That's 14–20 nodes. The complexity is the point — the diagram is making a claim about the number of distinct integration surfaces. Compressing them collapses the claim.
When this gets unwieldy:
- Combine clearly-identical source rows (e.g., four MariaDB databases → one
Databasesnode with sublabel4 × MariaDB) - Split into two diagrams (one per integration plane: data vs. identity vs. observability)
11. Anti-patterns
- Sources or consumers as a single collapsed node when ≥3 distinct items exist — defeats the whole point of this type. Use Architecture or High-level if you want collapsing.
- One bus arrow from "sources" to "the platform" — every wire is labeled with its protocol; this is how integration teams read the diagram.
- Per-tool color coding (teal-NiFi, magenta-MinIO, yellow-Jupyter) inside the zone — collapses hierarchy; only the two focal accents earn coral, plus up to 2 custom colors on cross-cutting components (§4 cap).
- More than 2 focal components — focal exists to distinguish "platform" from "pile of tools"; >2 erases the signal (same rule as SKILL.md §1).
coloroverride on a focal component — ignored. Focal_accent always wins.- Footer wired to one specific tool (e.g., AD → Airflow only) — wrong unless that service truly only protects one tool. The default is the layer-wide connection.
- Footer or identity inside the zone — identity gates the layer from outside. Drawing it inside misrepresents the trust model.
- Phase chevrons across the top — those belong on
high-level. - Custom-colored connectors — connectors are topology-driven. Style picks the color;
coloron a component never spreads to its edges.
12. Examples
assets/example-dp-integration.html— minimal light (1 footer = AD). Gallery default.assets/example-dp-integration-dark.html— same, dark skin.assets/example-dp-integration-full.html— same, editorial-card frame.