A tiny, zero-dependency fluid simulation for the web that reacts to device motion.
Most fluid simulations are heavy particle engines (100KB+). fluid.js is different. It uses a 2D spring-mass system coupled with inertial angular physics to simulate the feeling of liquid in a container.
It is designed for UI Backgrounds, Loading States, and Interactive Cards.
- Micro-Library: ~4KB (minified + gzipped).
- Device Ready: Reacts to Gyroscope/Accelerometer (Mobile) and Mouse/Slider (PC).
- Inertial Physics: Simulates "Slosh", momentum, and wall climbing (U-Shape).
- Zero Dependencies: Pure Vanilla JS. Works with React, Vue, Svelte, or plain HTML.
npm install fluid.js<canvas id="my-fluid-canvas"></canvas>
<script type="module">
import { Fluid } from 'fluid.js';
const fluid = new Fluid('#my-fluid-canvas', {
color: '#00aaff', // Hex color
tension: 0.01, // Surface tension
dampening: 0.02 // Ripple decay
});
// Set initial fill level (0 to 100)
fluid.setFill(50);
</script>import { useEffect, useRef } from 'react';
import { Fluid } from 'fluid.js';
export default function LiquidCard() {
const canvasRef = useRef(null);
useEffect(() => {
const myFluid = new Fluid(canvasRef.current, {
color: '#ff4444'
});
myFluid.setFill(60);
}, []);
return <canvas ref={canvasRef} style={{ width: '100%', height: '100%' }} />;
}You can tune the liquid to feel like Water, Oil, or Jelly.
| Option | Default | Description |
|---|---|---|
color |
#3b82f6 |
The hex color of the liquid. |
tension |
0.01 |
Surface stiffness. Lower = more waves. |
dampening |
0.02 |
Friction. Lower = waves last longer. |
spread |
0.25 |
How fast ripples travel across the surface. |
inertia |
0.96 |
Momentum conservation. Higher = more slosh. |
wallClimb |
2.5 |
How high fluid climbs walls during rotation. |
If you don't want to tune physics manually, copy these values:
Water (Default)
{ tension: 0.01, dampening: 0.02, inertia: 0.96 }Oil / Honey
{ tension: 0.03, dampening: 0.1, inertia: 0.90 }Slime / Jelly
{ tension: 0.08, dampening: 0.05, inertia: 0.80 }On iOS 13+, you must request permission to access the Gyroscope. The browser will not let you access sensors automatically. You must trigger this from a button click (e.g., "Enable Gravity").
// Run this inside a button click handler
if (typeof DeviceMotionEvent.requestPermission === 'function') {
DeviceMotionEvent.requestPermission()
.then(response => {
if (response === 'granted') {
// Sensors are now active, fluid.js will auto-detect them
}
})
.catch(console.error);
}MIT
{ github.com/mgks }