# Water: every water block, with depth, light and flow

Place `B.WATER` blocks in any volume, island or `World` and the SDK draws them as block-game
water with depth and light: an animated picture of streaks in four shades, clear shallows you see
the bed through, darker deep water, the sky at a grazing angle, pixel glints on the crests where
they mirror the sun (the moon at night), a thin line of foam where the water meets the banks and
anything floating, whitecaps lapping by the banks, light dancing on the shallow bed, currents
carrying it all downstream, white water on rapids, falling water streaking down and churning
where it lands, little splashes where rain falls. Nothing to set up: the depths, edges and flow
come from your blocks, and the light from your stage's sky. Everything it shows is a setting you
can change live, and `style: 'classic'` brings back the water from before this version.

Pixel style, like the rest: a flat surface with no smeared highlights, every pattern on the
16-texel-a-unit grid the block textures use, stepping 8 frames a second.

## Contents

1. What you get for free
2. The look: `engine.water.set`
3. Flow: a water block's meta
4. Rivers: `flowFromPath`
5. Falling water
6. Floating things: `field`, `ring`
7. The light: sky, night, rain, lamps
8. Quality and phones
9. Opting out: `style: 'classic'`
10. How it works, and pitfalls

---

## 1. What you get for free

Any water block meshed by `meshVolume`, `addVoxelMeshes`, an `Island` or a `WorldView` is drawn
with the shared `mats.water`, and its volume's **field** is baked when it's meshed: per column,
how deep the water is (to the bed; water with nothing under it counts as bottomless sea), how
far it is from the edge (banks, rocks, anything standing in it), which way it flows (the blocks'
meta, below) and where its surface is. The blocks under the water (`mats.solid`) take the water's
colour the deeper they are and get caustics by day.

- A `World` on screen (`WorldView`) keeps its field up to date: when blocks change, only the
  columns under the chunks that changed are baked again, in the same frame's budget as its
  re-meshing. Pour a lake, dig a channel, drop a stone in: the foam follows.
- Meshes can move, be instanced or batched: each finds its own field in its own space. Up to 32
  volumes with water at once (dispose meshes you don't show any more).
- Published games draw with the site's runtime, so they get this without being published again.

## 2. The look: `engine.water.set`

`ctx.engine.water` is the one water every mesh uses. `set` changes any settings, live (the others
keep their values); the platform resets them after each game.

```ts
create(ctx) {
  ctx.engine.water.set({ depthTint: 'tropical', flow: 'E', foam: 0.6 });
}
```

| Setting | Default | |
|---|---|---|
| `depthTint` | `'lake'` | the colours by depth: `'lake'`, `'pond'` (teal), `'tropical'` (clear turquoise), `'swamp'` (murky green), `'murky'` (grey-green); or yours: `{ shallow, mid?, deep }` (CSS colours) |
| `clarity` | the preset's | 0 murky … 1 crystal: how deep you see the bed (`'lake'` 0.45, `'pond'` 0.75, `'tropical'` 0.95) |
| `foam` | 1 | 0 none … 1: the edge line, whitecaps, rings, white water, churn |
| `caustics` | 1 | 0 none … 1: light on the shallow bed by day |
| `glitter` | 1 | 0 none … 1: the glints of sun, moon and lamps on the crests |
| `flow` | `'none'` | a current wherever the cells have none: `'N'`, `'E'`, `'S'`, `'W'` (a gentle one) or `[x, z]` units a second |
| `rain` | `'auto'` | splashes where rain lands: 0..1, or `'auto'` (the mood's rain: `storm` rains; or `light({ rain })`) |
| `waves` | 0.035 | how high the surface bobs, units |
| `quality` | `'auto'` | `'low'`, `'high'`, or `'auto'`: the player's graphics setting (section 8) |
| `style` | `'default'` | `'classic'`: the water before SDK 3.13, exactly (section 9) |

A game that tints its water blocks (a `meshVolume` `tint`) keeps the tint: it colours the depth
colours. The presets are in `WATER_PRESETS`.

## 3. Flow: a water block's meta

A water cell's meta byte is its flow (`/core` has the helpers):

| Bits | |
|---|---|
| 0–2 | direction: 0 N (−z), 1 NE, 2 E (+x), 3 SE, 4 S (+z), 5 SW, 6 W, 7 NW |
| 3–5 | speed level: 0 still … 7, `FLOW_STEP` (0.3 units a second) each |
| 6 | `FLOW_FALLS`: falling water lands here (churning foam) |

```ts
import { B, flowMeta, flowOf, metaOf } from '@voxelparty/sdk/core';

world.set(x, y, z, B.WATER, flowMeta(2, 4));    // flowing east, 1.2 units a second
vol.set(x, y, z, B.WATER, metaOf(0.9, -0.3));   // the nearest byte to a vector
const [vx, vz] = flowOf(world.metaAt(x, y, z)); // push a boat along with it
```

The flow is read from the topmost water cell of each column. Fast water (about 0.75 units a
second and up) breaks into white water; faster water has more whitecaps. The picture and flecks of
froth drift with it. A water block's meta isn't used for anything else.

## 4. Rivers: `flowFromPath`

For a river, give its centre line from upstream to downstream, each point `[x, z, half-width,
speed]` in world units, and get a flow byte per column: fastest mid-channel, slack by the banks.

```ts
import { flowFromPath, paintFlow } from '@voxelparty/sdk/core';

const path = [[-30, 0, 3, 0.8], [0, 6, 2, 1.6], [30, -4, 4, 0.6]] as const;   // a fast narrow bend in the middle
const flow = flowFromPath(vol, origin, path);      // origin: where cell (0, 0, 0)'s corner is
paintFlow(vol, flow);                              // into the water cells' meta, then mesh
// or, without touching the meta:
ctx.engine.water.field(vol, { at: origin, flow });
```

For a `World`, pass `[world.x0, world.y0, world.z0]` and `world.cell` (the last argument), and
set each water cell with its byte (`world.set(x, y, z, B.WATER, flow[x + z * world.nx])`), so the
change is synced and drawn; `paintFlow` is for a `Volume` before it's meshed.

## 5. Falling water

The mesher tells water's side faces apart: water with more water above it, or the edge of deep
water with nothing beside it below, is **falling** (it streaks downwards); the side of a pool
standing on a step is the water's own edge (barely there). The field finds the waterfalls itself
(a column of water standing two or more cells over open air beside it) and churns foam where
they land. To add churn where your game says water lands, set `FLOW_FALLS` in those cells' meta,
or give world points with `engine.water.feet([[x, z, radius], …])` (at most 4).

## 6. Floating things: `field`, `ring`

Things standing in the water (rocks, posts) are edges already: they're blocks. Things floating on
it aren't: tell the water about them, and their edges foam like a bank's.

```ts
// Before meshing (or after: it bakes again). World units; `at` is where the volume's cell (0,0,0) is.
ctx.engine.water.field(vol, {
  at: [ox, oy, oz],
  discs: lilies.map((l) => [l.x, l.z, 0.42]),          // lily pads: [x, z, radius]
  bars: logs.map((l) => [l.x0, l.z0, l.x1, l.z1, l.r]),  // logs: [x0, z0, x1, z1, radius]
});
const [vx, vz] = ctx.engine.water.flowAt(vol, x, z);   // the current there, for drifting things

// Every frame: something bobbing (a float, a duck, a fish thrashing): a ring of foam round it.
ctx.engine.water.ring(float.x, float.z, 0.15);          // at most 16 a frame
```

## 7. The light: sky, night, rain, lamps

The water reads its light from the scene it's drawn in, every frame: the sun (direction and
colour), the fog's colour (the sky near the horizon), the stage's mood (the sky overhead, and
`rain`: the `storm` mood rains 0.6; add `rain` to your own moods), and how dark it is (a dark,
cold sky is night: the glints of sun become the moon's). With block light (glowing blocks,
`stage.blockLight`, a `WorldView` with `light`) the crests glint with it at night.

- **Lamps**: `engine.water.lamps([[x, y, z], …])` names lights by the water whose light glints on
  it at night (at most 12, nearest first); with none named, block light glints instead.
- **Your own sky**: a game with its own day, night and weather gives the light itself, every
  frame; what it leaves out is still worked out:

```ts
ctx.engine.water.light({ day: 1 - night, night, rain, sun: toSun, sunColor, sky: fogColour, skyTop, lamps: night, moon: toMoon });
ctx.engine.water.light(null);    // back to the scene's
```

`engine.water.lit` has the light it used last.

## 8. Quality and phones

One shader draws all water; its cost is a few texture reads and some hashing per water pixel.
`quality: 'auto'` follows `ctx.engine.quality`, the player's graphics setting (`'low' | 'medium'
| 'high'`, automatic unless they picked one: `low` on weak GPUs and most phones). On `'low'` the
water drops the lamps' glints, the rain splashes, the flecks of froth and the second layer of
caustics. `ctx.engine.quality` is yours to read too (fewer particles on `'low'`).

## 9. Opting out: `style: 'classic'`

```ts
ctx.engine.water.set({ style: 'classic' });   // the water before this SDK: a bobbing, scrolling, see-through texture
```

Use it where the new look fights the game: a see-through pool whose floor is the gameplay, ice,
or water that should read as a flat colour from far away. It's live, like every setting.

## 10. How it works, and pitfalls

- Every field lives in one texture (an atlas); a water or solid vertex carries its field's number
  in the mesher's `aux` attribute. Only meshes made by `meshVolume` (and so `addVoxelMeshes`,
  `Island`) or `WorldView` have one: water geometry you build by hand draws as open water of
  middling depth, with no edges.
- A volume's field is baked when it's meshed. Changed the blocks of a `Volume`? Mesh it again (a
  `WorldView` does this by itself).
- Shapes (`discs`, `bars`) and `flowAt` are in world units from `at`; for a `World`, its origin.
- Water with nothing under it (a single layer, a sea at the bottom of the volume) is bottomless:
  as deep and dark as it gets. Put a bed under water you want to look shallow.
- The field is 2 texels a unit: detail smaller than half a unit (a one-voxel gap) blurs.
- More than 32 volumes with water on screen at once: the rest draw as open water.
