Gradient Walker

Pick a function f(x), a starting x, and a learning rate η. The walker steps in the direction of −f'(x) — vanilla gradient descent — until the update drops below 1e-4 (converged) or maxSteps is reached. The trajectory of x-values traces out as a polyline, the tangent at the current step is overlaid on the curve, and a transport bar plays, pauses, scrubs, or replays the descent.

y = x². Step 0 of 26. x = 3.000, f(x) = 9.000, slope = 6.000. Status: running.
y = x²step 00 / 26
-2-10123456789101112131415161718-4-3-2-101234
x = 3.000f(x) = 9.000f'(x) = 6.000η = 0.150
Customize
Function
x^2
Walk
3.00
0.15
Playback

Installation

npx shadcn@latest add https://craftbits.dev/r/gradient-walker.json

Usage

import { GradientWalker } from "@craft-bits/core";
 
<GradientWalker
  defaultActiveFunction="x^2"
  defaultStartX={3}
  learningRate={0.15}
/>

Drive playback from outside the component:

const [step, setStep] = useState(0);
const [playing, setPlaying] = useState(true);
 
<GradientWalker
  defaultActiveFunction="x^2"
  defaultStartX={3}
  learningRate={0.1}
  currentStep={step}
  onCurrentStepChange={setStep}
  playing={playing}
  onPlayingChange={setPlaying}
/>

Watch convergence into a local minimum on the double-well x⁴ − x²:

<GradientWalker
  defaultActiveFunction="x^4-x^2"
  defaultStartX={1.2}
  learningRate={0.1}
  maxSteps={80}
/>

Understanding the component

  1. Five built-in functions, each with analytical derivative. , x² + 2x + 1 (offset bowl), sin(x), x⁴ − x² (double well — two local minima!), ½x² + 0.3·sin(2x) (wavy bowl). Every derivative is the exact closed form, so the walker's step direction is the true gradient.
  2. Whole walk is precomputed. Given the active function, start, learning rate, and max steps, the full trajectory is simulated once and stored. Scrubbing by currentStep is O(1); the convergence check (|x_new − x_old| < 1e-4) is built in.
  3. Trajectory is drawn cumulatively. Every visited point is a small dot fading from muted into accent toward the current step; a thin accent polyline connects them. The current step gets a larger walker dot and a short tangent line whose slope is f'(x).
  4. Convergence ring. When the walker's final step is below 1e-4, a cb-success ring lights up around the dot and the legend reads "converged".
  5. Autoplay uses setTimeout. The interval is playSpeed ms (default 400). The effect cleans up on unmount, pause, or step change — no orphaned timers. Reduced-motion users have autoplay disabled and the walker snaps to the final step on mount.
  6. Controlled and uncontrolled, four times. activeFunction, startX, playing, and currentStep each ship a value + onChange pair for controlled use, or a default* prop for uncontrolled.
  7. Domain guards keep the walker on screen. If a step would leave the visible range, the simulator stops there — a too-aggressive learning rate gracefully truncates the trail instead of crashing.

Props

PropTypeDefaultDescription
functionsreadonly FunctionDef[]five built-insSelectable function list.
activeFunctionstringControlled active function.
defaultActiveFunctionstringfirst entry of functionsUncontrolled initial active function.
startXnumberControlled starting x.
defaultStartXnumberrange[1] − ¼ × spanUncontrolled initial starting x.
learningRatenumber0.1Gradient-descent learning rate η.
maxStepsnumber50Maximum number of steps simulated.
playingbooleanControlled play state.
defaultPlayingbooleanfalseUncontrolled initial play state.
currentStepnumberControlled current step index.
defaultCurrentStepnumber0Uncontrolled initial step.
rangereadonly [number, number][-4, 4]Visible x-axis domain.
playSpeednumber400Milliseconds between autoplay steps.
transitionTransitionSPRINGS.snapSpring for the walker dot / tangent.
classNamestringMerged onto the root <div> via cn().

Accessibility

  • The whole figure is role="figure" with aria-label="Gradient descent walker on <function>".
  • An aria-live="polite" summary above the chart announces the current step, x, f(x), f'(x), and status (running / stopped / converged) whenever the step or function changes.
  • The play / pause button uses aria-pressed so screen readers track the toggle state.
  • Step controls ( / ) and the scrubber each carry explicit aria-labels.
  • The function picker is a role="radiogroup" of role="radio" buttons, each tagged data-state="on" | "off".
  • Animation respects prefers-reduced-motion: reduce — autoplay is disabled, the walker snaps to the final step on mount, and all springs collapse to an instant swap.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/math/GradientWalker.tsx). Reframed the lesson primitive into a general 1-D gradient-descent visualizer: stripped the lesson-specific stage state machine, narration, success badges, and SvgLabel / ChallengeBtn dependencies; generalized to controlled / uncontrolled state pairs across four axes; added a five-function built-in roster (including a double-well to demonstrate local minima); added a precomputed-trajectory simulator with explicit convergence detection.