LR Schedule Viz
A line plot of learning rate over training. Drop in one of the five built-in schedules — constant, linear, cosine, step, warmup-cosine — or pass a custom (step, total) -> number. Use it to teach why warmup matters, the cosine annealing pattern, and the tradeoff between aggressive decay and stable convergence.
Learning rate schedule: cosine.Learning rate schedule: cosine, current step 50 of 100, LR 0.500
cosinepeak 1.00 step 50/100 lr 0.500
Customize
Schedule
cosine
Curve
1.00
10
Cursor
50
Installation
npx shadcn@latest add https://craftbits.dev/r/lr-schedule-viz.jsonUsage
import { LRScheduleViz } from "@craft-bits/core";
<LRScheduleViz schedule="cosine" peakLR={1.0} totalSteps={100} />Highlight a specific step on the curve:
<LRScheduleViz
schedule="warmup-cosine"
peakLR={1.0}
totalSteps={100}
warmupSteps={10}
currentStep={42}
/>Pass a custom schedule:
<LRScheduleViz
schedule={{ fn: (step, total) => 1 / (1 + step / total) }}
peakLR={1.0}
totalSteps={200}
/>Understanding the component
- Five canonical schedules, each with a teaching point.
constantkeeps LR flat.linearramps LR linearly down toward zero (floored atdecayFloor).cosineis the canonical smooth anneal — half a cosine wave from peak down to the floor.stephalves LR three times across training.warmup-cosineramps from zero up to peak overwarmupSteps, then cosine-decays the rest of the way. - Custom schedules via
{ fn }. Any pure(step, total) -> numberplugs in. The y-axis is normalised againstpeakLR, so make sure your function stays within[0, peakLR]. - Cursor is fully opt-in. Pass
currentStep(controlled) ordefaultCurrentStep(uncontrolled) to surface a vertical guide and a dot at that step on the curve. Without either, the chart just shows the curve and the peak/total readout. - Two springs, two roles. The curve animates between schedule changes with
SPRINGS.smooth(slow enough to read the shape changing). The cursor dot usesSPRINGS.snap(crisp enough to track a slider). - Decay floor matters. Learning rates below
decayFloorare clamped — keeps the curve readable and matches the safety rail you would want in real training code. - Reduced-motion fallback.
prefers-reduced-motion: reducesnaps both the curve and the cursor with no spring.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
schedule | 'constant' | 'linear' | 'cosine' | 'step' | 'warmup-cosine' | { fn } | 'cosine' | Built-in schedule or custom function. |
peakLR | number | 1.0 | Peak learning rate — the curve's maximum value. |
totalSteps | number | 100 | Total training steps over which to plot. |
currentStep | number | — | Controlled cursor step. |
defaultCurrentStep | number | — | Uncontrolled initial cursor step. |
onCurrentStepChange | (step: number) => void | — | Fires when the cursor step changes. |
warmupSteps | number | 10 | Warmup duration (used by warmup-cosine). |
decayFloor | number | 0.01 | Minimum LR for decaying schedules. |
transition | Transition | SPRINGS.snap | Spring for the cursor dot. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The figure is
role="figure"with a labelled title that names the active schedule. - An
aria-live="polite"summary announces the schedule, current step, and current LR — readable without color. - The textual readout above the chart spells out peak LR, current step, and current LR, so color is never the only signal.
prefers-reduced-motion: reducesnaps both the curve and the cursor with no spring.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/viz/LRScheduleViz.tsx). Stripped the lesson-specific Explore/Predict mode strip, prediction quiz rounds, three-schedule toggle pills, slider controls, drag-to-scrub interaction, and the lesson chrome. Generalised to a pure schedule-plot primitive: five built-in schedules, a custom{ fn }escape hatch, controlled and uncontrolled cursor, and a single-curve render with a springed dot.