Themeable React components for visualizing footprintjs pipeline execution — time-travel debugging, flowchart overlays, subflow drill-down, and collapsible detail panels.
npm install footprint-explainable-uiPeer dependencies: react >= 18, react-dom >= 18
For flowchart components, also install:
npm install @xyflow/react| Import path | What it provides |
|---|---|
footprint-explainable-ui |
Core components, themes, adapters |
footprint-explainable-ui/flowchart |
Flowchart visualization (requires @xyflow/react) |
import { FlowChartExecutor } from "footprintjs";
import { toVisualizationSnapshots } from "footprint-explainable-ui";
const executor = new FlowChartExecutor(chart);
await executor.run({ input: data });
const snapshots = toVisualizationSnapshots(
executor.getSnapshot(),
executor.getNarrativeEntries(), // optional — enables rich narrative
);import { ExplainableShell } from "footprint-explainable-ui";
import { TracedFlowchartView } from "footprint-explainable-ui/flowchart";
function DebugView({ snapshots, spec, narrative, narrativeEntries }) {
return (
<ExplainableShell
snapshots={snapshots}
spec={spec}
narrative={narrative}
narrativeEntries={narrativeEntries}
title="My Pipeline"
panelLabels={{ topology: "What Ran", details: "What Happened", timeline: "How Long" }}
renderFlowchart={({ spec, snapshots, selectedIndex, onNodeClick }) => (
<TracedFlowchartView
spec={spec}
snapshots={snapshots}
snapshotIndex={selectedIndex}
onNodeClick={onNodeClick}
/>
)}
/>
);
}This gives you:
- Flowchart (center) — execution path overlay, click subflow nodes to drill-down
- Topology panel (left) — subflow tree navigator, collapsible via VLinePill handle
- Details panel (right) — Memory state + Narrative tabs, collapsible
- Timeline (bottom) — Gantt-style stage durations, collapsible
- Time-travel slider — scrub through execution steps
- Breadcrumbs — navigate back from subflow drill-down
- Mobile responsive — auto-stacks vertically below 640px
import {
TimeTravelControls,
MemoryInspector,
ScopeDiff,
GanttTimeline,
NarrativeTrace,
} from "footprint-explainable-ui";
function MyDebugger({ snapshots }) {
const [idx, setIdx] = useState(0);
const current = snapshots[idx];
const previous = idx > 0 ? snapshots[idx - 1] : null;
return (
<>
<TimeTravelControls
snapshots={snapshots}
selectedIndex={idx}
onIndexChange={setIdx}
/>
<MemoryInspector snapshots={snapshots} selectedIndex={idx} />
<ScopeDiff
previous={previous?.memory ?? null}
current={current.memory}
hideUnchanged
/>
<NarrativeTrace narrative={snapshots.map(s => s.narrative)} />
<GanttTimeline snapshots={snapshots} selectedIndex={idx} onSelect={setIdx} />
</>
);
}The all-in-one orchestrator. Handles time-travel, subflow drill-down, memory/narrative panels, and responsive layout.
| Prop | Type | Default | Description |
|---|---|---|---|
snapshots |
StageSnapshot[] |
required | Visualization snapshots |
spec |
SpecNode | null |
— | Pipeline spec (enables flowchart + subflow tree) |
title |
string |
"Flowchart" |
Breadcrumb root label |
narrative |
string[] |
— | Flat narrative lines |
narrativeEntries |
NarrativeEntry[] |
— | Structured narrative (rich rendering) |
panelLabels |
PanelLabels |
{ topology: "Topology", details: "Details", timeline: "Timeline" } |
Customize collapsible pill labels |
defaultExpanded |
DefaultExpanded |
{ details: true } |
Which panels start open |
tabs |
ShellTab[] |
["result", "explainable"] |
Visible tabs |
renderFlowchart |
(props) => ReactNode |
— | Flowchart renderer (pass TracedFlowchartView) |
resultData |
Record<string, unknown> |
— | Final output data for Result tab |
size |
"compact" | "default" | "detailed" |
"default" |
Size variant |
unstyled |
boolean |
false |
Strip styles, render data-fp attributes |
Customize the text on collapsible pill buttons. Semantic keys — not tied to position:
<ExplainableShell
panelLabels={{
topology: "What Ran", // left panel (subflow tree)
details: "What Happened", // right panel (memory/narrative)
timeline: "How Long", // bottom panel (Gantt)
}}
/>Control which panels start open. Desktop default: details panel open (flowchart + memory = the library's unique value). For mobile, pass all false:
// Desktop (default) — memory panel open
<ExplainableShell snapshots={...} spec={...} />
// Mobile — all collapsed, flowchart fills screen
<ExplainableShell
snapshots={...}
defaultExpanded={{ details: false }}
/>
// Everything open
<ExplainableShell
snapshots={...}
defaultExpanded={{ topology: true, details: true, timeline: true }}
/>The shell auto-detects container width via ResizeObserver:
- Desktop (≥640px): 3-column layout — SubflowTree | Flowchart | Memory/Narrative. Side panels collapse to VLinePill handles.
- Mobile (<640px): Stacked vertical — Flowchart (350px) → collapsible HLinePill sections. All panels auto-collapse on narrow.
All panels use the line + pill pattern:
- Collapsed: Thin divider line with a centered pill button (label + arrow)
- Expanded: Full content with a pill handle on the closing edge
- VLinePill (left/right panels): Vertical line with centered vertical pill.
sideprop controls arrow direction. - HLinePill (bottom timeline): Horizontal line with centered pill.
Import from footprint-explainable-ui/flowchart:
Self-contained flowchart renderer. Handles overlay computation, auto-fitView on resize.
import { TracedFlowchartView } from "footprint-explainable-ui/flowchart";
<div style={{ height: 400 }}>
<TracedFlowchartView
spec={spec}
snapshots={snapshots}
snapshotIndex={idx}
onNodeClick={(nodeId) => handleClick(nodeId)}
/>
</div>Without snapshots, renders a plain static flowchart. With snapshots, shows the execution trace path with Google Maps-style glow.
Auto-fitView: The flowchart automatically calls fitView() when its container resizes (e.g. panel expand/collapse).
import { specToReactFlow, StageNode, type ExecutionOverlay } from "footprint-explainable-ui/flowchart";
import { ReactFlow } from "@xyflow/react";
const overlay: ExecutionOverlay = {
doneStages: new Set(["LoadOrder", "ProcessPayment"]),
activeStage: "ShipOrder",
executedStages: new Set(["LoadOrder", "ProcessPayment", "ShipOrder"]),
executionOrder: ["LoadOrder", "ProcessPayment", "ShipOrder"],
};
const { nodes, edges } = specToReactFlow(spec, overlay);
<ReactFlow
nodes={nodes}
edges={edges}
nodeTypes={{ stage: StageNode }}
fitView
/>Consumer controls theme via --fp-* CSS custom properties. Components use var(--fp-*, fallback):
:root {
--fp-color-primary: #7c6cf0;
--fp-bg-primary: #1e1a2e;
--fp-bg-secondary: #2a2540;
--fp-bg-tertiary: #3a3455;
--fp-text-primary: #f0e6d6;
--fp-text-secondary: #b0a898;
--fp-text-muted: #6b6b80;
--fp-border: #3a3455;
--fp-radius: 8px;
--fp-font-sans: 'Inter', system-ui, sans-serif;
--fp-font-mono: 'JetBrains Mono', monospace;
}import { FootprintTheme, warmDark } from "footprint-explainable-ui";
<FootprintTheme tokens={warmDark}>
<MyApp />
</FootprintTheme>| Preset | Description |
|---|---|
coolDark |
Default — indigo/slate dark theme |
warmDark |
Charcoal-purple with warm text |
warmLight |
Cream/peach light theme |
coolLight |
Light indigo theme |
| Component | Description |
|---|---|
ExplainableShell |
All-in-one orchestrator with collapsible panels and responsive layout |
TimeTravelControls |
Play/pause, prev/next, scrubber timeline |
MemoryPanel |
Memory state + scope diff (composite right-panel view) |
NarrativePanel |
Narrative trace with progressive reveal |
StoryNarrative |
Rich rendering of structured NarrativeEntry[] |
NarrativeTrace |
Collapsible stage groups with progressive reveal |
NarrativeLog |
Simple timeline-style execution log |
ScopeDiff |
Side-by-side scope changes (added/changed/removed) |
ResultPanel |
Final pipeline output + console logs |
MemoryInspector |
Accumulated memory state viewer |
GanttTimeline |
Horizontal duration timeline (collapsible) |
SnapshotPanel |
All-in-one inspector (scrubber + memory + narrative + Gantt) |
| Export | Description |
|---|---|
TracedFlowchartView |
Self-contained flowchart with trace overlay and auto-fitView |
FlowchartView |
Lower-level ReactFlow wrapper |
StageNode |
Custom node with state-aware coloring, step badges, pulse rings |
specToReactFlow |
Convert pipeline spec → ReactFlow nodes/edges with overlay |
SubflowBreadcrumb |
Breadcrumb bar for subflow drill-down |
SubflowTree |
Tree view of all subflows (used in shell's left panel) |
| Export | Description |
|---|---|
toVisualizationSnapshots |
Convert FlowChartExecutor.getSnapshot() → StageSnapshot[] |
subflowResultToSnapshots |
Convert subflow result → StageSnapshot[] |
createSnapshots |
Build StageSnapshot[] from simple arrays (testing/custom data) |
| Export | Description |
|---|---|
PanelLabels |
{ topology?, details?, timeline? } — pill label customization |
DefaultExpanded |
{ topology?, details?, timeline? } — initial panel state |
StageSnapshot |
Core snapshot type for all components |
NarrativeEntry |
Structured narrative entry with type/depth/stageName |
All components accept a size prop: "compact", "default", or "detailed".
<GanttTimeline snapshots={snapshots} size="compact" />
<MemoryInspector snapshots={snapshots} size="detailed" />Strip all built-in styles for full CSS control. Components render semantic data-fp attributes:
<NarrativeTrace narrative={lines} unstyled className="my-narrative" />[data-fp="narrative-header"] { font-weight: bold; }
[data-fp="narrative-step"] { padding-left: 2rem; }MIT