npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

footprint-explainable-ui

v0.30.0

Published

Themeable React components for visualizing FootPrint pipeline execution

Readme

footprint-explainable-ui

Themeable React components for visualizing footprintjs pipeline execution — time-travel debugging, flowchart overlays, subflow drill-down, and collapsible detail panels.

Part of the footprintjs ecosystem — the self-explaining stack.

Install

npm install footprint-explainable-ui

Peer dependencies: react >= 18, react-dom >= 18

For flowchart components, also install:

npm install @xyflow/react

Entry Points

| Import path | What it provides | |---|---| | footprint-explainable-ui | Core components, themes, adapters | | footprint-explainable-ui/flowchart | Flowchart visualization (requires @xyflow/react) |

Quick Start

1. Convert execution data to snapshots

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
);

2. Render with the all-in-one shell

import { ExplainableShell } from "footprint-explainable-ui";

function DebugView({ snapshots, narrativeEntries, traceGraph, runtimeOverlay }) {
  return (
    <ExplainableShell
      snapshots={snapshots}
      narrativeEntries={narrativeEntries}
      traceGraph={traceGraph}
      runtimeOverlay={runtimeOverlay}
      title="My Pipeline"
      panelLabels={{ topology: "What Ran", details: "What Happened", timeline: "How Long" }}
    />
  );
}

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

3. Or compose individual components

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} />
    </>
  );
}

ExplainableShell

The all-in-one orchestrator. Handles time-travel, subflow drill-down, memory/narrative panels, and responsive layout.

Props

| Prop | Type | Default | Description | |---|---|---|---| | snapshots | StageSnapshot[] | required | Visualization snapshots | | traceGraph | TraceGraph \| null | — | Build-time graph — drives the flowchart + subflow drill-down | | runtimeOverlay | RuntimeOverlay | — | Per-step execution overlay — lights the executed path | | 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 |

Tracing a value — walk the timeline backward through its causes

Tracing mode: the rail becomes the walk

Open Inspector → Data Trace and click one of the "Trace a value" chips. The time slider stays the same rail — the stages that made that value light up as stops, everything else fades to unlandable ticks, and the buttons become ◀ earlier cause / toward result ▶. This works because every ingredient of a value was always written earlier in the run than the value it fed, so the dependency chain is a sub-sequence of the timeline you already have. One cursor, no new axis.

  • A value made from two ingredients shows both as colored chips — pressing "earlier cause" visits both (most recent first); nothing is ever silently skipped. Click a chip to follow just that ingredient (the breadcrumb shows key ▸ via ingredient · show all).
  • Every stop shows the world as it was at that moment — the state panel time-travels with the walk for free.
  • Honest absence: a value nobody wrote gets a truthful card ("never written in this run — it arrived with the run's inputs"), and a value not written yet at the cursor's moment says exactly that, naming where its first write happens. Reads-off runs say "unknowable, not absent".
  • [Copy story] emits the same text an LLM backtrack tool returns — the human's board and the agent's answer are one artifact.
  • Tracing lives on the root rail: drilling into a subflow exits it honestly.
  • Trace anything: below the current step's chips, a search box lists every variable the run ever wrote — trace any of them from wherever you stand.
  • Forks ask, never assume: at a value made from two or more ingredients the walk-back button becomes ⑂ choose cause… and asks which ingredient to follow (or "visit all, in time order"). Nothing is ever silently picked.

The fork chooser: which cause should the walk follow?

  • Unmistakable mode: the whole tracing rail wears its own color (--fp-tracing, teal by default — themeable) so tracing can never be confused with normal time-travel.

Panel Labels

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)
  }}
/>

Default Expanded

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={...} traceGraph={...} runtimeOverlay={...} />

// Mobile — all collapsed, flowchart fills screen
<ExplainableShell
  snapshots={...}
  defaultExpanded={{ details: false }}
/>

// Everything open
<ExplainableShell
  snapshots={...}
  defaultExpanded={{ topology: true, details: true, timeline: true }}
/>

Responsive Layout

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.

Collapsible Panel UX

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. side prop controls arrow direction.
  • HLinePill (bottom timeline): Horizontal line with centered pill.

Flowchart Visualization

Import from footprint-explainable-ui/flowchart:

TracedFlowchartView (recommended)

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).

Manual control with specToReactFlow

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
/>

Theming

CSS Variables (recommended)

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;
}

ThemeProvider

import { FootprintTheme, warmDark } from "footprint-explainable-ui";

<FootprintTheme tokens={warmDark}>
  <MyApp />
</FootprintTheme>

Built-in Presets

| Preset | Description | |---|---| | coolDark | Default — indigo/slate dark theme | | warmDark | Charcoal-purple with warm text | | warmLight | Cream/peach light theme | | coolLight | Light indigo theme |


Components Reference

Core Components

| 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) |

Flowchart Components (footprint-explainable-ui/flowchart)

| 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) |

Adapters

| Export | Description | |---|---| | toVisualizationSnapshots | Convert FlowChartExecutor.getSnapshot()StageSnapshot[] | | subflowResultToSnapshots | Convert subflow result → StageSnapshot[] | | createSnapshots | Build StageSnapshot[] from simple arrays (testing/custom data) |

Types

| 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 |


Size Variants

All components accept a size prop: "compact", "default", or "detailed".

<GanttTimeline snapshots={snapshots} size="compact" />
<MemoryInspector snapshots={snapshots} size="detailed" />

Unstyled Mode

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; }

Golden-Trace Fixtures (contributors)

The pipeline (structure/runtime translators, dagre layout, snapshot adapter, narrative sync) is pinned against real footprintjs engine output, not hand-built mocks. test/fixtures/golden/ holds recorded traces from 4 representative charts (linear+decider, subflow+loop, parallel fork, pause/resume); test/golden/goldenTraces.test.ts replays them through the full pipeline and snapshot-asserts the outputs in test/golden/__snapshots__/.

  • Engine shape changed (new footprintjs): npm i -D --save-exact footprintjs@<version> && npm run fixtures:regen. The generator runs every chart twice and fails on any nondeterminism.
  • Pipeline output changed intentionally (eui edit): npx vitest run test/golden -u, then review the snapshot diff.
  • test/fixtures/golden/manifest.json records the footprintjs version the fixtures were recorded with.

footprintjs is a devDependency used ONLY by the generator — the published library still has zero footprintjs dependency (it consumes plain JSON shapes).

The footprintjs ecosystem

The self-explaining stack — from backend pipelines to AI agents. → overview

| Project | Role | |---|---| | footprintjs | the flowchart pattern (core engine) | | agentfootprint | build self-explaining AI agents | | Explainable UI ← you are here | visualize a footprintjs run | | Lens | debug an agentfootprint run | | Thinking UI | replay an agent run for non-devs |


License

MIT