Solshine commited on
Commit
96dc654
·
verified ·
1 Parent(s): 831e63e

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. WaveformVisualizer.js +61 -24
  2. game.js +40 -0
WaveformVisualizer.js CHANGED
@@ -15,6 +15,13 @@ uniform vec2 u_resolution;
15
  uniform vec3 u_color;
16
  uniform float u_breathe;
17
 
 
 
 
 
 
 
 
18
  vec2 cmul(vec2 a, vec2 b) {
19
  return vec2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
20
  }
@@ -46,7 +53,7 @@ vec2 rot(vec2 p, float a) {
46
  void main() {
47
  vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution) / min(u_resolution.x, u_resolution.y);
48
 
49
- // Texture breathing: subtle scale pulsation independent of audio
50
  uv *= 1.0 + 0.05 * (u_breathe - 0.5);
51
 
52
  float breathe = 1.0 + 0.15 * u_amplitude;
@@ -59,14 +66,25 @@ void main() {
59
  return;
60
  }
61
 
62
- float rotSpeed = 0.08 + 0.05 * u_amplitude;
 
 
 
 
 
 
 
 
63
  uv = rot(uv, u_time * rotSpeed);
64
 
65
- float n = 7.0;
 
66
  float angleStep = 6.283185 / n;
67
 
68
- float coshR = cos(3.14159265 / 3.0) / sin(3.14159265 / n);
69
- float sinhR = sqrt(coshR * coshR - 1.0);
 
 
70
  float tr = sinhR / (coshR + 1.0);
71
 
72
  vec2 z = uv;
@@ -89,27 +107,27 @@ void main() {
89
 
90
  float d = hdist(z);
91
 
92
- // Color palette: deep purples, teals, magentas — psychedelic but dark
93
  float t = mod(iter * 0.1 + u_time * 0.02, 1.0);
94
- vec3 col1 = vec3(0.03, 0.01, 0.08); // deep purple-black
95
- vec3 col2 = vec3(0.02, 0.10, 0.15); // dark teal
96
- vec3 col3 = vec3(0.12, 0.02, 0.10); // dark magenta
97
 
98
  vec3 color = mix(col1, col2, sin(iter * 0.7 + u_time * 0.1) * 0.5 + 0.5);
99
  color = mix(color, col3, sin(iter * 1.1 - u_time * 0.15) * 0.5 + 0.5);
100
 
101
- // Breathe-modulated saturation
102
  float sat = 0.85 + 0.15 * u_breathe;
103
  color *= sat;
104
 
105
- // Tint toward the hand-gesture color
106
- float satBoost = 0.3 + 0.2 * u_amplitude;
107
- color = mix(color, u_color * 0.15, satBoost * 0.3);
108
 
109
- // Edge highlights with glow from amplitude
110
- float edgeThreshold = (0.04 - 0.02 * u_amplitude) * (1.0 + 0.3 * u_breathe);
111
- float edgeLine = 1.0 - smoothstep(0.0, edgeThreshold, abs(fract(d * 1.5) - 0.5) - 0.45);
112
- color += vec3(0.06, 0.08, 0.14) * edgeLine * (1.0 + u_amplitude);
 
113
 
114
  // Sector pattern
115
  float ang = atan(z.y, z.x);
@@ -119,13 +137,18 @@ void main() {
119
  // Audio reactive brightness
120
  color *= 0.8 + 0.25 * u_amplitude;
121
 
 
 
 
 
 
122
  // Disk edge fade
123
  float diskEdge = smoothstep(0.98, 0.92, r);
124
  color *= diskEdge;
125
 
126
  color = min(color, vec3(1.0));
127
 
128
- gl_FragColor = vec4(color, 0.45);
129
  }
130
  `;
131
 
@@ -143,7 +166,13 @@ export class WaveformVisualizer {
143
  u_amplitude: { value: 0.0 },
144
  u_resolution: { value: new THREE.Vector2(canvasWidth, canvasHeight) },
145
  u_color: { value: this.currentColor },
146
- u_breathe: { value: 0 }
 
 
 
 
 
 
147
  };
148
 
149
  this._createVisualizer();
@@ -169,13 +198,9 @@ export class WaveformVisualizer {
169
  update() {
170
  if (!this.analyser || !this.mesh) return;
171
 
172
- // Interpolate color
173
  this.currentColor.lerp(this.targetColor, 0.05);
174
-
175
- // Update time
176
  this.uniforms.u_time.value = this.clock.getElapsedTime();
177
 
178
- // Compute RMS amplitude from analyser
179
  var waveformData = this.analyser.getValue();
180
  var sum = 0;
181
  for (var i = 0; i < waveformData.length; i++) {
@@ -185,10 +210,22 @@ export class WaveformVisualizer {
185
  this.uniforms.u_amplitude.value = amplitude;
186
  this.lastAmplitude = amplitude;
187
 
188
- var breathe = 0.5 + 0.5 * Math.sin(this.uniforms.u_time.value * 2.094); // ~3 second cycle
189
  this.uniforms.u_breathe.value = breathe;
190
  }
191
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  updateColor(newColor) {
193
  this.targetColor.set(newColor);
194
  }
 
15
  uniform vec3 u_color;
16
  uniform float u_breathe;
17
 
18
+ // Hand-driven uniforms
19
+ uniform vec2 u_handPos; // -1 to 1, normalized hand position
20
+ uniform float u_handSpread; // 0-1 finger spread
21
+ uniform float u_wristAngle; // -1 to 1
22
+ uniform float u_pitch; // 0-1 hand height (low=bass, high=treble)
23
+ uniform float u_fingerGlow; // 0-1 average finger extension
24
+
25
  vec2 cmul(vec2 a, vec2 b) {
26
  return vec2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
27
  }
 
53
  void main() {
54
  vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution) / min(u_resolution.x, u_resolution.y);
55
 
56
+ // Texture breathing
57
  uv *= 1.0 + 0.05 * (u_breathe - 0.5);
58
 
59
  float breathe = 1.0 + 0.15 * u_amplitude;
 
66
  return;
67
  }
68
 
69
+ // === HAND-DRIVEN GEOMETRY WARPING ===
70
+
71
+ // Warp the disk toward hand position (Möbius transform)
72
+ // Hand position pulls the hyperbolic space toward where your hand is
73
+ vec2 handWarp = u_handPos * 0.35; // scale to stay within Poincaré disk
74
+ uv = mobius(uv, handWarp);
75
+
76
+ // Rotation speed driven by wrist angle + audio
77
+ float rotSpeed = 0.06 + 0.04 * u_amplitude + u_wristAngle * 0.15;
78
  uv = rot(uv, u_time * rotSpeed);
79
 
80
+ // Symmetry: finger spread morphs from 5-fold to 11-fold
81
+ float n = 5.0 + u_handSpread * 6.0;
82
  float angleStep = 6.283185 / n;
83
 
84
+ // Tiling scale shifts with pitch (hand height)
85
+ float tileScale = 3.0 - u_pitch * 1.5; // lower hand = larger tiles, higher = finer
86
+ float coshR = cos(3.14159265 / tileScale) / sin(3.14159265 / n);
87
+ float sinhR = sqrt(max(coshR * coshR - 1.0, 0.001));
88
  float tr = sinhR / (coshR + 1.0);
89
 
90
  vec2 z = uv;
 
107
 
108
  float d = hdist(z);
109
 
110
+ // Color palette: psychedelic, hand-tinted
111
  float t = mod(iter * 0.1 + u_time * 0.02, 1.0);
112
+ vec3 col1 = vec3(0.03, 0.01, 0.08);
113
+ vec3 col2 = vec3(0.02, 0.10, 0.15);
114
+ vec3 col3 = vec3(0.12, 0.02, 0.10);
115
 
116
  vec3 color = mix(col1, col2, sin(iter * 0.7 + u_time * 0.1) * 0.5 + 0.5);
117
  color = mix(color, col3, sin(iter * 1.1 - u_time * 0.15) * 0.5 + 0.5);
118
 
 
119
  float sat = 0.85 + 0.15 * u_breathe;
120
  color *= sat;
121
 
122
+ // Tint toward hand-gesture color (stronger when fingers active)
123
+ float satBoost = 0.3 + 0.3 * u_fingerGlow;
124
+ color = mix(color, u_color * 0.2, satBoost * 0.4);
125
 
126
+ // Edge highlights glow stronger with finger extension
127
+ float edgeGlow = 0.04 - 0.02 * u_amplitude - 0.01 * u_fingerGlow;
128
+ float edgeLine = 1.0 - smoothstep(0.0, max(edgeGlow, 0.005), abs(fract(d * 1.5) - 0.5) - 0.45);
129
+ vec3 edgeColor = vec3(0.08, 0.12, 0.2) * (1.0 + u_fingerGlow * 2.0 + u_amplitude);
130
+ color += edgeColor * edgeLine;
131
 
132
  // Sector pattern
133
  float ang = atan(z.y, z.x);
 
137
  // Audio reactive brightness
138
  color *= 0.8 + 0.25 * u_amplitude;
139
 
140
+ // Hand proximity brightening — geometry glows near your hand
141
+ float handDist = length(uv - u_handPos * 0.5);
142
+ float handGlow = 0.15 * u_fingerGlow / (1.0 + handDist * 4.0);
143
+ color += u_color * handGlow;
144
+
145
  // Disk edge fade
146
  float diskEdge = smoothstep(0.98, 0.92, r);
147
  color *= diskEdge;
148
 
149
  color = min(color, vec3(1.0));
150
 
151
+ gl_FragColor = vec4(color, 0.5);
152
  }
153
  `;
154
 
 
166
  u_amplitude: { value: 0.0 },
167
  u_resolution: { value: new THREE.Vector2(canvasWidth, canvasHeight) },
168
  u_color: { value: this.currentColor },
169
+ u_breathe: { value: 0 },
170
+ // Hand-driven uniforms
171
+ u_handPos: { value: new THREE.Vector2(0, 0) },
172
+ u_handSpread: { value: 0 },
173
+ u_wristAngle: { value: 0 },
174
+ u_pitch: { value: 0.5 },
175
+ u_fingerGlow: { value: 0 }
176
  };
177
 
178
  this._createVisualizer();
 
198
  update() {
199
  if (!this.analyser || !this.mesh) return;
200
 
 
201
  this.currentColor.lerp(this.targetColor, 0.05);
 
 
202
  this.uniforms.u_time.value = this.clock.getElapsedTime();
203
 
 
204
  var waveformData = this.analyser.getValue();
205
  var sum = 0;
206
  for (var i = 0; i < waveformData.length; i++) {
 
210
  this.uniforms.u_amplitude.value = amplitude;
211
  this.lastAmplitude = amplitude;
212
 
213
+ var breathe = 0.5 + 0.5 * Math.sin(this.uniforms.u_time.value * 2.094);
214
  this.uniforms.u_breathe.value = breathe;
215
  }
216
 
217
+ // Called from game.js with hand tracking data
218
+ updateHandData(data) {
219
+ if (!data) return;
220
+ if (data.handPos !== undefined) {
221
+ this.uniforms.u_handPos.value.set(data.handPos.x || 0, data.handPos.y || 0);
222
+ }
223
+ if (data.handSpread !== undefined) this.uniforms.u_handSpread.value = data.handSpread;
224
+ if (data.wristAngle !== undefined) this.uniforms.u_wristAngle.value = data.wristAngle;
225
+ if (data.pitch !== undefined) this.uniforms.u_pitch.value = data.pitch;
226
+ if (data.fingerGlow !== undefined) this.uniforms.u_fingerGlow.value = data.fingerGlow;
227
+ }
228
+
229
  updateColor(newColor) {
230
  this.targetColor.set(newColor);
231
  }
game.js CHANGED
@@ -1584,6 +1584,46 @@ export var Game = /*#__PURE__*/ function() {
1584
  this._updateBeatIndicator();
1585
  if (this.waveformVisualizer) {
1586
  this.waveformVisualizer.update();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1587
  }
1588
  if (this.mandalaVisualizer) {
1589
  var mandalaHands = this.hands.map(function(h) { return h.points3D || null; }).filter(Boolean);
 
1584
  this._updateBeatIndicator();
1585
  if (this.waveformVisualizer) {
1586
  this.waveformVisualizer.update();
1587
+ // Pipe hand data into the hyperbolic geometry
1588
+ var synthHand = this.hands[0];
1589
+ if (synthHand && synthHand.landmarks) {
1590
+ var palm = synthHand.landmarks[9];
1591
+ // Normalize hand pos to -1..1 (mirrored X)
1592
+ var hx = -(palm.x * 2 - 1);
1593
+ var hy = -(palm.y * 2 - 1);
1594
+ // Compute finger glow (avg distance from palm)
1595
+ var fglow = 0;
1596
+ var tipIndices = [8, 12, 16, 20];
1597
+ for (var ti = 0; ti < tipIndices.length; ti++) {
1598
+ var tip = synthHand.landmarks[tipIndices[ti]];
1599
+ var fdx = tip.x - palm.x, fdy = tip.y - palm.y;
1600
+ fglow += Math.sqrt(fdx*fdx + fdy*fdy);
1601
+ }
1602
+ var palmDist = Math.abs(synthHand.landmarks[0].y - palm.y) || 0.05;
1603
+ fglow = Math.min(1, (fglow / 4) / (palmDist * 2));
1604
+ // Pitch from Y position (0=bottom, 1=top)
1605
+ var pitch = 1 - palm.y;
1606
+ // Hand spread
1607
+ var tips = [synthHand.landmarks[4], synthHand.landmarks[8], synthHand.landmarks[12], synthHand.landmarks[16], synthHand.landmarks[20]];
1608
+ var spreadSum = 0;
1609
+ for (var si = 0; si < tips.length - 1; si++) {
1610
+ var sdx = tips[si].x - tips[si+1].x, sdy = tips[si].y - tips[si+1].y;
1611
+ spreadSum += Math.sqrt(sdx*sdx + sdy*sdy);
1612
+ }
1613
+ var spread = Math.min(1, (spreadSum / 4) / (palmDist * 2));
1614
+ // Wrist angle
1615
+ var wdx = palm.x - synthHand.landmarks[0].x;
1616
+ var wdy = palm.y - synthHand.landmarks[0].y;
1617
+ var wAngle = Math.max(-1, Math.min(1, Math.atan2(wdx, -wdy) / (Math.PI / 2)));
1618
+
1619
+ this.waveformVisualizer.updateHandData({
1620
+ handPos: { x: hx, y: hy },
1621
+ handSpread: spread,
1622
+ wristAngle: wAngle,
1623
+ pitch: pitch,
1624
+ fingerGlow: fglow
1625
+ });
1626
+ }
1627
  }
1628
  if (this.mandalaVisualizer) {
1629
  var mandalaHands = this.hands.map(function(h) { return h.points3D || null; }).filter(Boolean);