Skip to content

jayf0x/fluidity

Repository files navigation

fluidity-js — Upgrade your UX

npm version npm downloads bundle size license TypeScript CI

Fluid text and image effects in React

Demo & Examples →

Star this repository if you’d like to support its growth

Quickstart

Choose your weapon:

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

FluidText

Prop Type Default
text string
fontSize number 100
color string '#ffffff'
fontFamily string 'sans-serif'
fontWeight string | number 900
textBlur number 1

FluidImage

Prop Type Default
src string
imageSize string | number 'cover'
effect number 0
obstacleStrength number 0
refraction number 1.0
warpStrength number 0.04

Shared props

Prop Type Default
algorithm FluidAlgorithm 'aurora'
preset PresetKey
pixelRatio number 1
simResolution number 0.5
simMaxPixels number — (uncapped)
densityDissipation number 0.83
velocityDissipation number 0.91
pressureIterations number 1
curl number 0
splatRadius number 0.1
splatForce number 0.08
specularExp number 0
shine number 0
waterColor FluidColor '#000000'
glowColor FluidColor '#b3d9ff'
backgroundColor string '#0a0a0a'
backgroundSrc string
backgroundSize string | number 'cover'
mouseEnabled boolean true
workerEnabled boolean true
webGPUEnabled boolean true
alphaEnabled boolean true
className string
style CSSProperties

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

Works in all modern browsers. Automatically picks the best renderer available — no configuration needed.

Browser Support
Chrome 113+
Edge 113+
Firefox
Safari 17+
Safari < 17
Mobile Chrome

Contributing

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


License

MIT © jayf0x

About

React library for interactive fluid effects on text and images — water, ink, glass, aurora. Runs off the main thread, works in all modern browsers.

Topics

Resources

License

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors