Two Step Optimizer
A six-click walkthrough of two complete gradient-descent training iterations on the parabola L(w) = (w − wOpt)². Each iteration is split into three sub-steps — Forward, Backward, Update — so the learner feels the cycle as three distinct moves rather than one monolithic step.
Forward → compute L(w)
Backward → compute dL/dw = 2(w − wOpt)
Update → w ← w − lr × dL/dw
The fixed learning rate keeps the focus on the cycle. The key visual is that the gradient arrow visibly shrinks between the two iterations — closer to the minimum means a gentler slope, which means a smaller arrow and a smaller step.
Two training steps. Each step is a cycle: forward pass, backward pass, update. Click Forward to begin. The minimum is at w = 3.
Installation
npx shadcn@latest add https://craftbits.dev/r/two-step-optimizer.jsonUsage
import { TwoStepOptimizer } from "@craft-bits/viz/two-step-optimizer";
<TwoStepOptimizer />Re-key the parabola — descend toward w = 5:
<TwoStepOptimizer startWeight={1} optimalWeight={5} />Use a more aggressive learning rate so the two-step preview lands closer to the minimum:
<TwoStepOptimizer learningRate={0.2} />Subscribe to phase changes to drive an external trace:
<TwoStepOptimizer
onPhaseChange={(phase, iteration) => {
if (iteration) {
/* iteration.wNew, iteration.lossNew available here */
}
}}
/>Understanding the component
- The plot. A wide SVG renders the
w ∈ [−1, 7],L ∈ [0, 16]window with a faint grid and a dashed target marker at(wOpt, 0). The parabola is sampled at 121 points and stroked once on first render. - The pipeline. Three labels —
FORWARD,BACKWARD,UPDATE— sit above the plot with→between them. The active sub-step is bold and full opacity; completed sub-steps fade; the iteration counter lives on the right. - Forward phase. The current weight and loss appear in monospaced labels next to the probe.
- Backward phase. A gradient arrow grows from the probe pointing toward the minimum. On iteration 2 the arrow is visibly shorter — a small banner reads
was −6.0 → now −4.8to make the comparison legible. - Update phase. The probe springs along the parabola from
wtow − lr × dL/dw. A faint dashed polyline records the trail of visited weights. - Idle pulse and completion ring. Before the first click and after the last, a soft breathing pulse and a celebratory ring play around the dot. Both disable under
prefers-reduced-motion: reduce. - Reduced motion. Under the reduced-motion preference, all springs collapse to instant attribute writes.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
optimalWeight | number | 3 | The minimum of L(w) = (w − optimalWeight)². |
learningRate | number | 0.1 | Fixed learning rate applied at each update. |
startWeight | number | 0 | Weight at the start of iteration 1. |
transition | Transition | SPRINGS.smooth | Override the dot's update spring. |
onPhaseChange | (phase, iteration) => void | — | Fires after each phase advance. Receives the iteration record on update phases (3 and 6); null otherwise. |
onReset | () => void | — | Fires when the user clicks Reset. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The plot SVG is
role="img"with anaria-labelsummarising the current phase, weight, loss, and learning rate. - The advance button is the single primary control;
Resetreplaces it once the cycle completes. - A live region below the button announces the current phase, weight, and loss after each step.
- The narration paragraph also has
aria-live="polite"and reads as plain prose — the canonical explanation for each phase. - Colour is never the only signal — the active pipeline step is encoded in bold weight and an arrow position in addition to colour.
- Motion respects
prefers-reduced-motion: reduce— the dot and arrow snap instantly, and the idle and completion pulses disable.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/math/TwoStepOptimizer.tsx). The source depended on lesson-chrome primitives (SvgLabel,ChallengeBtn), on per-track palette tokens, and on hand-tuned spring names from the lesson's motion lib. The viz extract drops the lesson chrome, generalises the parabola viastartWeightandoptimalWeightprops, generalises the learning rate vialearningRate, remaps every colour to thevar(--cb-*)semantic palette, and re-keys the dot animation toSPRINGS.smoothand the gradient arrow toSPRINGS.snap.