# The Sphere as a Number

*Task 1 of 6 · [Ray-Marched Metaballs](https://gpu.rocks/learn/ray-marched-metaballs-8b1282bd.md) · GPU.js Learn*

A **signed distance field** describes a shape with one function:
for any point in space it returns the distance to the nearest surface — positive outside,
*negative* inside, exactly zero on the skin. A whole sphere collapses into one line:
`length(p - center) - radius`. No vertices, no triangles, just math.

That's a perfect fit for a kernel: one thread per sample point, each evaluating the same
tiny function. Here every pixel owns a point on the `z = 0` slice through the
scene — pixel `(ix, iy)` maps to world `((ix - 32) / 16, (iy - 32) / 16)`,
so the canvas spans −2…2 and the center pixel sits exactly at the origin.

## Figures

- **one function knows the whole sphere: + outside, 0 on the skin, − inside**

## Goal

**Goal:** make the kernel return the signed distance from this thread's
world point to a sphere at `(cx, cy)` with radius `r`.

## Requirements

- Map the thread to world space: `(this.thread.x - 32) / 16` (already wired up)
- Measure the offset from the sphere center: `(wx - cx, wy - cy)`
- Return its length via `Math.sqrt`, **minus** `r`

## Hint 1 — what should the numbers look like?

For the unit sphere at the origin: the center pixel is *inside*, distance
`-1`. A pixel one unit from the center sits exactly on the surface —
distance `0`. The far corner at (−2, −2) reads `√8 − 1 ≈ 1.83`.

## Hint 2 — the whole thing

```js
const dx = wx - cx;
const dy = wy - cy;
return Math.sqrt(dx * dx + dy * dy) - r;
```

## Same idea elsewhere

Distance fields are a production technique, not a toy: Valve renders crisp text
from SDF textures, and every WebGPU fragment shader that draws rounded rectangles is
evaluating exactly this per-pixel field — one invocation per pixel, one signed distance out.

## Starter code

```js
// A sphere in one line of math: length(p - center) - radius.
const gpu = new GPU({ mode });

const sliceSDF = gpu.createKernel(function (cx, cy, r) {
  // This thread's point on the z = 0 slice: center pixel = origin.
  const wx = (this.thread.x - 32) / 16;
  const wy = (this.thread.y - 32) / 16;
  // TODO: return the signed distance from (wx, wy) to the sphere:
  // the length of (wx - cx, wy - cy), minus r.
  return 0;
}, { output: [64, 64] });

const field = await sliceSDF(0, 0, 1);
console.log('center (inside, should be -1):', field[32][32]);
console.log('far corner (outside):', field[0][0]);
```

---

Interactive version: https://gpu.rocks/learn/ray-marched-metaballs-8b1282bd/1

[Next task](https://gpu.rocks/learn/ray-marched-metaballs-8b1282bd/2.md)
