@jayf0x/fluidity-js 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -118
- package/dist/globals.d.ts +63 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +1017 -0
- package/package.json +10 -7
- package/dist/fluidity-js.js +0 -956
- package/types/index.d.ts +0 -290
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
**WebGL fluid simulation for React — interactive text and image effects powered by Navier-Stokes.**
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/fluidity-js)
|
|
6
|
-
[](./LICENSE)
|
|
7
|
-
[](https://bundlephobia.com/package/fluidity-js)
|
|
5
|
+
[](https://www.npmjs.com/package/@jayf0x/fluidity-js)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
[](https://bundlephobia.com/package/@jayf0x/fluidity-js)
|
|
8
8
|
|
|
9
9
|
[**Live demo →**](https://jayf0x.github.io/fluidity)
|
|
10
10
|
|
|
@@ -13,26 +13,24 @@
|
|
|
13
13
|
## Install
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npm i fluidity-js
|
|
17
|
-
# or
|
|
18
|
-
pnpm add fluidity-js
|
|
16
|
+
npm i @jayf0x/fluidity-js
|
|
19
17
|
```
|
|
20
18
|
|
|
21
|
-
Requires React ≥ 17 and
|
|
19
|
+
Requires React ≥ 17 and WebGL (WebGL2 recommended; WebGL1 supported as fallback).
|
|
22
20
|
|
|
23
21
|
---
|
|
24
22
|
|
|
25
|
-
##
|
|
23
|
+
## Usage
|
|
26
24
|
|
|
27
25
|
### FluidText
|
|
28
26
|
|
|
29
27
|
```tsx
|
|
30
|
-
import { FluidText } from 'fluidity-js';
|
|
28
|
+
import { FluidText } from '@jayf0x/fluidity-js';
|
|
31
29
|
|
|
32
30
|
export function Hero() {
|
|
33
31
|
return (
|
|
34
32
|
<div style={{ width: '100%', height: 300 }}>
|
|
35
|
-
<FluidText text="hello
|
|
33
|
+
<FluidText text="hello" fontSize={120} color="#ffffff" />
|
|
36
34
|
</div>
|
|
37
35
|
);
|
|
38
36
|
}
|
|
@@ -41,154 +39,139 @@ export function Hero() {
|
|
|
41
39
|
### FluidImage
|
|
42
40
|
|
|
43
41
|
```tsx
|
|
44
|
-
import { FluidImage } from 'fluidity-js';
|
|
42
|
+
import { FluidImage } from '@jayf0x/fluidity-js';
|
|
45
43
|
|
|
46
44
|
export function Cover() {
|
|
47
45
|
return (
|
|
48
46
|
<div style={{ width: '100%', height: '100vh' }}>
|
|
49
|
-
<FluidImage src="/hero.jpg"
|
|
47
|
+
<FluidImage src="/hero.jpg" algorithm="aurora" />
|
|
50
48
|
</div>
|
|
51
49
|
);
|
|
52
50
|
}
|
|
53
51
|
```
|
|
54
52
|
|
|
55
|
-
###
|
|
53
|
+
### Ref API
|
|
56
54
|
|
|
57
55
|
```tsx
|
|
58
|
-
import { useRef
|
|
59
|
-
import { useFluid } from 'fluidity-js';
|
|
56
|
+
import { useRef } from 'react';
|
|
60
57
|
|
|
61
|
-
|
|
62
|
-
const containerRef = useRef<HTMLDivElement>(null);
|
|
63
|
-
const controllerRef = useFluid(containerRef, { worker: false });
|
|
58
|
+
import { FluidText } from '@jayf0x/fluidity-js';
|
|
64
59
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}, []);
|
|
60
|
+
export function Interactive() {
|
|
61
|
+
const fluid = useRef<FluidHandle>(null);
|
|
68
62
|
|
|
69
|
-
return
|
|
63
|
+
return (
|
|
64
|
+
<>
|
|
65
|
+
<div style={{ width: '100%', height: 300 }}>
|
|
66
|
+
<FluidText ref={fluid} text="fluid" fontSize={120} color="#fff" />
|
|
67
|
+
</div>
|
|
68
|
+
<button onClick={() => fluid.current?.reset()}>Reset</button>
|
|
69
|
+
<button onClick={() => fluid.current?.updateConfig({ curl: 0.3 })}>Swirl</button>
|
|
70
|
+
</>
|
|
71
|
+
);
|
|
70
72
|
}
|
|
71
73
|
```
|
|
72
74
|
|
|
75
|
+
`FluidHandle` is a global type — no import needed.
|
|
76
|
+
|
|
77
|
+
More examples → [`demo/src/examples/`](./demo/src/examples/)
|
|
78
|
+
|
|
73
79
|
---
|
|
74
80
|
|
|
75
81
|
## Props
|
|
76
82
|
|
|
77
|
-
###
|
|
78
|
-
|
|
79
|
-
| Prop | Type | Default | Description |
|
|
80
|
-
|------|------|---------|-------------|
|
|
81
|
-
| `text` | `string` | — | Text to render. Changes trigger a texture rebuild. |
|
|
82
|
-
| `fontSize` | `number` | `100` | Font size in pixels. |
|
|
83
|
-
| `color` | `string` | `'#ffffff'` | CSS colour string for the text. |
|
|
84
|
-
| `fontFamily` | `string` | `'sans-serif'` | Font family. |
|
|
85
|
-
| `fontWeight` | `string \| number` | `900` | Font weight. |
|
|
86
|
-
| `config` | `Partial<FluidConfig>` | — | Simulation config overrides. |
|
|
87
|
-
| `preset` | `PresetKey` | — | Named preset as base config. |
|
|
88
|
-
| `algorithm` | `FluidAlgorithm` | `'standard'` | Rendering algorithm (see below). |
|
|
89
|
-
| `backgroundColor` | `string` | `'#0a0a0a'` | CSS colour behind the canvas (shows through transparent areas). |
|
|
90
|
-
| `backgroundSrc` | `string` | — | URL/path composited as background behind text. |
|
|
91
|
-
| `backgroundSize` | `string \| number` | `'cover'` | Sizing mode for `backgroundSrc`. |
|
|
92
|
-
| `isMouseEnabled` | `boolean` | `true` | Auto-wire mouse/touch events. |
|
|
93
|
-
| `isWorkerEnabled` | `boolean` | `true` | Run in Web Worker via OffscreenCanvas. |
|
|
94
|
-
| `className` | `string` | — | Class applied to the container div. |
|
|
95
|
-
| `style` | `CSSProperties` | — | Inline styles merged on container div. |
|
|
96
|
-
|
|
97
|
-
### FluidImageProps
|
|
98
|
-
|
|
99
|
-
All shared props (above) plus:
|
|
100
|
-
|
|
101
|
-
| Prop | Type | Default | Description |
|
|
102
|
-
|------|------|---------|-------------|
|
|
103
|
-
| `src` | `string` | — | Image URL. Changing reloads the simulation. |
|
|
104
|
-
| `effect` | `number` | `0.4` | Obstacle boundary strength (0–1). |
|
|
105
|
-
| `imageSize` | `string \| number` | `'cover'` | `'cover'` \| `'contain'` \| `'50%'` \| `'200px'` \| scale factor. |
|
|
106
|
-
|
|
107
|
-
### FluidAlgorithm
|
|
108
|
-
|
|
109
|
-
| Value | Visual character |
|
|
110
|
-
|-------|-----------------|
|
|
111
|
-
| `'standard'` | Colour overlay blended over refracted background (default) |
|
|
112
|
-
| `'glass'` | Strong UV distortion only — bent-glass, no colour overlay |
|
|
113
|
-
| `'ink'` | Dense opaque pigment accumulates and stains |
|
|
114
|
-
| `'aurora'` | Velocity-field UV warp — liquid metal / lava-lamp |
|
|
115
|
-
| `'ripple'` | Exaggerated normals + Fresnel rim — calm water surface |
|
|
83
|
+
### FluidText
|
|
116
84
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
85
|
+
| Prop | Type | Default |
|
|
86
|
+
| ------------ | ------------------ | -------------- |
|
|
87
|
+
| `text` | `string` | — |
|
|
88
|
+
| `fontSize` | `number` | `100` |
|
|
89
|
+
| `color` | `string` | `'#ffffff'` |
|
|
90
|
+
| `fontFamily` | `string` | `'sans-serif'` |
|
|
91
|
+
| `fontWeight` | `string \| number` | `900` |
|
|
92
|
+
|
|
93
|
+
### FluidImage
|
|
121
94
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
|
125
|
-
|
|
126
|
-
| `
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
|
131
|
-
|
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
95
|
+
| Prop | Type | Default |
|
|
96
|
+
| ----------- | ------------------ | --------- |
|
|
97
|
+
| `src` | `string` | — |
|
|
98
|
+
| `imageSize` | `string \| number` | `'cover'` |
|
|
99
|
+
| `effect` | `number` | `0` |
|
|
100
|
+
|
|
101
|
+
### Shared props
|
|
102
|
+
|
|
103
|
+
| Prop | Type | Default |
|
|
104
|
+
| ----------------- | ---------------------- | ------------ |
|
|
105
|
+
| `config` | `Partial<FluidConfig>` | — |
|
|
106
|
+
| `preset` | `PresetKey` | — |
|
|
107
|
+
| `algorithm` | `FluidAlgorithm` | `'standard'` |
|
|
108
|
+
| `backgroundColor` | `string` | `'#0a0a0a'` |
|
|
109
|
+
| `backgroundSrc` | `string` | — |
|
|
110
|
+
| `backgroundSize` | `string \| number` | `'cover'` |
|
|
111
|
+
| `isMouseEnabled` | `boolean` | `true` |
|
|
112
|
+
| `isWorkerEnabled` | `boolean` | `true` |
|
|
113
|
+
| `className` | `string` | — |
|
|
114
|
+
| `style` | `CSSProperties` | — |
|
|
139
115
|
|
|
140
116
|
---
|
|
141
117
|
|
|
142
|
-
##
|
|
118
|
+
## Algorithms
|
|
119
|
+
|
|
120
|
+
| Value | Character |
|
|
121
|
+
| ------------ | ------------------------------------------------- |
|
|
122
|
+
| `'standard'` | Colour overlay + gentle refraction (default) |
|
|
123
|
+
| `'glass'` | Strong UV distortion only — bent-glass, no colour |
|
|
124
|
+
| `'ink'` | Dense opaque pigment that accumulates and stains |
|
|
125
|
+
| `'aurora'` | Velocity-field UV warp — liquid metal / lava-lamp |
|
|
126
|
+
| `'ripple'` | Exaggerated normals + Fresnel rim — still water |
|
|
143
127
|
|
|
144
128
|
```tsx
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
ref.current?.reset();
|
|
148
|
-
ref.current?.updateConfig({ shine: 0.05, curl: 0.2 });
|
|
149
|
-
ref.current?.updateLocation({ x: 200, y: 150, strength: 5 });
|
|
129
|
+
<FluidImage src="/photo.jpg" algorithm="aurora" />
|
|
130
|
+
<FluidText text="fluid" algorithm="ripple" config={{ warpStrength: 0.03 }} />
|
|
150
131
|
```
|
|
151
132
|
|
|
152
|
-
| Method | Description |
|
|
153
|
-
|--------|-------------|
|
|
154
|
-
| `reset()` | Re-initialises simulation and reloads source. |
|
|
155
|
-
| `updateConfig(patch)` | Merges a partial config update into the running simulation. |
|
|
156
|
-
| `updateLocation({ x, y, strength? })` | Programmatic pointer input (coordinates relative to canvas). |
|
|
157
|
-
|
|
158
133
|
---
|
|
159
134
|
|
|
160
|
-
##
|
|
135
|
+
## FluidConfig
|
|
136
|
+
|
|
137
|
+
| Key | Default | Description |
|
|
138
|
+
| --------------------- | ------------------ | ----------------------------------------- |
|
|
139
|
+
| `densityDissipation` | `0.992` | How long ink lingers (0–1) |
|
|
140
|
+
| `velocityDissipation` | `0.93` | How fast velocity decays (0–1) |
|
|
141
|
+
| `pressureIterations` | `1` | Jacobi iterations — accuracy vs. cost |
|
|
142
|
+
| `curl` | `0.0001` | Vorticity / swirl. `0.2`–`0.5` for eddies |
|
|
143
|
+
| `splatRadius` | `0.004` | Brush radius |
|
|
144
|
+
| `splatForce` | `0.91` | Force applied by brush |
|
|
145
|
+
| `refraction` | `0.25` | Background warp strength |
|
|
146
|
+
| `specularExp` | `1.01` | Specular highlight sharpness |
|
|
147
|
+
| `shine` | `0.01` | Highlight intensity |
|
|
148
|
+
| `waterColor` | `[0, 0, 0]` | Base fluid colour `[R, G, B]` (0–1) |
|
|
149
|
+
| `glowColor` | `[0.7, 0.85, 1.0]` | Glow / specular colour `[R, G, B]` (0–1) |
|
|
150
|
+
| `warpStrength` | `0.015` | UV warp intensity (`aurora` algorithm) |
|
|
161
151
|
|
|
162
|
-
|
|
152
|
+
---
|
|
163
153
|
|
|
164
|
-
|
|
165
|
-
<FluidText text="wave" preset="wave" />
|
|
166
|
-
```
|
|
154
|
+
## FluidHandle (ref)
|
|
167
155
|
|
|
168
|
-
|
|
|
169
|
-
|
|
170
|
-
| `
|
|
171
|
-
| `
|
|
172
|
-
| `
|
|
173
|
-
| `
|
|
174
|
-
| `smoke` | Dense, rising smoke |
|
|
156
|
+
| Method | Description |
|
|
157
|
+
| -------------------------------- | ----------------------------------------------------- |
|
|
158
|
+
| `reset()` | Re-initialise simulation and reload source |
|
|
159
|
+
| `updateConfig(patch)` | Merge a partial config update into running sim |
|
|
160
|
+
| `move({ x, y, strength? })` | Programmatic pointer input (canvas-relative px) |
|
|
161
|
+
| `splat(x, y, vx, vy, strength?)` | Inject a fluid splat directly — safe to call N×/frame |
|
|
175
162
|
|
|
176
|
-
|
|
163
|
+
---
|
|
177
164
|
|
|
178
|
-
|
|
179
|
-
import { PRESETS } from 'fluidity-js';
|
|
180
|
-
// PRESETS.storm → Partial<FluidConfig>
|
|
181
|
-
```
|
|
165
|
+
## Presets
|
|
182
166
|
|
|
183
|
-
|
|
167
|
+
```tsx
|
|
168
|
+
<FluidText text="Wicked" preset="neon" />
|
|
169
|
+
<FluidText text="Wicked" preset="calm" />
|
|
170
|
+
```
|
|
184
171
|
|
|
185
|
-
|
|
172
|
+
Available: `calm` · `sand` · `wave` · `neon` · `smoke`
|
|
186
173
|
|
|
187
|
-
|
|
188
|
-
|---------|---------|
|
|
189
|
-
| WebGL2 | Required (Chrome 56+, Firefox 51+, Safari 15+) |
|
|
190
|
-
| WebGL1 | Automatic fallback |
|
|
191
|
-
| OffscreenCanvas + Worker | Chrome 69+, Firefox 105+ (auto-detected; falls back to main thread) |
|
|
174
|
+
`preset` is reactive — changing it re-applies the preset config. Any `config` values you pass override the preset. `algorithm` prop also overrides the preset's algorithm.
|
|
192
175
|
|
|
193
176
|
---
|
|
194
177
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
|
|
3
|
+
type FluidAlgorithm = 'standard' | 'glass' | 'ink' | 'aurora' | 'ripple';
|
|
4
|
+
|
|
5
|
+
interface FluidConfig {
|
|
6
|
+
densityDissipation: number;
|
|
7
|
+
velocityDissipation: number;
|
|
8
|
+
pressureIterations: number;
|
|
9
|
+
curl: number;
|
|
10
|
+
splatRadius: number;
|
|
11
|
+
splatForce: number;
|
|
12
|
+
refraction: number;
|
|
13
|
+
specularExp: number;
|
|
14
|
+
shine: number;
|
|
15
|
+
waterColor: [number, number, number];
|
|
16
|
+
glowColor: [number, number, number];
|
|
17
|
+
algorithm: FluidAlgorithm;
|
|
18
|
+
warpStrength: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type PresetKey = 'calm' | 'sand' | 'wave' | 'neon' | 'smoke';
|
|
22
|
+
|
|
23
|
+
interface FluidHandle {
|
|
24
|
+
reset(): void;
|
|
25
|
+
move(opts: { x: number; y: number; strength?: number }): void;
|
|
26
|
+
splat(x: number, y: number, vx: number, vy: number, strength?: number): void;
|
|
27
|
+
updateConfig(config: Partial<FluidConfig>): void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface FluidBaseProps {
|
|
31
|
+
className?: string;
|
|
32
|
+
style?: React.CSSProperties;
|
|
33
|
+
config?: Partial<FluidConfig>;
|
|
34
|
+
isMouseEnabled?: boolean;
|
|
35
|
+
isWorkerEnabled?: boolean;
|
|
36
|
+
preset?: PresetKey;
|
|
37
|
+
algorithm?: FluidAlgorithm;
|
|
38
|
+
backgroundColor?: string;
|
|
39
|
+
backgroundSrc?: string;
|
|
40
|
+
backgroundSize?: string | number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface FluidTextProps extends FluidBaseProps {
|
|
44
|
+
text: string;
|
|
45
|
+
fontSize?: number;
|
|
46
|
+
color?: string;
|
|
47
|
+
fontFamily?: string;
|
|
48
|
+
fontWeight?: string | number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface FluidImageProps extends FluidBaseProps {
|
|
52
|
+
src: string;
|
|
53
|
+
effect?: number;
|
|
54
|
+
imageSize?: string | number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface TextSourceOpts {
|
|
58
|
+
text: string;
|
|
59
|
+
fontSize: number;
|
|
60
|
+
color: string;
|
|
61
|
+
fontFamily?: string;
|
|
62
|
+
fontWeight?: string | number;
|
|
63
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/// <reference path="./globals.d.ts" />
|
|
2
|
+
|
|
3
|
+
export declare const FluidText: React.ForwardRefExoticComponent<FluidTextProps & React.RefAttributes<FluidHandle>>;
|
|
4
|
+
export declare const FluidImage: React.ForwardRefExoticComponent<FluidImageProps & React.RefAttributes<FluidHandle>>;
|
|
5
|
+
|
|
6
|
+
export declare function useFluid(
|
|
7
|
+
containerRef: React.RefObject<HTMLElement>,
|
|
8
|
+
opts?: { isWorkerEnabled?: boolean; config?: Partial<FluidConfig> }
|
|
9
|
+
): React.RefObject<FluidController | null>;
|
|
10
|
+
|
|
11
|
+
export declare class FluidController {
|
|
12
|
+
constructor(canvas: HTMLCanvasElement, opts?: { isWorkerEnabled?: boolean; config?: Partial<FluidConfig> });
|
|
13
|
+
setTextSource(opts: TextSourceOpts): void;
|
|
14
|
+
setImageSource(src: string, effect?: number, size?: string | number): void;
|
|
15
|
+
setBackground(bitmap: ImageBitmap | null, size?: string | number): void;
|
|
16
|
+
handleMove(x: number, y: number, strength?: number): void;
|
|
17
|
+
splat(x: number, y: number, vx: number, vy: number, strength?: number): void;
|
|
18
|
+
resize(width: number, height: number): void;
|
|
19
|
+
updateConfig(config: Partial<FluidConfig>): void;
|
|
20
|
+
destroy(): void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export declare class FluidSimulation {
|
|
24
|
+
constructor(canvas: HTMLCanvasElement | OffscreenCanvas, config?: Partial<FluidConfig>);
|
|
25
|
+
setTextSource(opts: TextSourceOpts): void;
|
|
26
|
+
setImageSource(src: string, effect?: number, size?: string | number): Promise<void>;
|
|
27
|
+
setImageBitmap(bitmap: ImageBitmap, effect?: number, size?: string | number): void;
|
|
28
|
+
setBackground(bitmap: ImageBitmap | null, size?: string | number): void;
|
|
29
|
+
handleMove(x: number, y: number, strength?: number): void;
|
|
30
|
+
splat(x: number, y: number, vx: number, vy: number, strength?: number): void;
|
|
31
|
+
resize(width?: number, height?: number): void;
|
|
32
|
+
updateConfig(config: Partial<FluidConfig>): void;
|
|
33
|
+
start(): void;
|
|
34
|
+
stop(): void;
|
|
35
|
+
destroy(): void;
|
|
36
|
+
readonly isRunning: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type DefaultPropsShared = {
|
|
40
|
+
readonly backgroundColor: string;
|
|
41
|
+
readonly backgroundSize: string | number;
|
|
42
|
+
readonly isMouseEnabled: boolean;
|
|
43
|
+
readonly isWorkerEnabled: boolean;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type DefaultPropsImage = DefaultPropsShared & {
|
|
47
|
+
readonly effect: number;
|
|
48
|
+
readonly imageSize: string | number;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type DefaultPropsText = DefaultPropsShared & {
|
|
52
|
+
readonly fontSize: number;
|
|
53
|
+
readonly color: string;
|
|
54
|
+
readonly fontFamily: string;
|
|
55
|
+
readonly fontWeight: string | number;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export declare const DEFAULT_CONFIG: FluidConfig;
|
|
59
|
+
export declare const DEFAULT_CONFIG_TEXT: FluidConfig;
|
|
60
|
+
export declare const DEFAULT_PROPS_SHARED: DefaultPropsShared;
|
|
61
|
+
export declare const DEFAULT_PROPS_IMAGE: DefaultPropsImage;
|
|
62
|
+
export declare const DEFAULT_PROPS_TEXT: DefaultPropsText;
|
|
63
|
+
export declare const PRESETS: Record<PresetKey, Partial<FluidConfig>>;
|
|
64
|
+
export declare function mergeConfig(user?: Partial<FluidConfig>, preset?: PresetKey, base?: FluidConfig): FluidConfig;
|
|
65
|
+
export declare function loadImageBitmap(src: string): Promise<ImageBitmap>;
|