# One Step of Gray–Scott

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

Now the chemistry. Gray–Scott tracks two chemicals on the same grid:
`U` (food, fed in everywhere) and `V` (the eater —
`U + 2V → 3V`, so V converts U into more V, and is itself slowly removed).
Per cell, per step:

`u' = u + (Du·∇²u − u·v² + F·(1 − u))·dt`

`v' = v + (Dv·∇²v + u·v² − (F + K)·v)·dt`

Each equation is your task-1 Laplacian plus three pointwise terms — diffusion,
reaction, feed/kill. One kernel per chemical: both are gathers over the *old*
grids, so all 1,024 cells of a step can run in parallel.

## Figures

- **one snapshot in, two grids out — u·v² is where the chemistry happens**

## Goal

**Goal:** finish the two update kernels — `stepU` and
`stepV` each return their chemical's next value. The Laplacians are already
gathered for you.

## Requirements

- Keep the kernel order as wired: `stepU` first, then `stepV`
- The reaction term is `u·v·v` — U loses it, V gains it
- `stepU` returns `uc + (du·lap − uc·vc·vc + f·(1 − uc))·dt`
- `stepV` returns `vc + (dv·lap + uc·vc·vc − (f + k)·vc)·dt`

## Hint 1 — everything is already in scope

`lap`, `uc` and `vc` are computed for you;
the parameters live in `this.constants` (`du`, `f`,
`dt` in stepU; `dv`, `f`, `k`,
`dt` in stepV). The TODO is one `return` per kernel.

## Hint 2 — stepU, spelled out

```js
return uc + (this.constants.du * lap - uc * vc * vc
  + this.constants.f * (1 - uc)) * this.constants.dt;
```

stepV is the same shape
with `+ uc·vc·vc` and `− (f + k)·vc`.

## Same idea elsewhere

Fusing the stencil and the pointwise chemistry into one kernel is a classic
GPU move — in CUDA or a WGSL compute shader you'd do exactly this to touch each grid
cell's memory once per step instead of once per term. Separate passes per term would
triple the bandwidth bill.

## Starter code

```js
// Two chemicals, two kernels. Both read the OLD u and v grids.
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;
  // TODO: return uc + (du * lap - uc*vc*vc + f * (1 - uc)) * dt
  //       (parameters live in this.constants)
  return uc;
}, { output: [32, 32], constants: { size: 32, 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;
  // TODO: return vc + (dv * lap + uc*vc*vc - (f + k) * vc) * dt
  return vc;
}, { output: [32, 32], constants: { size: 32, dv: 0.1, f: 0.035, k: 0.06, dt: 1 } });

const newU = await stepU(u0, v0);
const newV = await stepV(u0, v0);
console.log('center after one step — U:', newU[16][16], ' V:', newV[16][16]);
```

---

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

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