@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
@@ -1,191 +0,0 @@
1
- export interface Cluster {
2
- centroid: number[];
3
- members: number[];
4
- cohesion: number;
5
- separation: number;
6
- }
7
-
8
- export interface VoronoiCell {
9
- siteIndex: number;
10
- site: [number, number];
11
- vertices: Array<[number, number]>;
12
- neighbors: number[];
13
- }
14
-
15
- export interface VoronoiDiagram {
16
- cells: VoronoiCell[];
17
- vertices: Array<[number, number]>;
18
- edges: Array<[[number, number], [number, number]]>;
19
- }
20
-
21
- export function kMeansClustering(points: number[][], k: number): Cluster[] {
22
- if (points.length === 0 || k <= 0) return [];
23
- const clusters: Cluster[] = Array.from({ length: k }, () => ({
24
- centroid: new Array(points[0]?.length || 0).fill(0),
25
- members: [],
26
- cohesion: 0,
27
- separation: 0,
28
- }));
29
-
30
- points.forEach((_point, index) => {
31
- clusters[index % k].members.push(index);
32
- });
33
-
34
- for (const cluster of clusters) {
35
- if (cluster.members.length === 0) continue;
36
- const centroid = cluster.centroid.map((_, dim) => {
37
- const sum = cluster.members.reduce(
38
- (acc, memberIdx) => acc + (points[memberIdx]?.[dim] ?? 0),
39
- 0
40
- );
41
- return sum / cluster.members.length;
42
- });
43
- cluster.centroid = centroid;
44
- cluster.cohesion =
45
- cluster.members.reduce((sum, idx) => {
46
- const point = points[idx];
47
- const distance = Math.sqrt(
48
- centroid.reduce((acc, value, dim) => {
49
- const diff = value - (point?.[dim] ?? 0);
50
- return acc + diff * diff;
51
- }, 0)
52
- );
53
- return sum + distance;
54
- }, 0) / cluster.members.length;
55
- }
56
-
57
- return clusters;
58
- }
59
-
60
- export function dbscan(
61
- points: number[][],
62
- _eps: number,
63
- _minPoints: number
64
- ): Cluster[] {
65
- if (points.length === 0) return [];
66
- return kMeansClustering(points, Math.min(1, points.length));
67
- }
68
-
69
- export function computeVoronoi(
70
- sites: Array<[number, number]>,
71
- bounds: { minX: number; maxX: number; minY: number; maxY: number }
72
- ): VoronoiDiagram {
73
- const vertices: Array<[number, number]> = [
74
- [bounds.minX, bounds.minY],
75
- [bounds.maxX, bounds.minY],
76
- [bounds.maxX, bounds.maxY],
77
- [bounds.minX, bounds.maxY],
78
- ];
79
-
80
- const cells: VoronoiCell[] = sites.map((site, index) => ({
81
- siteIndex: index,
82
- site,
83
- vertices,
84
- neighbors: sites.map((_s, i) => i).filter((i) => i !== index),
85
- }));
86
-
87
- const edges: Array<[[number, number], [number, number]]> = [];
88
- for (let i = 0; i < vertices.length; i++) {
89
- const start = vertices[i];
90
- const end = vertices[(i + 1) % vertices.length];
91
- edges.push([start, end]);
92
- }
93
-
94
- return { cells, vertices, edges };
95
- }
96
-
97
- export function analyzeTerritorBoundaries(
98
- infections: Map<number, { photoId: string }>,
99
- neighbors: number[][]
100
- ): {
101
- frontLength: Map<string, number>;
102
- hotspots: number[];
103
- } {
104
- const frontLength = new Map<string, number>();
105
- const hotspots: number[] = [];
106
-
107
- infections.forEach((value, idx) => {
108
- const neighborList = neighbors[idx] ?? [];
109
- const different = neighborList.filter(
110
- (neighborIdx) => infections.get(neighborIdx)?.photoId !== value.photoId
111
- );
112
- if (different.length > 0) {
113
- hotspots.push(idx);
114
- }
115
- const current = frontLength.get(value.photoId) ?? 0;
116
- frontLength.set(value.photoId, current + different.length);
117
- });
118
-
119
- return { frontLength, hotspots };
120
- }
121
-
122
- export function kMeansClustering2D(
123
- points: Array<[number, number]>,
124
- k: number
125
- ): Cluster[] {
126
- const asPoints = points.map((p) => [p[0], p[1]]);
127
- return kMeansClustering(asPoints, k);
128
- }
129
-
130
- export function findConnectedComponents(graph: {
131
- nodes: number[];
132
- edges: Map<number, number[]>;
133
- }): number[][] {
134
- const visited = new Set<number>();
135
- const components: number[][] = [];
136
-
137
- for (const node of graph.nodes) {
138
- if (visited.has(node)) continue;
139
- const stack = [node];
140
- const component: number[] = [];
141
-
142
- while (stack.length > 0) {
143
- const current = stack.pop();
144
- if (current === undefined || visited.has(current)) continue;
145
- visited.add(current);
146
- component.push(current);
147
- const neighbors = graph.edges.get(current) ?? [];
148
- for (const neighbor of neighbors) {
149
- if (!visited.has(neighbor)) {
150
- stack.push(neighbor);
151
- }
152
- }
153
- }
154
-
155
- components.push(component);
156
- }
157
-
158
- return components;
159
- }
160
-
161
- export function louvainCommunities(graph: {
162
- nodes: number[];
163
- edges: Map<number, number[]>;
164
- weights?: Map<string, number>;
165
- }): Array<{ members: number[]; modularity: number }> {
166
- const components = findConnectedComponents(graph);
167
- return components.map((members) => ({
168
- members,
169
- modularity: members.length / Math.max(1, graph.nodes.length),
170
- }));
171
- }
172
-
173
- export function computeVoronoiGraph(sites: Array<[number, number]>) {
174
- return computeVoronoi(sites, {
175
- minX: Math.min(...sites.map((s) => s[0])),
176
- maxX: Math.max(...sites.map((s) => s[0])),
177
- minY: Math.min(...sites.map((s) => s[1])),
178
- maxY: Math.max(...sites.map((s) => s[1])),
179
- });
180
- }
181
-
182
- export function kMeansCluster(points: number[][], k: number): Cluster[] {
183
- return kMeansClustering(points, k);
184
- }
185
-
186
- export function kMeansClusteringWithLabels(
187
- points: number[][],
188
- k: number
189
- ): Cluster[] {
190
- return kMeansClustering(points, k);
191
- }
@@ -1,425 +0,0 @@
1
- export interface OutlierStats {
2
- mean: number;
3
- stdDev: number;
4
- }
5
-
6
- export interface OutlierResult {
7
- outlierIndices: number[];
8
- scores: number[];
9
- stats: OutlierStats;
10
- threshold: number;
11
- }
12
-
13
- export interface TimeSeriesAnomaly {
14
- index: number;
15
- isAnomaly: boolean;
16
- zScore: number;
17
- expectedValue: number;
18
- actualValue: number;
19
- confidence: number;
20
- anomalyType: 'spike' | 'drop' | 'change';
21
- }
22
-
23
- export interface VarianceChangeResult {
24
- index: number;
25
- ratio: number;
26
- beforeVariance: number;
27
- afterVariance: number;
28
- }
29
-
30
- function mean(values: number[]): number {
31
- if (values.length === 0) return 0;
32
- return values.reduce((sum, value) => sum + value, 0) / values.length;
33
- }
34
-
35
- function stdDev(values: number[], avg: number): number {
36
- if (values.length === 0) return 0;
37
- const variance =
38
- values.reduce((sum, value) => sum + (value - avg) ** 2, 0) / values.length;
39
- return Math.sqrt(variance);
40
- }
41
-
42
- export function detectOutliersZScore(
43
- values: number[],
44
- threshold: number = 3
45
- ): OutlierResult {
46
- const avg = mean(values);
47
- const deviation = stdDev(values, avg);
48
- const scores = values.map((value) =>
49
- deviation === 0 ? 0 : (value - avg) / deviation
50
- );
51
-
52
- const outlierIndices = scores
53
- .map((score, index) => ({ score, index }))
54
- .filter(({ score }) => Math.abs(score) >= threshold)
55
- .map(({ index }) => index);
56
-
57
- return {
58
- outlierIndices,
59
- scores,
60
- stats: { mean: avg, stdDev: deviation },
61
- threshold,
62
- };
63
- }
64
-
65
- export function detectOutliersModifiedZScore(
66
- values: number[],
67
- threshold: number = 3.5
68
- ): OutlierResult {
69
- if (values.length === 0) {
70
- return {
71
- outlierIndices: [],
72
- scores: [],
73
- stats: { mean: 0, stdDev: 0 },
74
- threshold,
75
- };
76
- }
77
-
78
- const sorted = [...values].sort((a, b) => a - b);
79
- const median = sorted[Math.floor(sorted.length / 2)] ?? 0;
80
- const deviations = values.map((value) => Math.abs(value - median));
81
- const sortedDeviations = [...deviations].sort((a, b) => a - b);
82
- const mad = sortedDeviations[Math.floor(sortedDeviations.length / 2)] || 0;
83
-
84
- const scores = values.map((value) =>
85
- mad === 0 ? 0 : (0.6745 * (value - median)) / mad
86
- );
87
-
88
- const outlierIndices = scores
89
- .map((score, index) => ({ score, index }))
90
- .filter(({ score }) => Math.abs(score) >= threshold)
91
- .map(({ index }) => index);
92
-
93
- return {
94
- outlierIndices,
95
- scores,
96
- stats: { mean: median, stdDev: mad },
97
- threshold,
98
- };
99
- }
100
-
101
- export function detectOutliersIQR(
102
- values: number[],
103
- threshold: number = 1.5
104
- ): OutlierResult {
105
- if (values.length === 0) {
106
- return {
107
- outlierIndices: [],
108
- scores: [],
109
- stats: { mean: 0, stdDev: 0 },
110
- threshold,
111
- };
112
- }
113
-
114
- const sorted = [...values].sort((a, b) => a - b);
115
- const q1 = sorted[Math.floor(sorted.length * 0.25)] ?? 0;
116
- const q3 = sorted[Math.floor(sorted.length * 0.75)] ?? 0;
117
- const iqr = q3 - q1;
118
-
119
- const lowerBound = q1 - threshold * iqr;
120
- const upperBound = q3 + threshold * iqr;
121
-
122
- const outlierIndices = values
123
- .map((value, index) => ({ value, index }))
124
- .filter(({ value }) => value < lowerBound || value > upperBound)
125
- .map(({ index }) => index);
126
-
127
- const avg = mean(values);
128
- const deviation = stdDev(values, avg);
129
- const scores = values.map((value) =>
130
- deviation === 0 ? 0 : (value - avg) / deviation
131
- );
132
-
133
- return {
134
- outlierIndices,
135
- scores,
136
- stats: { mean: avg, stdDev: deviation },
137
- threshold,
138
- };
139
- }
140
-
141
- export function detectGrowthSpikes(values: number[]): TimeSeriesAnomaly[] {
142
- if (values.length < 2) return [];
143
-
144
- const diffs = values.slice(1).map((value, index) => value - values[index]);
145
- const diffStats = detectOutliersZScore(diffs, 2.5);
146
-
147
- return diffs.map((diff, index) => {
148
- const score = diffStats.scores[index] ?? 0;
149
- const isAnomaly = Math.abs(score) >= 2.5;
150
- return {
151
- index: index + 1,
152
- isAnomaly,
153
- zScore: Math.abs(score),
154
- expectedValue: values[index],
155
- actualValue: values[index + 1],
156
- confidence: Math.min(0.99, Math.abs(score) / 4),
157
- anomalyType: diff >= 0 ? 'spike' : 'drop',
158
- };
159
- });
160
- }
161
-
162
- export function detectVarianceChanges(
163
- values: number[]
164
- ): VarianceChangeResult[] {
165
- if (values.length < 6) return [];
166
- const results: VarianceChangeResult[] = [];
167
- const windowSize = Math.max(3, Math.floor(values.length / 4));
168
-
169
- for (let i = windowSize; i < values.length - windowSize; i++) {
170
- const before = values.slice(i - windowSize, i);
171
- const after = values.slice(i, i + windowSize);
172
- const beforeMean = mean(before);
173
- const afterMean = mean(after);
174
- const beforeVar = stdDev(before, beforeMean) ** 2;
175
- const afterVar = stdDev(after, afterMean) ** 2;
176
- const ratio =
177
- beforeVar === 0 ? (afterVar === 0 ? 1 : Infinity) : afterVar / beforeVar;
178
-
179
- results.push({
180
- index: i,
181
- ratio,
182
- beforeVariance: beforeVar,
183
- afterVariance: afterVar,
184
- });
185
- }
186
-
187
- return results;
188
- }
189
-
190
- export function mahalanobisOutliers(
191
- values: number[],
192
- threshold: number = 3
193
- ): OutlierResult {
194
- return detectOutliersZScore(values, threshold);
195
- }
196
-
197
- // Game Anomaly Detection
198
- export interface GameAnomaly {
199
- index: number;
200
- type: 'sudden_change' | 'pattern_break' | 'statistical_outlier';
201
- severity: number;
202
- description: string;
203
- }
204
-
205
- export function detectGameAnomalies(
206
- values: number[],
207
- windowSize: number = 5
208
- ): GameAnomaly[] {
209
- const anomalies: GameAnomaly[] = [];
210
- if (values.length < windowSize * 2) return anomalies;
211
-
212
- for (let i = windowSize; i < values.length - windowSize; i++) {
213
- const before = values.slice(i - windowSize, i);
214
- const after = values.slice(i, i + windowSize);
215
- const beforeMean = before.reduce((s, v) => s + v, 0) / before.length;
216
- const afterMean = after.reduce((s, v) => s + v, 0) / after.length;
217
- const change = Math.abs(afterMean - beforeMean);
218
- const threshold =
219
- before.reduce((s, v) => s + Math.abs(v - beforeMean), 0) / before.length;
220
-
221
- if (change > threshold * 2) {
222
- anomalies.push({
223
- index: i,
224
- type: 'sudden_change',
225
- severity: Math.min(1, change / (threshold || 1)),
226
- description: `Sudden change detected at index ${i}`,
227
- });
228
- }
229
- }
230
-
231
- return anomalies;
232
- }
233
-
234
- // Comprehensive Outlier Analysis
235
- export interface MultivariateOutlierResult {
236
- outliers: number[];
237
- scores: number[];
238
- method: string;
239
- }
240
-
241
- export function comprehensiveOutlierAnalysis(
242
- values: number[]
243
- ): MultivariateOutlierResult {
244
- const zScore = detectOutliersZScore(values);
245
- const iqr = detectOutliersIQR(values);
246
- const combined = new Set([...zScore.outlierIndices, ...iqr.outlierIndices]);
247
-
248
- return {
249
- outliers: Array.from(combined),
250
- scores: values.map((v, i) =>
251
- combined.has(i)
252
- ? Math.max(
253
- Math.abs(zScore.scores[i] ?? 0),
254
- Math.abs(iqr.scores[i] ?? 0)
255
- )
256
- : 0
257
- ),
258
- method: 'comprehensive',
259
- };
260
- }
261
-
262
- // Local Outlier Factor (simplified)
263
- export function localOutlierFactor(
264
- values: number[],
265
- k: number = 5
266
- ): OutlierResult {
267
- // Simplified LOF implementation
268
- if (values.length < k + 1) {
269
- return {
270
- outlierIndices: [],
271
- scores: values.map(() => 0),
272
- stats: { mean: 0, stdDev: 0 },
273
- threshold: 1.5,
274
- };
275
- }
276
-
277
- const scores: number[] = [];
278
- for (let i = 0; i < values.length; i++) {
279
- const distances = values
280
- .map((v, j) => (i === j ? Infinity : Math.abs(v - values[i]!)))
281
- .sort((a, b) => a - b);
282
- const kthDistance = distances[k] ?? 0;
283
- const reachability = values.map((v, j) =>
284
- Math.max(kthDistance, Math.abs(v - values[i]!))
285
- );
286
- const lrd = k / reachability.reduce((s, r) => s + r, 0);
287
- scores.push(lrd);
288
- }
289
-
290
- const avgLrd = scores.reduce((s, lrd) => s + lrd, 0) / scores.length;
291
- const lofScores = scores.map((lrd) => (lrd === 0 ? 0 : avgLrd / lrd));
292
- const threshold = 1.5;
293
- const outlierIndices = lofScores
294
- .map((score, idx) => ({ score, idx }))
295
- .filter(({ score }) => score > threshold)
296
- .map(({ idx }) => idx);
297
-
298
- const avg = values.reduce((s, v) => s + v, 0) / values.length;
299
- const variance =
300
- values.reduce((s, v) => s + Math.pow(v - avg, 2), 0) / values.length;
301
- const stdDev = Math.sqrt(variance);
302
-
303
- return {
304
- outlierIndices,
305
- scores: lofScores,
306
- stats: { mean: avg, stdDev },
307
- threshold,
308
- };
309
- }
310
-
311
- // Isolation Forest (simplified)
312
- export function isolationForest(
313
- values: number[],
314
- trees: number = 100,
315
- samples: number = 256
316
- ): OutlierResult {
317
- // Simplified isolation forest
318
- const scores: number[] = [];
319
- const sampleSize = Math.min(samples, values.length);
320
-
321
- for (let i = 0; i < values.length; i++) {
322
- let pathLengthSum = 0;
323
- for (let t = 0; t < trees; t++) {
324
- const sample = [];
325
- for (let s = 0; s < sampleSize; s++) {
326
- sample.push(values[Math.floor(Math.random() * values.length)] ?? 0);
327
- }
328
- const min = Math.min(...sample);
329
- const max = Math.max(...sample);
330
- const range = max - min || 1;
331
- const normalized = (values[i]! - min) / range;
332
- pathLengthSum += Math.log2(Math.max(1, normalized * sampleSize));
333
- }
334
- const avgPathLength = pathLengthSum / trees;
335
- const anomalyScore = Math.pow(2, -avgPathLength / Math.log2(sampleSize));
336
- scores.push(anomalyScore);
337
- }
338
-
339
- const threshold = 0.5;
340
- const outlierIndices = scores
341
- .map((score, idx) => ({ score, idx }))
342
- .filter(({ score }) => score > threshold)
343
- .map(({ idx }) => idx);
344
-
345
- const avg = values.reduce((s, v) => s + v, 0) / values.length;
346
- const variance =
347
- values.reduce((s, v) => s + Math.pow(v - avg, 2), 0) / values.length;
348
- const stdDev = Math.sqrt(variance);
349
-
350
- return {
351
- outlierIndices,
352
- scores,
353
- stats: { mean: avg, stdDev },
354
- threshold,
355
- };
356
- }
357
-
358
- // CUSUM Chart
359
- export function cusumChart(
360
- values: number[],
361
- target: number,
362
- h: number = 5,
363
- k: number = 0.5
364
- ): TimeSeriesAnomaly[] {
365
- const anomalies: TimeSeriesAnomaly[] = [];
366
- let sPos = 0;
367
- let sNeg = 0;
368
-
369
- for (let i = 0; i < values.length; i++) {
370
- const deviation = values[i]! - target;
371
- sPos = Math.max(0, sPos + deviation - k);
372
- sNeg = Math.max(0, sNeg - deviation - k);
373
-
374
- if (sPos > h || sNeg > h) {
375
- anomalies.push({
376
- index: i,
377
- isAnomaly: true,
378
- zScore: Math.max(sPos, sNeg) / h,
379
- expectedValue: target,
380
- actualValue: values[i]!,
381
- confidence: Math.min(0.99, Math.max(sPos, sNeg) / (h * 2)),
382
- anomalyType: sPos > sNeg ? 'spike' : 'drop',
383
- });
384
- }
385
- }
386
-
387
- return anomalies;
388
- }
389
-
390
- // EWMA Chart (Exponentially Weighted Moving Average)
391
- export function ewmaChart(
392
- values: number[],
393
- lambda: number = 0.2,
394
- lcl: number = -3,
395
- ucl: number = 3
396
- ): TimeSeriesAnomaly[] {
397
- const anomalies: TimeSeriesAnomaly[] = [];
398
- if (values.length === 0) return anomalies;
399
-
400
- let ewma = values[0]!;
401
- const mean = values.reduce((s, v) => s + v, 0) / values.length;
402
- const variance =
403
- values.reduce((s, v) => s + Math.pow(v - mean, 2), 0) / values.length;
404
- const stdDev = Math.sqrt(variance);
405
- const ewmaStdDev = stdDev * Math.sqrt(lambda / (2 - lambda));
406
-
407
- for (let i = 1; i < values.length; i++) {
408
- ewma = lambda * values[i]! + (1 - lambda) * ewma;
409
- const zScore = (ewma - mean) / (ewmaStdDev || 1);
410
-
411
- if (zScore < lcl || zScore > ucl) {
412
- anomalies.push({
413
- index: i,
414
- isAnomaly: true,
415
- zScore: Math.abs(zScore),
416
- expectedValue: mean,
417
- actualValue: values[i]!,
418
- confidence: Math.min(0.99, Math.abs(zScore) / 5),
419
- anomalyType: zScore > 0 ? 'spike' : 'drop',
420
- });
421
- }
422
- }
423
-
424
- return anomalies;
425
- }
@@ -1,95 +0,0 @@
1
- import { Vector2 } from '../math/Vector3';
2
-
3
- type ParticleEffect = 'birth' | 'trail' | 'victory' | 'sparkle';
4
-
5
- export interface ParticleConfig {
6
- maxParticles: number;
7
- gravity: Vector2;
8
- }
9
-
10
- export interface Particle {
11
- x: number;
12
- y: number;
13
- size: number;
14
- color: string;
15
- alpha: number;
16
- }
17
-
18
- export class ParticleSystem {
19
- private particles: Particle[] = [];
20
-
21
- addParticle(particle: Particle): void {
22
- this.particles.push(particle);
23
- }
24
-
25
- update(_deltaTime: number): void {
26
- // No-op for stub
27
- }
28
-
29
- getPositions(): Particle[] {
30
- return this.particles;
31
- }
32
-
33
- clear(): void {
34
- this.particles = [];
35
- }
36
- }
37
-
38
- export class ParticleEffectManager {
39
- private systems: Map<string, ParticleSystem> = new Map();
40
- private config: ParticleConfig;
41
-
42
- constructor(config: ParticleConfig) {
43
- this.config = config;
44
- this.systems.set('default', new ParticleSystem());
45
- }
46
-
47
- triggerEffect(
48
- effect: ParticleEffect,
49
- position: Vector2,
50
- options?: {
51
- count?: number;
52
- color?: [number, number, number];
53
- velocity?: Vector2;
54
- }
55
- ): void {
56
- const system = this.systems.get('default');
57
- if (!system) return;
58
- const count = options?.count ?? 1;
59
- const color = options?.color ?? [1, 1, 1];
60
- for (let i = 0; i < count; i++) {
61
- system.addParticle({
62
- x: position.x,
63
- y: position.y,
64
- size: 4,
65
- color: `rgb(${Math.round(color[0] * 255)}, ${Math.round(
66
- color[1] * 255
67
- )}, ${Math.round(color[2] * 255)})`,
68
- alpha: 1,
69
- });
70
- }
71
- }
72
-
73
- update(deltaTime: number): void {
74
- for (const system of this.systems.values()) {
75
- system.update(deltaTime);
76
- }
77
- }
78
-
79
- getSystem(name: string): ParticleSystem | undefined {
80
- return this.systems.get(name);
81
- }
82
-
83
- clearAll(): void {
84
- for (const system of this.systems.values()) {
85
- system.clear();
86
- }
87
- }
88
- }
89
-
90
- export const ParticlePresets: Record<string, ParticleEffect> = {
91
- birth: 'birth',
92
- trail: 'trail',
93
- victory: 'victory',
94
- sparkle: 'sparkle',
95
- };