Trace Waterfall Viz
An interactive OpenTelemetry-style trace waterfall for a single AI request. Spans nest by depth and are laid out on a shared 0-3500ms time axis. A pulsing LOW badge on the retrieval span surfaces the bug — the top-3 relevance scores are all below the 0.75 threshold, so the model is answering from irrelevant context. Toggle "Fix retrieval" to swap in a second trace where scores climb above the threshold, input tokens drop from 4.8K → 3.0K, cost drops from $0.026 → $0.017, and the answer flips from Incorrect to Correct.
This is an OpenTelemetry-style trace for a single AI request. Each horizontal bar is a span — a unit of work with a name, start time, and duration. Click any span to inspect its details. Look for the warning badge.
Installation
npx shadcn@latest add https://craftbits.dev/r/trace-waterfall-viz.jsonUsage
import { TraceWaterfallViz } from "@craft-bits/viz/trace-waterfall-viz";
<TraceWaterfallViz />Start in the fixed state:
<TraceWaterfallViz defaultFixed />Bring your own traces:
<TraceWaterfallViz
brokenTrace={{
totalMs: 2000,
answerCorrect: false,
answerLabel: "Incorrect",
spans: [
{
id: "request",
name: "request",
category: "request",
depth: 0,
startMs: 0,
durationMs: 2000,
details: { traceId: "t-001", method: "POST" },
},
{
id: "retrieval",
name: "retrieval",
category: "retrieval",
depth: 1,
startMs: 10,
durationMs: 80,
details: { docCount: 4, topRelevance: [0.4, 0.3], threshold: 0.75 },
warning: "Low relevance — model is hallucinating.",
},
],
}}
fixedTrace={{
/* ...same shape, higher scores... */
}}
/>Subscribe to fix-toggle and selection events:
<TraceWaterfallViz
onFixChange={(fixed) => {
/* lift the toggle state into analytics */
}}
onSpanSelect={(span) => {
/* fires on every selection / deselection */
}}
/>Understanding the component
- Header. The mono "Trace Waterfall" wordmark sits beside a semantic answer badge (
var(--cb-success)when correct,var(--cb-error)when not), the total wall-clock duration in tabular-nums, and the right-aligned "Fix retrieval" toggle. The toggle is am.buttonwitharia-pressed, a sliding pip animated bySPRINGS.snap, and a(F)keyboard hint. - Time axis. Tick labels every 500ms across the
maxMswindow, fixed at 3500ms by default so the broken and fixed traces share a scale. The label column is reserved atlabelColumnWidth(160px default) so barleft%andwidth%stay readable. - Span rows. Each row is a
role="listitem"button with a label column (depth-indented, kind-coloured when selected) and a bar column. Selection lifts the row's background to acolor-mixof the kind colour at 8% alpha and adds a soft outer glow via inset+outerbox-shadow. Bars animate fromscaleX: 0toscaleX: 1on entry, staggered bySTAGGER. - Warning badge. Spans with a
warningstring surface a pulsingLOWchip in their label, swap the solid bar for alinear-gradientfrom the kind colour tovar(--cb-error), and gate the colour transition on thebug-foundphase. - Detail panel. Selecting a span opens the side panel (full-width on mobile, 280px on
lg). Top section shows kind dot + name; middle shows duration/start/end summary; the third section walksselected.detailswith special renderers fortopRelevance(per-score above/below threshold badges),categories(chip strip), andsources(numbered list). Pure key/value entries fall through to the genericDetailRow. - Comparison summary. When
fixedflips on, a four-stat row slides in beneath the waterfall (SPRINGS.smooth) showing strike-through before → highlighted after for total time, input tokens, cost, and top relevance — wholly driven bycomparisonStats. - Phases. State derives from selection + fix and exposes via
data-phaseon the root:explore→bug-found(a warning span is selected) →fixed(toggle is on). The narration banner's background tints from accent → error → success on phase change. - Reduced motion. Under
prefers-reduced-motion: reduce, every entrance collapses to a snap, theLOWbadge stops pulsing, the toggle pip jumps, bars skip their grow-in, and the comparison stats appear instantly.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
brokenTrace | TraceWaterfallVizTrace | bundled 11-span RAG trace | Trace shown when the fix toggle is off. |
fixedTrace | TraceWaterfallVizTrace | bundled 11-span fixed RAG trace | Trace shown when the fix toggle is on. |
comparisonStats | readonly TraceWaterfallVizComparisonStat[] | 4 stats | Before/after stats shown in the comparison summary. |
defaultFixed | boolean | false | Whether the viz starts in the fixed state. |
maxMs | number | 3500 | Upper bound of the time axis in milliseconds. |
labelColumnWidth | number | 160 | Width of the label column in pixels. |
maxHeight | number | 440 | Cap on the visible waterfall height; scrolls past it. |
transition | Transition | SPRINGS.smooth | Override the entrance spring for span rows and bars. |
onFixChange | (fixed: boolean) => void | — | Fires when the fix toggle flips. |
onSpanSelect | (span | null) => void | — | Fires when the selected span changes. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The root is
role="figure"with anaria-labelsummarising span count, total duration, and the keyboard model. - A polite live region (
aria-live="polite") announces selection, warnings, and the fix-applied state. - Span rows are
role="listitem"buttons witharia-pressedreflecting selection and anaria-labelincluding name, duration, and warning state. The depth connector glyph isaria-hidden. - The "Fix retrieval" toggle is a button with
aria-pressed, an explicitaria-label, and a visible(F)keyboard hint. - Keyboard model:
↑/↓move selection between spans,Entertoggles the detail panel,Ftoggles the retrieval fix,Escdeselects. The handler chains to user-providedonKeyDownand skips default-prevented events. - Colour is never the only signal — every warning span pairs the gradient bar with a
LOWchip and a side-panel callout; every relevance score badge spells "all above" / "all below" the threshold in text. - Motion respects
prefers-reduced-motion: reduce— entrances collapse to{ duration: 0 }, theLOWchip stops pulsing, the toggle pip jumps, and the comparison summary appears instantly.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/systems/TraceWaterfallViz.tsx). The source was a lesson primitive with hard-coded broken / fixedTRACEconstants, CA palette tokens (--color-accent-400/--color-ink-*/--color-surface-raised,ca-narration), inlineoklch(0.76 0.16 155)success /oklch(0.70 0.20 25)warning constants, and CA-specific spring aliases (SPRINGS.snappy/SPRINGS.gentle,STAGGER.tight). The craft-bits extract lifts the broken / fixed traces and the comparison summary into thebrokenTrace/fixedTrace/comparisonStatsprops with the originals exposed asTRACE_WATERFALL_VIZ_DEFAULT_BROKEN/TRACE_WATERFALL_VIZ_DEFAULT_FIXED/TRACE_WATERFALL_VIZ_DEFAULT_COMPARISON. The six-slot category palette re-keys to canonicalcb-*tokens; inline OKLCH success / warning constants becomevar(--cb-success)/var(--cb-error). InlineSPRINGS.snappy/SPRINGS.gentlere-key to canonicalSPRINGS.snap/SPRINGS.smoothfrom@craft-bits/core/motion;STAGGER.tightcollapses to the canonicalSTAGGERscalar.forwardRef+cn()+...propsspread + chainedonKeyDown+data-phase/data-fixed+onFixChange/onSpanSelectcallbacks were added.SvgLabel/ChallengeBtn/lessonIdlesson chrome was stripped (none was present in source). Keyboard model extended withEscapeto deselect.