Partial Derivative Explorer
Visualise both partial derivatives of a two-variable function f(x, y) as side-by-side slices. The left panel renders f(·, y₀) along x with the tangent at x₀ (slope = ∂f/∂x); the right panel renders f(x₀, ·) along y with the tangent at y₀ (slope = ∂f/∂y). Partials are estimated by symmetric finite differences, so any caller-supplied fn works without needing an analytical derivative.
Partial derivatives of f(x, y)x = 1.00 · y = 1.00 · f = 0.000
∂f/∂xy = 1.00
∂f/∂yx = 1.00
∂f/∂x ≈ 0.000∂f/∂y ≈ 0.000dh = 0.01
1.00
1.00
Customize
Function
x·y − x²/2 − y²/2
Evaluation point
1.00
1.00
Tangents
Installation
npx shadcn@latest add https://craftbits.dev/r/partial-derivative-explorer.jsonUsage
import { PartialDerivativeExplorer } from "@craft-bits/core";
<PartialDerivativeExplorer defaultX={1} defaultY={1} />Probe a saddle and watch the two slices respond independently:
<PartialDerivativeExplorer
fn={(x, y) => x * x - y * y}
xRange={[-2, 2]}
yRange={[-2, 2]}
defaultX={0.5}
defaultY={0.5}
/>Drive x and y from outside:
const [x, setX] = useState(1);
const [y, setY] = useState(1);
<PartialDerivativeExplorer
fn={(x, y) => Math.sin(x) * Math.cos(y)}
x={x}
y={y}
onXChange={setX}
onYChange={setY}
/>Understanding the component
- Two slices, two panels. For the current evaluation point
(x₀, y₀)the left panel rendersf(·, y₀)overxRangeand the right panel rendersf(x₀, ·)overyRange. Each panel auto-fits its value axis to its sampled slice and pads by 15% so the curve never grazes the frame. - Tangent lines visualise the partials. The left panel's tangent at
x₀has slope∂f/∂x; the right panel's tangent aty₀has slope∂f/∂y. Both span the full visible axis so the slope is easy to read off. - Symmetric finite differences. Each partial is estimated as
(f(x+dh, y) - f(x-dh, y)) / (2·dh)with a configurabledh(default0.01). Second-order accurate; works for anyfn. - Spring transitions. Curves, tangents, and markers animate with
SPRINGS.smooth.prefers-reduced-motion: reducecollapses every spring to an instant swap. - Auto-clamped sliders.
xRangeandyRangedriveLabeledSlidermin / max / step. Stale controlled values outside the range are clamped on render so the curve always stays sensible. - Controlled and uncontrolled, twice. Both
xandyacceptvalue+onChangefor controlled use, ordefault*for uncontrolled.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
fn | (x: number, y: number) => number | (x,y) => x*y - x²/2 - y²/2 | Two-variable function under exploration. |
xRange | readonly [number, number] | [-2, 2] | Visible x-axis domain. |
yRange | readonly [number, number] | [-2, 2] | Visible y-axis domain. |
x | number | — | Controlled x evaluation point. |
defaultX | number | midpoint of xRange | Uncontrolled initial x. |
onXChange | (x: number) => void | — | Fires on every x slider drag. |
y | number | — | Controlled y evaluation point. |
defaultY | number | midpoint of yRange | Uncontrolled initial y. |
onYChange | (y: number) => void | — | Fires on every y slider drag. |
showTangents | boolean | true | Render tangent lines on both panels. |
dh | number | 0.01 | Finite-difference step for partial estimation. |
transition | Transition | SPRINGS.smooth | Spring for tangent / marker follow. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The whole figure is
role="figure"witharia-labelledbyandaria-describedbypointing at the heading and live summary. - Each panel is
role="img"with anaria-labelnaming the slice and pinned-variable value. - An
aria-live="polite"summary above the panels reads outx,y, andf(x, y)whenever anything changes. - Sliders are native
<input type="range">— full keyboard (←/→,Home/End,Page Up/Page Down) and AT support out of the box. - Animation respects
prefers-reduced-motion: reduce.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/math/PartialDerivativeExplorer.tsx). Stripped the lesson-specific stage state machine, narration heuristics, pinned-variable preset buttons, drag-on-curve handle, andf(x, y) = x²yhard-coding; generalised to any caller-providedfn, swapped the analytical derivative for symmetric finite differences, replaced bespoke pin buttons withLabeledSliders, and added controlled / uncontrolled state pairs for bothxandy.