Task 5 of 6

Images Are Just Arrays

Task 3 painted pixels. But an image doesn't have to stay an image: in this course an image is a nested array — photo[y][x] is an [r, g, b, a] pixel with channels 0–1 — and a kernel can read it like any other array argument.

Drop graphical: true, and the same per-pixel indexing produces numbers instead of colors: a measurement per pixel, ready for JavaScript.

Array layout in gpu.js

Image data comes in row-major: image[y][x] is the pixel in row y, column x, and each pixel is an [r, g, b, a] array with channels from 0 to 1. Mind the inversion that catches everyone — sizes are given width-first (output: [width, height]), but indexing runs row-first, so this thread's own pixel is image[this.thread.y][this.thread.x]. Swap those two and you read the transpose of your image. Three-dimensional data follows the same rule: output: [w, h, d] is indexed [z][y][x].

drop graphical: true and a pixel is just four numbers
Goal: compute a 64×64 brightness map of photo — each cell the average of that pixel's red, green and blue channels.

Requirements

Hint 1 — same indexing as task 3

The pixel lookup is identical to the grayscale task — only the ending changes: return a number instead of calling this.color().

Hint 2 — the average
const pixel = photo[this.thread.y][this.thread.x];
return (pixel[0] + pixel[1] + pixel[2]) / 3;

Same idea elsewhere

Treating an image as a data grid is how real pipelines work: computer-vision pre-processing, depth-map filtering, scientific imaging. In CUDA/WebGPU this is a compute pass sampling a texture and writing to a plain buffer.

All tasks in Data In, Data Out

  1. Pass an Array In
  2. Shape the Output: 2D
  3. Grayscale, the GPU way
  4. Read the Results Back
  5. Images Are Just Arrays
  6. Put It Together: Two Kernels

This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.