Convolution Animator

A 2D convolution viz: render an input matrix, drop a kernel on top, and animate the kernel sliding across the input in row-major order. The receptive field at each step is highlighted with a translucent accent overlay; the output matrix fills in one cell at a time as the kernel advances. Use it to teach CNNs, image filters, feature extraction, or how a kernel's weights determine the response on a given neighbourhood.

Convolution animator: 5×5 input, 3×3 kernel, stride 1, padding 0.Step 1 of 9. Output (0, 0) = 15.
Input (5×5)
0
0
5
5
5
0
0
5
5
5
0
0
5
5
5
0
0
5
5
5
0
0
5
5
5
Kernel (3×3)
-1
0
1
-1
0
1
-1
0
1
Output (3×3)
15
Customize
Kernel
edge detect
Playback
600

Installation

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

Usage

import { ConvolutionAnimator } from "@craft-bits/core";
 
const input = [
  [0, 0, 5, 5, 5],
  [0, 0, 5, 5, 5],
  [0, 0, 5, 5, 5],
  [0, 0, 5, 5, 5],
  [0, 0, 5, 5, 5],
];
 
const edgeKernel = [
  [-1, 0, 1],
  [-1, 0, 1],
  [-1, 0, 1],
];
 
<ConvolutionAnimator input={input} kernel={edgeKernel} defaultPlaying />;

Drive playback from outside the component, e.g. synced to a scrollytelling scrubber:

const [step, setStep] = useState(0);
 
<ConvolutionAnimator
  input={input}
  kernel={edgeKernel}
  currentStep={step}
  onCurrentStepChange={setStep}
/>;

Use stride + padding to model "same"-mode downsampling:

<ConvolutionAnimator
  input={image}
  kernel={edgeKernel}
  stride={2}
  padding={1}
/>;

Understanding the component

  1. Row-major slide. currentStep is a single 0-indexed counter that counts output cells. Step 0 is the top-left output, step 1 the next column, etc. The kernel's position in input space is (step / outW, step % outW) * stride.
  2. Translucent overlay over real cells. The input grid renders real <div> cells (numbered, color-tinted by magnitude). The kernel position is one motion.div overlaying the grid — sliding it via transform: translate keeps motion on the compositor and avoids reflowing every cell.
  3. SPRINGS.smooth for the slide. The kernel overlay animates with SPRINGS.smooth from @craft-bits/core/motion — slow enough to read, springy enough to feel like a real slide.
  4. Output fills in cell by cell. Cells before currentStep render their value at full opacity; the current cell highlights in --cb-accent-muted; future cells render dim and showing .
  5. Stride + padding aware. Output dimensions follow the canonical floor((H + 2p - K) / s) + 1 formula; padding zero-pads the input on every side before sliding.
  6. setInterval autoplay. When playing, the component advances currentStep every playSpeed ms via a single window.setInterval. The interval is cleaned up on unmount, on pause, and whenever the step or dimensions change.
  7. Reduced-motion fallback. With prefers-reduced-motion: reduce, the kernel overlay snaps to position with no spring, and autoplay is disabled.

Props

PropTypeDefaultDescription
inputreadonly (readonly number[])[]required2D input matrix, rows × cols.
kernelreadonly (readonly number[])[]required2D convolution kernel.
stridenumber1Step between consecutive kernel positions.
paddingnumber0Zero-padding around the input on every side.
currentStepnumberControlled step (0-indexed).
defaultCurrentStepnumber0Uncontrolled initial step.
onCurrentStepChange(step: number) => voidFires on tick and on external changes.
playingbooleanControlled play state. Pair with onPlayingChange.
defaultPlayingbooleanfalseUncontrolled initial play state.
onPlayingChange(playing: boolean) => voidFires when play / pause flips.
playSpeednumber600Milliseconds between autoplay steps.
showOutputbooleantrueRender the output matrix to the right of the input.
cellSizenumber40Pixel size of an input cell.
transitionTransitionSPRINGS.smoothSpring for the kernel overlay slide.
classNamestringMerged onto the root <div> via cn().

Accessibility

  • The figure is role="figure" with a visually hidden caption announcing the input dimensions, kernel dimensions, stride, and padding.
  • An aria-live="polite" summary announces the current step and the value of the output cell that just lit up whenever the kernel advances.
  • Color is never the only signal — every output cell renders its numeric value (or when not yet computed); the kernel overlay also draws a solid 2px outline in --cb-accent so it remains visible at any color scale.
  • prefers-reduced-motion: reduce snaps the kernel overlay to position and disables autoplay; users can still scrub via the controlled currentStep prop.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/viz/ConvolutionAnimator.tsx). Stripped the lesson-specific Explore/Predict mode strip, 6-round predict quiz, narration heuristics, kernel presets, and click-to-edit input. Generalised to a pure convolution primitive: arbitrary input + kernel, stride / padding awareness, controlled + uncontrolled state pairs for currentStep and playing, and a playSpeed knob.