Pooling Explorer
A 2D pooling viz: render an input feature map, slide a poolSize × poolSize window across it in row-major order, and reduce each window with max, avg, or min. The window's contributing cell(s) glow in the input grid; the output matrix fills in one cell at a time as the window advances. Use it to teach CNN pooling layers, downsampling, translation invariance, or how the choice of pooling op shapes the response on a given neighbourhood.
Pooling explorer: 4×4 input, 2×2 Max pool, stride 2.Step 1 of 4. Max pool output (0, 0) = 8.
Input (4×4)
1
0
3
2
0
8
2
1
3
1
0
5
0
2
6
1
Pool
Max · 2×2
Output (2×2)
8
—
—
—
Customize
Pooling
max
2×2
Playback
600
Installation
npx shadcn@latest add https://craftbits.dev/r/pooling-explorer.jsonUsage
import { PoolingExplorer } from "@craft-bits/core";
const input = [
[1, 0, 3, 2],
[0, 8, 2, 1],
[3, 1, 0, 5],
[0, 2, 6, 1],
];
<PoolingExplorer input={input} poolSize={2} defaultPool="max" defaultPlaying />;Drive playback and pooling op from outside the component:
const [step, setStep] = useState(0);
const [pool, setPool] = useState<"max" | "avg" | "min">("max");
<PoolingExplorer
input={input}
poolSize={2}
pool={pool}
onPoolChange={setPool}
currentStep={step}
onCurrentStepChange={setStep}
/>;Use overlapping windows with a smaller stride:
<PoolingExplorer input={image} poolSize={3} stride={2} />;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 window's position in input space is(step / outW, step % outW) * stride. - Three reductions.
maxreturns the largest value in the window;minthe smallest;avgthe arithmetic mean (rounded to two decimals). Formaxandmin, the cell(s) matching the extreme value are highlighted as "contributing" —avgtreats every cell equally. - Translucent overlay over real cells. The input grid renders real
<div>cells (numbered, color-tinted by magnitude). The window position is onemotion.divoverlaying the grid — sliding it viatransform: translatekeeps motion on the compositor and avoids reflowing every cell. SPRINGS.smoothfor the slide. The window 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 show—. - Stride aware.
stridedefaults topoolSize(non-overlapping); set lower for overlapping windows. Output dimensions followfloor((H - poolSize) / stride) + 1. 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 window 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. |
poolSize | number | 2 | Side length of the square pooling window. |
stride | number | poolSize | Step between consecutive window positions. |
pool | "max" | "avg" | "min" | — | Controlled pooling op. |
defaultPool | "max" | "avg" | "min" | "max" | Uncontrolled initial pooling op. |
onPoolChange | (pool) => void | — | Fires when the pooling op changes. |
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 window 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, pooling op, window size, and stride. - An
aria-live="polite"summary announces the current step, pooling op, and the value of the output cell that just lit up whenever the window advances. - Color is never the only signal — every output cell renders its numeric value (or
—when not yet computed); the window overlay also draws a solid 2px outline in--cb-accent, and contributing input cells get an inset 2px ring so they remain visible at any color scale. prefers-reduced-motion: reducesnaps the window overlay to position and disables autoplay; users can still scrub via the controlledcurrentStepprop.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/viz/PoolingExplorer.tsx). Stripped the lesson-specific Explore/Predict mode strip, 6-round predict quiz, narration heuristics, hover-to-trace interaction, and hardcoded 6×6 grid. Generalised to a pure pooling primitive: arbitrary input + window size + stride, max/avg/min ops, controlled + uncontrolled state pairs forpool,currentStep, andplaying, and aplaySpeedknob. Added contributing-cell highlighting so the argmax/argmin link to the input is explicit.