@buley/hexgrid-3d 3.1.0 → 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 (208) 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 -0
  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/{src/index.ts → dist/index.js} +0 -9
  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 -408
  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/lib/narration.ts +0 -17
  186. package/src/lib/stats-tracker.ts +0 -25
  187. package/src/lib/theme-colors.ts +0 -12
  188. package/src/math/HexCoordinates.ts +0 -863
  189. package/src/math/Matrix4.ts +0 -25
  190. package/src/math/Quaternion.ts +0 -37
  191. package/src/math/SpatialIndex.ts +0 -114
  192. package/src/math/Vector3.ts +0 -540
  193. package/src/note-adapter.ts +0 -132
  194. package/src/ontology-adapter.ts +0 -84
  195. package/src/stores/uiStore.ts +0 -85
  196. package/src/types/index.ts +0 -3
  197. package/src/types/shared-utils.d.ts +0 -10
  198. package/src/types/wgsl.d.ts +0 -4
  199. package/src/types.ts +0 -164
  200. package/src/utils/image-utils.ts +0 -28
  201. package/src/wasm/HexGridWasmWrapper.ts +0 -801
  202. package/src/webgpu/WebGPUContext.ts +0 -71
  203. package/src/webgpu/shaders/fluid_sim.wgsl +0 -140
  204. package/src/webnn/WebNNContext.ts +0 -99
  205. package/src/workers/hexgrid-math.ts +0 -182
  206. package/src/workers/hexgrid-worker.worker.ts +0 -2781
  207. package/tsconfig.json +0 -26
  208. /package/{src/stores/index.ts → dist/stores/index.js} +0 -0
@@ -0,0 +1,610 @@
1
+ /**
2
+ * TypeScript wrapper for hexgrid-wasm
3
+ *
4
+ * Provides a seamless interface to the Rust/WASM module with
5
+ * automatic fallback to pure TypeScript implementations.
6
+ *
7
+ * @module wasm/HexGridWasmWrapper
8
+ */
9
+ /**
10
+ * Wrapper class that provides TypeScript interface to WASM
11
+ * with automatic fallback
12
+ */
13
+ export class HexGridWasmWrapper {
14
+ constructor(width, height) {
15
+ this.width = width;
16
+ this.height = height;
17
+ this.wasmInstance = null;
18
+ this.fallbackData = null;
19
+ }
20
+ /**
21
+ * Load the WASM module
22
+ */
23
+ static async loadModule() {
24
+ if (this.loadFailed)
25
+ return false;
26
+ if (this.module)
27
+ return true;
28
+ if (this.loading) {
29
+ const result = await this.loading;
30
+ return result !== null;
31
+ }
32
+ this.loading = (async () => {
33
+ try {
34
+ // Try to dynamically import the WASM module
35
+ // @ts-expect-error - WASM module may not exist at compile time, has fallback
36
+ const wasmModule = await import('../rust/pkg/hexgrid_wasm');
37
+ await wasmModule.default();
38
+ this.module = wasmModule;
39
+ console.log('[HexGrid] WASM module loaded successfully');
40
+ return this.module;
41
+ }
42
+ catch (error) {
43
+ console.warn('[HexGrid] WASM module not available, using fallback:', error);
44
+ this.loadFailed = true;
45
+ return null;
46
+ }
47
+ })();
48
+ const result = await this.loading;
49
+ return result !== null;
50
+ }
51
+ /**
52
+ * Create a new HexGrid wrapper
53
+ */
54
+ static async create(width, height) {
55
+ const wrapper = new HexGridWasmWrapper(width, height);
56
+ const hasWasm = await this.loadModule();
57
+ if (hasWasm && this.module) {
58
+ wrapper.wasmInstance = new this.module.HexGridWasm(width, height);
59
+ }
60
+ else {
61
+ // Initialize fallback data
62
+ const size = width * height;
63
+ wrapper.fallbackData = {
64
+ width,
65
+ height,
66
+ owners: new Uint8Array(size),
67
+ populations: new Float32Array(size),
68
+ neighborCache: [],
69
+ };
70
+ // Precompute neighbors
71
+ for (let y = 0; y < height; y++) {
72
+ for (let x = 0; x < width; x++) {
73
+ const neighbors = new Int32Array(6).fill(-1);
74
+ const offset = y % 2 === 1 ? 1 : 0;
75
+ // Odd-r offset coordinates
76
+ const dirs = y % 2 === 1
77
+ ? [
78
+ [1, 0],
79
+ [0, -1],
80
+ [-1, -1],
81
+ [-1, 0],
82
+ [-1, 1],
83
+ [0, 1],
84
+ ]
85
+ : [
86
+ [1, 0],
87
+ [1, -1],
88
+ [0, -1],
89
+ [-1, 0],
90
+ [0, 1],
91
+ [1, 1],
92
+ ];
93
+ for (let i = 0; i < 6; i++) {
94
+ const nx = x + dirs[i][0];
95
+ const ny = y + dirs[i][1];
96
+ if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
97
+ neighbors[i] = ny * width + nx;
98
+ }
99
+ }
100
+ wrapper.fallbackData.neighborCache.push(neighbors);
101
+ }
102
+ }
103
+ }
104
+ return wrapper;
105
+ }
106
+ /**
107
+ * Check if WASM is being used
108
+ */
109
+ isUsingWasm() {
110
+ return this.wasmInstance !== null;
111
+ }
112
+ /**
113
+ * Get cell owner
114
+ */
115
+ getOwner(index) {
116
+ if (this.wasmInstance) {
117
+ return this.wasmInstance.get_owner(index);
118
+ }
119
+ return this.fallbackData?.owners[index] ?? 0;
120
+ }
121
+ /**
122
+ * Set cell owner
123
+ */
124
+ setOwner(index, owner) {
125
+ if (this.wasmInstance) {
126
+ this.wasmInstance.set_owner(index, owner);
127
+ }
128
+ else if (this.fallbackData) {
129
+ this.fallbackData.owners[index] = owner;
130
+ }
131
+ }
132
+ /**
133
+ * Set cell population
134
+ */
135
+ setPopulation(index, population) {
136
+ if (this.wasmInstance) {
137
+ this.wasmInstance.set_population(index, population);
138
+ }
139
+ else if (this.fallbackData) {
140
+ this.fallbackData.populations[index] = population;
141
+ }
142
+ }
143
+ /**
144
+ * Get neighbors of a cell
145
+ */
146
+ getNeighbors(index) {
147
+ if (this.wasmInstance) {
148
+ return this.wasmInstance.get_neighbors(index);
149
+ }
150
+ return (this.fallbackData?.neighborCache[index] ?? new Int32Array(6).fill(-1));
151
+ }
152
+ /**
153
+ * Step the infection simulation
154
+ */
155
+ stepInfection(infectionRate = 0.1, infectionThreshold = 1.0) {
156
+ if (this.wasmInstance) {
157
+ return Array.from(this.wasmInstance.step_infection(infectionRate, infectionThreshold));
158
+ }
159
+ // Fallback implementation
160
+ const changed = [];
161
+ const data = this.fallbackData;
162
+ const size = data.width * data.height;
163
+ // Simple infection spread (basic fallback)
164
+ const newOwners = new Uint8Array(data.owners);
165
+ for (let i = 0; i < size; i++) {
166
+ if (data.owners[i] === 0)
167
+ continue;
168
+ const neighbors = data.neighborCache[i];
169
+ for (const ni of neighbors) {
170
+ if (ni < 0)
171
+ continue;
172
+ if (data.owners[ni] !== data.owners[i] &&
173
+ Math.random() < infectionRate) {
174
+ newOwners[ni] = data.owners[i];
175
+ changed.push(ni);
176
+ }
177
+ }
178
+ }
179
+ data.owners = newOwners;
180
+ return changed;
181
+ }
182
+ /**
183
+ * Find connected regions for an owner
184
+ */
185
+ findConnectedRegions(owner) {
186
+ if (this.wasmInstance) {
187
+ return Array.from(this.wasmInstance.find_connected_regions(owner));
188
+ }
189
+ // Fallback: BFS implementation
190
+ const data = this.fallbackData;
191
+ const size = data.width * data.height;
192
+ const regionIds = new Array(size).fill(0);
193
+ const visited = new Array(size).fill(false);
194
+ let currentRegion = 1;
195
+ for (let start = 0; start < size; start++) {
196
+ if (visited[start] || data.owners[start] !== owner)
197
+ continue;
198
+ const queue = [start];
199
+ visited[start] = true;
200
+ while (queue.length > 0) {
201
+ const idx = queue.shift();
202
+ regionIds[idx] = currentRegion;
203
+ for (const ni of data.neighborCache[idx]) {
204
+ if (ni < 0 || visited[ni] || data.owners[ni] !== owner)
205
+ continue;
206
+ visited[ni] = true;
207
+ queue.push(ni);
208
+ }
209
+ }
210
+ currentRegion++;
211
+ }
212
+ return regionIds;
213
+ }
214
+ /**
215
+ * Find border cells for an owner
216
+ */
217
+ findBorderCells(owner) {
218
+ if (this.wasmInstance) {
219
+ return Array.from(this.wasmInstance.find_border_cells(owner));
220
+ }
221
+ const data = this.fallbackData;
222
+ const borders = [];
223
+ for (let i = 0; i < data.owners.length; i++) {
224
+ if (data.owners[i] !== owner)
225
+ continue;
226
+ const isBorder = data.neighborCache[i].some((ni) => {
227
+ if (ni < 0)
228
+ return true;
229
+ return data.owners[ni] !== owner;
230
+ });
231
+ if (isBorder)
232
+ borders.push(i);
233
+ }
234
+ return borders;
235
+ }
236
+ /**
237
+ * Find path between two cells
238
+ */
239
+ findPath(start, end, ownerFilter = 0) {
240
+ if (this.wasmInstance) {
241
+ return Array.from(this.wasmInstance.find_path(start, end, ownerFilter));
242
+ }
243
+ // Fallback: A* implementation
244
+ const data = this.fallbackData;
245
+ const gScore = new Map();
246
+ const fScore = new Map();
247
+ const cameFrom = new Map();
248
+ const openSet = new Set([start]);
249
+ const heuristic = (a, b) => {
250
+ const ax = a % data.width;
251
+ const ay = Math.floor(a / data.width);
252
+ const bx = b % data.width;
253
+ const by = Math.floor(b / data.width);
254
+ return Math.abs(bx - ax) + Math.abs(by - ay);
255
+ };
256
+ gScore.set(start, 0);
257
+ fScore.set(start, heuristic(start, end));
258
+ while (openSet.size > 0) {
259
+ // Find node with lowest fScore
260
+ let current = -1;
261
+ let lowestF = Infinity;
262
+ for (const node of openSet) {
263
+ const f = fScore.get(node) ?? Infinity;
264
+ if (f < lowestF) {
265
+ lowestF = f;
266
+ current = node;
267
+ }
268
+ }
269
+ if (current === end) {
270
+ // Reconstruct path
271
+ const path = [current];
272
+ while (cameFrom.has(current)) {
273
+ current = cameFrom.get(current);
274
+ path.unshift(current);
275
+ }
276
+ return path;
277
+ }
278
+ openSet.delete(current);
279
+ for (const neighbor of data.neighborCache[current]) {
280
+ if (neighbor < 0)
281
+ continue;
282
+ if (ownerFilter !== 0 && data.owners[neighbor] !== ownerFilter)
283
+ continue;
284
+ const tentativeG = (gScore.get(current) ?? Infinity) + 1;
285
+ if (tentativeG < (gScore.get(neighbor) ?? Infinity)) {
286
+ cameFrom.set(neighbor, current);
287
+ gScore.set(neighbor, tentativeG);
288
+ fScore.set(neighbor, tentativeG + heuristic(neighbor, end));
289
+ openSet.add(neighbor);
290
+ }
291
+ }
292
+ }
293
+ return []; // No path found
294
+ }
295
+ /**
296
+ * Get territory counts
297
+ */
298
+ getTerritoryCounts() {
299
+ if (this.wasmInstance) {
300
+ const counts = this.wasmInstance.get_territory_counts();
301
+ const result = new Map();
302
+ for (let i = 0; i < counts.length; i++) {
303
+ if (counts[i] > 0) {
304
+ result.set(i, counts[i]);
305
+ }
306
+ }
307
+ return result;
308
+ }
309
+ const data = this.fallbackData;
310
+ const counts = new Map();
311
+ for (const owner of data.owners) {
312
+ if (owner !== 0) {
313
+ counts.set(owner, (counts.get(owner) ?? 0) + 1);
314
+ }
315
+ }
316
+ return counts;
317
+ }
318
+ /**
319
+ * Compute Gini coefficient
320
+ */
321
+ computeGini() {
322
+ if (this.wasmInstance) {
323
+ return this.wasmInstance.compute_gini();
324
+ }
325
+ const populations = Array.from(this.fallbackData?.populations ?? [])
326
+ .filter((p) => p > 0)
327
+ .sort((a, b) => a - b);
328
+ if (populations.length === 0)
329
+ return 0;
330
+ const n = populations.length;
331
+ let sum = 0;
332
+ for (let i = 0; i < n; i++) {
333
+ sum += (2 * (i + 1) - n - 1) * populations[i];
334
+ }
335
+ const mean = populations.reduce((a, b) => a + b, 0) / n;
336
+ if (mean === 0)
337
+ return 0;
338
+ return sum / (n * n * mean);
339
+ }
340
+ /**
341
+ * Compute Shannon entropy
342
+ */
343
+ computeEntropy() {
344
+ if (this.wasmInstance) {
345
+ return this.wasmInstance.compute_entropy();
346
+ }
347
+ const counts = this.getTerritoryCounts();
348
+ const total = Array.from(counts.values()).reduce((a, b) => a + b, 0);
349
+ if (total === 0)
350
+ return 0;
351
+ let entropy = 0;
352
+ for (const count of counts.values()) {
353
+ if (count > 0) {
354
+ const p = count / total;
355
+ entropy -= p * Math.log(p);
356
+ }
357
+ }
358
+ return entropy;
359
+ }
360
+ /**
361
+ * K-means clustering
362
+ */
363
+ kmeansCluster(k, iterations = 20) {
364
+ if (this.wasmInstance) {
365
+ return Array.from(this.wasmInstance.kmeans_cluster(k, iterations));
366
+ }
367
+ // Fallback implementation
368
+ const data = this.fallbackData;
369
+ const positions = [];
370
+ for (let i = 0; i < data.owners.length; i++) {
371
+ if (data.owners[i] !== 0) {
372
+ positions.push({
373
+ x: i % data.width,
374
+ y: Math.floor(i / data.width),
375
+ idx: i,
376
+ });
377
+ }
378
+ }
379
+ if (positions.length === 0 || k === 0) {
380
+ return new Array(data.owners.length).fill(0);
381
+ }
382
+ // Initialize centroids randomly
383
+ const centroids = [];
384
+ const shuffled = [...positions].sort(() => Math.random() - 0.5);
385
+ for (let i = 0; i < Math.min(k, shuffled.length); i++) {
386
+ centroids.push({ x: shuffled[i].x, y: shuffled[i].y });
387
+ }
388
+ const assignments = new Array(positions.length).fill(0);
389
+ // Run iterations
390
+ for (let iter = 0; iter < iterations; iter++) {
391
+ // Assign points to nearest centroid
392
+ for (let i = 0; i < positions.length; i++) {
393
+ let minDist = Infinity;
394
+ let bestCluster = 0;
395
+ for (let j = 0; j < centroids.length; j++) {
396
+ const dx = positions[i].x - centroids[j].x;
397
+ const dy = positions[i].y - centroids[j].y;
398
+ const dist = dx * dx + dy * dy;
399
+ if (dist < minDist) {
400
+ minDist = dist;
401
+ bestCluster = j;
402
+ }
403
+ }
404
+ assignments[i] = bestCluster;
405
+ }
406
+ // Update centroids
407
+ const sums = centroids.map(() => ({ x: 0, y: 0, count: 0 }));
408
+ for (let i = 0; i < positions.length; i++) {
409
+ const cluster = assignments[i];
410
+ sums[cluster].x += positions[i].x;
411
+ sums[cluster].y += positions[i].y;
412
+ sums[cluster].count++;
413
+ }
414
+ for (let j = 0; j < centroids.length; j++) {
415
+ if (sums[j].count > 0) {
416
+ centroids[j].x = sums[j].x / sums[j].count;
417
+ centroids[j].y = sums[j].y / sums[j].count;
418
+ }
419
+ }
420
+ }
421
+ // Return cluster assignments for all cells
422
+ const result = new Array(data.owners.length).fill(0);
423
+ for (let i = 0; i < positions.length; i++) {
424
+ result[positions[i].idx] = assignments[i];
425
+ }
426
+ return result;
427
+ }
428
+ /**
429
+ * Get size
430
+ */
431
+ size() {
432
+ return this.wasmInstance?.size() ?? this.width * this.height;
433
+ }
434
+ /**
435
+ * Clear all cells
436
+ */
437
+ clear() {
438
+ if (this.wasmInstance) {
439
+ this.wasmInstance.clear();
440
+ }
441
+ else if (this.fallbackData) {
442
+ this.fallbackData.owners.fill(0);
443
+ this.fallbackData.populations.fill(0);
444
+ }
445
+ }
446
+ /**
447
+ * Dispose resources
448
+ */
449
+ dispose() {
450
+ if (this.wasmInstance) {
451
+ this.wasmInstance.free();
452
+ this.wasmInstance = null;
453
+ }
454
+ this.fallbackData = null;
455
+ }
456
+ }
457
+ HexGridWasmWrapper.module = null;
458
+ HexGridWasmWrapper.loading = null;
459
+ HexGridWasmWrapper.loadFailed = false;
460
+ /**
461
+ * Flow Field WASM Wrapper
462
+ */
463
+ export class FlowFieldWasmWrapper {
464
+ constructor(width, height) {
465
+ this.width = width;
466
+ this.height = height;
467
+ this.wasmInstance = null;
468
+ this.fallbackData = null;
469
+ }
470
+ static async create(width, height) {
471
+ const wrapper = new FlowFieldWasmWrapper(width, height);
472
+ const hasWasm = await HexGridWasmWrapper.loadModule();
473
+ if (hasWasm) {
474
+ try {
475
+ // @ts-expect-error - WASM module may not exist at compile time, has fallback
476
+ const module = await import('../rust/pkg/hexgrid_wasm');
477
+ wrapper.wasmInstance = new module.FlowFieldWasm(width, height);
478
+ }
479
+ catch {
480
+ // Fall through to fallback
481
+ }
482
+ }
483
+ if (!wrapper.wasmInstance) {
484
+ const size = width * height;
485
+ wrapper.fallbackData = {
486
+ width,
487
+ height,
488
+ velocityX: new Float32Array(size),
489
+ velocityY: new Float32Array(size),
490
+ };
491
+ }
492
+ return wrapper;
493
+ }
494
+ isUsingWasm() {
495
+ return this.wasmInstance !== null;
496
+ }
497
+ addSource(x, y, strength) {
498
+ if (this.wasmInstance) {
499
+ this.wasmInstance.add_source(x, y, strength);
500
+ return;
501
+ }
502
+ const data = this.fallbackData;
503
+ for (let j = 0; j < data.height; j++) {
504
+ for (let i = 0; i < data.width; i++) {
505
+ const dx = i - x;
506
+ const dy = j - y;
507
+ const distSq = dx * dx + dy * dy + 0.0001;
508
+ const dist = Math.sqrt(distSq);
509
+ const idx = j * data.width + i;
510
+ data.velocityX[idx] += (strength * dx) / (dist * distSq);
511
+ data.velocityY[idx] += (strength * dy) / (dist * distSq);
512
+ }
513
+ }
514
+ }
515
+ addVortex(x, y, strength) {
516
+ if (this.wasmInstance) {
517
+ this.wasmInstance.add_vortex(x, y, strength);
518
+ return;
519
+ }
520
+ const data = this.fallbackData;
521
+ for (let j = 0; j < data.height; j++) {
522
+ for (let i = 0; i < data.width; i++) {
523
+ const dx = i - x;
524
+ const dy = j - y;
525
+ const distSq = dx * dx + dy * dy + 0.0001;
526
+ const idx = j * data.width + i;
527
+ data.velocityX[idx] += (-strength * dy) / distSq;
528
+ data.velocityY[idx] += (strength * dx) / distSq;
529
+ }
530
+ }
531
+ }
532
+ sample(x, y) {
533
+ if (this.wasmInstance) {
534
+ const result = this.wasmInstance.sample(x, y);
535
+ return [result[0], result[1]];
536
+ }
537
+ const data = this.fallbackData;
538
+ const x0 = Math.min(Math.floor(x), data.width - 2);
539
+ const y0 = Math.min(Math.floor(y), data.height - 2);
540
+ const x1 = x0 + 1;
541
+ const y1 = y0 + 1;
542
+ const tx = x - x0;
543
+ const ty = y - y0;
544
+ const i00 = y0 * data.width + x0;
545
+ const i10 = y0 * data.width + x1;
546
+ const i01 = y1 * data.width + x0;
547
+ const i11 = y1 * data.width + x1;
548
+ const vx = data.velocityX[i00] * (1 - tx) * (1 - ty) +
549
+ data.velocityX[i10] * tx * (1 - ty) +
550
+ data.velocityX[i01] * (1 - tx) * ty +
551
+ data.velocityX[i11] * tx * ty;
552
+ const vy = data.velocityY[i00] * (1 - tx) * (1 - ty) +
553
+ data.velocityY[i10] * tx * (1 - ty) +
554
+ data.velocityY[i01] * (1 - tx) * ty +
555
+ data.velocityY[i11] * tx * ty;
556
+ return [vx, vy];
557
+ }
558
+ computeDivergence() {
559
+ if (this.wasmInstance) {
560
+ return this.wasmInstance.compute_divergence();
561
+ }
562
+ const data = this.fallbackData;
563
+ const div = new Float32Array(data.width * data.height);
564
+ for (let j = 1; j < data.height - 1; j++) {
565
+ for (let i = 1; i < data.width - 1; i++) {
566
+ const idx = j * data.width + i;
567
+ const dudx = (data.velocityX[idx + 1] - data.velocityX[idx - 1]) * 0.5;
568
+ const dvdy = (data.velocityY[idx + data.width] -
569
+ data.velocityY[idx - data.width]) *
570
+ 0.5;
571
+ div[idx] = dudx + dvdy;
572
+ }
573
+ }
574
+ return div;
575
+ }
576
+ computeCurl() {
577
+ if (this.wasmInstance) {
578
+ return this.wasmInstance.compute_curl();
579
+ }
580
+ const data = this.fallbackData;
581
+ const curl = new Float32Array(data.width * data.height);
582
+ for (let j = 1; j < data.height - 1; j++) {
583
+ for (let i = 1; i < data.width - 1; i++) {
584
+ const idx = j * data.width + i;
585
+ const dvdx = (data.velocityY[idx + 1] - data.velocityY[idx - 1]) * 0.5;
586
+ const dudy = (data.velocityX[idx + data.width] -
587
+ data.velocityX[idx - data.width]) *
588
+ 0.5;
589
+ curl[idx] = dvdx - dudy;
590
+ }
591
+ }
592
+ return curl;
593
+ }
594
+ clear() {
595
+ if (this.wasmInstance) {
596
+ this.wasmInstance.clear();
597
+ }
598
+ else if (this.fallbackData) {
599
+ this.fallbackData.velocityX.fill(0);
600
+ this.fallbackData.velocityY.fill(0);
601
+ }
602
+ }
603
+ dispose() {
604
+ if (this.wasmInstance) {
605
+ this.wasmInstance.free();
606
+ this.wasmInstance = null;
607
+ }
608
+ this.fallbackData = null;
609
+ }
610
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * WASM Module Exports
3
+ *
4
+ * @module wasm
5
+ */
6
+ export * from './HexGridWasmWrapper';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wasm/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,sBAAsB,CAAC"}
@@ -3,5 +3,4 @@
3
3
  *
4
4
  * @module wasm
5
5
  */
6
-
7
6
  export * from './HexGridWasmWrapper';
@@ -0,0 +1,20 @@
1
+ /**
2
+ * WebGPU Context Manager
3
+ * Handles the creation and management of the WebGPU Device and Adapter.
4
+ */
5
+ export declare class WebGPUContext {
6
+ private static instance;
7
+ private adapter;
8
+ private device;
9
+ private isSupported;
10
+ private constructor();
11
+ static getInstance(): WebGPUContext;
12
+ /**
13
+ * Initialize WebGPU context.
14
+ */
15
+ initialize(): Promise<boolean>;
16
+ getDevice(): GPUDevice | null;
17
+ getAdapter(): GPUAdapter | null;
18
+ isAvailable(): boolean;
19
+ }
20
+ //# sourceMappingURL=WebGPUContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebGPUContext.d.ts","sourceRoot":"","sources":["../../src/webgpu/WebGPUContext.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgB;IACvC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,WAAW,CAAkB;IAErC,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,aAAa;IAOnC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAoCpC,SAAS,IAAI,SAAS,GAAG,IAAI;IAI7B,UAAU,IAAI,UAAU,GAAG,IAAI;IAI/B,WAAW,IAAI,OAAO;CAGvB"}