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.
Press Step to start. The model will try to fit the orange line to the blue data.
Installation
npx shadcn@latest add https://craftbits.dev/r/training-loop-viz.jsonUsage
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
- 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 equationy = mx + bsit on the right. - 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.
- Forward phase. Warning-coloured prediction dots appear at
(x_i, ŷ_i)with their values inline. Motion'sanimateslides the dots between phases so a re-step doesn't cause a teleport. - Loss phase. Red rectangles grow vertically between each true
y_iand 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. - Backward phase. A green dashed ghost line shows the post-update fit. The user sees the gradient as a direction, not just a number.
- 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.
- Auto mode. Re-uses the same step machine in a
setInterval, capped byautoMaxStepsand short-circuited as soon as the loss drops belowautoStopLoss. Stopping is idempotent (clicking Auto while running halts). - 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
| Prop | Type | Default | Description |
|---|---|---|---|
data | readonly TrainingLoopVizPoint[] | four classic points | Training dataset — {x, y} pairs. |
defaultSlope | number | 0.3 | Initial value of m. |
defaultIntercept | number | -0.5 | Initial value of b. |
learningRate | number | 0.015 | Step-size multiplier on both gradients. |
autoStepIntervalMs | number | 600 | Delay between phases when Auto is running. |
autoStopLoss | number | 0.3 | Auto halts once the MSE drops below this. |
autoMaxSteps | number | 200 | Hard ceiling on Auto iterations. |
transition | Transition | SPRINGS.smooth | Override the fitted-line / prediction-dot tween. |
onPhaseChange | (snap) => void | — | Fires after every phase transition. |
onReset | () => void | — | Fires when the user clicks Reset. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The SVG canvas is
role="img"with anaria-labelsummarising 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), theWidgetchrome (bookmarks, undo/redo, reset, formula slot), the lessonModeStrip,ChallengeBtn,FeedbackBadge,ScoreDots,usePredictRoundshook, and theSvgLabelprimitive. 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}-*tovar(--cb-*)semantic tokens, and re-keys the motion to the canonicalSPRINGS.smooth.