Stop Screenshotting Architecture Diagrams: Build Them as Single-File HTML

작성자

카테고리:

← 피드로
DEV Community · Nasrul Hazim · 2026-07-23 개발(SW)

TL;DR

  • Spent today rebuilding two training diagrams — a layered reference architecture and a workflow swimlane — as single-file HTML instead of exported images.
  • The trick: data in a plain JS array, layout in CSS Grid, connectors in an SVG overlay measured at runtime.
  • Result: diagrams you can step through, click into, and hand over as one file that opens offline.

Why not just export a PNG?

Because a screenshot is stale by the next sprint, and nobody re-opens the drawing tool to fix it.

Approach Editable by a dev Interactive Portable PNG from a drawing tool No (need the source file) No Yes Mermaid in a doc Yes No Needs a renderer Hand-built HTML Yes (it’s a data array) Yes One file, opens anywhere

The third option costs a few hours once. After that, updating a component is editing one object in an array.

Separate the data from the drawing

This is the whole design. Nothing about position, colour, or DOM lives in the content:

const TIERS = [
  { key: 'clients', label: 'Clients', sub: 'consumers · admins' },
  { key: 'edge',    label: 'Edge',    sub: 'TLS · load balancing' },
  // ...
];

const COMPONENTS = [
  { id: 'app', tier: 'app', x: .34, label: 'Control Plane', tech: 'PHP-FPM',
    role: 'Governance UI and sync orchestration.',
    points: [{ type: 'info', text: 'Pushes approved config downstream' }] },
  // ...
];

const LINKS = [['consumers', 'edge'], ['edge', 'gateway'], /* ... */];

Enter fullscreen mode Exit fullscreen mode

tier picks the row. x is a fraction (0..1) across that row, not a pixel. So the layout survives any viewport without me hand-tuning coordinates.

Layout: Grid for the boxes, SVG on top for the wires

  +--------------------------------------------------+
  | lane label |  [card 1]   [card 2]   [card 3]      |  <- CSS Grid row
  |------------+-------------------------------------|
  | lane label |       [card 4]      [card 5]         |
  +--------------------------------------------------+
        ^                    ^
   sticky column      SVG overlay (position:absolute; inset:0)
                      draws paths between measured centres

Enter fullscreen mode Exit fullscreen mode

CSS Grid does the honest work:

grid.style.gridTemplateColumns = `186px repeat(${steps.length}, 178px)`;
grid.style.gridTemplateRows = `repeat(${LANES.length}, 1fr)`;

Enter fullscreen mode Exit fullscreen mode

Then measure the rendered cards and draw connectors into the overlay:

function centre(el) {
  const r = el.getBoundingClientRect(), base = board.getBoundingClientRect();
  return { x: r.left - base.left + r.width / 2, y: r.top - base.top + r.height / 2 };
}

Enter fullscreen mode Exit fullscreen mode

Measure after paint (requestAnimationFrame), and re-measure on resize or when a side drawer opens — otherwise your wires point at where the boxes used to be. That was the one bug that cost me real time.

The bit learners actually respond to

A dot that travels along the flow as you step through it. No library, ~10 lines:

function moveToken(from, to) {
  const a = centres[from], b = centres[to], t0 = performance.now(), dur = 650;
  (function tick(now) {
    const p = Math.min((now - t0) / dur, 1);
    const e = p < .5 ? 2 * p * p : 1 - Math.pow(-2 * p + 2, 2) / 2; // easeInOutQuad
    token.style.left = (a.x + (b.x - a.x) * e - 6) + 'px';
    token.style.top  = (a.y + (b.y - a.y) * e - 6) + 'px';
    if (p < 1) requestAnimationFrame(tick);
  })(performance.now());
}

Enter fullscreen mode Exit fullscreen mode

It’s cosmetic, and it’s the thing that makes a request’s journey land in a room. Movement encodes causality better than an arrow does.

Trade-offs, honestly

Win Cost One file, no build step, opens offline You hand-write the layout logic Content is a data array anyone can edit No auto-layout — you place things Full control of interaction Accessibility is on you (add keyboard nav)

If your diagram is throwaway, use Mermaid. If it’s going to be taught from repeatedly and evolve with the system, the data-driven HTML pays for itself fast.

Next

Extracting the shell into a reusable template so a new diagram is just a new data file. That’s the real deliverable — not the diagram, the mould it came out of.

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다