Wrapping edge-cell neighbor lookups with the modulo operator creates a toroidal grid topology that prevents out-of-bounds buffer access
In a cellular automaton, cells at the grid boundary have fewer than 8 neighbors unless you define wrap-around. The standard approach treats the grid as a torus: the left edge’s neighbors include the right edge’s cells. In WGSL, apply the modulo operator to both coordinates in the cell-index function: (cell.y % gridHeight) * gridWidth + (cell.x % gridWidth). This also prevents out-of-bounds reads (undefined behavior). For u32 arithmetic, subtracting 1 from 0 wraps to a very large number — modulo-based indexing is essential rather than clamping.
Examples
fn cellIndex(cell: vec2u) -> u32 {
return (cell.y % u32(grid.y)) * u32(grid.x) + (cell.x % u32(grid.x));
}
// When cell.x == 0 and we compute cell.x-1: u32 underflows to ~4B; % grid.x wraps to rightmost column
Assessment
Why does subtracting 1 from a u32 value of 0 produce a very large number rather than -1? How does the modulo in cellIndex handle this correctly for left-edge cells?