LiquidEther
liquid-etherProduces a pointer-stirred liquid color field with metaball-like motion.
Usage
Basic usage
Just put it into the relative container. The component comes with absolute inset-0; the default is to automatically patrol and stir the liquid level, and the color is chart token with adaptive light and dark.
<div className="relative h-64 overflow-hidden rounded-xl bg-neutral-950">
<LiquidEther />
<div className="relative z-10 flex h-full items-center justify-center text-white/85">
LiquidEther
</div>
</div>Custom Palette · Large Blob
colors Connect to any CSS color (hex / oklch / var token); scale The larger the chromophore, the more macroscopic it is, and speed controls the tumbling speed.
<LiquidEther
colors={[
"var(--color-chart-3)",
"oklch(0.72 0.22 30)",
"var(--color-chart-1)",
]}
scale={1.6}
speed={0.7}
/>Still waiting for interaction
autoDemo={false} Turn off the automatic tour, the screen remains still and wait for the real pointer; mouseForce Turn it up to make the stirring more convenient.
<LiquidEther autoDemo={false} mouseForce={1.5} />Wallpaper level overlay
Slow + Translucent (opacity) reduces the visual weight and serves as the title area background to overlap below the text.
Hulian component library
Liquid color gamut · Mouse driver
<div className="relative h-64 overflow-hidden rounded-xl bg-neutral-950">
<LiquidEther speed={0.3} scale={1.2} opacity={0.7} />
<div className="relative z-10 flex h-full flex-col items-center justify-center gap-2">
<p className="text-lg font-semibold text-white">Hulian Component Library</p>
<p className="text-xs text-white/60">Liquid color gamut · Mouse driver</p>
</div>
</div>When to Use
Use LiquidEther behind a creative landing page, product hero, or sign-in surface when color should move organically and react to the pointer. Its visual weight is high; lower opacity beneath text and reserve full opacity for artwork-led layouts. Choose DotPattern or GridPattern for regular geometry, or Spotlight for a localized pointer glow.
Import
import { LiquidEther } from "@hulianui/ui"Props
| Name | Type | Default | Description |
|---|---|---|---|
| colors | string[] | ["var(--color-chart-1)","var(--color-chart-2)","var(--color-chart-4)"] | Palette of CSS colors. One value is repeated across the three shader stops; two values reuse the second for the final stop. Theme variables update with light and dark modes. |
| speed | number | 0.5 | Animation-speed multiplier; 0.2–1.5 is recommended |
| scale | number | 1 | Liquid-blob scale; lower values create smaller separated forms and higher values merge them, with 0.6–2 recommended |
| mouseForce | number | 1 | Strength of the real or automatic pointer force; 0 removes pointer-driven force while time-based metaball motion continues, with 0–2 recommended |
| autoDemo | boolean | true | Drive the force point along a virtual path until a real pointer enters; false leaves the force at rest until real input arrives |
| opacity | number | 1 | Root opacity from 0 to 1; 0.6–0.85 often works behind foreground content |
| className | string | — | Class name forwarded to the canvas wrapper or fallback root |
| style | CSSProperties | — | Inline styles forwarded to the root |
Slots
| Slot | Type | Description |
|---|---|---|
| fallback | ReactNode | Decorative content rendered inside the static multipoint chart-token gradient when reduced motion is enabled; the fallback root is aria-hidden |
Usage Guidelines
- The live root is
absolute inset-0 z-0and receives pointer events. Put it in arelative overflow-hiddenparent, layer content atrelative z-10, and usepointer-events-noneonly on decorative foreground copy so movement can still reach LiquidEther. See [[webgl-canvas-rendered-but-invisible-negative-zindex-covered]]. - During SSR, the live root has no canvas. After hydration, a canvas is appended before OGL import and scene setup; if either step fails, that uninitialized or blank canvas remains and LiquidEther does not switch to the reduced-motion fallback. Reduced motion instead renders the static gradient plus decorative
fallbackcontent. - CSS variables in
colorsare resolved through an off-screen canvas. Use full names such asvar(--color-chart-1); bare values such asvar(--primary)cannot be resolved. See [[oklch-css-var-color-must-parse-via-offscreen-canvas]]. - A throttled animation frame loop can make headless screenshots appear static or empty. Verify motion on a real device or through Playwright frame measurements; see [[recharts-headless-screenshot-blank-clippath-animation-starved]].
Related
DotPattern · GridPattern · StripedPattern · Spotlight · RetroGrid · Ripple
Playground
<div className="relative h-64 overflow-hidden rounded-xl"
style={{ background: "oklch(0.14 0.02 270)" }}>
<LiquidEther
speed={0.5}
scale={1}
mouseForce={1}
autoDemo={true}
opacity={1}
/>
</div>