Tile Grid Viz
A teaching visualisation for tensor tiling — the pattern at the heart of blocked GEMM, tiled attention, and any hierarchical decomposition that breaks a large matrix into block-sized chunks that fit in a fast memory tier. The component renders an N × M cell grid with thin strokes between cells inside the same tile and thick strokes between tiles. A cursor walks (row, col) row-major over the tile grid: the active tile glows accent, tiles already visited inherit a soft accent tint, and tiles ahead sit plain.
Tile 1 of 16: tile row 1, tile column 1. Tile size 2 × 2.
Tile gridtile 01 / 16
Customize
Matrix
8
8
Tile
2
2
Playback
600
Installation
npx shadcn@latest add https://craftbits.dev/r/tile-grid-viz.jsonUsage
import { TileGridViz } from "@craft-bits/core";
<TileGridViz totalRows={8} totalCols={8} tileRows={2} tileCols={2} />Drive the cursor from outside the component:
const [tile, setTile] = useState({ row: 0, col: 0 });
<TileGridViz
totalRows={8}
totalCols={8}
tileRows={2}
tileCols={2}
currentTile={tile}
onCurrentTileChange={setTile}
playing={false}
/>Slow the sweep down for an explainer, and hide the (row, col) labels:
<TileGridViz
totalRows={12}
totalCols={12}
tileRows={3}
tileCols={3}
playSpeed={1200}
showTileLabels={false}
/>Understanding the component
- Cells inside, tiles outside. Every cell of the underlying
totalRows × totalColsmatrix is drawn; thin half-opacity strokes separate cells in the same tile, full-weight strokes separate tiles. The thick borders are the contract the component teaches — they are where a kernel's data boundaries land. - Row-major sweep. Autoplay advances
(row, col)in row-major order and wraps back to the origin once every tile has been visited. The scrubber exposes the same flat index. - Three tile states. The current tile fills with
--cb-accentand lifts its border to accent weight; past tiles inherit a soft accent tint whose opacity ramps with their distance from the cursor; future tiles sit in--cb-border-mutedat ~8% opacity. - Non-square tiles work.
tileRows ≠ tileColsis supported; tiles on the right and bottom edges are smaller iftotalRows / tileRowsdoesn't divide evenly. The cursor still treats the tile grid as a uniform(tileRowsCount × tileColsCount)lattice. SPRINGS.smoothfor tile transitions. Fill and border-weight transitions animate via a smooth spring from@craft-bits/core/motion.prefers-reduced-motion: reduceparks the cursor on the final tile, pauses autoplay, and collapses every transition to an instant swap.- Pure primitive. The matrix has no numeric values — this is a layout primitive. Pair it with Attention Heatmap if you want real per-cell weights, or with Flash Attention Viz for the full Q / Kᵀ / O tiling story.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
totalRows | number | 8 | Total rows in the underlying matrix — clamped to 1..64. |
totalCols | number | 8 | Total columns in the underlying matrix — clamped to 1..64. |
tileRows | number | 2 | Rows per tile — clamped to 1..totalRows. |
tileCols | number | 2 | Columns per tile — clamped to 1..totalCols. |
currentTile | TileGridCoord | — | Controlled active tile. Pair with onCurrentTileChange. |
defaultCurrentTile | TileGridCoord | { row: 0, col: 0 } | Uncontrolled initial tile. |
onCurrentTileChange | (tile) => void | — | Fires on autoplay tick and manual scrub. |
playing | boolean | — | Controlled play state. Pair with onPlayingChange. |
defaultPlaying | boolean | true | Uncontrolled initial play state. |
onPlayingChange | (playing) => void | — | Fires when play / pause flips. |
playSpeed | number | 600 | Milliseconds between tile advances. |
showTileLabels | boolean | true | Draw (row, col) labels at the center of every tile. Auto-hides on tiles too small to read. |
transition | Transition | SPRINGS.smooth | Spring for fill + border transitions. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The root is
role="figure"witharia-labelledbypointing at the "Tile grid" heading andaria-describedbyat a visually-hiddenaria-live="polite"summary. - The summary announces the current tile index and
(row, col)whenever the cursor advances. - The play / pause button uses
aria-pressed; the label flips between "Play tile sweep" and "Pause tile sweep". - The scrubber is a native
<input type="range">with an explicitaria-label, so keyboard arrows step the cursor and screen readers narrate the value. - Colour is never the only signal — every tile carries a
(row, col)label (when room allows) and the live summary is textual. prefers-reduced-motion: reduceparks the cursor on the final tile, pauses autoplay, and suppresses tile transitions.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/nn/TileGridViz.tsx). Stripped the lesson-specific phase machine, the SRAM-fit narration, the dualN/Bslider panel, theChallengeBtndependency, the breathing pulse, the active-tile glow filter, the row/column hover crosshair, and themax 32 × 32rendering cap. Generalised the fixedSEQ_LENGTHS/BLOCK_SIZESchoice arrays to arbitrarytotalRows / totalCols / tileRows / tileColsand replaced the timed scan animation with a clean row-majorsetIntervalautoplay matching theFlashAttentionVizcursor model.