Heatmap Grid
Cell grid filling by intensity, contribution-graph style. Install with npx remotion-ui@latest add heatmap-grid.
PrimitiveData & mediaAdvanced
$ npx remotion-ui@latest add heatmap-gridA contribution graph that fills in on a diagonal wave.
import { HeatmapGrid } from "@/remotion/primitives/heatmap-grid";
<HeatmapGrid
cells={weeks}
rowLabels={["Mon", "", "Wed", "", "Fri", "", "Sun"]}
columnStaggerInFrames={3.4}
rowStaggerInFrames={1.6}
/>cells is row-major. Ragged rows are padded with empty cells, so a partial
final week needs no placeholder values.
The wave
Cells are staggered by column × columnStaggerInFrames + row × rowStaggerInFrames. Keep the row stagger smaller than the column stagger and
the fill sweeps as a diagonal front. Staggering by flat index instead makes the
fill snake back to the left edge on every new row, which reads as a glitch.
The exit drains along the same diagonal.
Reading intensity
Intensity drives colour and a small scale step. Colour alone is hard to judge
at cell size on a dark stage; the size difference is what lets a busy column
register in peripheral vision. Empty cells stay at emptyColor and never scale
up, so a quiet week stays quiet.
maxValue pins the top of the ramp. Leave it unset and the busiest cell present
defines it — set it explicitly when several grids need to be compared.
Staggering by column plus row makes the fill sweep as a diagonal front; a flat index stagger snakes back to the left edge on every new row and reads as a glitch. Intensity drives colour and a small scale step together — colour alone is hard to judge at cell size on a dark stage.
Agent notes
Install first, then import the copied source component locally. AI guide →
@/remotion/primitives/heatmap-grid- Use when: frame-level motion primitives and reusable animation wrappers.
- Customize: cells, maxValue, cellSize, gap, plus copied source for timing, layout, colors, and typography.
- Rule: do not import this component from the
remotion-uinpm package; it is copied into your project.
Usage
import { HeatmapGrid } from "@/remotion/primitives/heatmap-grid";
<HeatmapGrid
cells={weeks}
rowLabels={["Mon", "", "Wed", "", "Fri", "", "Sun"]}
columnStaggerInFrames={3.4}
/>API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| cells | number[][] | required | Row-major intensities. Ragged rows are padded with empty cells. |
| maxValue | number | busiest cell | Top of the ramp. Set it explicitly to compare two grids. |
| cellSize | number | 34 | Cell edge length in px. |
| gap | number | 8 | Space between cells. |
| color | string | "#e8b86d" | Colour at full intensity. |
| emptyColor | string | rgba(250,250,250,0.07) | Colour of a zero cell. |
| rowLabels | string[] | undefined | Labels down the left gutter, one per row. |
| columnLabels | string[] | undefined | Labels along the top. Sparse arrays are fine. |
| showLegend | boolean | true | "Less → more" ramp under the grid. |
| durationInFrames | number | 14 | Length of one cell's fill. |
| columnStaggerInFrames | number | 3 | Frames added per column as the wave crosses. |
| rowStaggerInFrames | number | 1.5 | Frames added per row. Keep it below the column stagger. |
| exitAtInFrames | number | undefined | Frame the grid drains on, along the same diagonal. |
| frame | number | undefined | Frame override — pass the parent frame inside a `<Sequence>`. |