# Watch the Glider Fly

*Task 4 of 5 · [Cellular Automata](https://gpu.rocks/learn/cellular-automata-407c2c34.md) · GPU.js Learn*

The **glider** is five cells that *travel*. No individual cell
moves — each one just dies or is born in place, like every other cell — yet after four
ticks an identical copy of the pattern stands one cell down and one cell right. Motion as
pure side effect. When it was discovered in 1970 it changed the game: Life could transmit
information.

Time to see it. You already know both halves from earlier tracks: a numeric
`step` kernel computes generations, and a **graphical** kernel
turns the final grid into pixels. Simulation pass, then render pass — the fundamental
division of labor in every real-time visualization.

## Goal

**Goal:** complete the `paint` kernel so live cells glow
green and dead cells stay near-black, then watch the glider that started in the top-left
arrive further down the board.

## Requirements

- Read this thread's cell from `cells` — same indexing as every task so far
- Live cells: `this.color(0.2, 1, 0.4, 1)`; dead cells: `this.color(0.05, 0.06, 0.09, 1)`
- Leave the 8-generation loop and `render()` call as they are

## Hint 1 — numbers in, colors out

`cells` is the plain 2D grid the step kernel produced. Read
`cells[this.thread.y][this.thread.x]` into a variable — it's 0 or 1.

## Hint 2 — the branch

```js
if (alive === 1) {
  this.color(0.2, 1, 0.4, 1);
} else {
  this.color(0.05, 0.06, 0.09, 1);
}
```

## Same idea elsewhere

Sim pass feeding a render pass is the standard split in every API: a WebGPU compute
shader writes the state a fragment shader then draws, and CUDA–OpenGL interop exists purely
so simulation buffers can be displayed without a round trip through the CPU.

## Starter code

```js
// Two kernels, two jobs: step computes the world, paint shows it.
const gpu = new GPU({ mode });

const step = gpu.createKernel(function (world) {
  let count = 0;
  for (let dy = -1; dy < 2; dy++) {
    for (let dx = -1; dx < 2; dx++) {
      const yy = (this.thread.y + dy + 16) % 16;
      const xx = (this.thread.x + dx + 16) % 16;
      count += world[yy][xx];
    }
  }
  const self = world[this.thread.y][this.thread.x];
  count -= self;
  let next = 0;
  if (self === 1 && (count === 2 || count === 3)) next = 1;
  if (self === 0 && count === 3) next = 1;
  return next;
}, { output: [16, 16] });

const paint = gpu.createKernel(function (cells) {
  // TODO: live cells glow this.color(0.2, 1, 0.4, 1),
  // dead cells stay this.color(0.05, 0.06, 0.09, 1).
  this.color(1, 0, 1, 1);
}, { output: [16, 16], graphical: true });

// world starts as a glider in the top-left. Fly, little guy.
//
// A dial, not a constant: slider() re-runs the whole program when you drag it,
// so this is the generation counter — scrub it and watch the glider walk.
const generations = slider('generations', { min: 0, max: 32, value: 8, step: 1 });

let current = world;
for (let g = 0; g < generations; g++) {
  current = await step(current);
}
await paint(current);
render(paint.canvas);
```

---

Interactive version: https://gpu.rocks/learn/cellular-automata-407c2c34/4

[Previous task](https://gpu.rocks/learn/cellular-automata-407c2c34/3.md) · [Next task](https://gpu.rocks/learn/cellular-automata-407c2c34/5.md)
