Skip to content

Commit 66ad2cd

Browse files
committed
add new geometry types
1 parent b21994f commit 66ad2cd

File tree

2 files changed

+180
-28
lines changed

2 files changed

+180
-28
lines changed

geometry.js

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,158 @@ function createTorus(i, count) {
105105
);
106106
}
107107

108-
const patterns = [createGrid, createSphere, createSpiral, createHelix, createTorus];
108+
function createVortex(i, count) {
109+
// Vortex parameters
110+
const height = 60; // Total height of the vortex
111+
const maxRadius = 35; // Maximum radius at the top
112+
const minRadius = 5; // Minimum radius at the bottom
113+
const numRotations = 3; // Number of full rotations from top to bottom
114+
115+
// Calculate normalized height position (0 = bottom, 1 = top)
116+
const t = i / count;
117+
118+
// Add some randomness to distribute particles more naturally
119+
const randomOffset = 0.05 * Math.random();
120+
const heightPosition = t + randomOffset;
121+
122+
// Calculate radius that decreases from top to bottom
123+
const radius = minRadius + (maxRadius - minRadius) * heightPosition;
124+
125+
// Calculate angle with more rotations at the bottom
126+
const angle = numRotations * Math.PI * 2 * (1 - heightPosition) + (i * 0.1);
127+
128+
// Calculate the vertical position (from bottom to top)
129+
const y = (heightPosition - 0.5) * height;
130+
131+
return new THREE.Vector3(
132+
Math.cos(angle) * radius,
133+
y,
134+
Math.sin(angle) * radius
135+
);
136+
}
137+
138+
function createGalaxy(i, count) {
139+
// Galaxy parameters
140+
const numArms = 4; // Number of spiral arms
141+
const armWidth = 0.15; // Width of each arm (0-1)
142+
const maxRadius = 40; // Maximum radius of the galaxy
143+
const thickness = 5; // Vertical thickness
144+
const twistFactor = 2.5; // How much the arms twist
145+
146+
// Determine which arm this particle belongs to
147+
const armIndex = i % numArms;
148+
const indexInArm = Math.floor(i / numArms) / Math.floor(count / numArms);
149+
150+
// Calculate radial distance from center
151+
const radialDistance = indexInArm * maxRadius;
152+
153+
// Add some randomness for arm width
154+
const randomOffset = (Math.random() * 2 - 1) * armWidth;
155+
156+
// Calculate angle with twist that increases with distance
157+
const armOffset = (2 * Math.PI / numArms) * armIndex;
158+
const twistAmount = twistFactor * indexInArm;
159+
const angle = armOffset + twistAmount + randomOffset;
160+
161+
// Add height variation that decreases with distance from center
162+
const verticalPosition = (Math.random() * 2 - 1) * thickness * (1 - indexInArm * 0.8);
163+
164+
return new THREE.Vector3(
165+
Math.cos(angle) * radialDistance,
166+
verticalPosition,
167+
Math.sin(angle) * radialDistance
168+
);
169+
}
170+
171+
function createWave(i, count) {
172+
// Wave/ocean parameters
173+
const width = 60; // Total width of the wave field
174+
const depth = 60; // Total depth of the wave field
175+
const waveHeight = 10; // Maximum height of waves
176+
const waveDensity = 0.1; // Controls wave frequency
177+
178+
// Create a grid of points (similar to your grid function but for a 2D plane)
179+
const gridSize = Math.ceil(Math.sqrt(count));
180+
const spacingX = width / gridSize;
181+
const spacingZ = depth / gridSize;
182+
183+
// Calculate 2D grid position
184+
const ix = i % gridSize;
185+
const iz = Math.floor(i / gridSize);
186+
187+
// Convert to actual coordinates with proper spacing
188+
const halfWidth = width / 2;
189+
const halfDepth = depth / 2;
190+
const x = ix * spacingX - halfWidth;
191+
const z = iz * spacingZ - halfDepth;
192+
193+
// Create wave pattern using multiple sine waves for a more natural look
194+
// We use the x and z coordinates to create a position-based wave pattern
195+
const y = Math.sin(x * waveDensity) * Math.cos(z * waveDensity) * waveHeight +
196+
Math.sin(x * waveDensity * 2.5) * Math.cos(z * waveDensity * 2.1) * (waveHeight * 0.3);
197+
198+
return new THREE.Vector3(x, y, z);
199+
}
200+
201+
function createMobius(i, count) {
202+
// Möbius strip parameters
203+
const radius = 25; // Major radius of the strip
204+
const width = 10; // Width of the strip
205+
206+
// Distribute points evenly along the length of the Möbius strip
207+
// and across its width
208+
const lengthSteps = Math.sqrt(count);
209+
const widthSteps = count / lengthSteps;
210+
211+
// Calculate position along length and width of strip
212+
const lengthIndex = i % lengthSteps;
213+
const widthIndex = Math.floor(i / lengthSteps) % widthSteps;
214+
215+
// Normalize to 0-1 range
216+
const u = lengthIndex / lengthSteps; // Position around the strip (0 to 1)
217+
const v = (widthIndex / widthSteps) - 0.5; // Position across width (-0.5 to 0.5)
218+
219+
// Parametric equations for Möbius strip
220+
const theta = u * Math.PI * 2; // Full loop around
221+
222+
// Calculate the Möbius strip coordinates
223+
// This creates a half-twist in the strip
224+
const x = (radius + width * v * Math.cos(theta / 2)) * Math.cos(theta);
225+
const y = (radius + width * v * Math.cos(theta / 2)) * Math.sin(theta);
226+
const z = width * v * Math.sin(theta / 2);
227+
228+
return new THREE.Vector3(x, y, z);
229+
}
230+
231+
function createSupernova(i, count) {
232+
// Supernova parameters
233+
const maxRadius = 40; // Maximum explosion radius
234+
const coreSize = 0.2; // Size of the dense core (0-1)
235+
const outerDensity = 0.7; // Density of particles in outer shell
236+
237+
// Use golden ratio distribution for even spherical coverage
238+
const phi = Math.acos(1 - 2 * (i / count));
239+
const theta = Math.PI * 2 * i * (1 + Math.sqrt(5));
240+
241+
// Calculate radial distance with more particles near center and at outer shell
242+
let normalizedRadius;
243+
const random = Math.random();
244+
245+
if (i < count * coreSize) {
246+
// Dense core - distribute within inner radius
247+
normalizedRadius = Math.pow(random, 0.5) * 0.3;
248+
} else {
249+
// Explosion wave - distribute with more particles at the outer shell
250+
normalizedRadius = 0.3 + Math.pow(random, outerDensity) * 0.7;
251+
}
252+
253+
// Scale to max radius
254+
const radius = normalizedRadius * maxRadius;
255+
256+
// Convert spherical to Cartesian coordinates
257+
return new THREE.Vector3(
258+
Math.sin(phi) * Math.cos(theta) * radius,
259+
Math.sin(phi) * Math.sin(theta) * radius,
260+
Math.cos(phi) * radius
261+
);
262+
}

main.js

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,10 @@ Blur shader?
55
*/
66

77
// main.js
8-
// Add this helper function somewhere accessible, e.g., near the top or before onResults
9-
function calculateDistance(landmark1, landmark2) {
10-
if (!landmark1 || !landmark2) return Infinity;
11-
const dx = landmark1.x - landmark2.x;
12-
const dy = landmark1.y - landmark2.y;
13-
// Optional: include z distance if needed, but for screen-space pinch, x/y is often enough
14-
// const dz = landmark1.z - landmark2.z;
15-
// return Math.sqrt(dx * dx + dy * dy + dz * dz);
16-
return Math.sqrt(dx * dx + dy * dy);
17-
}
8+
const patterns = [createGrid, createSphere, createSpiral,
9+
createHelix, createTorus, createVortex, createGalaxy,
10+
createWave, createMobius, createSupernova];
11+
const patternNames = ["Cube", "Sphere", "Spiral", "Helix", "Torus", "Vortex", "Galaxy", "Wave", "Möbius", "Supernova"];
1812

1913
let hands;
2014
let handDetected = false; // Flag if *any* hand is detected
@@ -100,8 +94,6 @@ function startExperience() {
10094
window.onload = startExperience;
10195
// --- End of Execution Start block ---
10296

103-
const patternNames = ["Cube", "Sphere", "Spiral", "Helix", "Torus"];
104-
10597
// --- PARTICLE TEXTURE ---
10698
function createParticleTexture() {
10799
const canvas = document.createElement('canvas');
@@ -157,9 +149,7 @@ function createParticleSystem() {
157149
positions[i * 3 + 1] = pos.y;
158150
positions[i * 3 + 2] = pos.z;
159151

160-
//const colorIndex = Math.floor(Math.random() * initialPalette.length);
161-
const colorIndex = 0;
162-
const baseColor = initialPalette[colorIndex];
152+
const baseColor = initialPalette[0];
163153
const variation = 1.0; // Add variation
164154

165155
colors[i * 3] = baseColor.r * variation;
@@ -342,23 +332,21 @@ function transitionToPattern(newPattern) {
342332

343333
// Generate new positions
344334
for (let i = 0; i < count; i++) {
345-
const p = patternFn(i, count);
346-
newPos[i * 3] = p.x;
347-
newPos[i * 3 + 1] = p.y;
348-
newPos[i * 3 + 2] = p.z;
335+
const p = patternFn(i, count);
336+
newPos[i * 3] = p.x;
337+
newPos[i * 3 + 1] = p.y;
338+
newPos[i * 3 + 2] = p.z;
349339
}
350340

351341
// Generate new colors
352342
const newCol = new Float32Array(curCol.length);
353-
const palette = colorPalettes[newPattern];
343+
const palette = colorPalettes[newPattern%colorPalettes.length];
354344
for (let i = 0; i < count; i++) {
355-
//const idx = Math.floor(Math.random() * palette.length);
356-
const idx = 0;
357-
const base = palette[idx];
358-
const variation = 1.0; // Keep color variation consistent
359-
newCol[i * 3] = base.r * variation;
360-
newCol[i * 3 + 1] = base.g * variation;
361-
newCol[i * 3 + 2] = base.b * variation;
345+
const base = palette[0];
346+
const variation = 1.0; // Keep color variation consistent
347+
newCol[i * 3] = base.r * variation;
348+
newCol[i * 3 + 1] = base.g * variation;
349+
newCol[i * 3 + 2] = base.b * variation;
362350
}
363351

364352
// Store transition data
@@ -858,4 +846,14 @@ function setupBloom() {
858846
}
859847
}
860848
};
849+
}
850+
851+
function calculateDistance(landmark1, landmark2) {
852+
if (!landmark1 || !landmark2) return Infinity;
853+
const dx = landmark1.x - landmark2.x;
854+
const dy = landmark1.y - landmark2.y;
855+
// Optional: include z distance if needed, but for screen-space pinch, x/y is often enough
856+
// const dz = landmark1.z - landmark2.z;
857+
// return Math.sqrt(dx * dx + dy * dy + dz * dz);
858+
return Math.sqrt(dx * dx + dy * dy);
861859
}

0 commit comments

Comments
 (0)