Chain Rule Stepper

Walks through differentiating h(x) = f(g(x)) one step at a time. The canonical 4-step walkthrough is: (1) identify the outer f and inner g, (2) compute g'(x), (3) compute f'(g(x)), (4) multiply through to get h'(x) = f'(g(x)) · g'(x). Each step highlights the relevant subterm. Built for teaching the chain rule rigorously to ML students who need it for backpropagation.

Step 1 of 4.
Chain rulestep 01 / 04
Step 1
sin()

Outer function f(u) = sin(u); inner function g(x) = x².

Customize
Cursor
1 / 4
Playback

Installation

npx shadcn@latest add https://craftbits.dev/r/chain-rule-stepper.json

Usage

import { ChainRuleStepper } from "@craft-bits/core";
 
<ChainRuleStepper defaultCurrentStep={0} />

Customise the function labels (still using the abstract 4-step walkthrough):

<ChainRuleStepper outerLabel="σ" innerLabel="w·x + b" variableLabel="x" />

Provide concrete steps for a specific function — e.g. h(x) = sin(x²):

import { ChainRuleStepper, type ChainRuleStep } from "@craft-bits/core";
 
const steps: readonly ChainRuleStep[] = [
  {
    label: "Identify outer and inner",
    expression: <span>sin(x²)</span>,
    explanation: "Outer: sin. Inner: x².",
  },
  {
    label: "Differentiate the inner",
    expression: <span>g'(x) = 2x</span>,
  },
  {
    label: "Differentiate the outer",
    expression: <span>f'(g(x)) = cos(x²)</span>,
  },
  {
    label: "Multiply through",
    expression: <span>h'(x) = cos(x²) · 2x</span>,
  },
];
 
<ChainRuleStepper
  outerLabel="sin"
  innerLabel="x²"
  composedExpression={<span>sin(x²)</span>}
  steps={steps}
/>

Control the cursor from the outside:

const [step, setStep] = useState(0);
const [playing, setPlaying] = useState(false);
 
<ChainRuleStepper
  currentStep={step}
  onCurrentStepChange={setStep}
  playing={playing}
  onPlayingChange={setPlaying}
  playSpeed={1500}
/>

Understanding the component

  1. Four canonical steps by default. When steps is omitted, the component generates the abstract four-step walkthrough from outerLabel / innerLabel / variableLabel: identify, differentiate inner, differentiate outer, multiply.
  2. Custom steps for concrete examples. Pass any ChainRuleStep[] to override. Each step carries a short label for the step indicator, an expression rendered in the focus card, and an optional explanation paragraph.
  3. Header expression is overridable. The default header is h(x) = f(g(x)). For concrete examples (sin(x²), e^{w·x+b}, …) pass composedExpression so the header doesn't render nonsense like sin(x²(x)).
  4. Step indicator highlights the active step. Numbered pills (1..N) act as a role="tablist"; the active one is accent-coloured. Clicking a pill jumps to that step and pauses autoplay.
  5. Focus card morphs between steps. AnimatePresence with mode="popLayout" cross-fades the expression and explanation. SPRINGS.smooth for card transitions, SPRINGS.snap for the step-indicator scale.
  6. Transport: prev / play / next / scrub. A range input scrubs across the steps; the play button autoplays at playSpeed (default 1200ms). Reaching the last step in autoplay wraps back to the start.
  7. Controlled and uncontrolled, twice. Both currentStep and playing can be controlled (pair with onCurrentStepChange / onPlayingChange) or left to internal state via defaultCurrentStep / defaultPlaying.
  8. Reduced-motion friendly. prefers-reduced-motion: reduce collapses all transitions to instant and disables autoplay.

Props

PropTypeDefaultDescription
outerLabelstring"f"Label for the outer function.
innerLabelstring"g"Label for the inner function.
variableLabelstring"x"Label for the input variable.
stepsreadonly ChainRuleStep[]canonical 4-step walkthroughCustom step list.
composedExpressionReactNodeabstract compositionHeader override for concrete examples.
currentStepnumberControlled step index.
defaultCurrentStepnumber0Uncontrolled initial step.
onCurrentStepChange(step: number) => voidFires on every step change.
playingbooleanControlled play state.
defaultPlayingbooleanfalseUncontrolled initial play state.
onPlayingChange(playing: boolean) => voidFires on play / pause flip.
playSpeednumber1200Milliseconds between autoplay step advances.
transitionTransitionSPRINGS.smoothSpring for the expression card.
classNamestringMerged onto the root <div> via cn().

Accessibility

  • The figure is role="figure" with aria-label="Chain rule walkthrough for h(x) = f(g(x))".
  • An aria-live="polite" summary announces the current step number whenever it changes.
  • The step indicator is a role="tablist" of role="tab" buttons, each tagged aria-selected and data-state="active" | "inactive".
  • The focus card is a role="tabpanel" linked back to its tab via aria-controls.
  • Prev / next / play buttons carry explicit aria-labels; play uses aria-pressed so screen readers track the toggle state.
  • The scrubber input has its own aria-label="Step cursor".
  • Animation respects prefers-reduced-motion: reduce — transitions collapse to instant and autoplay is disabled.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/math/ChainRuleStepper.tsx). Reframed the lesson primitive (which tracked nudge counts through a phase state machine of observe / propagating / chain / insight with colored ripples, narration heuristics, and a Δx preset slider) into a general step-by-step walkthrough primitive: controlled / uncontrolled state pairs on currentStep and playing, custom step lists via a ChainRuleStep[] prop, a configurable header expression, and a setInterval-driven autoplay loop.