Skip to content

Repository files navigation

fluidity-js

npm version npm downloads bundle size license TypeScript CI

Fluid text and image effects in React

Demo & Examples →

Quickstart

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>

Programmatic control

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

Props

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.

FluidText

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.

FluidImage

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.


Algorithms

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" />

Quality

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 reference

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)

Browser support

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.


Contributing

See CONTRIBUTING.md for setup and AGENTS.md for code conventions.


License

MIT © jayf0x

About

React components that add interactive fluid effects — water, ink, glass, aurora — to text and images.

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages