Shape Tracer Viz

A pipeline visualisation for the shape-arithmetic side of tensor programming. Each step renders as a labelled card with an op name, the tensor shape in tabular-nums, and an optional note. Adjacent steps are joined by an arrow whose label echoes the next op — useful for debugging real tensor pipelines and for teaching how attention, conv, and RNN shapes flow.

Active step 3 of 5: matmul → [B, H, T, T].
Tensor shape pipeline05 steps
  1. input
    [B, T, D]batch, tokens, model dim
  2. reshape
    [B, T, H, D/H]split D into H heads
  3. matmul
    [B, H, T, T]Q @ Kᵀ → attention scores
  4. softmax
    [B, H, T, T]over last axis
  5. output
    [B, T, D]merge heads back
Customize
Cursor
2
Layout
vertical

Installation

npx shadcn@latest add https://craftbits.dev/r/shape-tracer-viz.json

Usage

import { ShapeTracerViz } from "@craft-bits/core";
 
<ShapeTracerViz
  steps={[
    { id: "in",      op: "input",   shape: ["B", "T", "D"] },
    { id: "rsh",     op: "reshape", shape: ["B", "T", "H", "D/H"] },
    { id: "matmul",  op: "matmul",  shape: ["B", "H", "T", "T"] },
    { id: "softmax", op: "softmax", shape: ["B", "H", "T", "T"] },
    { id: "out",     op: "output",  shape: ["B", "T", "D"] },
  ]}
/>

Highlight a single step:

const [step, setStep] = useState(2);
 
<ShapeTracerViz steps={steps} currentStep={step} />

Annotate steps for teaching:

<ShapeTracerViz
  steps={[
    { id: "in",   op: "input",   shape: ["B", "T", "D"], note: "batch, tokens, model dim" },
    { id: "rsh",  op: "reshape", shape: ["B", "T", "H", "D/H"], note: "split D into H heads" },
    { id: "perm", op: "permute", shape: ["B", "H", "T", "D/H"], note: "(0, 2, 1, 3) — heads to the front" },
  ]}
/>

Flow horizontally instead of top-to-bottom:

<ShapeTracerViz steps={steps} orientation="horizontal" />

Understanding the component

  1. Steps are cards; edges are arrows with op labels. Each step renders as a bordered card containing a step-number badge, the op name in monospace, the shape tuple in tabular-nums, and an optional note. Between adjacent cards, the arrow's label echoes the next card's op — the edge reads "what's about to happen" and the card reads "what shape we have now".
  2. Symbolic shapes welcome. Each entry in shape is number | string, so [B, T, D], [32, 128, 768], and ["B", "H", "T", "T"] all render. Strings render verbatim; numbers render as digits. The tuple is joined […, …] to mirror PyTorch / NumPy printing.
  3. currentStep is optional. Pass nothing and every step renders at the default tone — a static reference. Pass an index and that card brightens to accent, the inbound arrow lights up, and the aria-live summary announces the active op.
  4. SPRINGS.smooth on the active highlight. The active card scales to 1.02 and accents via a smooth spring from @craft-bits/core/motion — the cursor settles on each card rather than snapping.
  5. Reduced-motion fallback. With prefers-reduced-motion: reduce, transitions collapse to instant: the active-card pop is a hard swap, no scaling spring.
  6. Two orientations, same DOM. vertical (default — pipelines read naturally top-to-bottom) and horizontal. Only the flex direction, arrow glyph, and edge axis change.

Props

PropTypeDefaultDescription
stepsreadonly ShapeTracerStep[]Ordered tensor-op steps. Required.
currentStepnumberActive-step index. Out-of-range values are clamped. Pass undefined for a static diagram.
orientation'vertical' | 'horizontal''vertical'Layout direction.
showArrowsbooleantrueRender arrow + op-label edges between cards.
transitionTransitionSPRINGS.smoothSpring used for the active-step highlight.
classNamestringMerged onto the root <div> via cn().

ShapeTracerStep

FieldTypeDescription
idstringStable React key.
opstringOperation label (e.g. "matmul", "reshape").
shapereadonly (number | string)[]Output tensor shape. Mix concrete and symbolic dims.
notestringOptional one-line annotation rendered under the shape.

Accessibility

  • The root is role="figure" with aria-labelledby pointing at the "Tensor shape pipeline" heading and aria-describedby at a visually-hidden aria-live="polite" summary.
  • The summary announces the active step's op and shape whenever currentStep changes.
  • Steps are rendered in a semantic <ol> with aria-current="step" on the active card.
  • Arrow glyphs are aria-hidden — the op transitions are conveyed by textual labels on the cards themselves.
  • Color is never the only signal — step number, op label, shape tuple, and note are all textual.
  • prefers-reduced-motion: reduce collapses the active-step scale spring to an instant swap.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/nn/ShapeTracerViz.tsx). The source was a stateful CNN-shape tracer with internal layer-construction state, hardcoded conv/pool/GAP/FC op semantics, an SVG pipeline canvas, phase-driven narration, and project-specific colour vars (--color-accent-400, --color-ink-800). Re-architected as a declarative steps: ShapeTracerStep[] component — the caller supplies the shapes; the library just renders them. Op-specific colours, layer-construction buttons, glow animations, and CNN-specific shape arithmetic were all stripped. Shapes generalised from { h, w, c } triples to arbitrary readonly (number | string)[] tuples so attention, RNN, conv, and audio pipelines all render with the same component.