The page is a launch site for a chip nobody makes: scroll from the module down to a transistor, take the package apart in 3D, and then — section three — put it to work. Pick Idle, Inference or Training and the floorplan starts to glow where that work would land.
The glow is not an animation. It is a grid of numbers stepped forward by the heat equation, and the temperature and power printed beside it are read out of the same grid.
Run it yourself
This is the same floorplan, the same loads and the same constants. The one thing added is a slider for the spread constant α, so you can see what it does — including past the point where the maths stops working.
It starts on Inference. Switch to Idle and let it cool, then to Training, and count: the blocks reach their new load in under two seconds, the heat takes nearly six. Then switch between Inference and Training and watch the hotspot: 79 °C against 92. Until this page was written, both read 92 — the last section is about why.
1 · The floorplan is data
Eight rectangles, each given as fractions of the die, each split into a few cells that heat independently, each with a load for the three workloads. Everything else is computed from this list.
// rect = [x, y, width, height] as fractions of the die; cells = columns × rows of heaters
const BLOCKS = [
{ name: 'Performance cores', rect: [0.05, 0.05, 0.36, 0.34], cells: [4, 2],
load: { idle: 0.12, inference: 0.35, training: 0.55 } },
{ name: 'Neural accelerator', rect: [0.44, 0.05, 0.51, 0.40], cells: [2, 2],
load: { idle: 0.04, inference: 0.78, training: 1.0 } },
// … six more: efficiency cores, cache, memory controller, graphics, secure enclave, I/O
];
The die is drawn as 26 mm square, so one grid cell stands for about 0.2 mm. The neural block covers 20.4 % of the area and carries the heaviest load, which is why the eye goes there first. The loads are concept values — the page says so under the canvas — but they are consistent with each other, and that is what the picture needs.
2 · A workload is a target
Choosing a workload does not set the loads. It sets what each block is heading for, and every block eases toward it at a fixed rate.
const STEP = 1 / 60; // one simulation step
// each block's level moves a fixed share of the way to its target every step
level[i] += (BLOCKS[i].load[target] - level[i]) * (1 - Math.exp(-STEP / 0.6));
A 0.6 s time constant puts a block 95 % of the way there in 1.8 s. The heat lags behind the load: from Idle to Training the hottest cell needs 5.6 s to reach 98 % of its final value. That second delay is what reads as thermal mass — the difference between a die warming up and a picture changing colour.
3 · Every cell is a heater
The 64 cells each inject heat into the grid in proportion to their block's level, with a slow flicker so a busy die never freezes into a still.
const rnd = mulberry32(2026); // seeded: the live page and a 4K render agree
const phases = BLOCKS.map((b) => Array.from({ length: b.cells[0] * b.cells[1] },
() => [rnd() * 6.283, 0.6 + rnd() * 1.8])); // phase, speed per cell
// inside one step, for cell (i, j) of block b
const [ph, sp] = phases[b][j * cx + i];
const q = level[b] * (0.7 + 0.3 * Math.sin(t * sp + ph)) * 0.022;
const x0 = Math.floor((x + w * i / cx) * N) + 1; // +1 and −1 leave a one-cell cold seam
const x1 = Math.floor((x + w * (i + 1) / cx) * N) - 1; // between neighbouring heaters
for (let yy = y0; yy <= y1; yy++) for (let xx = x0; xx <= x1; xx++) src[yy * N + xx] += q;
The flicker swings each cell ±30 % with a period between 2.6 and 10.5 s. Slow enough that nobody calls it flashing; fast enough that the die is visibly alive. Because the phases come from a seed, the same moment always looks the same — which is what lets the page render a frame-exact video of itself.
4 · Heat spreads, the cooler takes it away
This is the whole physics: one line inside two loops. The explicit five-point scheme for the heat equation, with a loss term for the heatsink.
for (let y = 1; y < N - 1; y++) for (let x = 1; x < N - 1; x++) {
const k = y * N + x;
const lap = heat[k - 1] + heat[k + 1] + heat[k - N] + heat[k + N] - 4 * heat[k];
next[k] = heat[k] + 0.22 * lap + src[k] - 0.02 * heat[k];
// spread made taken away
}
heat.set(next); // the rim is never written: it stays at 0
Two constants decide the look. Their ratio sets how far a hotspot glows before the cooler wins: √(α / c) = √(0.22 / 0.02) ≈ 3.3 cells, about 0.67 mm of silicon. Lower α and the hotspots stay sharp; raise the cooling and the die never lights up.
α also has a ceiling, and it is not a matter of taste. The textbook bound for this scheme is 8α + c ≤ 2 — α just under ¼. Measured with the training load: at 0.24 the die settles normally. At 0.25 the peak reads 6 870 after 20 seconds and 3.4 × 10²³ after a minute, as a checkerboard that grows about 2 % every step. Take the slider in the toy to 0.26 and you will see it; the toy wipes the grid when it runs away.
5 · The numbers come out of the same grid
The readouts beside the die are not a second model. They scan the grid the picture is drawn from.
function stats() {
let max = 0;
for (let k = 0; k < N * N; k++) if (heat[k] > max) max = heat[k];
const areaPower = BLOCKS.reduce((s, b, i) => s + level[i] * b.rect[2] * b.rect[3], 0);
return {
hot: 34 + Math.min(1, max / HOT_PEAK) * 58, // °C, concept scale; HOT_PEAK = 0.992
power: Math.min(350, 22 + areaPower * 640), // W, concept scale
};
}
// the picture has its own gain: colour(heat[k] * 1.6), through
// transparent → deep copper → copper → amber → ice white
Settled, the three workloads read 40 °C · 50 W, 79 °C · 230 W and
92 °C · 322 W. The 128 × 128 image is then stretched over the floorplan with a
screen blend and a blur of 0.6 of a cell, so the grid reads as light on silicon rather
than as squares.
The page accumulates real time and steps the grid in exact sixtieths of a second, so a 120 Hz display heats the die at the same rate as a 60 Hz one. The elapsed time is capped at 0.1 s, so a tab that stalls catches up with at most six steps instead of a burst of hundreds.
What it costs
A live simulation sounds expensive. This one is smaller than most hero images.
| Part | Size | Note |
|---|---|---|
The simulation (js/diemap.js) | 9.8 KB | floorplan, model, colour and drawing; no dependencies |
| The grid | 192 KB | three 128 × 128 Float32Arrays: heat, next, source |
| One step | 0.069 ms | the physics alone, M1 Pro |
| One step and one draw | 0.56 ms | in Chrome, on a 1120 × 1120 canvas, M1 Pro |
At sixty steps a second that is about 34 ms of main thread per second — 3 % of it. No worker, no WebGL, no shader: a typed array, two loops and a 2D canvas.
What the measurement found
Measuring the model for this page turned up something no screenshot had: two of the three workloads printed the same temperature.
After twenty seconds the grid's peak is 0.774 under Inference and 0.992 under
Training. Both are multiplied by the gain of 1.6, both come out above 1, and
Math.min(1, …) clamps them to the same place: 92 °C either way. The picture clamps
with it — the top colour covers 10.6 % of the die under Inference and 17.7 % under
Training, and the neural block is the same white in both. Only the power readout tells them apart.
The gain had been chosen so the heaviest workload reaches the top of the scale. Nothing checked that the second-heaviest stays below it. The fix separates the two jobs the gain was doing: the picture keeps its 1.6, because the white-hot neural block is the look of the section, and the temperature gets a scale of its own, taken from the measured peak.
const HOT_PEAK = 0.992; // training, measured after 20 s
hot = 34 + Math.min(1, max / HOT_PEAK) * 58; // idle 40 °C · inference 79 °C · training 92 °C
The live page runs this now. Clicked through on the real site: Inference settles at 79 °C, Training at 92 °C, and the two can be told apart again without reading the power.
A readout that clamps looks exactly like one that works. Put every state through it once and read the numbers side by side: if two different inputs print the same value, the scale is wrong, not the model.
See it running
The die is the third section of the page. Scroll there, pick a workload, and point at a block to read what it does.
The explicit (forward-time, centred-space) scheme for the heat equation and its stability bound: Press et al., Numerical Recipes, the chapter on diffusive initial-value problems. Seeded random numbers: mulberry32, public domain. The floorplan, loads, temperatures and power figures are concept values; ARCLITH One is fictional.