I like to use the external loop for rows and the internal loop for columns. Someone told me once (yeah, I know, it's vague) that it is somehow a convention.

The grayscale value is the sum of the cell indexes (vertical and horizontal) divided by the sum of the total amount of columns and rows (minus two because ranges start from zero)

Here an example where they are combined with matrix transformations:

```
cols = 10
rows = 10
size(200, 200)
stroke(1)
cellWdt = width()/cols
cellHgt = height()/rows
for eachRow in range(rows):
save()
for eachCol in range(cols):
grayscale = 1-(eachRow+eachCol)/(rows+cols-2)
fill(grayscale)
rect(0, 0, cellWdt, cellHgt)
translate(cellWdt, 0)
restore()
translate(0, cellHgt)
```

resulting in

]]>

I like to use the external loop for rows and the internal loop for columns. Someone told me once (yeah, I know, it's vague) that it is somehow a convention.

The grayscale value is the sum of the cell indexes (vertical and horizontal) divided by the sum of the total amount of columns and rows (minus two because ranges start from zero)

Here an example where they are combined with matrix transformations:

```
cols = 10
rows = 10
size(200, 200)
stroke(1)
cellWdt = width()/cols
cellHgt = height()/rows
for eachRow in range(rows):
save()
for eachCol in range(cols):
grayscale = 1-(eachRow+eachCol)/(rows+cols-2)
fill(grayscale)
rect(0, 0, cellWdt, cellHgt)
translate(cellWdt, 0)
restore()
translate(0, cellHgt)
```

resulting in

]]>