Demo & Examples →
bun add @jayf0x/fluidity-js
# OR pnpm / aube / yarn / npm ...Text:
import { FluidText } from '@jayf0x/fluidity-js';
<div style={{ width: '100%', height: 400 }}>
<FluidText text="Howdy World" fontSize={140} />
</div>;Image:
import { FluidImage } from '@jayf0x/fluidity-js';
<div style={{ width: '100%', height: '100vh' }}>
<FluidImage src="/hero.png" algorithm="aurora" />
</div>;Text + Image:
<div style={{ width: '100%', height: 400 }}>
<FluidText text="Howdy World" backgroundSrc="/hero.png" />
</div>Use ref to trigger effects from code — scroll-driven splats, click bursts, attract particles:
import { useRef } from 'react';
import { FluidText } from '@jayf0x/fluidity-js';
export const Interactive = () => {
const fluid = useRef<FluidHandle>(null);
return (
<>
<div style={{ width: '100%', height: 400 }}>
<FluidText ref={fluid} text="Splash!" fontSize={120} color="#fff" />
</div>
<button onClick={() => fluid.current?.splat(200, 200, 8, -4)}>Splat</button>
<button onClick={() => fluid.current?.updateConfig({ curl: 0.5 })}>Swirl</button>
<button onClick={() => fluid.current?.reset()}>Reset</button>
</>
);
};| Method | What it does |
|---|---|
reset() |
Restart the simulation |
updateConfig(patch) |
Change any config value live |
move(x, y, strength?) |
Simulate a pointer move |
splat(x, y, vx, vy, strength?) |
Inject fluid directly — safe to call many times per frame |
Generated from the real component types by scripts/readme.ts (via
type-to-table) — re-run bun scripts/readme.ts
after any prop change, or just let npm:deploy do it before release.
| Prop | Type | Default | Description |
|---|---|---|---|
| text | string | ||
| fontSize? | number | undefined | 100 | |
| color? | string | undefined | #ffffff | |
| fontFamily? | string | undefined | sans-serif | |
| fontWeight? | string | number | undefined | 900 as string | number | |
| textAlign? | "center" | "left" | "right" | undefined | 'center' as 'left' | 'center' | 'right' | |
| textQuality? | number | undefined | 1 | |
| textBlur? | number | undefined | 1 | Edge softness (device px) for the glyph draw. Softens the dark AA fringe on solid-colour text against the black backdrop. Clamped to [0, 2]. Default: 1. |
| densityDissipation? | number | undefined | ||
| velocityDissipation? | number | undefined | ||
| pressureIterations? | number | undefined | ||
| curl? | number | undefined | ||
| splatRadius? | number | undefined | ||
| splatForce? | number | undefined | ||
| specularExp? | number | undefined | ||
| shine? | number | undefined | ||
| waterColor? | FluidColor | undefined | ||
| glowColor? | FluidColor | undefined | ||
| algorithm? | FluidAlgorithm | undefined | ||
| className? | string | undefined | Applied to the canvas container element. | |
| style? | CSSProperties | undefined | Applied to the canvas container element. | |
| pixelRatio? | number | undefined | DEFAULT_QUALITY.dpr | Canvas backing resolution as a fraction of devicePixelRatio. Range [0.1, 1]. Default 1 (native DPR). |
| simResolution? | number | undefined | DEFAULT_QUALITY.sim | Simulation FBO size as a fraction of canvas size. Range [0.1, 1]. Default 0.5. |
| simMaxPixels? | number | undefined | Caps simWidth × simHeight so extreme aspect ratios (ultra-wide/tall) stay responsive — both sim axes scale down together, preserving aspect ratio. Default: uncapped. |
|
| preset? | PresetKey | undefined | ||
| backgroundColor? | string | undefined | #0a0a0a | |
| backgroundSrc? | string | undefined | ||
| backgroundSize? | string | number | undefined | 'cover' as string | number | |
| mouseEnabled? | boolean | undefined | true | Forward pointer events to the simulation. Default true. |
| workerEnabled? | boolean | undefined | true | Run simulation in a Web Worker via OffscreenCanvas. Default true. |
| webGPUEnabled? | boolean | undefined | true | Prefer WebGPU renderer; falls back to WebGL. Default true. |
| alphaEnabled? | boolean | undefined | true | Enable transparent canvas. Default true. Set false for a minor perf gain when transparency is not needed. |
| Prop | Type | Default | Description |
|---|---|---|---|
| src | string | ||
| effect? | number | undefined | 0 as number | |
| imageSize? | string | number | undefined | 'cover' as string | number | |
| obstacleStrength? | number | undefined | 0 as number | 0–1 — how much the image's own luminance drives the physics obstacle. 0 (default)matches prior behaviour: the image is purely decorative, fluid flows unobstructed. 1: bright pixels fully block flow, dark pixels barely block it at all. |
| className? | string | undefined | Applied to the canvas container element. | |
| style? | CSSProperties | undefined | Applied to the canvas container element. | |
| pixelRatio? | number | undefined | DEFAULT_QUALITY.dpr | Canvas backing resolution as a fraction of devicePixelRatio. Range [0.1, 1]. Default 1 (native DPR). |
| simResolution? | number | undefined | DEFAULT_QUALITY.sim | Simulation FBO size as a fraction of canvas size. Range [0.1, 1]. Default 0.5. |
| simMaxPixels? | number | undefined | Caps simWidth × simHeight so extreme aspect ratios (ultra-wide/tall) stay responsive — both sim axes scale down together, preserving aspect ratio. Default: uncapped. |
|
| preset? | PresetKey | undefined | ||
| backgroundColor? | string | undefined | #0a0a0a | |
| backgroundSrc? | string | undefined | ||
| backgroundSize? | string | number | undefined | 'cover' as string | number | |
| mouseEnabled? | boolean | undefined | true | Forward pointer events to the simulation. Default true. |
| workerEnabled? | boolean | undefined | true | Run simulation in a Web Worker via OffscreenCanvas. Default true. |
| webGPUEnabled? | boolean | undefined | true | Prefer WebGPU renderer; falls back to WebGL. Default true. |
| alphaEnabled? | boolean | undefined | true | Enable transparent canvas. Default true. Set false for a minor perf gain when transparency is not needed. |
| densityDissipation? | number | undefined | ||
| velocityDissipation? | number | undefined | ||
| pressureIterations? | number | undefined | ||
| curl? | number | undefined | ||
| splatRadius? | number | undefined | ||
| splatForce? | number | undefined | ||
| refraction? | number | undefined | ||
| specularExp? | number | undefined | ||
| shine? | number | undefined | ||
| waterColor? | FluidColor | undefined | ||
| glowColor? | FluidColor | undefined | ||
| algorithm? | FluidAlgorithm | undefined | ||
| warpStrength? | number | undefined |
FluidImage inherits every shared prop above plus its own src/effect/imageSize/obstacleStrength/refraction/warpStrength; FluidText inherits the same shared props (minus refraction/warpStrength, see AGENTS.md) plus its own text-specific props.
| Value | Vibe |
|---|---|
'aurora' |
Liquid metal / lava-lamp (default) |
'standard' |
Colour overlay + gentle refraction |
'glass' |
Bent-glass distortion, no colour |
'ink' |
Dense opaque pigment that accumulates and stains |
'ripple' |
Still water surface with Fresnel rim |
<FluidImage src="/photo.jpg" algorithm="aurora" warpStrength={0.3} />
<FluidText text="fluid" algorithm="ripple" />Control rendering resolution on independent axes — all reactive at runtime.
| Prop | Range | Default | What it does |
|---|---|---|---|
pixelRatio |
0.1–1 | 1 |
Canvas resolution as fraction of devicePixelRatio. 0.5 on Retina saves ~75% GPU fill. |
simResolution |
0.1–1 | 0.5 |
Simulation FBO size. Lower = cheaper, less detail. |
simMaxPixels |
>0 | — (uncapped) | Hard cap on simWidth × simHeight, applied after simResolution. Both sim axes scale down together (aspect ratio preserved) so ultra-wide or ultra-tall containers stay responsive without a runaway texel count on one axis. |
// Ultra-wide hero banner — cap the sim grid regardless of how wide the container gets
<FluidImage src="/banner.jpg" simResolution={1} simMaxPixels={500_000} />// Sharp canvas, cheap simulation
<FluidImage src="/hero.jpg" pixelRatio={1} simResolution={0.2} />
// Lower canvas res, full simulation quality
<FluidImage src="/hero.jpg" pixelRatio={0.5} simResolution={1} />Simulation props that have a physics range accept a normalized 0–1 value — no need to know the raw shader units. Values outside [0, 1] are passed through as raw physics values for advanced overrides.
| Prop | Default | Range | Physics range | Description |
|---|---|---|---|---|
densityDissipation |
0.83 |
0–1 |
0.94–1.0 |
How long ink lingers |
velocityDissipation |
0.91 |
0–1 |
0.9–0.999 |
How fast fluid slows down |
pressureIterations |
1 |
1–50 |
— | Pressure solve quality vs. cost |
curl |
0 |
0–1 |
— | Swirl intensity |
splatRadius |
0.1 |
0–1 |
0.001–0.04 |
Brush radius |
splatForce |
0.08 |
0–1 |
0.1–5.0 |
Force applied by brush |
refraction |
1.0 |
0–1 |
— | Background warp strength |
specularExp |
0 |
0–1 |
0.1–10 |
Specular highlight sharpness |
shine |
0 |
0–1 |
0–0.15 |
Highlight intensity |
warpStrength |
0.04 |
0–1 |
0.001–0.1 |
UV warp intensity (aurora algorithm) |
waterColor |
#000 |
— | — | Base fluid colour (hex or [R, G, B] 0–1) |
glowColor |
#b3d9ff |
— | — | Glow / specular colour (hex or [R, G, B] 0–1) |
Picks the fastest renderer available at runtime: WebGPU where supported (Chrome/Edge 113+), WebGL2 otherwise, WebGL1 as the last resort. Works in any browser with WebGL.
See CONTRIBUTING.md for setup and AGENTS.md for code conventions.