A grid of cells stores a heat value; the pointer stamps heat along its path, and every cell cools over time. Simple state, strong feedback.
The canvas is divided into square cells, each holding a heat value from 0 to 1. A pointer move stamps heat 1 into every cell along the segment from the previous position, so fast strokes leave no gaps. Each frame subtracts dt / decay from every warm cell, and the loop stops itself once the whole grid is cold.
const stampSegment = (x0, y0, x1, y1) => {
const dist = Math.hypot(x1 - x0, y1 - y0);
const steps = Math.max(1, Math.ceil(dist / (cell * 0.5)));
for (let i = 0; i <= steps; i += 1) {
const t = i / steps;
stamp(x0 + (x1 - x0) * t, y0 + (y1 - y0) * t);
}
};
// per frame: linear, dt-based cooling
const step = dt / decay;
let any = false;
for (let i = 0; i < heat.length; i += 1) {
if (heat[i] > 0) {
heat[i] = Math.max(0, heat[i] - step);
if (heat[i] > 0) any = true;
}
}
drawTrail(); // alpha = heat, accent above 0.92
if (!any) stopLoop(); // idle until the next pointer move