Stride Padding Explorer

A stride + padding viz: render a square input feature map, drop the kernel in its top-left receptive field, and show — numerically and graphically — what the canonical convolution-output-size formula floor((H + 2p − K) / s) + 1 resolves to as you adjust kernel size, stride, and padding. Use it to teach "same" vs "valid" convolution, the discrete output-shape arithmetic of CNN layers, or how downsampling emerges from stride.

Stride and padding explorer: 7×7 input, 3×3 kernel, stride 1, padding 1.Input 7 by 7, kernel 3 by 3, stride 1, padding 1. Output is 7 by 7.
Input (7×7, pad=1)
kernel 3×3stride 1padding 1output 7×7

floor((7 + 2·13) / 1) + 1 = 7

Customize
Input
7×7
Kernel
3×3
1
1

Installation

npx shadcn@latest add https://craftbits.dev/r/stride-padding-explorer.json

Usage

import { StridePaddingExplorer } from "@craft-bits/core";
 
<StridePaddingExplorer
  inputSize={7}
  defaultKernelSize={3}
  defaultStride={1}
  defaultPadding={1}
/>;

Drive every knob from outside the component — e.g. synced to a lesson's slider rail:

const [kernelSize, setKernelSize] = useState(3);
const [stride, setStride] = useState(1);
const [padding, setPadding] = useState(0);
 
<StridePaddingExplorer
  inputSize={7}
  kernelSize={kernelSize}
  onKernelSizeChange={setKernelSize}
  stride={stride}
  onStrideChange={setStride}
  padding={padding}
  onPaddingChange={setPadding}
/>;

Use it to demonstrate "same"-mode output preservation:

<StridePaddingExplorer
  inputSize={7}
  defaultKernelSize={3}
  defaultStride={1}
  defaultPadding={1}
/>;

Understanding the component

  1. One formula, three knobs. The output dimension is floor((H + 2p − K) / s) + 1, where H is inputSize, K is kernelSize, s is stride, and p is padding. Every readout in the component is derived from that single expression — change a knob and watch the number update.
  2. Padded grid, real cells. The component renders the full (H + 2p) × (H + 2p) padded grid. Real input cells get a magnitude-tinted accent fill; padding cells render with a dashed border, a muted background, and a 0 label so it's visually unambiguous what padding is.
  3. Kernel overlay at the first receptive field. The kernel is drawn as a single motion.div overlaying the top-left receptive field (output cell (0, 0)). With padding > 0 the overlay starts inside the padding ring — sliding via transform: translate keeps motion on the compositor and animates kernel resizes cleanly.
  4. SPRINGS.smooth for layout changes. The kernel overlay animates with SPRINGS.smooth from @craft-bits/core/motion, so changes to kernelSize or padding morph smoothly instead of snapping.
  5. Reduced-motion fallback. With prefers-reduced-motion: reduce the kernel overlay snaps instantly into position — users still see every state change, just without animation.

Props

PropTypeDefaultDescription
inputSizenumber7Side length of the square input feature map (in cells).
kernelSizenumberControlled square kernel side. Pair with onKernelSizeChange.
defaultKernelSizenumber3Uncontrolled initial kernel size.
onKernelSizeChange(kernelSize: number) => voidFires when the kernel size changes.
stridenumberControlled stride. Pair with onStrideChange.
defaultStridenumber1Uncontrolled initial stride.
onStrideChange(stride: number) => voidFires when the stride changes.
paddingnumberControlled padding ring thickness. Pair with onPaddingChange.
defaultPaddingnumber0Uncontrolled initial padding.
onPaddingChange(padding: number) => voidFires when the padding changes.
cellSizenumber36Pixel size of a single grid cell.
transitionTransitionSPRINGS.smoothSpring for the kernel overlay's resize / reposition.
classNamestringMerged onto the root <div> via cn().

Accessibility

  • The whole 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 recomputed output dimension every time kernelSize, stride, or padding changes — so screen-reader users hear floor((H + 2p − K) / s) + 1 resolve.
  • Padding cells render with a visible dashed border and a 0 label, never relying on color alone to distinguish padding from real input.
  • The kernel overlay draws a solid 2px accent outline plus a translucent fill, so it remains visible against any palette.
  • prefers-reduced-motion: reduce snaps the kernel overlay instead of animating it.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/viz/StridePaddingExplorer.tsx). Stripped the lesson-specific Explore / Predict / Challenge mode strip, the predict-round helpers, the random-challenge target generator, the Widget chrome (bookmarks, undo/redo, eyebrow/premise/caption/formula plumbing), the auto-play step counter, the inline ModeStrip / ChallengeBtn / FeedbackBadge dependencies, and every --color-* token from CA's theme. Generalised to a pure inputSize / kernelSize / stride / padding primitive with controlled + uncontrolled state pairs on each knob, rebuilt against --cb-* semantic tokens and SPRINGS.smooth from @craft-bits/core/motion.