Training Loop Viz

A scatter-plot, phase-by-phase visualizer of the canonical linear-regression training loop. The user taps Step to advance through forward → loss → backward → update — prediction dots land on the fitted line, red bars grow to match each residual, then a green dashed "ghost" line previews where the next update will move the fit. A loss sparkline below the controls records the descent across cycles.

With the defaults (learningRate = 0.015) the four-point fit converges below the visual noise floor in roughly twenty Auto-stepped iterations: the orange line lays itself across the blue dots and the red error bars collapse.

Training-loop visualization: forward, loss, backward, update.
Forward
Loss
Backward
Update
step 0·y = 0.30x + -0.50

Press Step to start. The model will try to fit the orange line to the blue data.

Loss38.4
Phase Ready, step 0, loss 38.35.
Customize
Loop
0.30
-0.50
0.015
600ms

Installation

npx shadcn@latest add https://craftbits.dev/r/training-loop-viz.json

Usage

import { TrainingLoopViz } from "@craft-bits/viz/training-loop-viz";
 
<TrainingLoopViz />

Slow the descent down so the user sees more intermediate states:

<TrainingLoopViz learningRate={0.008} />

Fit a custom dataset:

<TrainingLoopViz
  data={[
    { x: 0, y: 1 },
    { x: 2, y: 3 },
    { x: 4, y: 4.5 },
    { x: 5, y: 6 },
  ]}
/>

Subscribe to phase changes to drive an external dashboard:

<TrainingLoopViz
  onPhaseChange={(snap) => {
    /* read snap.phase / snap.loss / snap.slope / snap.intercept */
  }}
/>

Understanding the component

  1. Phase strip. Four rounded pills — Forward, Loss, Backward, Update — sit above the scatter. The active phase lights up in its semantic colour (accent / error / warning / success); completed phases within the current cycle fade. The current step counter and the live equation y = mx + b sit on the right.
  2. Scatter plot. A 520×280 SVG with a grid of dots, axis ticks, and zero lines. Blue dots are the dataset; the orange line is the current fit. Both render even in the idle phase so the user knows what they're optimizing against.
  3. Forward phase. Warning-coloured prediction dots appear at (x_i, ŷ_i) with their values inline. Motion's animate slides the dots between phases so a re-step doesn't cause a teleport.
  4. Loss phase. Red rectangles grow vertically between each true y_i and its prediction. The bar at the worst point is darker and labelled with the absolute error — the rest stay subtler so the eye lands on the biggest miss first.
  5. Backward phase. A green dashed ghost line shows the post-update fit. The user sees the gradient as a direction, not just a number.
  6. Update phase. The fitted line tweens to the ghost line's coordinates and the prediction dots, error bars, and ghost line all exit. The cycle counter advances and the loss sparkline grows by one segment.
  7. Auto mode. Re-uses the same step machine in a setInterval, capped by autoMaxSteps and short-circuited as soon as the loss drops below autoStopLoss. Stopping is idempotent (clicking Auto while running halts).
  8. Reduced motion. Under prefers-reduced-motion: reduce, the line tween, dot slides, fade-in/out transitions, and narration cross-fade collapse to instant state changes, and Auto runs without a delay.

Props

PropTypeDefaultDescription
datareadonly TrainingLoopVizPoint[]four classic pointsTraining dataset — {x, y} pairs.
defaultSlopenumber0.3Initial value of m.
defaultInterceptnumber-0.5Initial value of b.
learningRatenumber0.015Step-size multiplier on both gradients.
autoStepIntervalMsnumber600Delay between phases when Auto is running.
autoStopLossnumber0.3Auto halts once the MSE drops below this.
autoMaxStepsnumber200Hard ceiling on Auto iterations.
transitionTransitionSPRINGS.smoothOverride the fitted-line / prediction-dot tween.
onPhaseChange(snap) => voidFires after every phase transition.
onReset() => voidFires when the user clicks Reset.
classNamestringMerged onto the root via cn().

Accessibility

  • The SVG canvas is role="img" with an aria-label summarising the current step, phase, fitted equation, and loss.
  • The Step / Auto / Reset controls are real <button type="button"> elements with focus-visible rings and a tap-down scale.
  • The narration paragraph is aria-live="polite" and reads as plain prose; a second screen-reader-only live region announces phase + step + loss on every transition.
  • Colour is never the only signal — every phase has a text label in the strip, the active phase is named in the narration, and the loss value is read out alongside the sparkline.
  • Motion respects prefers-reduced-motion: reduce — line tweens, dot slides, error-bar fades, and the narration cross-fade all collapse to instant state changes.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/viz/TrainingLoopViz.tsx). The source bundled three lesson modes (Explore / Predict / Challenge), the Widget chrome (bookmarks, undo/redo, reset, formula slot), the lesson ModeStrip, ChallengeBtn, FeedbackBadge, ScoreDots, usePredictRounds hook, and the SvgLabel primitive. The viz extract drops all of that lesson chrome, keeps the core scatter + 4-phase animation, promotes every magic number to a typed prop, remaps the palette from --color-{ink,accent,fail,warn,success}-* to var(--cb-*) semantic tokens, and re-keys the motion to the canonical SPRINGS.smooth.