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.jsonUsage
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
- Row-major slide.
currentStepis 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. - Translucent overlay over real cells. The input grid renders real
<div>cells (numbered, color-tinted by magnitude). The kernel position is onemotion.divoverlaying the grid — sliding it viatransform: translatekeeps motion on the compositor and avoids reflowing every cell. SPRINGS.smoothfor the slide. The kernel overlay animates withSPRINGS.smoothfrom@craft-bits/core/motion— slow enough to read, springy enough to feel like a real slide.- Output fills in cell by cell. Cells before
currentSteprender their value at full opacity; the current cell highlights in--cb-accent-muted; future cells render dim and showing—. - Stride + padding aware. Output dimensions follow the canonical
floor((H + 2p - K) / s) + 1formula; padding zero-pads the input on every side before sliding. setIntervalautoplay. Whenplaying, the component advancescurrentStepeveryplaySpeedms via a singlewindow.setInterval. The interval is cleaned up on unmount, on pause, and whenever the step or dimensions change.- Reduced-motion fallback. With
prefers-reduced-motion: reduce, the kernel overlay snaps to position with no spring, and autoplay is disabled.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
input | readonly (readonly number[])[] | required | 2D input matrix, rows × cols. |
kernel | readonly (readonly number[])[] | required | 2D convolution kernel. |
stride | number | 1 | Step between consecutive kernel positions. |
padding | number | 0 | Zero-padding around the input on every side. |
currentStep | number | — | Controlled step (0-indexed). |
defaultCurrentStep | number | 0 | Uncontrolled initial step. |
onCurrentStepChange | (step: number) => void | — | Fires on tick and on external changes. |
playing | boolean | — | Controlled play state. Pair with onPlayingChange. |
defaultPlaying | boolean | false | Uncontrolled initial play state. |
onPlayingChange | (playing: boolean) => void | — | Fires when play / pause flips. |
playSpeed | number | 600 | Milliseconds between autoplay steps. |
showOutput | boolean | true | Render the output matrix to the right of the input. |
cellSize | number | 40 | Pixel size of an input cell. |
transition | Transition | SPRINGS.smooth | Spring for the kernel overlay slide. |
className | string | — | Merged 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-accentso it remains visible at any color scale. prefers-reduced-motion: reducesnaps the kernel overlay to position and disables autoplay; users can still scrub via the controlledcurrentStepprop.
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 forcurrentStepandplaying, and aplaySpeedknob.