| 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 — 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:
F(from, to, wire, tone, note, opts)
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 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)
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'},
};
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'}),
]},
];
this.RUN_SM = { vb:[380,300], box:[96,24], states:{}, edges:[] };
this.STEP_SM = { vb:[380,206], box:[96,24], states:{}, edges:[] };
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 — 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.