Forward Pass Animator

A step-by-step animator for the simplest possible model — a line y = m·x + b. The learner taps one of the input buttons, watches the x-slot fill, the multiply readout appear, the add readout appear, and the result settle. Every completed pass deposits a dot at (x, y) on a mini scatter plot. Once three dots exist, the underlying line of the model is revealed dashed-through behind them, driving home the insight that the model IS the line.

This is the canonical introduction to "what is a forward pass." The model is a function with two learnable parameters; training is what finds the m and b that fit the data — but before any of that, the learner needs to feel viscerally that the function is just doing arithmetic, repeatedly, deterministically.

Forward pass animator for the model y equals 3 x plus 1.
Select an x value to compute y.

Pick an input x. Watch the model compute its prediction step by step.

Customize
Model
3
1

Installation

npx shadcn@latest add https://craftbits.dev/r/forward-pass-animator.json

Usage

import { ForwardPassAnimator } from "@craft-bits/viz/forward-pass-animator";
 
<ForwardPassAnimator />

Change the model:

<ForwardPassAnimator m={2} b={5} />

Subscribe to compute events to drive a sibling chart or transcript:

<ForwardPassAnimator
  onCompute={(history) => {
    /* read history.map((h) => h.y) */
  }}
/>

Understanding the component

  1. Equation row. The model y = [m] × [x] + [b] is rendered as three rounded slots. The m and b slots are pre-filled and stay static; the x slot starts holding the placeholder glyph x and is what the learner fills by tapping a button.
  2. Tap an input. Tapping x = k snaps k into the x-slot, then plays a four-stage animation: slot-fill, multiply readout, add readout, settled result. Each stage is driven imperatively via motion's animate() so the SVG never re-renders per frame.
  3. Phase machine. The animator classifies its own narrative phase from the history length: observe (no computations yet), computing (one or two done), insight (three or more done — the line appears). The phase drives the accent colour of the narration paragraph and the dot-pulse callouts.
  4. Scatter plot. Every completed pass deposits a dot at (x, y) on the mini plot underneath the equation. After three dots, a dashed line traces y = m·x + b across the plot — the dots literally fall on it, which is the aha of the lesson.
  5. Observe-phase breathing pulse. When no input has been picked yet, a small ring around the empty x slot breathes in and out so the eye lands on the next thing to do. The pulse disables under prefers-reduced-motion: reduce.
  6. Reduced motion. Under prefers-reduced-motion: reduce, the four-stage animation collapses to an instant attribute set, the dot-pop spring becomes a snap, and the observe-phase pulse is suppressed.

Props

PropTypeDefaultDescription
mnumber3Slope of the model.
bnumber1Intercept of the model.
xChoicesreadonly number[][1, 2, 5, 10]The set of input values exposed as tap-targets.
transitionTransitionSPRINGS.snapOverride the per-stage animation transition.
dotTransitionTransitionSPRINGS.bouncyOverride the dot-pop transition on the scatter plot.
onCompute(history) => voidFires after each computation completes, with the full history.
onReset() => voidFires when the user clicks Reset.
classNamestringMerged onto the root via cn().

Accessibility

  • The plot SVG is role="img" with an aria-label summarising the model and the number of computations completed.
  • Every input button has a visible label and is reachable in tab order; focus shows a visible ring via :focus-visible.
  • A live region below the buttons announces the most recent computation as plain prose so screen-reader users get the same outcome as sighted users.
  • 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 text and the live-region status.
  • Motion respects prefers-reduced-motion: reduce — the four-stage animation collapses to an instant attribute set, the dot-pop becomes a snap, and the observe-phase breathing pulse is suppressed.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/math/ForwardPassAnimator.tsx). The source was a tightly bundled lesson component — it consumed SvgLabel from the SVG primitives and ChallengeBtn from the lesson chrome, hardcoded the slope, intercept, and input choices to the canonical y = 3x + 1 walk-through, and depended on per-track lesson palette tokens. The viz extract drops the lesson chrome (raw <text> plus token-styled buttons), parameterises m, b, and xChoices so the animator works for any linear model, remaps the colour palette to var(--cb-*) semantic tokens so consumer themes repaint freely, and re-keys the per-stage springs to SPRINGS.snap and SPRINGS.bouncy so all motion comes from the same place as every other craft-bits component.