# Wave Field (Moonarc)

Draws a water surface in halftone. It runs the wave equation on the GPU (a height field and its previous step), so a drop spreads into rings that cross, interfere and settle, and the edges absorb them. The cursor drops ripples along its path, a wake of rings behind it; while it rests, a light rain falls around the focus. The steepness of the surface sizes a dot per cell, in two tones on the page's ground; `dots` 0 draws a smooth surface. Every constant is a custom property re-read when the element's style changes. Without WebGL2 or a colour-renderable float texture, or without JavaScript, still rings stand in. Fills its positioned parent.

- Pro block. Install: `npx shadcn@latest add @moonarc-pro/wave-field` (license key required)
- Tier C · category background · trigger pointer, always
- Readout: `<WaveField dots={6} rain={1.1}>`
- Browser support: widely (Chrome 56 · Firefox 51 · Safari 15); elsewhere: without WebGL2 or a colour-renderable float texture (EXT_color_buffer_float), still rings around the focus
- Measured cost: 2.3 kB raw JS · 1.3 kB gzip · + runtime + canvas + gl, 10.8 kB raw in all (with dependencies 10.8 kB raw; CSS 5.3 kB raw)
- Page: https://moonarc.dev/components/wave-field/

## Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `color` | `string` | `'oklch(0.62 0.19 262)'` | Dot colour; any CSS colour, theme tokens included. Re-read when the theme changes. |
| `core` | `string` | `color lifted 50 % toward white` | The second tone: the colour on the steepest wave fronts. |
| `dots` | `number` | `6` | Halftone cell in CSS px; 0 draws a smooth surface. |
| `speed` | `number` | `1` | Wave speed: 60 simulation steps a second at 1. Fixed steps, so the rings travel at the same pace at any frame rate. |
| `settle` | `number` | `0.65` | How fast ripples die out, per second. 0.3 lets them cross the box; 1.5 keeps them local. |
| `drop` | `number` | `1` | How deep the pointer drops into the surface; 0 turns the pointer off. |
| `rain` | `number` | `1.1` | Ambient drops per second while the pointer has rested for 1.5 s; 0 is a still pool. |
| `focus` | `string` | `'0.7 0.55'` | Where the rain falls and the fallback rings sit, as fractions of the box (x y, from the top-left). |

## Usage

```astro
<section class="relative min-h-[70vh]">
  <WaveField color="var(--primary)" />
  <h1 class="relative">Ripples on a halftone surface</h1>
</section>
```

## Reduced motion

No loop and no rain: three drops settle for a second of simulation and are drawn once, as a still. The pointer does not stir it.

## With ClientRouter

Bound through the shared runtime: the frame loop, observers and the pointer listener are released before the swap and the WebGL context is lost on purpose after it, so the GPU memory goes with the page; five round trips leave one context. Under transition:persist the canvas keeps its context and starts again on the next page.

## Craft

- The wave equation with c² = ½ (the stable limit of the explicit scheme) on one RG16F pair: height now in red, one step ago in green. No pressure solve, no second grid: a fraction of FluidField's work.
- Fixed steps (60 per second × speed, at most six a frame): the rings travel at the same speed on a 60 Hz and a 120 Hz display, and a dropped frame does not fling them.
- Absorbing edges: the step fades within 4 % of the border, so rings leave the box instead of bouncing into a mesh of reflections.
- Drops along the path, not every frame: one every 7 % of the short side, so a sweep leaves a wake of separate rings rather than one smeared trough.
- The dot is sized by the slope's steepness through 1 − e^(−k), whole rings rather than the half that faces a light, soft at the drop's centre instead of a solid disc.
- Rain on a Poisson clock (exponential intervals) with varied depth: it never reads as a metronome.
- Tried against reaction–diffusion (Gray–Scott) for the home hero: self-replicating patterns filled the box within seconds; ripples stay sparse by physics.

## Replaces

- Water ripple effect (jQuery ripples)
- Ripple shader backgrounds

## Source

Pro block. The source is served by the license-gated registry: `npx shadcn@latest add @moonarc-pro/wave-field` with a key in components.json (https://moonarc.dev/account/). Related free primitives: ripple.
