@jayf0x/fluidity-js 0.1.3 → 0.1.4
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 +104 -119
- package/dist/globals.d.ts +63 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +1012 -0
- package/package.json +7 -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,141 @@ 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 {
|
|
56
|
+
import { useRef } from 'react';
|
|
57
|
+
import { FluidText } from '@jayf0x/fluidity-js';
|
|
60
58
|
|
|
61
|
-
export function
|
|
62
|
-
const
|
|
63
|
-
const controllerRef = useFluid(containerRef, { worker: false });
|
|
59
|
+
export function Interactive() {
|
|
60
|
+
const fluid = useRef<FluidHandle>(null);
|
|
64
61
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
return (
|
|
63
|
+
<>
|
|
64
|
+
<div style={{ width: '100%', height: 300 }}>
|
|
65
|
+
<FluidText ref={fluid} text="fluid" fontSize={120} color="#fff" />
|
|
66
|
+
</div>
|
|
67
|
+
<button onClick={() => fluid.current?.reset()}>Reset</button>
|
|
68
|
+
<button onClick={() => fluid.current?.updateConfig({ curl: 0.3 })}>Swirl</button>
|
|
69
|
+
</>
|
|
70
|
+
);
|
|
70
71
|
}
|
|
71
72
|
```
|
|
72
73
|
|
|
74
|
+
`FluidHandle` is a global type — no import needed.
|
|
75
|
+
|
|
76
|
+
More examples → [`demo/src/examples/`](./demo/src/examples/)
|
|
77
|
+
|
|
73
78
|
---
|
|
74
79
|
|
|
75
80
|
## Props
|
|
76
81
|
|
|
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 |
|
|
82
|
+
### FluidText
|
|
116
83
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
84
|
+
| Prop | Type | Default |
|
|
85
|
+
| ------------- | ------------------ | -------------- |
|
|
86
|
+
| `text` | `string` | — |
|
|
87
|
+
| `fontSize` | `number` | `100` |
|
|
88
|
+
| `color` | `string` | `'#ffffff'` |
|
|
89
|
+
| `fontFamily` | `string` | `'sans-serif'` |
|
|
90
|
+
| `fontWeight` | `string \| number` | `900` |
|
|
91
|
+
| `textQuality` | `number` | `2` |
|
|
121
92
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
|
127
|
-
|
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
|
135
|
-
|
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
93
|
+
`textQuality` controls the oversample factor for text rendering. `2` (default) renders at 2× the simulation resolution before upload so edges are antialiased. Set to `1` for the exact simulation resolution; higher values are sharper but use more texture memory.
|
|
94
|
+
|
|
95
|
+
### FluidImage
|
|
96
|
+
|
|
97
|
+
| Prop | Type | Default |
|
|
98
|
+
| ----------- | ------------------ | --------- |
|
|
99
|
+
| `src` | `string` | — |
|
|
100
|
+
| `imageSize` | `string \| number` | `'cover'` |
|
|
101
|
+
| `effect` | `number` | `0` |
|
|
102
|
+
|
|
103
|
+
### Shared props
|
|
104
|
+
|
|
105
|
+
| Prop | Type | Default |
|
|
106
|
+
| ----------------- | ---------------------- | ------------ |
|
|
107
|
+
| `config` | `Partial<FluidConfig>` | — |
|
|
108
|
+
| `preset` | `PresetKey` | — |
|
|
109
|
+
| `algorithm` | `FluidAlgorithm` | `'standard'` |
|
|
110
|
+
| `backgroundColor` | `string` | `'#0a0a0a'` |
|
|
111
|
+
| `backgroundSrc` | `string` | — |
|
|
112
|
+
| `backgroundSize` | `string \| number` | `'cover'` |
|
|
113
|
+
| `isMouseEnabled` | `boolean` | `true` |
|
|
114
|
+
| `isWorkerEnabled` | `boolean` | `true` |
|
|
115
|
+
| `className` | `string` | — |
|
|
116
|
+
| `style` | `CSSProperties` | — |
|
|
139
117
|
|
|
140
118
|
---
|
|
141
119
|
|
|
142
|
-
##
|
|
120
|
+
## Algorithms
|
|
121
|
+
|
|
122
|
+
| Value | Character |
|
|
123
|
+
| ------------ | ------------------------------------------------- |
|
|
124
|
+
| `'standard'` | Colour overlay + gentle refraction (default) |
|
|
125
|
+
| `'glass'` | Strong UV distortion only — bent-glass, no colour |
|
|
126
|
+
| `'ink'` | Dense opaque pigment that accumulates and stains |
|
|
127
|
+
| `'aurora'` | Velocity-field UV warp — liquid metal / lava-lamp |
|
|
128
|
+
| `'ripple'` | Exaggerated normals + Fresnel rim — still water |
|
|
143
129
|
|
|
144
130
|
```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 });
|
|
131
|
+
<FluidImage src="/photo.jpg" algorithm="aurora" />
|
|
132
|
+
<FluidText text="fluid" algorithm="ripple" config={{ warpStrength: 0.03 }} />
|
|
150
133
|
```
|
|
151
134
|
|
|
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
135
|
---
|
|
159
136
|
|
|
160
|
-
##
|
|
137
|
+
## FluidConfig
|
|
138
|
+
|
|
139
|
+
| Key | Default | Description |
|
|
140
|
+
| --------------------- | ------------------ | ----------------------------------------- |
|
|
141
|
+
| `densityDissipation` | `0.992` | How long ink lingers (0–1) |
|
|
142
|
+
| `velocityDissipation` | `0.93` | How fast velocity decays (0–1) |
|
|
143
|
+
| `pressureIterations` | `1` | Jacobi iterations — accuracy vs. cost |
|
|
144
|
+
| `curl` | `0.0001` | Vorticity / swirl. `0.2`–`0.5` for eddies |
|
|
145
|
+
| `splatRadius` | `0.004` | Brush radius |
|
|
146
|
+
| `splatForce` | `0.91` | Force applied by brush |
|
|
147
|
+
| `refraction` | `0.25` | Background warp strength |
|
|
148
|
+
| `specularExp` | `1.01` | Specular highlight sharpness |
|
|
149
|
+
| `shine` | `0.01` | Highlight intensity |
|
|
150
|
+
| `waterColor` | `[0, 0, 0]` | Base fluid colour `[R, G, B]` (0–1) |
|
|
151
|
+
| `glowColor` | `[0.7, 0.85, 1.0]` | Glow / specular colour `[R, G, B]` (0–1) |
|
|
152
|
+
| `warpStrength` | `0.015` | UV warp intensity (`aurora` algorithm) |
|
|
161
153
|
|
|
162
|
-
|
|
154
|
+
---
|
|
163
155
|
|
|
164
|
-
|
|
165
|
-
<FluidText text="wave" preset="wave" />
|
|
166
|
-
```
|
|
156
|
+
## FluidHandle (ref)
|
|
167
157
|
|
|
168
|
-
|
|
|
169
|
-
|
|
170
|
-
| `
|
|
171
|
-
| `
|
|
172
|
-
| `
|
|
173
|
-
| `
|
|
174
|
-
| `smoke` | Dense, rising smoke |
|
|
158
|
+
| Method | Description |
|
|
159
|
+
| -------------------------------- | ----------------------------------------------------- |
|
|
160
|
+
| `reset()` | Re-initialise simulation and reload source |
|
|
161
|
+
| `updateConfig(patch)` | Merge a partial config update into running sim |
|
|
162
|
+
| `move({ x, y, strength? })` | Programmatic pointer input (canvas-relative px) |
|
|
163
|
+
| `splat(x, y, vx, vy, strength?)` | Inject a fluid splat directly — safe to call N×/frame |
|
|
175
164
|
|
|
176
|
-
|
|
165
|
+
---
|
|
177
166
|
|
|
178
|
-
|
|
179
|
-
import { PRESETS } from 'fluidity-js';
|
|
180
|
-
// PRESETS.storm → Partial<FluidConfig>
|
|
181
|
-
```
|
|
167
|
+
## Presets
|
|
182
168
|
|
|
183
|
-
|
|
169
|
+
```tsx
|
|
170
|
+
<FluidText text="storm" preset="storm" />
|
|
171
|
+
<FluidText text="calm" preset="calm" config={{ curl: 0.1 }} />
|
|
172
|
+
```
|
|
184
173
|
|
|
185
|
-
|
|
174
|
+
Available: `calm` · `storm` · `wave` · `neon` · `smoke`
|
|
186
175
|
|
|
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) |
|
|
176
|
+
`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
177
|
|
|
193
178
|
---
|
|
194
179
|
|
|
@@ -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' | 'storm' | '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>;
|