Skip to content

Components / Pointer

Gooey

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.

Live demo

Gooey.

move your cursor

Live, from the library itself: scroll, hover, navigate away and back. The demo is never gated.

Measured

JavaScript with its libs

10.6 kB raw

1.1 kB raw of its own, 752 B gzip. The rest is the runtime, the shader runner, the canvas helper and the GL core, loaded once for every effect on the page.

CSS 5.2 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.

Browser support

Baseline · widely available

Chrome 56 · Firefox 51 · Safari 15; needs webgl2. Elsewhere: without WebGL2, two still drops at the focus.

Install Pro

The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:

terminal
npx shadcn@latest add @moonarc-pro/gooey
src/pages/index.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>

Without a key the registry answers 401 with an upgrade message. Related free primitives: cursor, magnetic.

Props

PropTypeDefaultDescription
colorstring'oklch(0.66 0.2 292)'Drop colour; any CSS colour, theme tokens included.
corestringcolor lifted 45 % toward whiteThe colour where drops overlap.
sizenumber1Drop size multiplier.
speednumber1Orbit speed multiplier; accumulated, so a change never jumps.
spreadnumber1How far the drops wander from the focus.
follownumber0.6How much the cluster leans toward the pointer drop; 0 keeps it home.
focusstring'0.5 0.5'Where the cluster sits, as fractions of the box (x y, from the top-left).

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.

Why it is built this way

Replaces: MetaBalls (React Bits) · BlobCursor gooey (React Bits) · SVG goo filter. See the migration table.

Cursor

Pointer

A custom pointer that trails the real one: a dot, a ring that grows over links and buttons, or a label ("View") any element can ask for with data-cursor-label.

every browserpointer

Magnetic

Pointer

A button or icon is pulled toward the cursor while it is nearby and springs back when it leaves.

every browserpointerhover

Draws smoke that follows the cursor.

every browserpointeralways

Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown