@buley/hexgrid-3d 3.0.1 → 3.2.0

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.
Files changed (209) hide show
  1. package/dist/HexGridEnhanced.d.ts +15 -0
  2. package/dist/HexGridEnhanced.d.ts.map +1 -0
  3. package/dist/HexGridEnhanced.js +1 -0
  4. package/dist/Snapshot.d.ts +594 -0
  5. package/dist/Snapshot.d.ts.map +1 -0
  6. package/dist/Snapshot.js +757 -0
  7. package/dist/adapters/DashAdapter.d.ts +18 -0
  8. package/dist/adapters/DashAdapter.d.ts.map +1 -0
  9. package/dist/adapters/DashAdapter.js +42 -0
  10. package/dist/adapters.d.ts +53 -0
  11. package/dist/adapters.d.ts.map +1 -0
  12. package/dist/adapters.js +14 -0
  13. package/dist/algorithms/AdvancedStatistics.d.ts +52 -0
  14. package/dist/algorithms/AdvancedStatistics.d.ts.map +1 -0
  15. package/dist/algorithms/AdvancedStatistics.js +307 -0
  16. package/dist/algorithms/BayesianStatistics.d.ts +86 -0
  17. package/dist/algorithms/BayesianStatistics.d.ts.map +1 -0
  18. package/dist/algorithms/BayesianStatistics.js +263 -0
  19. package/dist/algorithms/FlowField.d.ts +55 -0
  20. package/dist/algorithms/FlowField.d.ts.map +1 -0
  21. package/dist/algorithms/FlowField.js +80 -0
  22. package/dist/algorithms/FlowField3D.d.ts +166 -0
  23. package/dist/algorithms/FlowField3D.d.ts.map +1 -0
  24. package/dist/algorithms/FlowField3D.js +327 -0
  25. package/dist/algorithms/FluidEngineFactory.d.ts +15 -0
  26. package/dist/algorithms/FluidEngineFactory.d.ts.map +1 -0
  27. package/dist/algorithms/FluidEngineFactory.js +41 -0
  28. package/dist/algorithms/FluidSimulation.d.ts +41 -0
  29. package/dist/algorithms/FluidSimulation.d.ts.map +1 -0
  30. package/dist/algorithms/FluidSimulation.js +74 -0
  31. package/dist/algorithms/FluidSimulation3D.d.ts +137 -0
  32. package/dist/algorithms/FluidSimulation3D.d.ts.map +1 -0
  33. package/dist/algorithms/FluidSimulation3D.js +464 -0
  34. package/dist/algorithms/FluidSimulation3DGPU.d.ts +41 -0
  35. package/dist/algorithms/FluidSimulation3DGPU.d.ts.map +1 -0
  36. package/dist/algorithms/FluidSimulation3DGPU.js +328 -0
  37. package/dist/algorithms/FluidSimulationWebNN.d.ts +56 -0
  38. package/dist/algorithms/FluidSimulationWebNN.d.ts.map +1 -0
  39. package/dist/algorithms/FluidSimulationWebNN.js +84 -0
  40. package/dist/algorithms/GraphAlgorithms.d.ts +48 -0
  41. package/dist/algorithms/GraphAlgorithms.d.ts.map +1 -0
  42. package/dist/algorithms/GraphAlgorithms.js +122 -0
  43. package/dist/algorithms/OutlierDetection.d.ts +49 -0
  44. package/dist/algorithms/OutlierDetection.d.ts.map +1 -0
  45. package/dist/algorithms/OutlierDetection.js +284 -0
  46. package/dist/algorithms/ParticleSystem.d.ts +36 -0
  47. package/dist/algorithms/ParticleSystem.d.ts.map +1 -0
  48. package/dist/algorithms/ParticleSystem.js +59 -0
  49. package/dist/algorithms/ParticleSystem3D.d.ts +206 -0
  50. package/dist/algorithms/ParticleSystem3D.d.ts.map +1 -0
  51. package/dist/algorithms/ParticleSystem3D.js +371 -0
  52. package/dist/algorithms/index.d.ts +16 -0
  53. package/dist/algorithms/index.d.ts.map +1 -0
  54. package/{src/algorithms/index.ts → dist/algorithms/index.js} +0 -2
  55. package/dist/compat.d.ts +24 -0
  56. package/dist/compat.d.ts.map +1 -0
  57. package/dist/compat.js +88 -0
  58. package/dist/components/HexGrid.d.ts +5 -0
  59. package/dist/components/HexGrid.d.ts.map +1 -0
  60. package/dist/components/HexGrid.js +39 -0
  61. package/dist/components/NarrationOverlay.d.ts +16 -0
  62. package/dist/components/NarrationOverlay.d.ts.map +1 -0
  63. package/dist/components/NarrationOverlay.js +132 -0
  64. package/{src/components/index.ts → dist/components/index.d.ts} +1 -1
  65. package/dist/components/index.d.ts.map +1 -0
  66. package/dist/components/index.js +1 -0
  67. package/dist/features.d.ts +54 -0
  68. package/dist/features.d.ts.map +1 -0
  69. package/dist/features.js +74 -0
  70. package/dist/index.d.ts +12 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +17 -0
  73. package/dist/lib/narration.d.ts +12 -0
  74. package/dist/lib/narration.d.ts.map +1 -0
  75. package/dist/lib/narration.js +8 -0
  76. package/dist/lib/stats-tracker.d.ts +7 -0
  77. package/dist/lib/stats-tracker.d.ts.map +1 -0
  78. package/dist/lib/stats-tracker.js +22 -0
  79. package/dist/lib/theme-colors.d.ts +7 -0
  80. package/dist/lib/theme-colors.d.ts.map +1 -0
  81. package/dist/lib/theme-colors.js +10 -0
  82. package/dist/math/HexCoordinates.d.ts +140 -0
  83. package/dist/math/HexCoordinates.d.ts.map +1 -0
  84. package/dist/math/HexCoordinates.js +741 -0
  85. package/dist/math/Matrix4.d.ts +9 -0
  86. package/dist/math/Matrix4.d.ts.map +1 -0
  87. package/dist/math/Matrix4.js +19 -0
  88. package/dist/math/Quaternion.d.ts +11 -0
  89. package/dist/math/Quaternion.d.ts.map +1 -0
  90. package/dist/math/Quaternion.js +23 -0
  91. package/dist/math/SpatialIndex.d.ts +34 -0
  92. package/dist/math/SpatialIndex.d.ts.map +1 -0
  93. package/dist/math/SpatialIndex.js +75 -0
  94. package/dist/math/Vector3.d.ts +110 -0
  95. package/dist/math/Vector3.d.ts.map +1 -0
  96. package/dist/math/Vector3.js +426 -0
  97. package/dist/math/index.d.ts +11 -0
  98. package/dist/math/index.d.ts.map +1 -0
  99. package/{src/math/index.ts → dist/math/index.js} +0 -1
  100. package/dist/note-adapter.d.ts +44 -0
  101. package/dist/note-adapter.d.ts.map +1 -0
  102. package/dist/note-adapter.js +86 -0
  103. package/dist/ontology-adapter.d.ts +13 -0
  104. package/dist/ontology-adapter.d.ts.map +1 -0
  105. package/dist/ontology-adapter.js +65 -0
  106. package/dist/stores/index.d.ts +2 -0
  107. package/dist/stores/index.d.ts.map +1 -0
  108. package/dist/stores/uiStore.d.ts +18 -0
  109. package/dist/stores/uiStore.d.ts.map +1 -0
  110. package/dist/stores/uiStore.js +77 -0
  111. package/dist/types/index.d.ts +4 -0
  112. package/dist/types/index.d.ts.map +1 -0
  113. package/dist/types/index.js +1 -0
  114. package/dist/types.d.ts +126 -0
  115. package/dist/types.d.ts.map +1 -0
  116. package/dist/types.js +4 -0
  117. package/dist/utils/image-utils.d.ts +13 -0
  118. package/dist/utils/image-utils.d.ts.map +1 -0
  119. package/dist/utils/image-utils.js +23 -0
  120. package/dist/wasm/HexGridWasmWrapper.d.ts +131 -0
  121. package/dist/wasm/HexGridWasmWrapper.d.ts.map +1 -0
  122. package/dist/wasm/HexGridWasmWrapper.js +610 -0
  123. package/dist/wasm/index.d.ts +7 -0
  124. package/dist/wasm/index.d.ts.map +1 -0
  125. package/{src/wasm/index.ts → dist/wasm/index.js} +0 -1
  126. package/dist/webgpu/WebGPUContext.d.ts +20 -0
  127. package/dist/webgpu/WebGPUContext.d.ts.map +1 -0
  128. package/dist/webgpu/WebGPUContext.js +60 -0
  129. package/dist/webnn/WebNNContext.d.ts +38 -0
  130. package/dist/webnn/WebNNContext.d.ts.map +1 -0
  131. package/dist/webnn/WebNNContext.js +66 -0
  132. package/dist/workers/hexgrid-math.d.ts +79 -0
  133. package/dist/workers/hexgrid-math.d.ts.map +1 -0
  134. package/dist/workers/hexgrid-math.js +136 -0
  135. package/dist/workers/hexgrid-worker.worker.d.ts +35 -0
  136. package/dist/workers/hexgrid-worker.worker.d.ts.map +1 -0
  137. package/dist/workers/hexgrid-worker.worker.js +2014 -0
  138. package/package.json +20 -7
  139. package/.eslintrc.json +0 -28
  140. package/build_log.txt +0 -500
  141. package/build_src_log.txt +0 -8
  142. package/examples/basic-usage.tsx +0 -52
  143. package/public/hexgrid-worker.js +0 -2475
  144. package/rust/Cargo.toml +0 -41
  145. package/rust/src/lib.rs +0 -740
  146. package/rust/src/math.rs +0 -574
  147. package/rust/src/spatial.rs +0 -245
  148. package/rust/src/statistics.rs +0 -496
  149. package/site/.eslintrc.json +0 -3
  150. package/site/DEPLOYMENT.md +0 -196
  151. package/site/INDEX.md +0 -127
  152. package/site/QUICK_START.md +0 -86
  153. package/site/README.md +0 -85
  154. package/site/SITE_SUMMARY.md +0 -180
  155. package/site/next.config.js +0 -12
  156. package/site/package.json +0 -26
  157. package/site/src/app/docs/page.tsx +0 -272
  158. package/site/src/app/examples/page.tsx +0 -151
  159. package/site/src/app/globals.css +0 -160
  160. package/site/src/app/layout.tsx +0 -39
  161. package/site/src/app/page.tsx +0 -235
  162. package/site/tsconfig.json +0 -29
  163. package/site/vercel.json +0 -6
  164. package/src/HexGridEnhanced.ts +0 -16
  165. package/src/Snapshot.ts +0 -1607
  166. package/src/adapters/DashAdapter.ts +0 -57
  167. package/src/adapters.ts +0 -63
  168. package/src/algorithms/AdvancedStatistics.ts +0 -362
  169. package/src/algorithms/BayesianStatistics.ts +0 -348
  170. package/src/algorithms/FlowField.ts +0 -150
  171. package/src/algorithms/FlowField3D.ts +0 -573
  172. package/src/algorithms/FluidEngineFactory.ts +0 -44
  173. package/src/algorithms/FluidSimulation.ts +0 -115
  174. package/src/algorithms/FluidSimulation3D.ts +0 -664
  175. package/src/algorithms/FluidSimulation3DGPU.ts +0 -402
  176. package/src/algorithms/FluidSimulationWebNN.ts +0 -141
  177. package/src/algorithms/GraphAlgorithms.ts +0 -191
  178. package/src/algorithms/OutlierDetection.ts +0 -425
  179. package/src/algorithms/ParticleSystem.ts +0 -95
  180. package/src/algorithms/ParticleSystem3D.ts +0 -567
  181. package/src/compat.ts +0 -96
  182. package/src/components/HexGrid.tsx +0 -61
  183. package/src/components/NarrationOverlay.tsx +0 -309
  184. package/src/features.ts +0 -125
  185. package/src/index.ts +0 -30
  186. package/src/lib/narration.ts +0 -17
  187. package/src/lib/stats-tracker.ts +0 -25
  188. package/src/lib/theme-colors.ts +0 -12
  189. package/src/math/HexCoordinates.ts +0 -863
  190. package/src/math/Matrix4.ts +0 -25
  191. package/src/math/Quaternion.ts +0 -37
  192. package/src/math/SpatialIndex.ts +0 -114
  193. package/src/math/Vector3.ts +0 -540
  194. package/src/note-adapter.ts +0 -132
  195. package/src/ontology-adapter.ts +0 -84
  196. package/src/stores/uiStore.ts +0 -85
  197. package/src/types/index.ts +0 -3
  198. package/src/types/shared-utils.d.ts +0 -10
  199. package/src/types/wgsl.d.ts +0 -4
  200. package/src/types.ts +0 -164
  201. package/src/utils/image-utils.ts +0 -28
  202. package/src/wasm/HexGridWasmWrapper.ts +0 -801
  203. package/src/webgpu/WebGPUContext.ts +0 -71
  204. package/src/webgpu/shaders/fluid_sim.wgsl +0 -140
  205. package/src/webnn/WebNNContext.ts +0 -99
  206. package/src/workers/hexgrid-math.ts +0 -182
  207. package/src/workers/hexgrid-worker.worker.ts +0 -2781
  208. package/tsconfig.json +0 -26
  209. /package/{src/stores/index.ts → dist/stores/index.js} +0 -0
@@ -1,664 +0,0 @@
1
- /**
2
- * 3D Stable Fluids Implementation
3
- *
4
- * Based on Jos Stam's "Stable Fluids" paper (SIGGRAPH 1999)
5
- * Extended to 3D for the Pensieve particle visualization.
6
- *
7
- * Key operations:
8
- * 1. Add sources (density, velocity)
9
- * 2. Diffuse (spread quantities)
10
- * 3. Advect (move quantities along velocity field)
11
- * 4. Project (make velocity field divergence-free)
12
- */
13
-
14
- import { Vector3 } from '../math/Vector3';
15
-
16
- export interface FluidConfig3D {
17
- /** Grid width in cells */
18
- width: number;
19
- /** Grid height in cells */
20
- height: number;
21
- /** Grid depth in cells */
22
- depth: number;
23
- /** Viscosity coefficient (0 = inviscid, higher = more viscous) */
24
- viscosity: number;
25
- /** Diffusion rate for density (0 = no diffusion) */
26
- diffusion: number;
27
- /** Number of iterations for linear solver (higher = more accurate but slower) */
28
- iterations?: number;
29
- }
30
-
31
- /**
32
- * 3D Stable Fluids solver for realistic fluid dynamics
33
- */
34
- export class StableFluids3D {
35
- private width: number;
36
- private height: number;
37
- private depth: number;
38
- private size: number;
39
- private viscosity: number;
40
- private diffusion: number;
41
- private iterations: number;
42
-
43
- // Current state
44
- private density: Float32Array;
45
- private velocityX: Float32Array;
46
- private velocityY: Float32Array;
47
- private velocityZ: Float32Array;
48
-
49
- // Previous state (for advection)
50
- private density0: Float32Array;
51
- private velocityX0: Float32Array;
52
- private velocityY0: Float32Array;
53
- private velocityZ0: Float32Array;
54
-
55
- constructor(config: FluidConfig3D) {
56
- this.width = Math.max(1, Math.round(config.width));
57
- this.height = Math.max(1, Math.round(config.height));
58
- this.depth = Math.max(1, Math.round(config.depth));
59
- this.size = this.width * this.height * this.depth;
60
- this.viscosity = config.viscosity;
61
- this.diffusion = config.diffusion;
62
- this.iterations = config.iterations ?? 4;
63
-
64
- // Allocate arrays
65
- this.density = new Float32Array(this.size);
66
- this.velocityX = new Float32Array(this.size);
67
- this.velocityY = new Float32Array(this.size);
68
- this.velocityZ = new Float32Array(this.size);
69
-
70
- this.density0 = new Float32Array(this.size);
71
- this.velocityX0 = new Float32Array(this.size);
72
- this.velocityY0 = new Float32Array(this.size);
73
- this.velocityZ0 = new Float32Array(this.size);
74
- }
75
-
76
- /**
77
- * Add density at a point with radius falloff
78
- */
79
- addDensity(
80
- x: number,
81
- y: number,
82
- z: number,
83
- amount: number,
84
- radius: number
85
- ): void {
86
- const r2 = radius * radius;
87
- const ix0 = Math.max(0, Math.floor(x - radius));
88
- const ix1 = Math.min(this.width - 1, Math.ceil(x + radius));
89
- const iy0 = Math.max(0, Math.floor(y - radius));
90
- const iy1 = Math.min(this.height - 1, Math.ceil(y + radius));
91
- const iz0 = Math.max(0, Math.floor(z - radius));
92
- const iz1 = Math.min(this.depth - 1, Math.ceil(z + radius));
93
-
94
- for (let iz = iz0; iz <= iz1; iz++) {
95
- for (let iy = iy0; iy <= iy1; iy++) {
96
- for (let ix = ix0; ix <= ix1; ix++) {
97
- const dx = ix - x;
98
- const dy = iy - y;
99
- const dz = iz - z;
100
- const dist2 = dx * dx + dy * dy + dz * dz;
101
- if (dist2 < r2) {
102
- const falloff = 1 - dist2 / r2;
103
- const idx = this.indexFor(ix, iy, iz);
104
- this.density[idx] += amount * falloff;
105
- }
106
- }
107
- }
108
- }
109
- }
110
-
111
- /**
112
- * Add force at a point with radius falloff
113
- */
114
- addForce(pos: Vector3, force: Vector3, radius: number): void {
115
- const r2 = radius * radius;
116
- const ix0 = Math.max(0, Math.floor(pos.x - radius));
117
- const ix1 = Math.min(this.width - 1, Math.ceil(pos.x + radius));
118
- const iy0 = Math.max(0, Math.floor(pos.y - radius));
119
- const iy1 = Math.min(this.height - 1, Math.ceil(pos.y + radius));
120
- const iz0 = Math.max(0, Math.floor(pos.z - radius));
121
- const iz1 = Math.min(this.depth - 1, Math.ceil(pos.z + radius));
122
-
123
- for (let iz = iz0; iz <= iz1; iz++) {
124
- for (let iy = iy0; iy <= iy1; iy++) {
125
- for (let ix = ix0; ix <= ix1; ix++) {
126
- const dx = ix - pos.x;
127
- const dy = iy - pos.y;
128
- const dz = iz - pos.z;
129
- const dist2 = dx * dx + dy * dy + dz * dz;
130
- if (dist2 < r2) {
131
- const falloff = 1 - dist2 / r2;
132
- const idx = this.indexFor(ix, iy, iz);
133
- this.velocityX[idx] += force.x * falloff;
134
- this.velocityY[idx] += force.y * falloff;
135
- this.velocityZ[idx] += force.z * falloff;
136
- }
137
- }
138
- }
139
- }
140
- }
141
-
142
- /**
143
- * Step the simulation forward by dt seconds
144
- */
145
- step(dt: number): void {
146
- // Velocity step
147
- this.velocityStep(dt);
148
-
149
- // Density step
150
- this.densityStep(dt);
151
- }
152
-
153
- /**
154
- * Get velocity at a point (with trilinear interpolation)
155
- */
156
- getVelocityAt(pos: Vector3): Vector3 {
157
- return new Vector3(
158
- this.sampleField(this.velocityX, pos.x, pos.y, pos.z),
159
- this.sampleField(this.velocityY, pos.x, pos.y, pos.z),
160
- this.sampleField(this.velocityZ, pos.x, pos.y, pos.z)
161
- );
162
- }
163
-
164
- /**
165
- * Get density at a point (with trilinear interpolation)
166
- */
167
- getDensityAt(pos: Vector3): number {
168
- return this.sampleField(this.density, pos.x, pos.y, pos.z);
169
- }
170
-
171
- /**
172
- * Get the raw velocity fields for direct access
173
- */
174
- getVelocityFields(): { x: Float32Array; y: Float32Array; z: Float32Array } {
175
- return { x: this.velocityX, y: this.velocityY, z: this.velocityZ };
176
- }
177
-
178
- /**
179
- * Get the raw density field
180
- */
181
- getDensityField(): Float32Array {
182
- return this.density;
183
- }
184
-
185
- /**
186
- * Get grid dimensions
187
- */
188
- getDimensions(): { width: number; height: number; depth: number } {
189
- return { width: this.width, height: this.height, depth: this.depth };
190
- }
191
-
192
- /**
193
- * Clear all fields
194
- */
195
- clear(): void {
196
- this.density.fill(0);
197
- this.velocityX.fill(0);
198
- this.velocityY.fill(0);
199
- this.velocityZ.fill(0);
200
- }
201
-
202
- // =========================================================================
203
- // PRIVATE METHODS
204
- // =========================================================================
205
-
206
- private velocityStep(dt: number): void {
207
- // Add sources
208
- this.addSource(this.velocityX, this.velocityX0, dt);
209
- this.addSource(this.velocityY, this.velocityY0, dt);
210
- this.addSource(this.velocityZ, this.velocityZ0, dt);
211
-
212
- // Diffuse
213
- this.swap(this.velocityX0, this.velocityX);
214
- this.swap(this.velocityY0, this.velocityY);
215
- this.swap(this.velocityZ0, this.velocityZ);
216
-
217
- this.diffuse(1, this.velocityX, this.velocityX0, this.viscosity, dt);
218
- this.diffuse(2, this.velocityY, this.velocityY0, this.viscosity, dt);
219
- this.diffuse(3, this.velocityZ, this.velocityZ0, this.viscosity, dt);
220
-
221
- // Project to make divergence-free
222
- this.project(
223
- this.velocityX,
224
- this.velocityY,
225
- this.velocityZ,
226
- this.velocityX0,
227
- this.velocityY0
228
- );
229
-
230
- // Advect
231
- this.swap(this.velocityX0, this.velocityX);
232
- this.swap(this.velocityY0, this.velocityY);
233
- this.swap(this.velocityZ0, this.velocityZ);
234
-
235
- this.advect(
236
- 1,
237
- this.velocityX,
238
- this.velocityX0,
239
- this.velocityX0,
240
- this.velocityY0,
241
- this.velocityZ0,
242
- dt
243
- );
244
- this.advect(
245
- 2,
246
- this.velocityY,
247
- this.velocityY0,
248
- this.velocityX0,
249
- this.velocityY0,
250
- this.velocityZ0,
251
- dt
252
- );
253
- this.advect(
254
- 3,
255
- this.velocityZ,
256
- this.velocityZ0,
257
- this.velocityX0,
258
- this.velocityY0,
259
- this.velocityZ0,
260
- dt
261
- );
262
-
263
- // Project again
264
- this.project(
265
- this.velocityX,
266
- this.velocityY,
267
- this.velocityZ,
268
- this.velocityX0,
269
- this.velocityY0
270
- );
271
- }
272
-
273
- private densityStep(dt: number): void {
274
- // Add sources
275
- this.addSource(this.density, this.density0, dt);
276
-
277
- // Diffuse
278
- this.swap(this.density0, this.density);
279
- this.diffuse(0, this.density, this.density0, this.diffusion, dt);
280
-
281
- // Advect
282
- this.swap(this.density0, this.density);
283
- this.advect(
284
- 0,
285
- this.density,
286
- this.density0,
287
- this.velocityX,
288
- this.velocityY,
289
- this.velocityZ,
290
- dt
291
- );
292
- }
293
-
294
- private addSource(
295
- target: Float32Array,
296
- source: Float32Array,
297
- dt: number
298
- ): void {
299
- for (let i = 0; i < this.size; i++) {
300
- target[i] += dt * source[i];
301
- }
302
- source.fill(0);
303
- }
304
-
305
- private diffuse(
306
- b: number,
307
- x: Float32Array,
308
- x0: Float32Array,
309
- diff: number,
310
- dt: number
311
- ): void {
312
- const a = dt * diff * this.width * this.height * this.depth;
313
- this.linearSolve(b, x, x0, a, 1 + 6 * a);
314
- }
315
-
316
- private advect(
317
- b: number,
318
- d: Float32Array,
319
- d0: Float32Array,
320
- u: Float32Array,
321
- v: Float32Array,
322
- w: Float32Array,
323
- dt: number
324
- ): void {
325
- const dtx = dt * (this.width - 2);
326
- const dty = dt * (this.height - 2);
327
- const dtz = dt * (this.depth - 2);
328
-
329
- for (let k = 1; k < this.depth - 1; k++) {
330
- for (let j = 1; j < this.height - 1; j++) {
331
- for (let i = 1; i < this.width - 1; i++) {
332
- const idx = this.indexFor(i, j, k);
333
-
334
- // Trace back
335
- let x = i - dtx * u[idx];
336
- let y = j - dty * v[idx];
337
- let z = k - dtz * w[idx];
338
-
339
- // Clamp to grid
340
- x = Math.max(0.5, Math.min(this.width - 1.5, x));
341
- y = Math.max(0.5, Math.min(this.height - 1.5, y));
342
- z = Math.max(0.5, Math.min(this.depth - 1.5, z));
343
-
344
- // Trilinear interpolation
345
- d[idx] = this.sampleField(d0, x, y, z);
346
- }
347
- }
348
- }
349
-
350
- this.setBoundary(b, d);
351
- }
352
-
353
- private project(
354
- u: Float32Array,
355
- v: Float32Array,
356
- w: Float32Array,
357
- p: Float32Array,
358
- div: Float32Array
359
- ): void {
360
- const h = 1.0 / Math.max(this.width, this.height, this.depth);
361
-
362
- // Calculate divergence
363
- for (let k = 1; k < this.depth - 1; k++) {
364
- for (let j = 1; j < this.height - 1; j++) {
365
- for (let i = 1; i < this.width - 1; i++) {
366
- const idx = this.indexFor(i, j, k);
367
- div[idx] =
368
- -0.5 *
369
- h *
370
- (u[this.indexFor(i + 1, j, k)] -
371
- u[this.indexFor(i - 1, j, k)] +
372
- v[this.indexFor(i, j + 1, k)] -
373
- v[this.indexFor(i, j - 1, k)] +
374
- w[this.indexFor(i, j, k + 1)] -
375
- w[this.indexFor(i, j, k - 1)]);
376
- p[idx] = 0;
377
- }
378
- }
379
- }
380
-
381
- this.setBoundary(0, div);
382
- this.setBoundary(0, p);
383
-
384
- // Solve for pressure
385
- this.linearSolve(0, p, div, 1, 6);
386
-
387
- // Subtract pressure gradient from velocity
388
- for (let k = 1; k < this.depth - 1; k++) {
389
- for (let j = 1; j < this.height - 1; j++) {
390
- for (let i = 1; i < this.width - 1; i++) {
391
- const idx = this.indexFor(i, j, k);
392
- u[idx] -=
393
- (0.5 *
394
- (p[this.indexFor(i + 1, j, k)] - p[this.indexFor(i - 1, j, k)])) /
395
- h;
396
- v[idx] -=
397
- (0.5 *
398
- (p[this.indexFor(i, j + 1, k)] - p[this.indexFor(i, j - 1, k)])) /
399
- h;
400
- w[idx] -=
401
- (0.5 *
402
- (p[this.indexFor(i, j, k + 1)] - p[this.indexFor(i, j, k - 1)])) /
403
- h;
404
- }
405
- }
406
- }
407
-
408
- this.setBoundary(1, u);
409
- this.setBoundary(2, v);
410
- this.setBoundary(3, w);
411
- }
412
-
413
- private linearSolve(
414
- b: number,
415
- x: Float32Array,
416
- x0: Float32Array,
417
- a: number,
418
- c: number
419
- ): void {
420
- const cRecip = 1.0 / c;
421
-
422
- for (let iter = 0; iter < this.iterations; iter++) {
423
- for (let k = 1; k < this.depth - 1; k++) {
424
- for (let j = 1; j < this.height - 1; j++) {
425
- for (let i = 1; i < this.width - 1; i++) {
426
- const idx = this.indexFor(i, j, k);
427
- x[idx] =
428
- (x0[idx] +
429
- a *
430
- (x[this.indexFor(i + 1, j, k)] +
431
- x[this.indexFor(i - 1, j, k)] +
432
- x[this.indexFor(i, j + 1, k)] +
433
- x[this.indexFor(i, j - 1, k)] +
434
- x[this.indexFor(i, j, k + 1)] +
435
- x[this.indexFor(i, j, k - 1)])) *
436
- cRecip;
437
- }
438
- }
439
- }
440
- this.setBoundary(b, x);
441
- }
442
- }
443
-
444
- private setBoundary(b: number, x: Float32Array): void {
445
- // Set boundary conditions (reflective for velocity, continuous for density)
446
- for (let k = 1; k < this.depth - 1; k++) {
447
- for (let j = 1; j < this.height - 1; j++) {
448
- x[this.indexFor(0, j, k)] =
449
- b === 1 ? -x[this.indexFor(1, j, k)] : x[this.indexFor(1, j, k)];
450
- x[this.indexFor(this.width - 1, j, k)] =
451
- b === 1
452
- ? -x[this.indexFor(this.width - 2, j, k)]
453
- : x[this.indexFor(this.width - 2, j, k)];
454
- }
455
- }
456
-
457
- for (let k = 1; k < this.depth - 1; k++) {
458
- for (let i = 1; i < this.width - 1; i++) {
459
- x[this.indexFor(i, 0, k)] =
460
- b === 2 ? -x[this.indexFor(i, 1, k)] : x[this.indexFor(i, 1, k)];
461
- x[this.indexFor(i, this.height - 1, k)] =
462
- b === 2
463
- ? -x[this.indexFor(i, this.height - 2, k)]
464
- : x[this.indexFor(i, this.height - 2, k)];
465
- }
466
- }
467
-
468
- for (let j = 1; j < this.height - 1; j++) {
469
- for (let i = 1; i < this.width - 1; i++) {
470
- x[this.indexFor(i, j, 0)] =
471
- b === 3 ? -x[this.indexFor(i, j, 1)] : x[this.indexFor(i, j, 1)];
472
- x[this.indexFor(i, j, this.depth - 1)] =
473
- b === 3
474
- ? -x[this.indexFor(i, j, this.depth - 2)]
475
- : x[this.indexFor(i, j, this.depth - 2)];
476
- }
477
- }
478
-
479
- // Corner cases - average of neighbors
480
- x[this.indexFor(0, 0, 0)] =
481
- 0.33 *
482
- (x[this.indexFor(1, 0, 0)] +
483
- x[this.indexFor(0, 1, 0)] +
484
- x[this.indexFor(0, 0, 1)]);
485
- x[this.indexFor(0, this.height - 1, 0)] =
486
- 0.33 *
487
- (x[this.indexFor(1, this.height - 1, 0)] +
488
- x[this.indexFor(0, this.height - 2, 0)] +
489
- x[this.indexFor(0, this.height - 1, 1)]);
490
- x[this.indexFor(0, 0, this.depth - 1)] =
491
- 0.33 *
492
- (x[this.indexFor(1, 0, this.depth - 1)] +
493
- x[this.indexFor(0, 1, this.depth - 1)] +
494
- x[this.indexFor(0, 0, this.depth - 2)]);
495
- x[this.indexFor(0, this.height - 1, this.depth - 1)] =
496
- 0.33 *
497
- (x[this.indexFor(1, this.height - 1, this.depth - 1)] +
498
- x[this.indexFor(0, this.height - 2, this.depth - 1)] +
499
- x[this.indexFor(0, this.height - 1, this.depth - 2)]);
500
- x[this.indexFor(this.width - 1, 0, 0)] =
501
- 0.33 *
502
- (x[this.indexFor(this.width - 2, 0, 0)] +
503
- x[this.indexFor(this.width - 1, 1, 0)] +
504
- x[this.indexFor(this.width - 1, 0, 1)]);
505
- x[this.indexFor(this.width - 1, this.height - 1, 0)] =
506
- 0.33 *
507
- (x[this.indexFor(this.width - 2, this.height - 1, 0)] +
508
- x[this.indexFor(this.width - 1, this.height - 2, 0)] +
509
- x[this.indexFor(this.width - 1, this.height - 1, 1)]);
510
- x[this.indexFor(this.width - 1, 0, this.depth - 1)] =
511
- 0.33 *
512
- (x[this.indexFor(this.width - 2, 0, this.depth - 1)] +
513
- x[this.indexFor(this.width - 1, 1, this.depth - 1)] +
514
- x[this.indexFor(this.width - 1, 0, this.depth - 2)]);
515
- x[this.indexFor(this.width - 1, this.height - 1, this.depth - 1)] =
516
- 0.33 *
517
- (x[this.indexFor(this.width - 2, this.height - 1, this.depth - 1)] +
518
- x[this.indexFor(this.width - 1, this.height - 2, this.depth - 1)] +
519
- x[this.indexFor(this.width - 1, this.height - 1, this.depth - 2)]);
520
- }
521
-
522
- private sampleField(
523
- field: Float32Array,
524
- x: number,
525
- y: number,
526
- z: number
527
- ): number {
528
- // Trilinear interpolation
529
- const i0 = Math.floor(x);
530
- const i1 = i0 + 1;
531
- const j0 = Math.floor(y);
532
- const j1 = j0 + 1;
533
- const k0 = Math.floor(z);
534
- const k1 = k0 + 1;
535
-
536
- const sx = x - i0;
537
- const sy = y - j0;
538
- const sz = z - k0;
539
-
540
- const c000 = field[this.indexForClamped(i0, j0, k0)];
541
- const c001 = field[this.indexForClamped(i0, j0, k1)];
542
- const c010 = field[this.indexForClamped(i0, j1, k0)];
543
- const c011 = field[this.indexForClamped(i0, j1, k1)];
544
- const c100 = field[this.indexForClamped(i1, j0, k0)];
545
- const c101 = field[this.indexForClamped(i1, j0, k1)];
546
- const c110 = field[this.indexForClamped(i1, j1, k0)];
547
- const c111 = field[this.indexForClamped(i1, j1, k1)];
548
-
549
- // Interpolate along x
550
- const c00 = c000 * (1 - sx) + c100 * sx;
551
- const c01 = c001 * (1 - sx) + c101 * sx;
552
- const c10 = c010 * (1 - sx) + c110 * sx;
553
- const c11 = c011 * (1 - sx) + c111 * sx;
554
-
555
- // Interpolate along y
556
- const c0 = c00 * (1 - sy) + c10 * sy;
557
- const c1 = c01 * (1 - sy) + c11 * sy;
558
-
559
- // Interpolate along z
560
- return c0 * (1 - sz) + c1 * sz;
561
- }
562
-
563
- private indexFor(x: number, y: number, z: number): number {
564
- return z * this.width * this.height + y * this.width + x;
565
- }
566
-
567
- private indexForClamped(x: number, y: number, z: number): number {
568
- const ix = Math.min(this.width - 1, Math.max(0, x));
569
- const iy = Math.min(this.height - 1, Math.max(0, y));
570
- const iz = Math.min(this.depth - 1, Math.max(0, z));
571
- return this.indexFor(ix, iy, iz);
572
- }
573
-
574
- private swap(a: Float32Array, b: Float32Array): void {
575
- // Swap contents efficiently
576
- const temp = new Float32Array(a);
577
- a.set(b);
578
- b.set(temp);
579
- }
580
- }
581
-
582
- /**
583
- * Pensieve-specific fluid simulator with aesthetic presets
584
- */
585
- export class PensieveFluidSimulator {
586
- private fluid: StableFluids3D;
587
- private time: number = 0;
588
-
589
- constructor(size: number = 64) {
590
- this.fluid = new StableFluids3D({
591
- width: size,
592
- height: size,
593
- depth: size,
594
- viscosity: 0.0001,
595
- diffusion: 0.00001,
596
- iterations: 4,
597
- });
598
- }
599
-
600
- /**
601
- * Add a "memory splash" - when a particle enters the pensieve
602
- */
603
- addMemorySplash(position: Vector3, intensity: number): void {
604
- this.fluid.addDensity(
605
- position.x,
606
- position.y,
607
- position.z,
608
- intensity * 10,
609
- 5
610
- );
611
- // Add a slight upward swirl
612
- this.fluid.addForce(position, new Vector3(0, intensity * 2, 0), 3);
613
- }
614
-
615
- /**
616
- * Add ambient swirling motion
617
- */
618
- addSwirl(dt: number): void {
619
- this.time += dt;
620
- const dims = this.fluid.getDimensions();
621
- const center = new Vector3(dims.width / 2, dims.height / 2, dims.depth / 2);
622
-
623
- // Rotating force around Y axis
624
- const angle = this.time * 0.5;
625
- const radius = dims.width * 0.3;
626
- const pos = new Vector3(
627
- center.x + Math.cos(angle) * radius,
628
- center.y,
629
- center.z + Math.sin(angle) * radius
630
- );
631
- const tangent = new Vector3(-Math.sin(angle), 0, Math.cos(angle));
632
- this.fluid.addForce(pos, tangent, radius * 0.5);
633
- }
634
-
635
- /**
636
- * Step the simulation
637
- */
638
- step(dt: number): void {
639
- this.addSwirl(dt);
640
- this.fluid.step(dt);
641
- }
642
-
643
- /**
644
- * Get velocity at a point for particle advection
645
- */
646
- getVelocityAt(pos: Vector3): Vector3 {
647
- return this.fluid.getVelocityAt(pos);
648
- }
649
-
650
- /**
651
- * Get the underlying fluid for direct access
652
- */
653
- getFluid(): StableFluids3D {
654
- return this.fluid;
655
- }
656
-
657
- /**
658
- * Clear the simulation
659
- */
660
- clear(): void {
661
- this.fluid.clear();
662
- this.time = 0;
663
- }
664
- }