Skip to content

Canvas interaction

The setup function returns several utilities for interacting with the grid at runtime. Beyond update and draw, you can read the current state, overwrite the entire grid, or update individual cells — all while the simulation is running.

const { update, draw, readGrid, writeGrid, writeCell, writeCellAt } = setup({
canvas,
automaton,
});

readGrid returns a Promise that resolves to a flat array of element indices, in row-major order (left to right, top to bottom). Each value corresponds to an element’s .index.

const snapshot = await readGrid();
// snapshot is a number[] of length width * height

This is useful for inspecting the current state, running analytics, or saving a snapshot that can be restored later.

writeGrid replaces every cell at once. Pass a flat array of element indices whose length must equal width * height:

writeGrid(snapshot); // restore a previously saved snapshot

The function validates every index in the array and throws if any value is out of range.

writeCell updates one cell without touching the rest of the grid. Pass the flat index of the cell and the element index to assign:

writeCell(index, alien.index);

The flat index for a cell at column x and row y in a grid of width width is y * width + x.

If you prefer working with grid coordinates instead of flat indices, use writeCellAt:

writeCellAt(x, y, alien.index);

Let users draw on the canvas by converting mouse coordinates to cell coordinates and calling writeCellAt:

const { update, draw, writeCellAt } = setup({ canvas, automaton });
canvas.addEventListener("click", (e) => {
const rect = canvas.getBoundingClientRect();
// Scale from CSS pixels to grid cells
const x = Math.floor((e.clientX - rect.left) * (canvas.width / rect.width));
const y = Math.floor((e.clientY - rect.top) * (canvas.height / rect.height));
writeCellAt(x, y, alien.index);
});

Save the grid state so you can rewind:

const { update, draw, readGrid, writeGrid } = setup({ canvas, automaton });
let saved: number[] | null = null;
document.getElementById("save")!.addEventListener("click", async () => {
saved = await readGrid();
});
document.getElementById("restore")!.addEventListener("click", () => {
if (saved) writeGrid(saved);
});