@jayf0x/fluidity-js 0.2.2 → 0.2.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/AGENTS.md +148 -0
- package/CONTRIBUTING.md +45 -0
- package/README.md +75 -90
- package/dist/index.js +653 -629
- package/llms.txt +156 -0
- package/package.json +34 -6
package/AGENTS.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# AGENTS.md — fluidity-js
|
|
2
|
+
|
|
3
|
+
> Universal agent instructions for GitHub Copilot, Cursor, GPT-4, Gemini, and all AI coding assistants.
|
|
4
|
+
> Claude Code users: see [CLAUDE.md](./CLAUDE.md) for deeper architecture notes.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## What this repo is
|
|
9
|
+
|
|
10
|
+
`@jayf0x/fluidity-js` — a WebGPU-first fluid simulation library for React. Implements a real-time Navier-Stokes solver (advection, divergence, pressure, vorticity confinement) that renders onto a `<canvas>` element. Falls back automatically to WebGL2 → WebGL1. Runs the heavy simulation loop in a Web Worker via OffscreenCanvas by default.
|
|
11
|
+
|
|
12
|
+
Two components: `<FluidText>` (text as obstacle/background) and `<FluidImage>` (bitmap as obstacle/background).
|
|
13
|
+
|
|
14
|
+
**Stack:** TypeScript · React 17+ · Vite 4 · Vitest · Bun
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Repo layout (critical paths)
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
src/
|
|
22
|
+
index.ts ← public exports
|
|
23
|
+
globals.d.ts ← ambient global types (FluidConfig, FluidHandle…)
|
|
24
|
+
core/
|
|
25
|
+
config.ts ← DEFAULT_CONFIG, presets, mergeConfig
|
|
26
|
+
gl-utils.ts ← WebGL context + FBO helpers
|
|
27
|
+
gpu-utils.ts ← WebGPU helpers
|
|
28
|
+
shaders.ts ← GLSL shader strings
|
|
29
|
+
wgsl-shaders.ts ← WGSL shader strings
|
|
30
|
+
simulation.ts ← FluidSimulation class (dual WebGPU/WebGL)
|
|
31
|
+
textures.ts ← texture creation for text + image modes
|
|
32
|
+
worker/index.ts ← Web Worker message handler
|
|
33
|
+
fluid-controller.ts ← worker vs main-thread abstraction
|
|
34
|
+
react/
|
|
35
|
+
FluidText.tsx ← React component
|
|
36
|
+
FluidImage.tsx ← React component
|
|
37
|
+
useFluid.ts ← core hook: canvas lifecycle + controller
|
|
38
|
+
tests/ ← Vitest + jsdom (83 tests)
|
|
39
|
+
demo/ ← standalone Vite 5 demo site (NOT the library)
|
|
40
|
+
dist/ ← built output (do not edit)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Commands
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Run tests (library root, Node 16 compat)
|
|
49
|
+
bun test:claude # preferred: runs vitest, tails last 8 lines
|
|
50
|
+
|
|
51
|
+
# Build library
|
|
52
|
+
bun build
|
|
53
|
+
|
|
54
|
+
# Demo (requires Node 20)
|
|
55
|
+
cd demo
|
|
56
|
+
PATH=/Users/me/.nvm/versions/node/v20.19.6/bin:$PATH bun dev
|
|
57
|
+
PATH=/Users/me/.nvm/versions/node/v20.19.6/bin:$PATH bun build
|
|
58
|
+
PATH=/Users/me/.nvm/versions/node/v20.19.6/bin:$PATH bun deploy # → gh-pages
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Public API
|
|
64
|
+
|
|
65
|
+
### Components
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
<FluidText text="Hello" fontSize={120} color="#fff" algorithm="glass" preset="neon" />
|
|
69
|
+
<FluidImage src="/hero.jpg" algorithm="aurora" quality={{ dpr: 1, sim: 0.5 }} />
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### FluidHandle ref
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
interface FluidHandle {
|
|
76
|
+
reset(): void;
|
|
77
|
+
move(opts: { x: number; y: number; strength?: number }): void;
|
|
78
|
+
splat(x: number, y: number, vx: number, vy: number, strength?: number): void;
|
|
79
|
+
updateConfig(config: Partial<FluidConfig>): void;
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Algorithms
|
|
84
|
+
`'standard'` · `'glass'` · `'ink'` · `'aurora'` · `'ripple'`
|
|
85
|
+
|
|
86
|
+
### Presets
|
|
87
|
+
`'calm'` · `'sand'` · `'wave'` · `'neon'` · `'smoke'`
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Code style / conventions
|
|
92
|
+
|
|
93
|
+
- **TypeScript strict** — no `any`, no non-null assertions without a comment
|
|
94
|
+
- **No file extensions** on imports within `src/` (e.g. `from './config'`)
|
|
95
|
+
Exception: worker import keeps `.js?worker&inline` for Vite query string
|
|
96
|
+
- **No default exports** from library modules; named exports only
|
|
97
|
+
- **No comments** unless the *why* is non-obvious (hidden constraint, invariant, workaround)
|
|
98
|
+
- **Formatting:** Prettier with `@trivago/prettier-plugin-sort-imports`
|
|
99
|
+
- **Tests:** All 83 must pass before any commit. Add tests for new behaviour.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Architecture invariants (do not violate)
|
|
104
|
+
|
|
105
|
+
| Rule | Reason |
|
|
106
|
+
|------|--------|
|
|
107
|
+
| `transferControlToOffscreen` called at most once per canvas | Irreversible — double-mount in StrictMode would crash |
|
|
108
|
+
| `useFluid` creates a **fresh** `<canvas>` element each mount inside a container `<div>` | StrictMode safety |
|
|
109
|
+
| `createBlit` sets up vertex buffers **once** | Performance — never call `vertexAttribPointer` per draw |
|
|
110
|
+
| Worker `.terminate()` always deferred 50ms after `postMessage({type:'destroy'})` | Lets the worker flush its destroy sequence |
|
|
111
|
+
| Display shader outputs **premultiplied alpha** | Transparent canvas compositing correctness |
|
|
112
|
+
| Coverage texture ref: `text` mode → `coverageTex === obstacleTex`; guard against double-delete | Memory safety |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## What agents MUST NOT do
|
|
117
|
+
|
|
118
|
+
- **Do not** edit files under `dist/` — these are build artefacts
|
|
119
|
+
- **Do not** add `// eslint-disable` or `@ts-ignore` without explaining why in the PR
|
|
120
|
+
- **Do not** introduce new peer dependencies without updating `peerDependencies` in `package.json`
|
|
121
|
+
- **Do not** call `vertexAttribPointer` inside the render loop
|
|
122
|
+
- **Do not** call `transferControlToOffscreen` more than once per canvas element
|
|
123
|
+
- **Do not** use `window.*` APIs directly inside `worker/index.ts` (worker context)
|
|
124
|
+
- **Do not** commit if `bun test:claude` fails
|
|
125
|
+
- **Do not** change the module format from ESM to CJS — consumers depend on tree-shaking
|
|
126
|
+
- **Do not** modify `CLAUDE.md` unless explicitly asked — it is the authoritative agent guide
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Testing notes
|
|
131
|
+
|
|
132
|
+
- Tests run under jsdom with a WebGL mock (`tests/setup.js`). `navigator.gpu` is absent — all tests exercise the WebGL path.
|
|
133
|
+
- `FluidText`/`FluidImage` are `forwardRef` ExoticComponents — check `$$typeof`, not `typeof`.
|
|
134
|
+
- React component mocks require `.ts` extension: `vi.mock('../../src/fluid-controller.ts', ...)`
|
|
135
|
+
- Worker mock: `vi.mock('../src/worker/index.ts?worker&inline', ...)`
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Where to find more
|
|
140
|
+
|
|
141
|
+
| Resource | Path |
|
|
142
|
+
|----------|------|
|
|
143
|
+
| Deep architecture guide (Claude-specific) | [CLAUDE.md](./CLAUDE.md) |
|
|
144
|
+
| Prioritised bug/feature backlog | [backlog.md](./backlog.md) |
|
|
145
|
+
| Version history | [changelog.md](./changelog.md) |
|
|
146
|
+
| Live demo source | [demo/src/examples/](./demo/src/examples/) |
|
|
147
|
+
| npm package | https://www.npmjs.com/package/@jayf0x/fluidity-js |
|
|
148
|
+
| Live demo | https://jayf0x.github.io/fluidity |
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Contributing to fluidity-js
|
|
2
|
+
|
|
3
|
+
## Setup
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
git clone https://github.com/jayf0x/fluidity
|
|
7
|
+
cd fluidity
|
|
8
|
+
bun install
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Run tests:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun test:claude
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Run the demo (requires Node 20):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cd demo
|
|
21
|
+
PATH=/Users/me/.nvm/versions/node/v20.19.6/bin:$PATH bun install
|
|
22
|
+
PATH=/Users/me/.nvm/versions/node/v20.19.6/bin:$PATH bun dev
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Before opening a PR
|
|
26
|
+
|
|
27
|
+
- All 83 tests pass (`bun test:claude`)
|
|
28
|
+
- No new peer dependencies without prior discussion
|
|
29
|
+
- Code formatted with `bun format`
|
|
30
|
+
- See [AGENTS.md](./AGENTS.md) for code style and architecture constraints
|
|
31
|
+
|
|
32
|
+
## Where to look
|
|
33
|
+
|
|
34
|
+
| Goal | Files |
|
|
35
|
+
|------|-------|
|
|
36
|
+
| Add/change a visual effect | `src/core/shaders.ts`, `src/core/wgsl-shaders.ts`, `src/core/simulation.ts` |
|
|
37
|
+
| Add a new prop | `src/globals.d.ts`, `src/react/FluidText.tsx` or `FluidImage.tsx`, `src/core/config.ts` |
|
|
38
|
+
| Add a preset | `src/core/config.ts` |
|
|
39
|
+
| Fix a simulation bug | `src/core/simulation.ts`, `src/core/gl-utils.ts`, `src/core/gpu-utils.ts` |
|
|
40
|
+
| Fix React lifecycle | `src/react/useFluid.ts`, `src/fluid-controller.ts` |
|
|
41
|
+
| Fix worker communication | `src/worker/index.ts`, `src/fluid-controller.ts` |
|
|
42
|
+
|
|
43
|
+
## Reporting issues
|
|
44
|
+
|
|
45
|
+
Use the GitHub issue templates — include a minimal repro snippet and your browser/renderer info.
|
package/README.md
CHANGED
|
@@ -1,87 +1,81 @@
|
|
|
1
|
-
# fluidity-js
|
|
1
|
+
# fluidity-js — Upgrade your UX
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@jayf0x/fluidity-js)
|
|
3
|
+
[](https://www.npmjs.com/package/@jayf0x/fluidity-js)
|
|
4
|
+
[](https://www.npmjs.com/package/@jayf0x/fluidity-js)
|
|
5
|
+
[](https://bundlephobia.com/package/@jayf0x/fluidity-js)
|
|
4
6
|
[](./LICENSE)
|
|
5
|
-
[](./tsconfig.json)
|
|
8
|
+
[](https://github.com/jayf0x/fluidity/actions/workflows/ci.yml)
|
|
6
9
|
|
|
7
|
-
<a href="https://
|
|
10
|
+
<a href="https://jayf0x.github.io/fluidity">
|
|
8
11
|
<p align="center">
|
|
9
|
-
<img src="assets/preview.gif" alt="
|
|
12
|
+
<img src="assets/preview.gif" alt="Fluid text and image effects in React" height="300px"/>
|
|
10
13
|
</p>
|
|
11
|
-
<p align="center"><strong>
|
|
14
|
+
<p align="center"><strong>Demo & Examples →</strong></p>
|
|
12
15
|
</a>
|
|
13
16
|
|
|
17
|
+
## Quickstart
|
|
18
|
+
|
|
14
19
|
```bash
|
|
15
20
|
bun add @jayf0x/fluidity-js
|
|
16
|
-
#
|
|
21
|
+
# npm / pnpm / aube
|
|
17
22
|
```
|
|
18
23
|
|
|
19
|
-
> **WebGPU-first** 🔥 — falls back automatically to WebGL2 / WebGL1.
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## React examples
|
|
24
|
-
|
|
25
|
-
**Text that moves with your cursor:**
|
|
26
|
-
|
|
27
24
|
```tsx
|
|
28
|
-
import { FluidText } from '@jayf0x/fluidity-js';
|
|
25
|
+
import { FluidImage, FluidText } from '@jayf0x/fluidity-js';
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+
// Fluid text — reacts to cursor movement
|
|
28
|
+
export const Hero = () => {
|
|
31
29
|
return (
|
|
32
30
|
<div style={{ width: '100%', height: 400 }}>
|
|
33
31
|
<FluidText text="Hello World" fontSize={140} color="#ffffff" />
|
|
34
32
|
</div>
|
|
35
33
|
);
|
|
36
|
-
}
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
**Full-bleed image cover — one line to make it alive:**
|
|
34
|
+
};
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
export function Cover() {
|
|
36
|
+
// Full-bleed fluid image
|
|
37
|
+
export const Cover = () => {
|
|
45
38
|
return (
|
|
46
39
|
<div style={{ width: '100%', height: '100vh' }}>
|
|
47
40
|
<FluidImage src="/hero.jpg" algorithm="aurora" />
|
|
48
41
|
</div>
|
|
49
42
|
);
|
|
50
|
-
}
|
|
43
|
+
};
|
|
51
44
|
```
|
|
52
45
|
|
|
53
|
-
|
|
46
|
+
---
|
|
54
47
|
|
|
55
|
-
|
|
56
|
-
<FluidText text="Wicked" preset="neon" algorithm="glass" />
|
|
57
|
-
<FluidImage src="/poster.jpg" algorithm="ripple" config={{ curl: 0.4, splatRadius: 0.008 }} />
|
|
58
|
-
<FluidText text="Chill" preset="calm" quality={{ dpr: 1, sim: 0.75 }} />
|
|
59
|
-
```
|
|
48
|
+
## Programmatic control
|
|
60
49
|
|
|
61
|
-
|
|
50
|
+
Use `ref` to trigger effects from code — scroll-driven splats, click bursts, attract particles:
|
|
62
51
|
|
|
63
52
|
```tsx
|
|
64
53
|
import { useRef } from 'react';
|
|
65
54
|
|
|
66
55
|
import { FluidText } from '@jayf0x/fluidity-js';
|
|
67
56
|
|
|
68
|
-
export
|
|
57
|
+
export const Interactive = () => {
|
|
69
58
|
const fluid = useRef<FluidHandle>(null);
|
|
70
59
|
|
|
71
60
|
return (
|
|
72
61
|
<>
|
|
73
62
|
<div style={{ width: '100%', height: 400 }}>
|
|
74
|
-
<FluidText ref={fluid} text="
|
|
63
|
+
<FluidText ref={fluid} text="Splash!" fontSize={120} color="#fff" />
|
|
75
64
|
</div>
|
|
76
65
|
<button onClick={() => fluid.current?.splat(200, 200, 8, -4)}>Splat</button>
|
|
77
66
|
<button onClick={() => fluid.current?.updateConfig({ curl: 0.5 })}>Swirl</button>
|
|
78
67
|
<button onClick={() => fluid.current?.reset()}>Reset</button>
|
|
79
68
|
</>
|
|
80
69
|
);
|
|
81
|
-
}
|
|
70
|
+
};
|
|
82
71
|
```
|
|
83
72
|
|
|
84
|
-
|
|
73
|
+
| Method | What it does |
|
|
74
|
+
| -------------------------------- | --------------------------------------------------------- |
|
|
75
|
+
| `reset()` | Restart the simulation |
|
|
76
|
+
| `updateConfig(patch)` | Change any config value live |
|
|
77
|
+
| `move({ x, y, strength? })` | Simulate a pointer move |
|
|
78
|
+
| `splat(x, y, vx, vy, strength?)` | Inject fluid directly — safe to call many times per frame |
|
|
85
79
|
|
|
86
80
|
---
|
|
87
81
|
|
|
@@ -126,13 +120,13 @@ Official examples → [`demo/src/examples/`](./demo/src/examples/)
|
|
|
126
120
|
|
|
127
121
|
## Algorithms
|
|
128
122
|
|
|
129
|
-
| Value |
|
|
130
|
-
| ------------ |
|
|
131
|
-
| `'standard'` | Colour overlay + gentle refraction (default)
|
|
132
|
-
| `'glass'` |
|
|
133
|
-
| `'ink'` | Dense opaque pigment that accumulates and stains
|
|
134
|
-
| `'aurora'` |
|
|
135
|
-
| `'ripple'` |
|
|
123
|
+
| Value | Vibe |
|
|
124
|
+
| ------------ | ------------------------------------------------ |
|
|
125
|
+
| `'standard'` | Colour overlay + gentle refraction (default) |
|
|
126
|
+
| `'glass'` | Bent-glass distortion, no colour |
|
|
127
|
+
| `'ink'` | Dense opaque pigment that accumulates and stains |
|
|
128
|
+
| `'aurora'` | Liquid metal / lava-lamp |
|
|
129
|
+
| `'ripple'` | Still water surface with Fresnel rim |
|
|
136
130
|
|
|
137
131
|
```tsx
|
|
138
132
|
<FluidImage src="/photo.jpg" algorithm="aurora" />
|
|
@@ -143,72 +137,63 @@ Official examples → [`demo/src/examples/`](./demo/src/examples/)
|
|
|
143
137
|
|
|
144
138
|
## Quality
|
|
145
139
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
| Field | Range | Default | Description |
|
|
149
|
-
| ----- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
150
|
-
| `dpr` | 0.1 – 1 | `1` | Canvas backing resolution as a fraction of `devicePixelRatio`. `0.5` on a Retina screen renders at 1× instead of 2×, saving ~75% fill rate. |
|
|
151
|
-
| `sim` | 0.1 – 1 | `0.5` | Simulation FBO size as a fraction of canvas size. Lower = cheaper GPU, less fluid detail. |
|
|
152
|
-
|
|
153
|
-
```tsx
|
|
154
|
-
<FluidText text="hello" quality={{ dpr: 0.75, sim: 0.25 }} />
|
|
155
|
-
```
|
|
140
|
+
Control rendering resolution on two independent axes — both reactive at runtime.
|
|
156
141
|
|
|
157
|
-
|
|
142
|
+
| Field | Range | Default | What it does |
|
|
143
|
+
| ----- | ----- | ------- | ----------------------------------------------------------------------------------------- |
|
|
144
|
+
| `dpr` | 0.1–1 | `1` | Canvas resolution as fraction of screen pixel ratio. `0.5` on Retina saves ~75% GPU fill. |
|
|
145
|
+
| `sim` | 0.1–1 | `0.5` | Simulation resolution. Lower = cheaper, less detail. |
|
|
158
146
|
|
|
159
147
|
```tsx
|
|
160
|
-
// Sharp
|
|
148
|
+
// Sharp canvas, cheap simulation
|
|
161
149
|
<FluidImage src="/hero.jpg" quality={{ dpr: 1, sim: 0.2 }} />
|
|
162
150
|
|
|
163
|
-
// Lower
|
|
151
|
+
// Lower canvas res, full simulation quality
|
|
164
152
|
<FluidImage src="/hero.jpg" quality={{ dpr: 0.5, sim: 1 }} />
|
|
165
153
|
```
|
|
166
154
|
|
|
167
155
|
---
|
|
168
156
|
|
|
169
|
-
## FluidConfig
|
|
170
|
-
|
|
171
|
-
| Key | Default | Description
|
|
172
|
-
| --------------------- | ------------------ |
|
|
173
|
-
| `densityDissipation` | `0.992` | How long ink lingers (0–1)
|
|
174
|
-
| `velocityDissipation` | `0.93` | How fast
|
|
175
|
-
| `pressureIterations` | `1` |
|
|
176
|
-
| `curl` | `0.0001` |
|
|
177
|
-
| `splatRadius` | `0.004` | Brush radius
|
|
178
|
-
| `splatForce` | `0.91` | Force applied by brush
|
|
179
|
-
| `refraction` | `0.25` | Background warp strength
|
|
180
|
-
| `specularExp` | `1.01` | Specular highlight sharpness
|
|
181
|
-
| `shine` | `0.01` | Highlight intensity
|
|
182
|
-
| `waterColor` | `[0, 0, 0]` | Base fluid colour `[R, G, B]` (0–1)
|
|
183
|
-
| `glowColor` | `[0.7, 0.85, 1.0]` | Glow / specular colour `[R, G, B]` (0–1)
|
|
184
|
-
| `warpStrength` | `0.015` | UV warp intensity (`aurora` algorithm)
|
|
157
|
+
## FluidConfig reference
|
|
158
|
+
|
|
159
|
+
| Key | Default | Description |
|
|
160
|
+
| --------------------- | ------------------ | ----------------------------------------------- |
|
|
161
|
+
| `densityDissipation` | `0.992` | How long ink lingers (0–1) |
|
|
162
|
+
| `velocityDissipation` | `0.93` | How fast fluid slows down (0–1) |
|
|
163
|
+
| `pressureIterations` | `1` | Quality vs. cost trade-off |
|
|
164
|
+
| `curl` | `0.0001` | Swirl intensity. `0.2`–`0.5` for visible eddies |
|
|
165
|
+
| `splatRadius` | `0.004` | Brush radius |
|
|
166
|
+
| `splatForce` | `0.91` | Force applied by brush |
|
|
167
|
+
| `refraction` | `0.25` | Background warp strength |
|
|
168
|
+
| `specularExp` | `1.01` | Specular highlight sharpness |
|
|
169
|
+
| `shine` | `0.01` | Highlight intensity |
|
|
170
|
+
| `waterColor` | `[0, 0, 0]` | Base fluid colour `[R, G, B]` (0–1) |
|
|
171
|
+
| `glowColor` | `[0.7, 0.85, 1.0]` | Glow / specular colour `[R, G, B]` (0–1) |
|
|
172
|
+
| `warpStrength` | `0.015` | UV warp intensity (`aurora` algorithm) |
|
|
185
173
|
|
|
186
174
|
---
|
|
187
175
|
|
|
188
|
-
##
|
|
176
|
+
## Browser support
|
|
189
177
|
|
|
190
|
-
|
|
191
|
-
| -------------------------------- | ----------------------------------------------------- |
|
|
192
|
-
| `reset()` | Re-initialise simulation and reload source |
|
|
193
|
-
| `updateConfig(patch)` | Merge a partial config update into running sim |
|
|
194
|
-
| `move({ x, y, strength? })` | Programmatic pointer input (canvas-relative px) |
|
|
195
|
-
| `splat(x, y, vx, vy, strength?)` | Inject a fluid splat directly — safe to call N×/frame |
|
|
178
|
+
Works in all modern browsers. Automatically picks the best renderer available — no configuration needed.
|
|
196
179
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
180
|
+
| Browser | Support |
|
|
181
|
+
| ------------- | ------- |
|
|
182
|
+
| Chrome 113+ | ✅ |
|
|
183
|
+
| Edge 113+ | ✅ |
|
|
184
|
+
| Firefox | ✅ |
|
|
185
|
+
| Safari 17+ | ✅ |
|
|
186
|
+
| Safari < 17 | ✅ |
|
|
187
|
+
| Mobile Chrome | ✅ |
|
|
200
188
|
|
|
201
|
-
|
|
202
|
-
<FluidText text="Wicked" preset="neon" />
|
|
203
|
-
<FluidText text="Wicked" preset="calm" />
|
|
204
|
-
```
|
|
189
|
+
---
|
|
205
190
|
|
|
206
|
-
|
|
191
|
+
## Contributing
|
|
207
192
|
|
|
208
|
-
|
|
193
|
+
Issues and PRs welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup and [AGENTS.md](./AGENTS.md) for code conventions.
|
|
209
194
|
|
|
210
195
|
---
|
|
211
196
|
|
|
212
197
|
## License
|
|
213
198
|
|
|
214
|
-
[MIT](./LICENSE)
|
|
199
|
+
[MIT](./LICENSE) © [jayf0x](https://github.com/jayf0x)
|