@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 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
- [![npm](https://img.shields.io/npm/v/fluidity-js)](https://www.npmjs.com/package/fluidity-js)
6
- [![license](https://img.shields.io/npm/l/fluidity-js)](./LICENSE)
7
- [![size](https://img.shields.io/bundlephobia/minzip/fluidity-js)](https://bundlephobia.com/package/fluidity-js)
5
+ [![npm](https://img.shields.io/npm/v/@jayf0x/fluidity-js)](https://www.npmjs.com/package/@jayf0x/fluidity-js)
6
+ [![license](https://img.shields.io/npm/l/@jayf0x/fluidity-js)](./LICENSE)
7
+ [![size](https://img.shields.io/bundlephobia/minzip/@jayf0x/fluidity-js)](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 a browser with WebGL2 support.
19
+ Requires React ≥ 17 and WebGL (WebGL2 recommended; WebGL1 supported as fallback).
22
20
 
23
21
  ---
24
22
 
25
- ## Quick start
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 world" fontSize={120} color="#ffffff" />
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" imageSize="cover" />
47
+ <FluidImage src="/hero.jpg" algorithm="aurora" />
50
48
  </div>
51
49
  );
52
50
  }
53
51
  ```
54
52
 
55
- ### useFluid hook (custom canvas)
53
+ ### Ref API
56
54
 
57
55
  ```tsx
58
- import { useRef, useEffect } from 'react';
59
- import { useFluid } from 'fluidity-js';
56
+ import { useRef } from 'react';
60
57
 
61
- export function Custom() {
62
- const containerRef = useRef<HTMLDivElement>(null);
63
- const controllerRef = useFluid(containerRef, { worker: false });
58
+ import { FluidText } from '@jayf0x/fluidity-js';
64
59
 
65
- useEffect(() => {
66
- controllerRef.current?.setTextSource({ text: 'custom', fontSize: 80, color: '#fff' });
67
- }, []);
60
+ export function Interactive() {
61
+ const fluid = useRef<FluidHandle>(null);
68
62
 
69
- return <div ref={containerRef} style={{ width: 400, height: 200 }} />;
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
- ### FluidTextProps
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
- ```tsx
118
- <FluidImage src="/photo.jpg" algorithm="aurora" />
119
- <FluidText text="fluid" algorithm="ripple" config={{ warpStrength: 0.03 }} />
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
- ### FluidConfig
123
-
124
- | Key | Type | Default | Description |
125
- |-----|------|---------|-------------|
126
- | `densityDissipation` | `number` | `0.992` | How long ink lingers (0–1). |
127
- | `velocityDissipation` | `number` | `0.93` | How quickly velocity decays (0–1). |
128
- | `pressureIterations` | `number` | `25` | Jacobi iterations — higher is more accurate but slower. |
129
- | `curl` | `number` | `0.0001` | Vorticity confinement — swirl factor. Visible effect starts around `0.1`; `0.2`–`0.5` for strong swirl. |
130
- | `splatRadius` | `number` | `0.004` | Brush radius. |
131
- | `splatForce` | `number` | `0.91` | Force applied by brush. |
132
- | `refraction` | `number` | `0.25` | Background warp / refraction strength. |
133
- | `specularExp` | `number` | `1.01` | Specular highlight exponent. |
134
- | `shine` | `number` | `0.01` | Highlight intensity. |
135
- | `waterColor` | `[R, G, B]` | `[0, 0, 0]` | Base fluid colour (0–1 each). |
136
- | `glowColor` | `[R, G, B]` | `[0.7, 0.85, 1.0]` | Glow / specular colour (0–1 each). |
137
- | `algorithm` | `FluidAlgorithm` | `'standard'` | Display rendering algorithm. |
138
- | `warpStrength` | `number` | `0.015` | UV warp intensity for the `aurora` algorithm. |
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
- ## FluidHandle (ref API)
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
- const ref = useRef<FluidHandle>(null);
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
- ## Presets
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
- Pass `preset="storm"` (or any key below) to use a named configuration bundle. Your own `config` props override preset values.
152
+ ---
163
153
 
164
- ```tsx
165
- <FluidText text="wave" preset="wave" />
166
- ```
154
+ ## FluidHandle (ref)
167
155
 
168
- | Preset | Description |
169
- |--------|-------------|
170
- | `calm` | Slow, peaceful drift |
171
- | `storm` | Violent, turbulent chaos |
172
- | `wave` | Rolling vortex eddies |
173
- | `neon` | Vivid glowing highlights |
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
- You can also import `PRESETS` directly:
163
+ ---
177
164
 
178
- ```ts
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
- ## Browser support
172
+ Available: `calm` · `sand` · `wave` · `neon` · `smoke`
186
173
 
187
- | Feature | Support |
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
+ }
@@ -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>;