# Feed It Back: 100 Steps

*Task 3 of 4 · [Reaction–Diffusion](https://gpu.rocks/learn/reaction-diffusion-bc3d0b34.md) · GPU.js Learn*

One step is chemistry; a hundred steps is *morphogenesis*. The kernels
stay on the GPU — the loop lives in JavaScript: call both step kernels, take their
outputs, feed them back in as next step's inputs. This is the same feedback move as
the cellular automata in 3.3, just with two grids in flight instead of one.

The trap: both kernels must read the **same snapshot**. If you
overwrite `u` before calling `stepV`, chemical V reacts with food
from the *future* — the simulation drifts and the tests will know. Hold both new
grids, *then* swap. Graphics folk call this ping-pong buffering.

## Goal

**Goal:** run 100 Gray–Scott steps from the seeded grids
`seedU` / `seedV`, feeding each step's outputs into the next —
both kernels always reading the same snapshot.

## Requirements

- Loop exactly `STEPS` (100) times in plain JavaScript
- Call `await stepU(u, v)` and `await stepV(u, v)` with the *same* `u` and `v`
- Only after both calls, replace `u` and `v` with the new grids

## Hint 1 — why the starter is wrong

The starter does

```js
u = await stepU(u, v);
v = await stepV(u, v);
```

— by the
second call, `u` is already next step's grid. Stash both results in
temporaries before assigning either.

## Hint 2 — the loop body

```js
const nextU = await stepU(u, v);
const nextV = await stepV(u, v);
u = nextU;
v = nextV;
```

Four lines, inside
`for (let i = 0; i < STEPS; i++)`.

## Same idea elsewhere

This snapshot discipline is double buffering, and GPUs institutionalize it:
a WebGPU or Metal simulation binds texture A for reading and texture B for writing,
then swaps the bindings each frame — you never write the buffer you're reading. CUDA
codes do the same by swapping two device pointers between kernel launches.

## Starter code

```js
// The kernels from last task, prewired at 48×48. Your job: the time loop.
const gpu = new GPU({ mode });

const stepU = gpu.createKernel(function (u, v) {
  const x = this.thread.x;
  const y = this.thread.y;
  let xl = x - 1; if (xl < 0) xl = this.constants.size - 1;
  let xr = x + 1; if (xr > this.constants.size - 1) xr = 0;
  let yd = y - 1; if (yd < 0) yd = this.constants.size - 1;
  let yu = y + 1; if (yu > this.constants.size - 1) yu = 0;
  const uc = u[y][x];
  const vc = v[y][x];
  const lap = u[y][xl] + u[y][xr] + u[yd][x] + u[yu][x] - 4 * uc;
  return uc + (this.constants.du * lap - uc * vc * vc
    + this.constants.f * (1 - uc)) * this.constants.dt;
}, { output: [48, 48], constants: { size: 48, du: 0.2, f: 0.035, dt: 1 } });

const stepV = gpu.createKernel(function (u, v) {
  const x = this.thread.x;
  const y = this.thread.y;
  let xl = x - 1; if (xl < 0) xl = this.constants.size - 1;
  let xr = x + 1; if (xr > this.constants.size - 1) xr = 0;
  let yd = y - 1; if (yd < 0) yd = this.constants.size - 1;
  let yu = y + 1; if (yu > this.constants.size - 1) yu = 0;
  const uc = u[y][x];
  const vc = v[y][x];
  const lap = v[y][xl] + v[y][xr] + v[yd][x] + v[yu][x] - 4 * vc;
  return vc + (this.constants.dv * lap + uc * vc * vc
    - (this.constants.f + this.constants.k) * vc) * this.constants.dt;
}, { output: [48, 48], constants: { size: 48, dv: 0.1, f: 0.035, k: 0.06, dt: 1 } });

const STEPS = 100;
let u = seedU;
let v = seedV;

// TODO: run STEPS steps. This single "step" has TWO bugs: it only runs
// once, and stepV reads the u we just overwrote — future food!
u = await stepU(u, v);
v = await stepV(u, v);

console.log('center V after', STEPS, 'steps:', v[24][24]);
```

---

Interactive version: https://gpu.rocks/learn/reaction-diffusion-bc3d0b34/3

[Previous task](https://gpu.rocks/learn/reaction-diffusion-bc3d0b34/2.md) · [Next task](https://gpu.rocks/learn/reaction-diffusion-bc3d0b34/4.md)
