Turn a Low-Level Design doc (Mermaid sequence diagrams, state machines, pipeline charts) into ONE interactive, single-screen request-flow explorer — a persistent system map where you pick any flow and watch a request travel end-to-end, hop by hop, with the active path highlighted, the wire message named, and run/step state shown live. Use when an LLD/HLD/RFC/runbook contains multiple flows through a shared set of components and static diagrams keep leaving the reader asking 'how does a reques...
Installs into .claude/skills of the current project.
Are you the author of lld-flow-explorer?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/si-jothee-lld-flow-explorer)
---
name: lld-flow-explorer
description: "Turn a Low-Level Design doc (Mermaid sequence diagrams, state machines, pipeline charts) into ONE interactive, single-screen request-flow explorer — a persistent system map where you pick any flow and watch a request travel end-to-end, hop by hop, with the active path highlighted, the wire message named, and run/step state shown live. Use when an LLD/HLD/RFC/runbook contains multiple flows through a shared set of components and static diagrams keep leaving the reader asking 'how does a request actually move through this?'. Triggers: /lld-flow-explorer, or any request to visualize/animate/explore an LLD, sequence diagrams, or service request flows."
---
# Skill — LLD → Interactive Request-Flow Explorer
Turn the sequence diagrams, state machines, and pipeline charts buried in a Low-Level Design (LLD) doc into **one interactive, single-screen explorer**: a persistent system map where you pick any flow and *watch a request travel the system end-to-end* — hop by hop, with the active path highlighted, the wire message named, and run/step state shown live.
This is the skill that produced the *Job Orchestration · Request Flow Explorer*. It is written so you can point it at **any** event-driven / service LLD and get the same artifact.
> A complete, working build ships with this skill at **[`references/request-flow-explorer.html`](references/request-flow-explorer.html)** — open it in a browser to see exactly what you're aiming for.
---
## 1. When to use this
Use it when an LLD (or HLD, RFC, runbook) contains **multiple flows through a shared set of components** — typically:
- Mermaid `sequenceDiagram` blocks ("create run", "retry", "failure → incident", …)
- `stateDiagram-v2` blocks (an entity's lifecycle)
- a pipeline / step-graph (`flowchart`)
…and the reader keeps asking *"okay, but how does a request actually move through this?"* Static diagrams answer that one flow at a time; this turns all of them into one explorable, animated map.
**Don't** use it for a single linear flow (a plain diagram is enough) or for pure data-model / class diagrams (no movement to animate).
---
## 2. Output contract
A single **Design Component** (`<Name> Flow Explorer.dc.html`) — streaming, opens in a browser, no build step. It contains:
| Region | What it shows |
|---|---|
| **Header** | Title + one-line "how to read it" + a status-color legend |
| **Flow tabs** | One tab per flow (`§x.y` + title). Clicking selects a flow. |
| **Transport bar** | ⏮ / ▶ Play-Pause / ⏭, a **hop counter**, a **scrubber** (jump to any hop), speed control |
| **System map** (center) | A *persistent* set of component nodes laid out once. The selected flow draws its path on top; a glowing packet + wire-message label travels the active edge; visited edges stay as a trail; uninvolved nodes dim. |
| **Inspector** (right) | Current flow meta/title, the wire message badge, call/return/event direction, a plain-English narration line, and the **run-state** + **step-state** machines with the current state highlighted. |
| **Pipeline strip** (bottom) | The step graph, highlighting the active stage. |
Interaction model: **live animated playback with a scrubber.** Pick a flow → Play → the request animates across the shared map; or scrub/step to any point.
---
## 3. Process
### Step 0 — Read the LLD, ask first
Read the whole doc. Then confirm with the user (one round of questions): interaction model (playback vs click-to-explore), which flows to include, one-shared-map vs per-flow diagrams, how much detail per hop (narration / state / wire message / DB rows), visual theme, audience. Defaults that work well: **playback + scrubber, one shared map, narration + run/step state + wire message, all sequence flows + both state machines + the pipeline.**
### Step 1 — Extract the system map (the nodes)
List every participant that appears across the sequence diagrams + the C4 container view. Collapse duplicates (e.g. one "Orchestrator" node even if diagrams name several use-cases). Give each a **kind** (drives its accent + tag): `actor, api, core, store, loop, queue, worker, sns, dlq, ext`.
Lay them out **once** on a fixed 1200×640 canvas, left→right along the dominant request direction, grouping by tier (ingress · core+DB · queues · workers · notifications). Keep ~180px between centers so the 152px node cards don't collide. You only draw a flow's *own* edges later, so don't worry about wiring every possible connection — just place nodes cleanly.
### Step 2 — Extract each flow as a list of hops
Each `sequenceDiagram` (and any worked example) becomes one **flow**: an ordered array of **hops**. Translate every arrow / note into one hop:
```js
F(from, to, wire, tone, note, opts)
// from,to : node ids (self-hop when from===to)
// wire : the on-the-wire label — STEP_EXECUTE, 202 Accepted, BEGIN TX, ITEM_READY…
// tone : color class — 'cmd'|'ok'|'err'|'wait'|'db'|'http'|'info'
// note : one plain-English sentence (the "walk it" narration)
// opts : { run, step, stage, dir }
// run : run-state AFTER this hop, if it changed (else omit) → highlights the run state machine
// step : step-state after this hop, if it changed → highlights the step state machine
// stage : pipeline stage now active, if it changed → highlights the pipeline strip
// dir : 'call'(default, solid) | 'ret'(dashed return) | 'event'(no packet — a crash/timeout note)
```
Rules of faithful translation:
- A solid arrow → `dir:'call'`; a dashed return/delivery → `dir:'ret'`; a `Note over X` with no message (crash, lease expiry) → a self/`event` hop on that node.
- Internal decisions ("RetryPolicy?", "compare hash") → a **self-hop** (`from===to`) that pulses the node.
- Set `run`/`step`/`stage` **only on the hop where they change**; the engine carries the last value forward. Give each flow an `init:{run,step,stage}` for the state it starts in.
- Keep `note` to one sentence. Don't editorialize or add facts the LLD doesn't state.
- Pick `tone` by message meaning: commands/dispatch=`cmd`, success/completed=`ok`, failure/cancel=`err`, wait/retry/resume=`wait`, DB writes/transactions=`db`, HTTP responses=`http`, plumbing/routing=`info`.
For branching flows (e.g. idempotent vs supersede), walk the **most instructive branch** and name the others in the first hop's narration — a single packet can't fork.
### Step 3 — Extract the state machines + pipeline
- Each `stateDiagram-v2` → `{ states:{NAME:[x,y]}, edges:[[from,to]] }` on its own small canvas. Position the hub state centrally. These render as static reference graphs; the **current** state (carried from the hops) is highlighted.
- The pipeline `flowchart` → an ordered list of stages `{key, queue, policy, wait?}`. The active stage is highlighted; mark any stage with an external-wait loop (`wait:true`).
### Step 4 — Build the Design Component
Drop your extracted `NODES`, `FLOWS`, `RUN_SM`, `STEP_SM`, `PIPE` into the **reusable engine** (Appendix B). The engine handles: rAF packet animation + easing, play/pause/next/prev/scrub, carry-forward of run/step/stage, a ResizeObserver that scales the fixed 1200×640 stage to fit, and all the rendering (map, state machines, pipeline, tabs, transport, badges). You only author **data**, not behavior.
Authoring notes specific to Design Components:
- Chrome (header, tabs bar, control bar, panels, narration, labels) lives in the **template** (`b_dc_html`) as inline-styled markup so it streams and stays editable.
- The data-driven visuals (the map SVG+nodes+packet, the two state machines, the pipeline strip, the tab/transport buttons) are built with `React.createElement` in the **logic class** and surfaced through `{{ holes }}`. This is the sanctioned exception: they're animated / per-frame state that the template can't express.
- Expose `accent` (color) and `loop` (boolean) as props so the deck is tweakable without code.
### Step 5 — Theme
Two ready palettes (see Appendix C): **light "architecture blueprint"** (paper-white panels, ink text, blue primary, soft shadows) and **dark "ops console"** (near-black canvas, glowing active path). The active path is the only thing that should *pop*: bold toned line + soft halo, everything else calm. Status colors are semantic and consistent everywhere (map, badges, state machines).
### Step 6 — Verify
Load it; step into 2–3 flows and confirm: the active edge + packet + wire label render, the trail builds, the run/step machines highlight the right state, the pipeline tracks the stage, and the scrubber jumps cleanly. Designed for a 1440×900 desktop viewport.
### (Optional) Ship it
- **Standalone offline HTML:** because the DC runtime pulls React from a CDN, add `<script src="…react…">` + `<script src="…react-dom…">` *before* the runtime script and a `<template id="__bundler_thumbnail">` splash, then bundle to a single self-contained file (inlines React + fonts; zero network). The shipped [`references/request-flow-explorer.html`](references/request-flow-explorer.html) is exactly this kind of bundle.
- **PPTX:** an interactive tool doesn't export meaningfully as slides — instead build a companion deck (title + system map, one slide per flow with its full path drawn and hops listed) and export that.
---
## Appendix A — Data schema (fill this in per LLD)
```js
// 1. NODES — id → {x,y,name,sub,kind}. Canvas is 1200×640; (x,y) is the node center.
this.NODES = {
API: {x:84, y:330, name:'API Controller', sub:'REST /createJob', kind:'api'},
UC: {x:322, y:322, name:'Orchestrator', sub:'use-cases', kind:'core'},
DB: {x:322, y:520, name:'Postgres', sub:'source of truth', kind:'store'},
// …one entry per participant. kinds: actor api core store loop queue worker sns dlq ext
};
// 2. FLOWS — one per sequence diagram. F(from,to,wire,tone,note,opts)
const F=(from,to,wire,tone,note,o)=>Object.assign(
{from,to,wire,tone,note,run:null,step:null,stage:null,dir:'call'}, o||{});
this.FLOWS = [
{ meta:'§9.1', title:'Create run → first step dispatched',
init:{run:null,step:null,stage:null}, hops:[
F('API','UC','CreateRun()','http','Caller hits POST /createJob; one DB transaction opens.'),
F('UC','DB','BEGIN TX','db','Insert the run (CREATED) + first step (QUEUED) + variables.',
{run:'CREATED',step:'QUEUED',stage:'preparation'}),
F('UC','API','202 Accepted','http','Return 202 with the runId immediately.',{dir:'ret'}),
// …
]},
// …one object per flow
];
// 3. State machines — {vb:[w,h], box:[w,h], states:{NAME:[cx,cy]}, edges:[[from,to]]}
this.RUN_SM = { vb:[380,300], box:[96,24], states:{/*…*/}, edges:[/*…*/] };
this.STEP_SM = { vb:[380,206], box:[96,24], states:{/*…*/}, edges:[/*…*/] };
// 4. Pipeline — ordered stages
this.PIPE = [
{key:'preparation', q:'wf-prep-jobs', pol:'retry×2 · lease 5m', wait:true},
{key:'generation', q:'wf-gen-jobs', pol:'retry×3 · lease 30m'},
// …
];
```
---
## Appendix B — Reusable engine (logic class `Component extends DCLogic`)
Paste this whole class; replace only the four data structures in the constructor (Appendix A). Everything else — animation, playback, scaling, rendering — is generic.
> A complete, working build ships with this skill: **[`references/request-flow-explorer.html`](references/request-flow-explorer.html)** — open it in a browser to see the target artifact, and read its logic class for the full engine. (It's the bundled standalone build with React inlined; the editable `.dc.html` source is the same logic class with the four data structures swapped.) Copy it, then swap its `NODES` / `FLOWS` / `RUN_SM` / `STEP_SM` / `PIPE` for your LLD's. Key methods and their roles:
| Method | Role |
|---|---|
| `animateHop()` | rAF loop: eases the packet 0→1 along the current edge; on finish, if playing, dwells then advances (or loops / stops). Instant for self/event hops. |
| `playPause() / next() / prev() / scrub(v) / selectFlow(i) / setSpeed(s)` | Transport + navigation; each (re)starts `animateHop()`. |
| `carry(field)` | Walks `init` + hops `0..current`, returning the last non-null `run`/`step`/`stage` — so state persists between the hops that change it. |
| `measure()` + ResizeObserver | Computes `scale = min(w/1200, h/640)` and scales the fixed stage to fit any panel size with no distortion. |
| `clampSeg(A,B,hw,hh)` | Trims an edge so it starts/ends at the node-box border (used for both the map and the state machines). |
| `buildMap()` | Renders the SVG edges (trail dim, current toned + halo, arrowheads per tone), node cards (dim/seen/endpoint/arrived states), and the traveling packet + wire label. |
| `buildSM(def,current)` | Renders a state machine; highlights `current`. |
| `buildPipeline(active)` | Renders the stage strip; highlights `active`. |
| `buildFlowTabs() / buildTransport() / buildSpeed() / buildLegend() / badge() / dirBadge()` | The chrome controls + badges. |
| `toneColor(t) / statusColor(s) / kindMeta(k)` | The single source of truth for color — edit these to retheme. |
| `renderVals()` | Assembles every `{{ hole }}` the template consumes. |
---
## Appendix C — Palettes (edit `toneColor` / `statusColor` / `kindMeta` + template literals)
**Light — "architecture blueprint"**
```
app #e9edf3 · panels #ffffff · soft #f3f6fa · canvas #fbfcfe
borders #d4dce6 / #e0e7f0 · ink #16202e · secondary #5a6a7e · muted #8693a4
accent #2f6df0
tones cmd #2f6df0 · ok #1a8f4a · err #d83a34 · wait #bd7d0c · db #7a4ddb · http #0e8aa0 · info #5f6f82
status CREATED #3b7fd0 · RUNNING/PUBLISHED/ACTIVE #2f6df0 · QUEUED #5f6f82 · WAITING/RETRYING/PAUSED #bd7d0c
INCIDENT/FAILED/ERROR #d83a34 · COMPLETED #1a8f4a · CANCELLED #94a3b8
active path = bold toned line + soft colored halo (drop-shadow ~0 1px 3px tone66); node glow = soft colored shadow, NOT neon
```
**Dark — "ops console"**
```
app #080b11 · panels #0b0f16 · soft #0a0e15 · borders #182230/#131c28
ink #e6edf3 · muted #6b7785 · accent #37d6e0
tones cmd #37d6e0 · ok #34d399 · err #ff5c6c · wait #f5b73d · db #a78bfa · http #5b9bff · info #8a99ab
active path glows (drop-shadow ~0 0 5px tone); nodes get an accent ring + outer glow
```
Status semantics are identical across themes — only the hex values shift for legibility on the background.
---
## Appendix D — Pitfalls
- **Node cards must scale with the stage.** Size the stage as a fixed 1200×640 element and `transform: scale()` it (via the ResizeObserver) — don't position nodes in `%` with `px` sizes, or they overlap when the panel shrinks.
- **One packet can't branch.** Model branching flows as the main branch + narration for the alternates.
- **Set state only on the hop that changes it.** Let `carry()` fill the gaps; don't repeat `run`/`step` on every hop.
- **Keep the map honest.** Route result events through the result queue node even when the source diagram condenses them, so every flow uses the same component vocabulary.
- **Don't invent content.** Wire names, states, and narration come from the LLD. If a stage has sub-steps the orchestrator doesn't track, keep them inside the worker node — don't add fake hops.
- **Offline build:** the DC runtime fetches React from a CDN; inline it (Step 6) or the standalone file breaks with no network.