Neuron Dot Product Animator

A nine-phase walk-through of how one neuron computes a dot product, ending in a zoom-out that reveals a linear layer is just this, repeated in parallel. The learner taps Step through phases 0–8: the three input pairs (x[i], w[i]) light up one at a time and contribute to a running sum inside the neuron, an arc fires the sum to the output, then the diagram zooms out to a two-neuron layer and animates both dot products at once. The terminal phase pulses both outputs and reveals y = Wx.

The component owns its own phase machine; Step advances it, and once you reach phase 8 the button becomes Replay and re-arms cleanly.

Neuron dot product animator. Inputs 1, 2, 4. Weight row 1, 0.5, -0.5.
Phase 0 / 8
Phase 0 of 8. One neuron, three inputs. Watch the dot product compute — one pair at a time.

One neuron, three inputs. Watch the dot product compute — one pair at a time.

Customize
Input vector x
1
2
4
Weight row W[0]
1.0
0.5
-0.5

Installation

npx shadcn@latest add https://craftbits.dev/r/neuron-dot-product-animator.json

Usage

import { NeuronDotProductAnimator } from "@craft-bits/viz/neuron-dot-product-animator";
 
<NeuronDotProductAnimator />

Re-skin the model — different weights, different inputs:

<NeuronDotProductAnimator
  W={[[0.7, -0.4, 1.2], [-1.5, 0.6, 0.3]]}
  x={[2, -1, 3]}
/>

Drive a parent reducer off each phase change:

<NeuronDotProductAnimator
  onPhaseChange={(phase) => {
    /* sync with sibling narration, analytics, etc. */
  }}
/>

Understanding the component

  1. Coordinate system. The single-neuron view is a 560 × 200 SVG with three inputs on the left, the neuron body in the centre, and the output on the right. The layer view is 560 × 260 and uses the same x-coordinates so the AnimatePresence swap reads as a zoom-out, not a context switch.
  2. Phase machine. Internal state is the phase index 0 to 8. Step advances; Replay resets to 0. Each phase has its own choreography (intro / pair 0 / pair 1 / pair 2 / sum lands / layer intro / zoom out / layer animates / terminal pop).
  3. Imperative animation. Every per-frame attribute write lands on a ref via motion's animate()strokeDashoffset for the connection draw, opacity for chips and glows, scale for the output pop. React only re-renders on phase changes, so the SVG itself never tears.
  4. Connection palette. The three input/weight pairs cycle through --cb-accent, --cb-warning, and --cb-error so they stay distinguishable independent of theme. Negative products colour their chip with --cb-error regardless of pair index, so the eye reads "this contribution pulled the sum down."
  5. Layer view. Phase 6 mounts the layer-view SVG and waits 50ms for refs to bind, then phase 7 draws all six connections in parallel with a tight 0.04s stagger, fills both Wx sums simultaneously, and pops both outputs.
  6. Reduced motion. Under prefers-reduced-motion: reduce, every phase collapses to an instant attribute set: the connection lines snap to their drawn state, the chips appear without slide, the arc and output skip their tweens, and the layer-view crossfade still fires but every internal animation is bypassed.

Props

PropTypeDefaultDescription
Wreadonly [readonly [number, number, number], readonly [number, number, number]][[1, 0.5, -0.5], [2, -1, 0.5]]2 × 3 weight matrix. Row 0 drives the single-neuron walk; row 1 enters at phase 6.
xreadonly [number, number, number][1, 2, 4]Three-element input vector.
transitionTransitionSPRINGS.bouncyOverride the chip / output pop spring.
onPhaseChange(phase) => voidFires after each Step (or Replay) with the new phase index.
onReset() => voidFires when the user clicks Replay.
classNamestringMerged onto the root via cn().

Accessibility

  • The active SVG has role="img" and an aria-label summarising the inputs, weight row, and current phase. The layer-view label also includes both output values once they've computed.
  • A live region below the buttons announces the current phase index and narration prose so screen-reader users get the same narrative 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 — every phase change updates the narration text and the live-region status as well as the SVG.
  • The Step / Replay button has a visible focus ring via :focus-visible and is the only operable control, so the entire animator is reachable in one Tab from the surrounding flow.
  • Motion respects prefers-reduced-motion: reduce — every staged animation collapses to an instant attribute set.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/math/NeuronDotProductAnimator.tsx). The source was a tightly bundled lesson component — it consumed SvgLabel for every text run and ChallengeBtn for the Step button, depended on per-track lesson palette tokens, and inlined an ad-hoc EASINGS.out import. The viz extract drops the lesson chrome (raw <text> plus a token-styled button), remaps the colour palette to var(--cb-*) semantic tokens so consumer themes repaint freely, re-keys the pop spring to the canonical SPRINGS.bouncy, and replaces the project-specific easing import with a literal cubic-bezier so the component carries no project-specific motion import.