Update Slider

A miniature gradient-descent playground on a 1-D number line. The learner taps Step and watches a parameter m slide toward the optimum m*, with a learning-rate slider exposing the trade-off between tiny progress and runaway overshoot. The dot, status text, and ledger row all repaint together as m approaches the target — green when close, yellow when nearby, red when far.

Each step is m_new = m − lr × 2(m − m*). Whenever a step crosses the optimum, the component flashes an Overshoot! warning — the visceral "I picked too big a learning rate" moment.

m = 1.00
Learning Rate0.10

m_new = 1.000.10 × grad → 1.00

Click Step to nudge the parameter toward the optimum.

Customize
Update slider
2.67
1.00
0.10

Installation

npx shadcn@latest add https://craftbits.dev/r/update-slider.json

Usage

import { UpdateSlider } from "@craft-bits/viz/update-slider";
 
<UpdateSlider />

Start with an aggressive learning rate so the visitor sees an overshoot on the first tap:

<UpdateSlider defaultLearningRate={1.1} />

Re-target the optimum and the parameter range for a different setup:

<UpdateSlider min={-5} max={5} optimum={-1.2} defaultValue={3} />

Subscribe to step events for an external loss-vs-step chart:

<UpdateSlider
  onStep={({ value, learningRate, step }) => {
    /* push (step, value, learningRate) into a logger */
  }}
/>

Understanding the component

  1. Number line. A 520px-wide rule from min to max is rendered in the muted border tone. A short vertical tick at optimum is labelled optimal in green so the target is unambiguous at any size.
  2. Trail. Every visited position is plotted as a small dot. Older ghosts fade toward transparent so the eye reads the trajectory at a glance — the most recent trailSize (default 20) positions are kept on screen.
  3. Current marker. A 16-px dot at m springs to its new position via the transition prop (default SPRINGS.snap). The marker has a 2-px ring in the canvas colour so it lifts clearly over the trail dots.
  4. Status colour. Distance to the optimum is bucketed into three bands — < 0.1 is close, < 1 is near, otherwise far. The big m = readout, the dot, and the data-attribute data-status on the root all reflect the same band.
  5. Overshoot detector. Whenever a step crosses the optimum, the component flashes Overshoot! m flew past the optimum under the readout.
  6. Learning-rate slider. A native <input type="range"> clamps to [0.01, 1.5] with a 0.01 step. The slider uses the canvas accent colour so it follows the theme.
  7. Ledger row. Below the controls the literal arithmetic prints — m_new = previous − lr × grad → next. This makes the math live for the learner instead of hiding it behind animation.

Props

PropTypeDefaultDescription
minnumber-2Lower bound of the parameter line.
maxnumber5Upper bound of the parameter line.
optimumnumber2.67Target the parameter is descending toward.
defaultValuenumber1Initial parameter value. Reset returns here.
defaultLearningRatenumber0.1Initial slider value. Clamped to [0.01, 1.5].
trailSizenumber20Max number of trailing positions kept on screen.
transitionTransitionSPRINGS.snapOverride the marker animation transition.
onStep(args) => voidFires after each step with value, learningRate, step.
onReset() => voidFires when the user clicks Reset.
classNamestringMerged onto the root via cn().

Accessibility

  • The learning-rate <input type="range"> is labelled via aria-labelledby and announces its value through aria-valuetext (e.g. Learning rate 0.10).
  • The big m = readout has aria-live="polite" on its container so step results announce naturally; the slider drags themselves are not announced repeatedly.
  • The Step and Reset buttons have visible focus-visible rings. Reset only appears after the first step.
  • Colour is never the only signal — the data-status attribute on the root reflects the same band the colour does, the literal arithmetic ledger row prints the post-step value, and overshoots produce a textual warning.
  • The first render does not animate (via AnimatePresence with initial={false}), matching the library's reduced-motion policy.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/viz/UpdateSlider.tsx). The source consumed the lesson palette (--color-accent-500, --color-success-500, --color-warn-500, --color-fail-500, --color-ink-*) and inlined a one-off SPRINGS.snappy spring. The viz extract drops the lesson tokens for the var(--cb-*) semantic system so consumer themes repaint freely, swaps the spring for the canonical SPRINGS.snap, and exposes the previously hard-coded min / max / optimum / defaultValue / trailSize / transition as props so the playground generalises beyond the one curriculum scenario.