Derivative Explorer

A curve sits on a coordinate plane. A draggable marker rides the curve and trails its tangent line, whose slope is read live from the analytical derivative f'(x). An optional dashed secant overlay connects (x, f(x)) to (x + Δx, f(x + Δx)) — as Δx shrinks, the secant converges on the tangent, putting the limit definition of the derivative in motion.

Derivative explorer for y = x².
Slope2.00at x = 1.00
y = x². x = 1.00, slope f'(x) = 2.00.
Secant line
Customize
Curve
Position
1.00
Secant
0.50

Installation

npx shadcn@latest add https://craftbits.dev/r/derivative-explorer.json

Usage

Uncontrolled — the component owns curve, x, secant, and Δx:

import { DerivativeExplorer } from "@craft-bits/viz/derivative-explorer";
 
<DerivativeExplorer />

Start on the cubic with the secant on:

<DerivativeExplorer
  defaultActiveCurve="x³"
  defaultShowSecant
  defaultDeltaX={0.8}
/>

Controlled — let a parent stage own the state:

const [x, setX] = useState(1);
const [curve, setCurve] = useState<"x²" | "x³" | "sin(x)">("x²");
 
<DerivativeExplorer
  activeCurve={curve}
  onActiveCurveChange={setCurve}
  x={x}
  onXChange={setX}
/>

Hide the chrome (curve picker + secant controls) when the chart is embedded inside a larger composition:

<DerivativeExplorer hideCurvePicker hideSecantControls />

Understanding the component

  1. The plot. A 520 × 380 SVG renders x ∈ [−3, 3], y ∈ [−2, 9] with a faint grid and axis labels. The curve is sampled at 201 points and resamples whenever the active curve flips.
  2. The marker. A glowing accent dot rides the curve at (x, f(x)). Its position springs via SPRINGS.snap so drag feels crisp and arrow-key nudges land with a quick, contained settle.
  3. Tangent line. Drawn through (x, f(x)) with slope f'(x) clipped to the visible x-domain. It recolours green when the slope is positive, amber when negative, neutral at zero — sign before number.
  4. Secant overlay. Toggling secant on draws a dashed warning-coloured line from (x, f(x)) to (x + Δx, f(x + Δx)). Shrinking Δx makes the secant converge on the tangent; the readout shows both slopes side by side.
  5. Slope readout. A pill below the chart prints the live slope in tabular-num mono, recolouring with the tangent. When the secant is on, it also prints the secant slope for comparison.
  6. Curve picker. A radiogroup of three chips for y = x², y = x³, y = sin(x). Picking a curve preserves x.
  7. Controlled + uncontrolled, four times. activeCurve, x, showSecant, and deltaX each accept a controlled value (with a matching onChange) or a default… uncontrolled initialiser.

Props

PropTypeDefaultDescription
activeCurve"x²" | "x³" | "sin(x)"Controlled active curve.
defaultActiveCurve"x²" | "x³" | "sin(x)""x²"Uncontrolled initial curve.
onActiveCurveChange(c) => voidFires when the curve changes.
xnumberControlled x position (clamped to [-3, 3]).
defaultXnumber1Uncontrolled initial x.
onXChange(x) => voidFires on every drag / keyboard nudge.
showSecantbooleanControlled secant flag.
defaultShowSecantbooleanfalseUncontrolled initial secant flag.
onShowSecantChange(show) => voidFires when the toggle flips.
deltaXnumberControlled Δx (clamped to (0, 1]).
defaultDeltaXnumber0.5Uncontrolled initial Δx.
onDeltaXChange(Δx) => voidFires when Δx changes.
hideCurvePickerbooleanfalseHide the curve chips.
hideSecantControlsbooleanfalseHide the secant toggle + Δx slider row.
transitionTransitionSPRINGS.snapSpring for the marker + slope readout.
classNamestringMerged onto the root <div> via cn().

Accessibility

  • The SVG is role="img" with an aria-label summarising curve, x, and slope.
  • The drag handle is role="slider" with full keyboard support: / nudge 0.1, Shift+← / Shift+→ nudge 0.5, Home and End jump to the domain bounds.
  • An aria-live="polite" summary mirrors the visible slope (and the secant slope when active) so screen-reader users get the same readout.
  • The curve picker is a role="radiogroup" of three role="radio" chips with data-state="on" | "off".
  • The secant toggle is aria-pressed with data-state="on" | "off".
  • Colour is never the only signal — slope is announced numerically in the live region.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/viz/DerivativeExplorer.tsx). The source bundled the chart with a Widget lesson chrome, a three-mode strip (Explore / Predict / Challenge), prediction inputs with feedback badges, target-slope mini-challenges, bookmark presets, and an undo / redo history — none of which generalise outside the lesson. The viz extract keeps the underlying interactive primitive (curve picker, draggable marker, tangent, optional secant), drops the lesson scaffolding, swaps the project-specific SvgLabel / ChallengeBtn / LabeledSlider for raw <text> + token-styled chips + a native <input type="range">, remaps the colour palette from --color-accent-500 / --color-ink-* / --color-warn-500 to our --cb-accent / --cb-fg-muted / --cb-warning semantic tokens, and re-keys every spring to SPRINGS.snap.