Sparsity Mask
A teaching visualisation for the sparsity patterns at the heart of structured pruning, sparse attention kernels, and GPU-friendly sparse matmul. The component renders a rows x cols grid where each cell is either kept (filled with cb-accent) or zeroed (filled with cb-bg-elevated and outlined with a dashed cb-border-strong stroke). A small badge above the grid declares the active pattern, and a kept-vs-total readout makes the ratio explicit.
2:4 sparsity mask, 8 by 8. 32 of 64 cells kept, 32 zeroed (50% sparse).
Sparsity mask32 / 64 kept· 50% sparse
Customize
Grid
8
8
Pattern
2:4
50%
42
Cursor reveal
32
Installation
npx shadcn@latest add https://craftbits.dev/r/sparsity-mask.jsonUsage
import { SparsityMask } from "@craft-bits/core";
<SparsityMask rows={8} cols={8} pattern="2:4" />Switch to unstructured random sparsity (an inline LabeledSlider exposes the rate):
<SparsityMask
rows={8}
cols={16}
pattern="random"
defaultSparsityRate={0.6}
/>Drive a row-major cursor so the mask "fills in" as the lesson progresses:
<SparsityMask
rows={8}
cols={8}
pattern="2:4"
currentBlock={{ row: 3, col: 5 }}
/>Pass a fully custom mask:
<SparsityMask
rows={4}
cols={4}
pattern={{
mask: [
[true, false, true, false],
[false, true, false, true],
[true, false, true, false],
[false, true, false, true],
],
}}
/>Anatomy
- Two cell states, two visual treatments. Kept cells are solid
cb-accentrectangles; zeroed cells arecb-bg-elevatedrectangles with a dashedcb-border-strongoutline. The dashed border is the contract — it reads as "this cell exists but contributes nothing" without relying on colour alone. - Three pattern families.
"2:4"and"4:8"implement NVIDIA-style structured sparsity, picking M survivors out of every N-wide row block."random"runs a deterministic LCG over each cell so the visible mask is stable across mounts but still varies withseed.{ mask }accepts a fully bespoke boolean grid. - Deterministic by default. All randomness flows through a seeded LCG keyed on seed, row, and column. Re-mounting the same component yields the identical mask, which is what you want inside an MDX explainer.
- Optional cursor reveal. When
currentBlockis set, cells up to and including that row-col render at full opacity; cells beyond fade to about 18% so the mask appears to fill in progressively. Pair with a parent stepper for animated walkthroughs. - Inline sparsity-rate slider (random only). When
pattern === "random", aLabeledSliderrenders below the grid for tuning the rate live. SetshowSparsitySlider={false}for a static figure, or passsparsityRateplusonSparsityRateChangefor a controlled rate. - SPRINGS.smooth for cell transitions. Opacity transitions animate via a smooth spring from
@craft-bits/core/motion.prefers-reduced-motion: reducecollapses every transition to instant.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
rows | number | 8 | Grid rows, clamped to 1..64. |
cols | number | 8 | Grid columns, clamped to 1..64. |
pattern | "2:4" | "4:8" | "random" | { mask } | "2:4" | Sparsity pattern applied across the grid. |
sparsityRate | number | — | Controlled rate in 0..1. Used by "random". Pair with onSparsityRateChange. |
defaultSparsityRate | number | 0.5 | Uncontrolled initial rate. Used by "random". |
onSparsityRateChange | (rate: number) => void | — | Fires when the inline slider moves. |
showSparsitySlider | boolean | true | Render the inline LabeledSlider (only in "random" mode). |
seed | number | 42 | Deterministic seed for the LCG that drives "random" and intra-block selection inside structured patterns. |
currentBlock | SparsityMaskBlock | — | Row-major cursor — cells beyond it fade to about 18% opacity. |
transition | Transition | SPRINGS.smooth | Spring for cell-opacity transitions. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The root is
role="figure"witharia-labelledbypointing at the heading andaria-describedbyat a visually-hiddenaria-live="polite"summary. - The summary announces grid shape, pattern, kept-vs-total counts, and the resulting sparsity percentage whenever the mask changes.
- Every cell carries a
data-state="kept"ordata-state="zeroed"attribute so styling never depends on colour alone — the dashed border on zeroed cells is the redundant visual signal. - The inline
LabeledSliderexposes nativearia-valuemin/aria-valuemax/aria-valuenow/aria-valuetextso keyboard arrows step the rate and screen readers narrate the value. prefers-reduced-motion: reducecollapses opacity transitions to instant.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/nn/SparsityMask.tsx). Re-architected from the source's stateful ReLU-demo (12 pre-activation bars, an "apply ReLU" button, staggered crush animation, project palette vars,SvgLabelandChallengeBtndependencies) into a pure declarative grid component. Generalised the fixed 1-D 12-bar layout to an arbitrary rows-by-cols grid, replaced the "negative pre-activations crushed by ReLU" framing with explicit pattern values so the component teaches the more general sparsity concept (structured pruning, sparse attention, custom masks). Added deterministic seeded mask generation, an optional row-majorcurrentBlockcursor for animated reveal, and an inlineLabeledSliderfor tuning the random rate live.