Freeze and Slice
A two-panel partial-derivative explainer on f(x, y) = x² + y². The left panel shows a contour plot with a fixed evaluation point. The right panel is empty until the learner clicks Freeze x or Freeze y — at which point a vertical or horizontal slice line appears on the contour, and the corresponding 1D parabolic slice shows up on the right with a tangent at the evaluation point. The tangent's slope IS the partial derivative.
At the default point (2, 1): freezing x gives the slice f(2, y) = 4 + y² with tangent slope 2y = 2 at y = 1 — that's ∂f/∂y. Freezing y gives f(x, 1) = x² + 1 with tangent slope 2x = 4 at x = 2 — that's ∂f/∂x. The ∂f/∂x slice is steeper because x = 2 is farther from the center than y = 1.
f(x, y) = x² + y² — a bowl centered at the origin. The point sits at (2, 1) where f = 5. Freeze x or y to slice the surface and reveal a partial derivative.
Installation
npx shadcn@latest add https://craftbits.dev/r/freeze-and-slice.jsonUsage
import { FreezeAndSlice } from "@craft-bits/viz/freeze-and-slice";
<FreezeAndSlice />Evaluate at a different point:
<FreezeAndSlice point={{ x: 1.5, y: -0.5 }} />Start with one variable already frozen:
<FreezeAndSlice defaultPhase="freeze-x" />React to phase changes:
<FreezeAndSlice
onPhaseChange={(phase) => {
/* now showing: phase */
}}
/>Understanding the component
- The contour plot. The left panel is a symmetric window around the origin with five concentric contour circles (since
f(x, y) = x² + y² = cis a circle of radius√c). A single accent-coloured dot marks the evaluation point and gently pulses in the idle state to draw the eye. - The slice plot. The right panel is empty in the
idlephase. Once a variable is frozen, it renders a parabolic slicef(P_x, y)orf(x, P_y)over the same variable domain, with a tangent line drawn at the evaluation point. - Freezing a variable. Clicking
Freeze xpaints a vertical dashed line atx = P_xon the contour, the contour circles fade to dim, the slice curve and tangent fade in on the right, and the narration switches to explain∂f/∂y. Clicking again toggles back to idle.Freeze yworks symmetrically. - The tangent IS the partial. The tangent's slope on the slice plot is computed from the closed-form derivative (
2yor2x) and never re-fits. That's the point of the visualization — a partial derivative is just an ordinary derivative on a slice. - Visual link between panels. Where the vertical/horizontal slice line crosses each contour circle on the left, a small accent-coloured dot appears. They're the same level sets read in 1D. A faint dashed line connects the panels along the mid-height to make the relationship explicit.
- Phase palette.
freeze-xuses the accent token,freeze-yuses the warning token so the two slices stay visually distinct. The narration background tints with the active colour so the eye lands on it after a click. - Reduced motion. Under
prefers-reduced-motion: reduce, slice / tangent / dot entrances skip the fade-in and the idle breathing pulse on the evaluation point disables.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
point | { x: number; y: number } | { x: 2, y: 1 } | Point at which the partials are evaluated and the tangent is drawn. |
defaultPhase | FreezeAndSlicePhase | "idle" | "idle", "freeze-x", or "freeze-y". |
transition | Transition | SPRINGS.smooth | Override the slice / tangent entrance transition. |
onPhaseChange | (phase) => void | — | Fires whenever the phase changes via the buttons. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The plot SVG is
role="img"with anaria-labelsummarising the current point, the frozen variable (if any), and the partial-derivative value. - The freeze buttons are real
<button>elements witharia-pressedreflecting whether that variable is currently frozen. - A live region (
aria-live="polite") below the buttons announces the current frozen state and the partial-derivative value whenever the phase changes. - The narration paragraph also has
aria-live="polite"and reads as plain prose; it is the canonical explanation for each phase. - Colour is never the only signal — the phase is also encoded in the narration prose, the button label flip ("Freeze x" / "Unfreeze x"), and the live-region status text.
- Motion respects
prefers-reduced-motion: reduce— the slice and tangent entrances skip the fade-in, and the idle breathing pulse on the evaluation point disables.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/math/FreezeAndSlice.tsx). The source was a tightly bundled lesson component — it consumedSvgLabelandChallengeBtnfrom the lesson chrome, depended on per-track lesson palette tokens, and inlined its own ad-hoc spring names. The viz extract drops the lesson chrome, remaps every colour tovar(--cb-*)semantic tokens so consumer themes repaint freely, exposes the evaluation point and starting phase as props, and re-keys all entrance animations to the canonicalSPRINGS.*so motion comes from the same place as every other craft-bits component.