# Gooey (Moonarc)

Draws a cluster of liquid drops that merge and pull apart: metaballs on the GPU with a compact kernel, cut with an edge exactly one pixel soft. Seven drops orbit a focus at their own pace; an eighth follows the pointer on a spring and the others lean toward it, so the cluster stretches after the cursor, necks form between drops, and it gathers again when the pointer leaves. Two tones: the body, and a core only where drops overlap. Every constant is a custom property re-read when the element's style changes. Without WebGL2 or JavaScript two still drops stand in. Fills its positioned parent.

- Pro block. Install: `npx shadcn@latest add @moonarc-pro/gooey` (license key required)
- Tier C · category pointer · trigger always, pointer
- Readout: `<Gooey follow={0.6}>`
- Browser support: widely (Chrome 56 · Firefox 51 · Safari 15); elsewhere: without WebGL2, two still drops at the focus
- Measured cost: 1.1 kB raw JS · 752 B gzip · + runtime + shader + canvas + gl, 10.6 kB raw in all (with dependencies 10.6 kB raw; CSS 5.2 kB raw)
- Page: https://moonarc.dev/components/gooey/

## Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `color` | `string` | `'oklch(0.66 0.2 292)'` | Drop colour; any CSS colour, theme tokens included. |
| `core` | `string` | `color lifted 45 % toward white` | The colour where drops overlap. |
| `size` | `number` | `1` | Drop size multiplier. |
| `speed` | `number` | `1` | Orbit speed multiplier; accumulated, so a change never jumps. |
| `spread` | `number` | `1` | How far the drops wander from the focus. |
| `follow` | `number` | `0.6` | How much the cluster leans toward the pointer drop; 0 keeps it home. |
| `focus` | `string` | `'0.5 0.5'` | Where the cluster sits, as fractions of the box (x y, from the top-left). |

## Usage

```astro
<section class="relative min-h-[60vh]">
  <Gooey color="var(--primary)" focus="0.7 0.5" />
  <h1 class="relative">Liquid drops that merge</h1>
</section>
```

## Reduced motion

No loop: the drops are drawn once at a fixed moment; the pointer drop stays home.

## With ClientRouter

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

## Craft

- A compact kernel, (1 − d²/R²)³, instead of the classic 1/d²: zero beyond its radius, so drops are separate shapes until they touch and a neck forms. The long tail of 1/d² would melt everything into one mass.
- The edge is fwidth(field) wide: exactly one pixel of anti-aliasing at any DPR and any drop size, never a blur.
- The core tone starts above 1.15, where only overlapping drops reach: a single drop is flat, a merge lights up.
- Each orbit has its own vertical frequency. With one shared ratio, the phases lined up on a diagonal.
- The pointer drop eases on a spring (1 − e^(−5 dt)) and the others lean toward it in proportion, so the cluster stretches instead of teleporting.

## Replaces

- MetaBalls (React Bits)
- BlobCursor gooey (React Bits)
- SVG goo filter

## Source

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