@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.
- package/dist/HexGridEnhanced.d.ts +15 -0
- package/dist/HexGridEnhanced.d.ts.map +1 -0
- package/dist/HexGridEnhanced.js +1 -0
- package/dist/Snapshot.d.ts +594 -0
- package/dist/Snapshot.d.ts.map +1 -0
- package/dist/Snapshot.js +757 -0
- package/dist/adapters/DashAdapter.d.ts +18 -0
- package/dist/adapters/DashAdapter.d.ts.map +1 -0
- package/dist/adapters/DashAdapter.js +42 -0
- package/dist/adapters.d.ts +53 -0
- package/dist/adapters.d.ts.map +1 -0
- package/dist/adapters.js +14 -0
- package/dist/algorithms/AdvancedStatistics.d.ts +52 -0
- package/dist/algorithms/AdvancedStatistics.d.ts.map +1 -0
- package/dist/algorithms/AdvancedStatistics.js +307 -0
- package/dist/algorithms/BayesianStatistics.d.ts +86 -0
- package/dist/algorithms/BayesianStatistics.d.ts.map +1 -0
- package/dist/algorithms/BayesianStatistics.js +263 -0
- package/dist/algorithms/FlowField.d.ts +55 -0
- package/dist/algorithms/FlowField.d.ts.map +1 -0
- package/dist/algorithms/FlowField.js +80 -0
- package/dist/algorithms/FlowField3D.d.ts +166 -0
- package/dist/algorithms/FlowField3D.d.ts.map +1 -0
- package/dist/algorithms/FlowField3D.js +327 -0
- package/dist/algorithms/FluidEngineFactory.d.ts +15 -0
- package/dist/algorithms/FluidEngineFactory.d.ts.map +1 -0
- package/dist/algorithms/FluidEngineFactory.js +41 -0
- package/dist/algorithms/FluidSimulation.d.ts +41 -0
- package/dist/algorithms/FluidSimulation.d.ts.map +1 -0
- package/dist/algorithms/FluidSimulation.js +74 -0
- package/dist/algorithms/FluidSimulation3D.d.ts +137 -0
- package/dist/algorithms/FluidSimulation3D.d.ts.map +1 -0
- package/dist/algorithms/FluidSimulation3D.js +464 -0
- package/dist/algorithms/FluidSimulation3DGPU.d.ts +41 -0
- package/dist/algorithms/FluidSimulation3DGPU.d.ts.map +1 -0
- package/dist/algorithms/FluidSimulation3DGPU.js +328 -0
- package/dist/algorithms/FluidSimulationWebNN.d.ts +56 -0
- package/dist/algorithms/FluidSimulationWebNN.d.ts.map +1 -0
- package/dist/algorithms/FluidSimulationWebNN.js +84 -0
- package/dist/algorithms/GraphAlgorithms.d.ts +48 -0
- package/dist/algorithms/GraphAlgorithms.d.ts.map +1 -0
- package/dist/algorithms/GraphAlgorithms.js +122 -0
- package/dist/algorithms/OutlierDetection.d.ts +49 -0
- package/dist/algorithms/OutlierDetection.d.ts.map +1 -0
- package/dist/algorithms/OutlierDetection.js +284 -0
- package/dist/algorithms/ParticleSystem.d.ts +36 -0
- package/dist/algorithms/ParticleSystem.d.ts.map +1 -0
- package/dist/algorithms/ParticleSystem.js +59 -0
- package/dist/algorithms/ParticleSystem3D.d.ts +206 -0
- package/dist/algorithms/ParticleSystem3D.d.ts.map +1 -0
- package/dist/algorithms/ParticleSystem3D.js +371 -0
- package/dist/algorithms/index.d.ts +16 -0
- package/dist/algorithms/index.d.ts.map +1 -0
- package/{src/algorithms/index.ts → dist/algorithms/index.js} +0 -2
- package/dist/compat.d.ts +24 -0
- package/dist/compat.d.ts.map +1 -0
- package/dist/compat.js +88 -0
- package/dist/components/HexGrid.d.ts +5 -0
- package/dist/components/HexGrid.d.ts.map +1 -0
- package/dist/components/HexGrid.js +39 -0
- package/dist/components/NarrationOverlay.d.ts +16 -0
- package/dist/components/NarrationOverlay.d.ts.map +1 -0
- package/dist/components/NarrationOverlay.js +132 -0
- package/{src/components/index.ts → dist/components/index.d.ts} +1 -1
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +1 -0
- package/dist/features.d.ts +54 -0
- package/dist/features.d.ts.map +1 -0
- package/dist/features.js +74 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/lib/narration.d.ts +12 -0
- package/dist/lib/narration.d.ts.map +1 -0
- package/dist/lib/narration.js +8 -0
- package/dist/lib/stats-tracker.d.ts +7 -0
- package/dist/lib/stats-tracker.d.ts.map +1 -0
- package/dist/lib/stats-tracker.js +22 -0
- package/dist/lib/theme-colors.d.ts +7 -0
- package/dist/lib/theme-colors.d.ts.map +1 -0
- package/dist/lib/theme-colors.js +10 -0
- package/dist/math/HexCoordinates.d.ts +140 -0
- package/dist/math/HexCoordinates.d.ts.map +1 -0
- package/dist/math/HexCoordinates.js +741 -0
- package/dist/math/Matrix4.d.ts +9 -0
- package/dist/math/Matrix4.d.ts.map +1 -0
- package/dist/math/Matrix4.js +19 -0
- package/dist/math/Quaternion.d.ts +11 -0
- package/dist/math/Quaternion.d.ts.map +1 -0
- package/dist/math/Quaternion.js +23 -0
- package/dist/math/SpatialIndex.d.ts +34 -0
- package/dist/math/SpatialIndex.d.ts.map +1 -0
- package/dist/math/SpatialIndex.js +75 -0
- package/dist/math/Vector3.d.ts +110 -0
- package/dist/math/Vector3.d.ts.map +1 -0
- package/dist/math/Vector3.js +426 -0
- package/dist/math/index.d.ts +11 -0
- package/dist/math/index.d.ts.map +1 -0
- package/{src/math/index.ts → dist/math/index.js} +0 -1
- package/dist/note-adapter.d.ts +44 -0
- package/dist/note-adapter.d.ts.map +1 -0
- package/dist/note-adapter.js +86 -0
- package/dist/ontology-adapter.d.ts +13 -0
- package/dist/ontology-adapter.d.ts.map +1 -0
- package/dist/ontology-adapter.js +65 -0
- package/dist/stores/index.d.ts +2 -0
- package/dist/stores/index.d.ts.map +1 -0
- package/dist/stores/uiStore.d.ts +18 -0
- package/dist/stores/uiStore.d.ts.map +1 -0
- package/dist/stores/uiStore.js +77 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types.d.ts +126 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/utils/image-utils.d.ts +13 -0
- package/dist/utils/image-utils.d.ts.map +1 -0
- package/dist/utils/image-utils.js +23 -0
- package/dist/wasm/HexGridWasmWrapper.d.ts +131 -0
- package/dist/wasm/HexGridWasmWrapper.d.ts.map +1 -0
- package/dist/wasm/HexGridWasmWrapper.js +610 -0
- package/dist/wasm/index.d.ts +7 -0
- package/dist/wasm/index.d.ts.map +1 -0
- package/{src/wasm/index.ts → dist/wasm/index.js} +0 -1
- package/dist/webgpu/WebGPUContext.d.ts +20 -0
- package/dist/webgpu/WebGPUContext.d.ts.map +1 -0
- package/dist/webgpu/WebGPUContext.js +60 -0
- package/dist/webnn/WebNNContext.d.ts +38 -0
- package/dist/webnn/WebNNContext.d.ts.map +1 -0
- package/dist/webnn/WebNNContext.js +66 -0
- package/dist/workers/hexgrid-math.d.ts +79 -0
- package/dist/workers/hexgrid-math.d.ts.map +1 -0
- package/dist/workers/hexgrid-math.js +136 -0
- package/dist/workers/hexgrid-worker.worker.d.ts +35 -0
- package/dist/workers/hexgrid-worker.worker.d.ts.map +1 -0
- package/dist/workers/hexgrid-worker.worker.js +2014 -0
- package/package.json +20 -7
- package/.eslintrc.json +0 -28
- package/build_log.txt +0 -500
- package/build_src_log.txt +0 -8
- package/examples/basic-usage.tsx +0 -52
- package/public/hexgrid-worker.js +0 -2475
- package/rust/Cargo.toml +0 -41
- package/rust/src/lib.rs +0 -740
- package/rust/src/math.rs +0 -574
- package/rust/src/spatial.rs +0 -245
- package/rust/src/statistics.rs +0 -496
- package/site/.eslintrc.json +0 -3
- package/site/DEPLOYMENT.md +0 -196
- package/site/INDEX.md +0 -127
- package/site/QUICK_START.md +0 -86
- package/site/README.md +0 -85
- package/site/SITE_SUMMARY.md +0 -180
- package/site/next.config.js +0 -12
- package/site/package.json +0 -26
- package/site/src/app/docs/page.tsx +0 -272
- package/site/src/app/examples/page.tsx +0 -151
- package/site/src/app/globals.css +0 -160
- package/site/src/app/layout.tsx +0 -39
- package/site/src/app/page.tsx +0 -235
- package/site/tsconfig.json +0 -29
- package/site/vercel.json +0 -6
- package/src/HexGridEnhanced.ts +0 -16
- package/src/Snapshot.ts +0 -1607
- package/src/adapters/DashAdapter.ts +0 -57
- package/src/adapters.ts +0 -63
- package/src/algorithms/AdvancedStatistics.ts +0 -362
- package/src/algorithms/BayesianStatistics.ts +0 -348
- package/src/algorithms/FlowField.ts +0 -150
- package/src/algorithms/FlowField3D.ts +0 -573
- package/src/algorithms/FluidEngineFactory.ts +0 -44
- package/src/algorithms/FluidSimulation.ts +0 -115
- package/src/algorithms/FluidSimulation3D.ts +0 -664
- package/src/algorithms/FluidSimulation3DGPU.ts +0 -402
- package/src/algorithms/FluidSimulationWebNN.ts +0 -141
- package/src/algorithms/GraphAlgorithms.ts +0 -191
- package/src/algorithms/OutlierDetection.ts +0 -425
- package/src/algorithms/ParticleSystem.ts +0 -95
- package/src/algorithms/ParticleSystem3D.ts +0 -567
- package/src/compat.ts +0 -96
- package/src/components/HexGrid.tsx +0 -61
- package/src/components/NarrationOverlay.tsx +0 -309
- package/src/features.ts +0 -125
- package/src/index.ts +0 -30
- package/src/lib/narration.ts +0 -17
- package/src/lib/stats-tracker.ts +0 -25
- package/src/lib/theme-colors.ts +0 -12
- package/src/math/HexCoordinates.ts +0 -863
- package/src/math/Matrix4.ts +0 -25
- package/src/math/Quaternion.ts +0 -37
- package/src/math/SpatialIndex.ts +0 -114
- package/src/math/Vector3.ts +0 -540
- package/src/note-adapter.ts +0 -132
- package/src/ontology-adapter.ts +0 -84
- package/src/stores/uiStore.ts +0 -85
- package/src/types/index.ts +0 -3
- package/src/types/shared-utils.d.ts +0 -10
- package/src/types/wgsl.d.ts +0 -4
- package/src/types.ts +0 -164
- package/src/utils/image-utils.ts +0 -28
- package/src/wasm/HexGridWasmWrapper.ts +0 -801
- package/src/webgpu/WebGPUContext.ts +0 -71
- package/src/webgpu/shaders/fluid_sim.wgsl +0 -140
- package/src/webnn/WebNNContext.ts +0 -99
- package/src/workers/hexgrid-math.ts +0 -182
- package/src/workers/hexgrid-worker.worker.ts +0 -2781
- package/tsconfig.json +0 -26
- /package/{src/stores/index.ts → dist/stores/index.js} +0 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 3D Particle System
|
|
3
|
+
*
|
|
4
|
+
* GPU-friendly particle physics for React Three Fiber InstancedMesh rendering.
|
|
5
|
+
* Supports forces, attractors, fluid coupling, and biometric visualization.
|
|
6
|
+
*/
|
|
7
|
+
import { Vector3 } from '../math/Vector3';
|
|
8
|
+
/**
|
|
9
|
+
* 3D Particle System with GPU-friendly output
|
|
10
|
+
*/
|
|
11
|
+
export class ParticleSystem3D {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.particles = new Map();
|
|
14
|
+
this.particleOrder = [];
|
|
15
|
+
this.time = 0;
|
|
16
|
+
this.idCounter = 0;
|
|
17
|
+
this.maxParticles = config.maxParticles;
|
|
18
|
+
this.gravity = config.gravity ?? new Vector3(0, 0, 0);
|
|
19
|
+
this.drag = config.drag ?? 0.99;
|
|
20
|
+
this.boundsSphereRadius = config.boundsSphereRadius ?? Infinity;
|
|
21
|
+
this.boundsCenter = config.boundsCenter ?? new Vector3(0, 0, 0);
|
|
22
|
+
this.bounceFactor = config.bounceFactor ?? 0.5;
|
|
23
|
+
// Pre-allocate buffers (unless provided via config for zero-copy)
|
|
24
|
+
if (config.sharedBuffers) {
|
|
25
|
+
this.positionBuffer = config.sharedBuffers.positions;
|
|
26
|
+
this.colorBuffer = config.sharedBuffers.colors;
|
|
27
|
+
this.scaleBuffer = config.sharedBuffers.scales;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
this.positionBuffer = new Float32Array(this.maxParticles * 3);
|
|
31
|
+
this.colorBuffer = new Float32Array(this.maxParticles * 3);
|
|
32
|
+
this.scaleBuffer = new Float32Array(this.maxParticles);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Zero-Copy Binding: Inject shared buffers from WASM/Dash
|
|
37
|
+
*/
|
|
38
|
+
setSharedBuffers(buffers) {
|
|
39
|
+
this.positionBuffer = buffers.positions;
|
|
40
|
+
this.colorBuffer = buffers.colors;
|
|
41
|
+
this.scaleBuffer = buffers.scales;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Emit particles at a position
|
|
45
|
+
*/
|
|
46
|
+
emit(position, options = {}) {
|
|
47
|
+
const count = options.count ?? 1;
|
|
48
|
+
const emittedIds = [];
|
|
49
|
+
for (let i = 0; i < count; i++) {
|
|
50
|
+
if (this.particles.size >= this.maxParticles) {
|
|
51
|
+
// Remove oldest particle
|
|
52
|
+
const oldest = this.particleOrder.shift();
|
|
53
|
+
if (oldest) {
|
|
54
|
+
this.particles.delete(oldest);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const id = `p_${this.idCounter++}`;
|
|
58
|
+
const spread = options.velocitySpread ?? new Vector3(0, 0, 0);
|
|
59
|
+
const sizeSpread = options.sizeSpread ?? 0;
|
|
60
|
+
const lifeSpread = options.lifeSpread ?? 0;
|
|
61
|
+
const particle = {
|
|
62
|
+
id,
|
|
63
|
+
position: new Vector3(position.x, position.y, position.z),
|
|
64
|
+
velocity: new Vector3((options.velocity?.x ?? 0) + (Math.random() - 0.5) * 2 * spread.x, (options.velocity?.y ?? 0) + (Math.random() - 0.5) * 2 * spread.y, (options.velocity?.z ?? 0) + (Math.random() - 0.5) * 2 * spread.z),
|
|
65
|
+
acceleration: new Vector3(0, 0, 0),
|
|
66
|
+
color: options.color ?? [1, 1, 1],
|
|
67
|
+
size: (options.size ?? 1) + (Math.random() - 0.5) * 2 * sizeSpread,
|
|
68
|
+
life: (options.life ?? 5) + (Math.random() - 0.5) * 2 * lifeSpread,
|
|
69
|
+
maxLife: options.life ?? 5,
|
|
70
|
+
mass: options.mass ?? 1,
|
|
71
|
+
userData: options.userData,
|
|
72
|
+
heartRate: options.heartRate,
|
|
73
|
+
hrvValue: options.hrvValue,
|
|
74
|
+
pulseScale: 1,
|
|
75
|
+
};
|
|
76
|
+
this.particles.set(id, particle);
|
|
77
|
+
this.particleOrder.push(id);
|
|
78
|
+
emittedIds.push(id);
|
|
79
|
+
}
|
|
80
|
+
return emittedIds;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Add or update a persistent particle (for memory particles that don't expire)
|
|
84
|
+
*/
|
|
85
|
+
setParticle(id, particle) {
|
|
86
|
+
const existing = this.particles.get(id);
|
|
87
|
+
if (existing) {
|
|
88
|
+
// Update existing
|
|
89
|
+
Object.assign(existing, particle);
|
|
90
|
+
existing.acceleration = new Vector3(0, 0, 0);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Add new
|
|
94
|
+
if (this.particles.size >= this.maxParticles) {
|
|
95
|
+
// Remove oldest non-persistent particle
|
|
96
|
+
for (let i = 0; i < this.particleOrder.length; i++) {
|
|
97
|
+
const oldId = this.particleOrder[i];
|
|
98
|
+
const oldParticle = this.particles.get(oldId);
|
|
99
|
+
if (oldParticle && oldParticle.life !== Infinity) {
|
|
100
|
+
this.particles.delete(oldId);
|
|
101
|
+
this.particleOrder.splice(i, 1);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const newParticle = {
|
|
107
|
+
...particle,
|
|
108
|
+
acceleration: new Vector3(0, 0, 0),
|
|
109
|
+
pulseScale: 1,
|
|
110
|
+
};
|
|
111
|
+
this.particles.set(id, newParticle);
|
|
112
|
+
this.particleOrder.push(id);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Remove a particle by ID
|
|
117
|
+
*/
|
|
118
|
+
removeParticle(id) {
|
|
119
|
+
this.particles.delete(id);
|
|
120
|
+
const idx = this.particleOrder.indexOf(id);
|
|
121
|
+
if (idx >= 0) {
|
|
122
|
+
this.particleOrder.splice(idx, 1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get a particle by ID
|
|
127
|
+
*/
|
|
128
|
+
getParticle(id) {
|
|
129
|
+
return this.particles.get(id);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Apply a force field to all particles
|
|
133
|
+
*/
|
|
134
|
+
applyForceField(field) {
|
|
135
|
+
Array.from(this.particles.values()).forEach((particle) => {
|
|
136
|
+
const force = field(particle.position);
|
|
137
|
+
particle.acceleration.x += force.x / particle.mass;
|
|
138
|
+
particle.acceleration.y += force.y / particle.mass;
|
|
139
|
+
particle.acceleration.z += force.z / particle.mass;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Apply an attractor force
|
|
144
|
+
*/
|
|
145
|
+
applyAttractor(center, strength, falloffRadius) {
|
|
146
|
+
Array.from(this.particles.values()).forEach((particle) => {
|
|
147
|
+
const dx = center.x - particle.position.x;
|
|
148
|
+
const dy = center.y - particle.position.y;
|
|
149
|
+
const dz = center.z - particle.position.z;
|
|
150
|
+
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
151
|
+
if (dist > 0.001) {
|
|
152
|
+
const falloff = Math.max(0, 1 - dist / falloffRadius);
|
|
153
|
+
const force = (strength * falloff * falloff) / (dist * dist);
|
|
154
|
+
const invDist = 1 / dist;
|
|
155
|
+
particle.acceleration.x += (dx * invDist * force) / particle.mass;
|
|
156
|
+
particle.acceleration.y += (dy * invDist * force) / particle.mass;
|
|
157
|
+
particle.acceleration.z += (dz * invDist * force) / particle.mass;
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Apply velocity from a fluid simulation
|
|
163
|
+
*/
|
|
164
|
+
applyFluidVelocity(fluid, strength = 1) {
|
|
165
|
+
Array.from(this.particles.values()).forEach((particle) => {
|
|
166
|
+
const fluidVel = fluid.getVelocityAt(particle.position);
|
|
167
|
+
particle.velocity.x += fluidVel.x * strength;
|
|
168
|
+
particle.velocity.y += fluidVel.y * strength;
|
|
169
|
+
particle.velocity.z += fluidVel.z * strength;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Update all particles
|
|
174
|
+
*/
|
|
175
|
+
update(dt) {
|
|
176
|
+
this.time += dt;
|
|
177
|
+
const deadParticles = [];
|
|
178
|
+
Array.from(this.particles.values()).forEach((particle) => {
|
|
179
|
+
// Apply gravity
|
|
180
|
+
particle.acceleration.x += this.gravity.x;
|
|
181
|
+
particle.acceleration.y += this.gravity.y;
|
|
182
|
+
particle.acceleration.z += this.gravity.z;
|
|
183
|
+
// Integrate velocity
|
|
184
|
+
particle.velocity.x += particle.acceleration.x * dt;
|
|
185
|
+
particle.velocity.y += particle.acceleration.y * dt;
|
|
186
|
+
particle.velocity.z += particle.acceleration.z * dt;
|
|
187
|
+
// Apply drag
|
|
188
|
+
particle.velocity.x *= this.drag;
|
|
189
|
+
particle.velocity.y *= this.drag;
|
|
190
|
+
particle.velocity.z *= this.drag;
|
|
191
|
+
// Integrate position
|
|
192
|
+
particle.position.x += particle.velocity.x * dt;
|
|
193
|
+
particle.position.y += particle.velocity.y * dt;
|
|
194
|
+
particle.position.z += particle.velocity.z * dt;
|
|
195
|
+
// Reset acceleration
|
|
196
|
+
particle.acceleration.x = 0;
|
|
197
|
+
particle.acceleration.y = 0;
|
|
198
|
+
particle.acceleration.z = 0;
|
|
199
|
+
// Sphere bounds collision
|
|
200
|
+
if (this.boundsSphereRadius < Infinity) {
|
|
201
|
+
const dx = particle.position.x - this.boundsCenter.x;
|
|
202
|
+
const dy = particle.position.y - this.boundsCenter.y;
|
|
203
|
+
const dz = particle.position.z - this.boundsCenter.z;
|
|
204
|
+
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
205
|
+
if (dist > this.boundsSphereRadius) {
|
|
206
|
+
// Push back inside
|
|
207
|
+
const invDist = 1 / dist;
|
|
208
|
+
const nx = dx * invDist;
|
|
209
|
+
const ny = dy * invDist;
|
|
210
|
+
const nz = dz * invDist;
|
|
211
|
+
particle.position.x =
|
|
212
|
+
this.boundsCenter.x + nx * this.boundsSphereRadius * 0.99;
|
|
213
|
+
particle.position.y =
|
|
214
|
+
this.boundsCenter.y + ny * this.boundsSphereRadius * 0.99;
|
|
215
|
+
particle.position.z =
|
|
216
|
+
this.boundsCenter.z + nz * this.boundsSphereRadius * 0.99;
|
|
217
|
+
// Reflect velocity
|
|
218
|
+
const dot = particle.velocity.x * nx +
|
|
219
|
+
particle.velocity.y * ny +
|
|
220
|
+
particle.velocity.z * nz;
|
|
221
|
+
particle.velocity.x =
|
|
222
|
+
(particle.velocity.x - 2 * dot * nx) * this.bounceFactor;
|
|
223
|
+
particle.velocity.y =
|
|
224
|
+
(particle.velocity.y - 2 * dot * ny) * this.bounceFactor;
|
|
225
|
+
particle.velocity.z =
|
|
226
|
+
(particle.velocity.z - 2 * dot * nz) * this.bounceFactor;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Update biometric pulse
|
|
230
|
+
if (particle.heartRate) {
|
|
231
|
+
const pulseFreq = particle.heartRate / 60; // Hz
|
|
232
|
+
const pulse = Math.sin(this.time * pulseFreq * Math.PI * 2);
|
|
233
|
+
particle.pulseScale = 1 + pulse * 0.15; // 15% size variation
|
|
234
|
+
}
|
|
235
|
+
// Decrease life (skip for Infinity life)
|
|
236
|
+
if (particle.life !== Infinity) {
|
|
237
|
+
particle.life -= dt;
|
|
238
|
+
if (particle.life <= 0) {
|
|
239
|
+
deadParticles.push(particle.id);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
// Remove dead particles
|
|
244
|
+
deadParticles.forEach((id) => {
|
|
245
|
+
this.particles.delete(id);
|
|
246
|
+
const idx = this.particleOrder.indexOf(id);
|
|
247
|
+
if (idx >= 0) {
|
|
248
|
+
this.particleOrder.splice(idx, 1);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Get instance data for React Three Fiber InstancedMesh
|
|
254
|
+
*/
|
|
255
|
+
getInstanceData() {
|
|
256
|
+
const count = this.particles.size;
|
|
257
|
+
const ids = [];
|
|
258
|
+
let i = 0;
|
|
259
|
+
const entries = Array.from(this.particles.entries());
|
|
260
|
+
for (let j = 0; j < entries.length && i < this.maxParticles; j++) {
|
|
261
|
+
const [id, particle] = entries[j];
|
|
262
|
+
// Position
|
|
263
|
+
this.positionBuffer[i * 3] = particle.position.x;
|
|
264
|
+
this.positionBuffer[i * 3 + 1] = particle.position.y;
|
|
265
|
+
this.positionBuffer[i * 3 + 2] = particle.position.z;
|
|
266
|
+
// Color with life-based alpha (encoded in color for now)
|
|
267
|
+
const lifeFactor = particle.life === Infinity
|
|
268
|
+
? 1
|
|
269
|
+
: Math.min(1, particle.life / particle.maxLife);
|
|
270
|
+
this.colorBuffer[i * 3] = particle.color[0] * lifeFactor;
|
|
271
|
+
this.colorBuffer[i * 3 + 1] = particle.color[1] * lifeFactor;
|
|
272
|
+
this.colorBuffer[i * 3 + 2] = particle.color[2] * lifeFactor;
|
|
273
|
+
// Scale with pulse
|
|
274
|
+
this.scaleBuffer[i] = particle.size * (particle.pulseScale ?? 1);
|
|
275
|
+
ids.push(id);
|
|
276
|
+
i++;
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
positions: this.positionBuffer.subarray(0, count * 3),
|
|
280
|
+
colors: this.colorBuffer.subarray(0, count * 3),
|
|
281
|
+
scales: this.scaleBuffer.subarray(0, count),
|
|
282
|
+
count,
|
|
283
|
+
ids,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Get all particles
|
|
288
|
+
*/
|
|
289
|
+
getParticles() {
|
|
290
|
+
return Array.from(this.particles.values());
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Get particle count
|
|
294
|
+
*/
|
|
295
|
+
getCount() {
|
|
296
|
+
return this.particles.size;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Clear all particles
|
|
300
|
+
*/
|
|
301
|
+
clear() {
|
|
302
|
+
this.particles.clear();
|
|
303
|
+
this.particleOrder = [];
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Find particle nearest to a point
|
|
307
|
+
*/
|
|
308
|
+
findNearest(point, maxDistance = Infinity) {
|
|
309
|
+
let nearest = null;
|
|
310
|
+
let nearestDist = maxDistance;
|
|
311
|
+
Array.from(this.particles.values()).forEach((particle) => {
|
|
312
|
+
const dist = particle.position.distanceTo(point);
|
|
313
|
+
if (dist < nearestDist) {
|
|
314
|
+
nearest = particle;
|
|
315
|
+
nearestDist = dist;
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
return nearest;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Find all particles within a radius
|
|
322
|
+
*/
|
|
323
|
+
findWithinRadius(center, radius) {
|
|
324
|
+
const results = [];
|
|
325
|
+
const r2 = radius * radius;
|
|
326
|
+
Array.from(this.particles.values()).forEach((particle) => {
|
|
327
|
+
const dx = particle.position.x - center.x;
|
|
328
|
+
const dy = particle.position.y - center.y;
|
|
329
|
+
const dz = particle.position.z - center.z;
|
|
330
|
+
if (dx * dx + dy * dy + dz * dz <= r2) {
|
|
331
|
+
results.push(particle);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
return results;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Pensieve-specific particle system with memory visualization presets
|
|
339
|
+
*/
|
|
340
|
+
export class PensieveParticleSystem extends ParticleSystem3D {
|
|
341
|
+
constructor(maxParticles = 10000) {
|
|
342
|
+
super({
|
|
343
|
+
maxParticles,
|
|
344
|
+
gravity: new Vector3(0, -0.1, 0), // Gentle downward drift
|
|
345
|
+
drag: 0.995,
|
|
346
|
+
boundsSphereRadius: 50,
|
|
347
|
+
boundsCenter: new Vector3(0, 0, 0),
|
|
348
|
+
bounceFactor: 0.3,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Add a memory particle with reflection data
|
|
353
|
+
*/
|
|
354
|
+
addMemoryParticle(id, position, color, options = {}) {
|
|
355
|
+
const size = 0.5 + (options.intensity ?? 0.5) * 0.5;
|
|
356
|
+
const ageFactor = options.ageFactor ?? 1;
|
|
357
|
+
this.setParticle(id, {
|
|
358
|
+
id,
|
|
359
|
+
position,
|
|
360
|
+
velocity: new Vector3((Math.random() - 0.5) * 0.5, (Math.random() - 0.5) * 0.5, (Math.random() - 0.5) * 0.5),
|
|
361
|
+
color: [color[0] * ageFactor, color[1] * ageFactor, color[2] * ageFactor],
|
|
362
|
+
size,
|
|
363
|
+
life: Infinity, // Memory particles don't expire
|
|
364
|
+
maxLife: Infinity,
|
|
365
|
+
mass: 1,
|
|
366
|
+
heartRate: options.heartRate,
|
|
367
|
+
hrvValue: options.hrvValue,
|
|
368
|
+
userData: options.userData,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Algorithms Module Exports
|
|
3
|
+
*
|
|
4
|
+
* @module algorithms
|
|
5
|
+
*/
|
|
6
|
+
export * from './GraphAlgorithms';
|
|
7
|
+
export * from './FlowField';
|
|
8
|
+
export * from './ParticleSystem';
|
|
9
|
+
export * from './FluidSimulation';
|
|
10
|
+
export * from './AdvancedStatistics';
|
|
11
|
+
export * from './BayesianStatistics';
|
|
12
|
+
export * from './OutlierDetection';
|
|
13
|
+
export * from './FluidSimulation3D';
|
|
14
|
+
export * from './ParticleSystem3D';
|
|
15
|
+
export * from './FlowField3D';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/algorithms/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC"}
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module algorithms
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
6
|
// 2D algorithms (existing)
|
|
8
7
|
export * from './GraphAlgorithms';
|
|
9
8
|
export * from './FlowField';
|
|
@@ -12,7 +11,6 @@ export * from './FluidSimulation';
|
|
|
12
11
|
export * from './AdvancedStatistics';
|
|
13
12
|
export * from './BayesianStatistics';
|
|
14
13
|
export * from './OutlierDetection';
|
|
15
|
-
|
|
16
14
|
// 3D algorithms (new - for Pensieve)
|
|
17
15
|
export * from './FluidSimulation3D';
|
|
18
16
|
export * from './ParticleSystem3D';
|
package/dist/compat.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backward compatibility layer for Photo and GridItem
|
|
3
|
+
*
|
|
4
|
+
* Provides conversion utilities to ensure existing Photo-based code
|
|
5
|
+
* continues to work while new code can use GridItem.
|
|
6
|
+
*/
|
|
7
|
+
import type { Photo, GridItem } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* Convert Photo to GridItem for backward compatibility
|
|
10
|
+
*/
|
|
11
|
+
export declare function photoToGridItem(photo: Photo): GridItem<Photo>;
|
|
12
|
+
/**
|
|
13
|
+
* Convert GridItem back to Photo if possible
|
|
14
|
+
*/
|
|
15
|
+
export declare function gridItemToPhoto(item: GridItem<Photo>): Photo | null;
|
|
16
|
+
/**
|
|
17
|
+
* Convert an array of Photos to GridItems
|
|
18
|
+
*/
|
|
19
|
+
export declare function photosToGridItems(photos: Photo[]): GridItem<Photo>[];
|
|
20
|
+
/**
|
|
21
|
+
* Convert an array of GridItems to Photos (filtering out non-photo items)
|
|
22
|
+
*/
|
|
23
|
+
export declare function gridItemsToPhotos(items: GridItem<Photo>[]): Photo[];
|
|
24
|
+
//# sourceMappingURL=compat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compat.d.ts","sourceRoot":"","sources":["../src/compat.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/C;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CA4B7D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,IAAI,CAkCnE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,CAEpE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,EAAE,CAInE"}
|
package/dist/compat.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backward compatibility layer for Photo and GridItem
|
|
3
|
+
*
|
|
4
|
+
* Provides conversion utilities to ensure existing Photo-based code
|
|
5
|
+
* continues to work while new code can use GridItem.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Convert Photo to GridItem for backward compatibility
|
|
9
|
+
*/
|
|
10
|
+
export function photoToGridItem(photo) {
|
|
11
|
+
return {
|
|
12
|
+
id: photo.id,
|
|
13
|
+
type: 'photo',
|
|
14
|
+
imageUrl: photo.imageUrl,
|
|
15
|
+
thumbnailUrl: photo.thumbnailUrl,
|
|
16
|
+
title: photo.title,
|
|
17
|
+
alt: photo.alt,
|
|
18
|
+
description: photo.description,
|
|
19
|
+
category: photo.category,
|
|
20
|
+
data: photo,
|
|
21
|
+
// Map all Photo fields
|
|
22
|
+
url: photo.imageUrl,
|
|
23
|
+
userId: photo.userId,
|
|
24
|
+
username: photo.username,
|
|
25
|
+
videoUrl: photo.videoUrl,
|
|
26
|
+
platform: photo.platform,
|
|
27
|
+
author: photo.author,
|
|
28
|
+
authorUrl: photo.authorUrl,
|
|
29
|
+
likes: photo.likes,
|
|
30
|
+
views: photo.views,
|
|
31
|
+
comments: photo.comments,
|
|
32
|
+
dominantColor: photo.dominantColor,
|
|
33
|
+
source: photo.source,
|
|
34
|
+
sourceUrl: photo.sourceUrl,
|
|
35
|
+
createdAt: photo.createdAt,
|
|
36
|
+
velocity: photo.velocity,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Convert GridItem back to Photo if possible
|
|
41
|
+
*/
|
|
42
|
+
export function gridItemToPhoto(item) {
|
|
43
|
+
// If item contains original Photo data, return it
|
|
44
|
+
if (item.type === 'photo' && item.data) {
|
|
45
|
+
return item.data;
|
|
46
|
+
}
|
|
47
|
+
// Fallback: construct Photo from GridItem fields
|
|
48
|
+
if (item.imageUrl || item.url) {
|
|
49
|
+
return {
|
|
50
|
+
id: item.id,
|
|
51
|
+
title: item.title ?? '',
|
|
52
|
+
alt: item.alt ?? item.title ?? '',
|
|
53
|
+
imageUrl: item.imageUrl || item.url || '',
|
|
54
|
+
category: item.category ?? 'uncategorized',
|
|
55
|
+
description: item.description,
|
|
56
|
+
source: item.source || 'unknown',
|
|
57
|
+
sourceUrl: item.sourceUrl,
|
|
58
|
+
createdAt: item.createdAt,
|
|
59
|
+
thumbnailUrl: item.thumbnailUrl,
|
|
60
|
+
userId: item.userId,
|
|
61
|
+
username: item.username,
|
|
62
|
+
videoUrl: item.videoUrl,
|
|
63
|
+
platform: item.platform,
|
|
64
|
+
author: item.author,
|
|
65
|
+
authorUrl: item.authorUrl,
|
|
66
|
+
likes: item.likes,
|
|
67
|
+
views: item.views,
|
|
68
|
+
comments: item.comments,
|
|
69
|
+
dominantColor: item.dominantColor,
|
|
70
|
+
velocity: item.velocity,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Convert an array of Photos to GridItems
|
|
77
|
+
*/
|
|
78
|
+
export function photosToGridItems(photos) {
|
|
79
|
+
return photos.map(photoToGridItem);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Convert an array of GridItems to Photos (filtering out non-photo items)
|
|
83
|
+
*/
|
|
84
|
+
export function gridItemsToPhotos(items) {
|
|
85
|
+
return items
|
|
86
|
+
.map(gridItemToPhoto)
|
|
87
|
+
.filter((photo) => photo !== null);
|
|
88
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HexGrid.d.ts","sourceRoot":"","sources":["../../src/components/HexGrid.tsx"],"names":[],"mappings":"AACA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAqD9D;AAED,eAAe,OAAO,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { FluidEngineFactory } from '../algorithms/FluidEngineFactory';
|
|
4
|
+
export function HexGrid(props) {
|
|
5
|
+
const canvasRef = useRef(null);
|
|
6
|
+
const [engine, setEngine] = useState(null);
|
|
7
|
+
const [error, setError] = useState(null);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
// Initialize Fluid Engine
|
|
10
|
+
const initEngine = async () => {
|
|
11
|
+
try {
|
|
12
|
+
const fluidEngine = await FluidEngineFactory.create({
|
|
13
|
+
width: 64,
|
|
14
|
+
height: 64,
|
|
15
|
+
depth: 64,
|
|
16
|
+
viscosity: 0.0001,
|
|
17
|
+
diffusion: 0.00001
|
|
18
|
+
});
|
|
19
|
+
setEngine(fluidEngine);
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
console.error("Failed to init fluid engine", err);
|
|
23
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
initEngine();
|
|
27
|
+
return () => {
|
|
28
|
+
// Cleanup if engine has cleanup method
|
|
29
|
+
if (engine && 'clear' in engine) {
|
|
30
|
+
engine.clear();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}, []);
|
|
34
|
+
if (error) {
|
|
35
|
+
return _jsxs("div", { className: "text-red-500", children: ["Error initializing simulation: ", error] });
|
|
36
|
+
}
|
|
37
|
+
return (_jsxs("div", { className: "hexgrid-container", style: { width: '100%', height: '100%', position: 'relative' }, children: [_jsx("canvas", { ref: canvasRef, width: 800, height: 600, style: { width: '100%', height: '100%' } }), _jsxs("div", { style: { position: 'absolute', top: 10, left: 10, background: 'rgba(0,0,0,0.5)', color: 'white', padding: '5px', pointerEvents: 'none' }, children: ["Engine: ", engine ? engine.constructor.name : 'Initializing...'] })] }));
|
|
38
|
+
}
|
|
39
|
+
export default HexGrid;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Narration Overlay Component
|
|
3
|
+
*
|
|
4
|
+
* Displays play-by-play narration messages with sparklines in a NOC dashboard style.
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { NarrationMessage } from '@/lib/narration';
|
|
8
|
+
import { StatsTracker } from '@/lib/stats-tracker';
|
|
9
|
+
export interface NarrationOverlayProps {
|
|
10
|
+
messages: NarrationMessage[];
|
|
11
|
+
statsTracker: StatsTracker | null;
|
|
12
|
+
isVisible: boolean;
|
|
13
|
+
onClose: () => void;
|
|
14
|
+
}
|
|
15
|
+
export declare const NarrationOverlay: React.FC<NarrationOverlayProps>;
|
|
16
|
+
//# sourceMappingURL=NarrationOverlay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NarrationOverlay.d.ts","sourceRoot":"","sources":["../../src/components/NarrationOverlay.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAA4B,MAAM,OAAO,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAkS5D,CAAC"}
|