Diamond Tracer

A click-to-propagate backward-pass visualizer on a diamond computation graph. The learner walks ∂y/∂a down from the output y, through two parallel branches (×2 and ×3) that reconverge at the input node a, and discovers the multipath rule of reverse-mode autodiff: when a variable fans out, the gradients from each path SUM at the fan-out point.

The forward model is y = 2a + 3a, so dy/da = 5. The backward walk reaches the same answer by carrying gradient 1 from y, splitting it equally through +, scaling each branch by the local derivative, and summing the two arrivals at a.

Diamond graph backward pass on y equals 2a plus 3a.

∂y/∂y = 1. The gradient starts at the output. The backward pass walks the graph top to bottom — the reverse of the forward pass. Click the + node to propagate the gradient backward.

stage: start
Customize
Wiring

Installation

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

Usage

import { DiamondTracer } from "@craft-bits/viz/diamond-tracer";
 
<DiamondTracer />

Hook into stage changes to drive an external phase ribbon:

<DiamondTracer
  onStageChange={(stage) => {
    /* phase ribbon: highlight `stage` */
  }}
/>

Understanding the component

  1. The diamond graph. Five nodes laid out top-to-bottom for backward flow: y (output) → + (addition) → ×2 and ×3 (two parallel multiply branches) → a (input). Forward values are rendered inside each node so the learner can cross-check the walk against the algebra.
  2. Stage machine. Four stages drive the palette, narration, and which nodes are clickable: start (only + is active), split (both ×2 and ×3 are active, in any order), both-done (auto-transitions to summation), complete (sum has landed, Reset appears). Every stage transition emits onStageChange.
  3. Click +. The addition node flashes warning-tone. Two pulses emit simultaneously from +, travel down both edges, and gradient-1 badges fade in at ×2 and ×3. Both mul nodes start breathing — they're now clickable.
  4. Click ×2 or ×3. The clicked node flashes accent-tone. A mid-edge badge briefly shows the chain-rule multiplication (1×2 or 1×3), then resolves to the result. A pulse travels down the edge to a, where a small badge lands.
  5. Summation. Once both branches have arrived, the walker auto-advances. A 2 + 3 text appears above a, then flashes to = 5. The two arrival badges fade out, the final ∂y/∂a = 5 badge fades in, and the input node lights up success-tone with a one-shot glow.
  6. Reduced motion. Under prefers-reduced-motion: reduce, every spring collapses to an instant attribute set, pulses snap to their endpoints, and the breathing rings on ready nodes disappear.

Props

PropTypeDefaultDescription
transitionTransitionSPRINGS.smoothOverride the spring used by per-node flashes and badge fades.
onStageChange(stage) => voidFires when the walker advances to split, both-done, or complete.
onReset() => voidFires when the user clicks Reset after completion.
classNamestringMerged onto the root via cn().

Accessibility

  • The graph SVG is role="img" with an aria-label summarising the current stage and the expression y = 2a + 3a.
  • Each interactive node is its own role="button" circle with a node-specific aria-label. Only the currently-ready nodes are focusable — the rest carry no tabIndex.
  • Enter and Space while a node is focused activate the same handler as a click — the entire walk is keyboard-reachable.
  • An aria-live="assertive" region announces which branch just landed and which node is next, so the walker is usable without sight.
  • The narration paragraph has aria-live="polite" and mutes during the in-flight animation so screen readers don't trip over per-frame redraws.
  • Colour is never the only signal: stage is encoded in the narration prose, the live-region status text, and a data-stage attribute on the root.
  • Motion respects prefers-reduced-motion: reduce — pulses snap, breathing rings disable, and every spring collapses to an instant attribute set.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/math/DiamondTracer.tsx). The source was a lesson-bound component — it imported SvgLabel and ChallengeBtn from the lesson chrome, depended on per-track palette tokens (--color-accent-500, --color-warn-400, etc.), and inlined ad-hoc spring names (gentle, snappy) that don't exist in the canonical motion module. The viz extract drops the lesson chrome, remaps every colour to var(--cb-*) semantic tokens so consumer themes repaint freely, re-keys the springs to SPRINGS.smooth / SPRINGS.snap / SPRINGS.bouncy, and exposes stage changes via onStageChange so the multipath teaching moment can drive an external UI.