mudra-skills 1.0.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 (149) hide show
  1. package/.claude-plugin/plugin.json +19 -0
  2. package/CLAUDE.md +35 -0
  3. package/bin/install.js +25 -0
  4. package/package.json +28 -0
  5. package/skills/mudra-master/SKILL.md +202 -0
  6. package/skills/mudra-master/mudra-preview/SKILL.md +151 -0
  7. package/skills/mudra-master/mudra-preview/assets/ar-menu.html +382 -0
  8. package/skills/mudra-master/mudra-preview/assets/document-scroller.html +468 -0
  9. package/skills/mudra-master/mudra-preview/assets/drum-machine.html +788 -0
  10. package/skills/mudra-master/mudra-preview/assets/emg-visualizer.html +390 -0
  11. package/skills/mudra-master/mudra-preview/assets/generative-art.html +408 -0
  12. package/skills/mudra-master/mudra-preview/assets/gesture-assistant.html +342 -0
  13. package/skills/mudra-master/mudra-preview/assets/gesture-speech.html +444 -0
  14. package/skills/mudra-master/mudra-preview/assets/hands-free-desktop.html +376 -0
  15. package/skills/mudra-master/mudra-preview/assets/model-rotator.html +365 -0
  16. package/skills/mudra-master/mudra-preview/assets/mudra-duel.html +3200 -0
  17. package/skills/mudra-master/mudra-preview/assets/mudra-monitor.html +1451 -0
  18. package/skills/mudra-master/mudra-preview/assets/mudra-ultimate-template.html +891 -0
  19. package/skills/mudra-master/mudra-preview/assets/music-sequencer.html +455 -0
  20. package/skills/mudra-master/mudra-preview/assets/neural-pong.html +380 -0
  21. package/skills/mudra-master/mudra-preview/assets/neural-snake.html +364 -0
  22. package/skills/mudra-master/mudra-preview/assets/presentation-controller.html +345 -0
  23. package/skills/mudra-master/mudra-preview/assets/pressure-painter.html +285 -0
  24. package/skills/mudra-master/mudra-preview/assets/runner.html +1812 -0
  25. package/skills/mudra-master/mudra-preview/assets/smart-home.html +461 -0
  26. package/skills/mudra-master/mudra-preview/assets/space-invaders.html +1154 -0
  27. package/skills/mudra-master/mudra-preview/assets/waterful-ring-toss.html +1624 -0
  28. package/skills/mudra-master/mudra-preview/references/agent_protocol.json +646 -0
  29. package/skills/mudra-master/mudra-preview/references/promt.md +16829 -0
  30. package/skills/mudra-master/mudra-xr/SKILL.md +245 -0
  31. package/skills/mudra-master/mudra-xr/assets/demos/3dgs-walkthrough.html +242 -0
  32. package/skills/mudra-master/mudra-xr/assets/demos/aisimulator.html +792 -0
  33. package/skills/mudra-master/mudra-xr/assets/demos/balloonpop.html +422 -0
  34. package/skills/mudra-master/mudra-xr/assets/demos/ballpit.html +284 -0
  35. package/skills/mudra-master/mudra-xr/assets/demos/drone.html +41 -0
  36. package/skills/mudra-master/mudra-xr/assets/demos/gemini-icebreakers.html +338 -0
  37. package/skills/mudra-master/mudra-xr/assets/demos/gemini-xrobject.html +302 -0
  38. package/skills/mudra-master/mudra-xr/assets/demos/math3d.html +188 -0
  39. package/skills/mudra-master/mudra-xr/assets/demos/measure.html +247 -0
  40. package/skills/mudra-master/mudra-xr/assets/demos/occlusion.html +251 -0
  41. package/skills/mudra-master/mudra-xr/assets/demos/rain.html +498 -0
  42. package/skills/mudra-master/mudra-xr/assets/demos/screenwiper.html +432 -0
  43. package/skills/mudra-master/mudra-xr/assets/demos/splash.html +519 -0
  44. package/skills/mudra-master/mudra-xr/assets/demos/webcam_gestures.html +253 -0
  45. package/skills/mudra-master/mudra-xr/assets/demos/xremoji.html +833 -0
  46. package/skills/mudra-master/mudra-xr/assets/demos/xrpoet.html +151 -0
  47. package/skills/mudra-master/mudra-xr/assets/samples/depthmap.html +266 -0
  48. package/skills/mudra-master/mudra-xr/assets/samples/depthmesh.html +100 -0
  49. package/skills/mudra-master/mudra-xr/assets/samples/game_rps.html +1099 -0
  50. package/skills/mudra-master/mudra-xr/assets/samples/gestures_custom.html +467 -0
  51. package/skills/mudra-master/mudra-xr/assets/samples/gestures_heuristic.html +256 -0
  52. package/skills/mudra-master/mudra-xr/assets/samples/lighting.html +163 -0
  53. package/skills/mudra-master/mudra-xr/assets/samples/mesh_detection.html +46 -0
  54. package/skills/mudra-master/mudra-xr/assets/samples/modelviewer.html +183 -0
  55. package/skills/mudra-master/mudra-xr/assets/samples/paint.html +133 -0
  56. package/skills/mudra-master/mudra-xr/assets/samples/planar-vst.html +45 -0
  57. package/skills/mudra-master/mudra-xr/assets/samples/reticle.html +95 -0
  58. package/skills/mudra-master/mudra-xr/assets/samples/skybox_agent.html +384 -0
  59. package/skills/mudra-master/mudra-xr/assets/samples/sound.html +390 -0
  60. package/skills/mudra-master/mudra-xr/assets/samples/ui.html +496 -0
  61. package/skills/mudra-master/mudra-xr/assets/samples/virtual-screens.html +808 -0
  62. package/skills/mudra-master/mudra-xr/assets/templates/0_basic.html +64 -0
  63. package/skills/mudra-master/mudra-xr/assets/templates/1_ui.html +107 -0
  64. package/skills/mudra-master/mudra-xr/assets/templates/2_hands.html +183 -0
  65. package/skills/mudra-master/mudra-xr/assets/templates/3_depth.html +89 -0
  66. package/skills/mudra-master/mudra-xr/assets/templates/4_stereo.html +84 -0
  67. package/skills/mudra-master/mudra-xr/assets/templates/5_camera.html +117 -0
  68. package/skills/mudra-master/mudra-xr/assets/templates/6_ai.html +154 -0
  69. package/skills/mudra-master/mudra-xr/assets/templates/7_ai_live.html +253 -0
  70. package/skills/mudra-master/mudra-xr/assets/templates/8_objects.html +95 -0
  71. package/skills/mudra-master/mudra-xr/assets/templates/9_xr-toggle.html +90 -0
  72. package/skills/mudra-master/mudra-xr/assets/templates/heuristic_hand_gestures.html +102 -0
  73. package/skills/mudra-master/mudra-xr/assets/templates/meshes.html +47 -0
  74. package/skills/mudra-master/mudra-xr/assets/templates/planes.html +47 -0
  75. package/skills/mudra-master/mudra-xr/assets/templates/uikit.html +187 -0
  76. package/skills/mudra-master/mudra-xr/references/agent_protocol.json +878 -0
  77. package/skills/mudra-master/mudra-xr/references/promt.md +1516 -0
  78. package/skills/mudra-preview/SKILL.md +151 -0
  79. package/skills/mudra-preview/assets/ar-menu.html +382 -0
  80. package/skills/mudra-preview/assets/document-scroller.html +468 -0
  81. package/skills/mudra-preview/assets/drum-machine.html +788 -0
  82. package/skills/mudra-preview/assets/emg-visualizer.html +390 -0
  83. package/skills/mudra-preview/assets/generative-art.html +408 -0
  84. package/skills/mudra-preview/assets/gesture-assistant.html +342 -0
  85. package/skills/mudra-preview/assets/gesture-speech.html +444 -0
  86. package/skills/mudra-preview/assets/hands-free-desktop.html +376 -0
  87. package/skills/mudra-preview/assets/model-rotator.html +365 -0
  88. package/skills/mudra-preview/assets/mudra-duel.html +3200 -0
  89. package/skills/mudra-preview/assets/mudra-monitor.html +1451 -0
  90. package/skills/mudra-preview/assets/mudra-ultimate-template.html +891 -0
  91. package/skills/mudra-preview/assets/music-sequencer.html +455 -0
  92. package/skills/mudra-preview/assets/neural-pong.html +380 -0
  93. package/skills/mudra-preview/assets/neural-snake.html +364 -0
  94. package/skills/mudra-preview/assets/presentation-controller.html +345 -0
  95. package/skills/mudra-preview/assets/pressure-painter.html +285 -0
  96. package/skills/mudra-preview/assets/runner.html +1812 -0
  97. package/skills/mudra-preview/assets/smart-home.html +461 -0
  98. package/skills/mudra-preview/assets/space-invaders.html +1154 -0
  99. package/skills/mudra-preview/assets/waterful-ring-toss.html +1624 -0
  100. package/skills/mudra-preview/references/agent_protocol.json +646 -0
  101. package/skills/mudra-preview/references/promt.md +16829 -0
  102. package/skills/mudra-xr/SKILL.md +245 -0
  103. package/skills/mudra-xr/assets/demos/3dgs-walkthrough.html +242 -0
  104. package/skills/mudra-xr/assets/demos/aisimulator.html +792 -0
  105. package/skills/mudra-xr/assets/demos/balloonpop.html +422 -0
  106. package/skills/mudra-xr/assets/demos/ballpit.html +284 -0
  107. package/skills/mudra-xr/assets/demos/drone.html +41 -0
  108. package/skills/mudra-xr/assets/demos/gemini-icebreakers.html +338 -0
  109. package/skills/mudra-xr/assets/demos/gemini-xrobject.html +302 -0
  110. package/skills/mudra-xr/assets/demos/math3d.html +188 -0
  111. package/skills/mudra-xr/assets/demos/measure.html +247 -0
  112. package/skills/mudra-xr/assets/demos/occlusion.html +251 -0
  113. package/skills/mudra-xr/assets/demos/rain.html +498 -0
  114. package/skills/mudra-xr/assets/demos/screenwiper.html +432 -0
  115. package/skills/mudra-xr/assets/demos/splash.html +519 -0
  116. package/skills/mudra-xr/assets/demos/webcam_gestures.html +253 -0
  117. package/skills/mudra-xr/assets/demos/xremoji.html +833 -0
  118. package/skills/mudra-xr/assets/demos/xrpoet.html +151 -0
  119. package/skills/mudra-xr/assets/samples/depthmap.html +266 -0
  120. package/skills/mudra-xr/assets/samples/depthmesh.html +100 -0
  121. package/skills/mudra-xr/assets/samples/game_rps.html +1099 -0
  122. package/skills/mudra-xr/assets/samples/gestures_custom.html +467 -0
  123. package/skills/mudra-xr/assets/samples/gestures_heuristic.html +256 -0
  124. package/skills/mudra-xr/assets/samples/lighting.html +163 -0
  125. package/skills/mudra-xr/assets/samples/mesh_detection.html +46 -0
  126. package/skills/mudra-xr/assets/samples/modelviewer.html +183 -0
  127. package/skills/mudra-xr/assets/samples/paint.html +133 -0
  128. package/skills/mudra-xr/assets/samples/planar-vst.html +45 -0
  129. package/skills/mudra-xr/assets/samples/reticle.html +95 -0
  130. package/skills/mudra-xr/assets/samples/skybox_agent.html +384 -0
  131. package/skills/mudra-xr/assets/samples/sound.html +390 -0
  132. package/skills/mudra-xr/assets/samples/ui.html +496 -0
  133. package/skills/mudra-xr/assets/samples/virtual-screens.html +808 -0
  134. package/skills/mudra-xr/assets/templates/0_basic.html +64 -0
  135. package/skills/mudra-xr/assets/templates/1_ui.html +107 -0
  136. package/skills/mudra-xr/assets/templates/2_hands.html +183 -0
  137. package/skills/mudra-xr/assets/templates/3_depth.html +89 -0
  138. package/skills/mudra-xr/assets/templates/4_stereo.html +84 -0
  139. package/skills/mudra-xr/assets/templates/5_camera.html +117 -0
  140. package/skills/mudra-xr/assets/templates/6_ai.html +154 -0
  141. package/skills/mudra-xr/assets/templates/7_ai_live.html +253 -0
  142. package/skills/mudra-xr/assets/templates/8_objects.html +95 -0
  143. package/skills/mudra-xr/assets/templates/9_xr-toggle.html +90 -0
  144. package/skills/mudra-xr/assets/templates/heuristic_hand_gestures.html +102 -0
  145. package/skills/mudra-xr/assets/templates/meshes.html +47 -0
  146. package/skills/mudra-xr/assets/templates/planes.html +47 -0
  147. package/skills/mudra-xr/assets/templates/uikit.html +187 -0
  148. package/skills/mudra-xr/references/agent_protocol.json +878 -0
  149. package/skills/mudra-xr/references/promt.md +1516 -0
@@ -0,0 +1,498 @@
1
+ <!doctype html>
2
+ <!-- reference: demos/rain -->
3
+ <html lang="en">
4
+ <head>
5
+ <title>Rain</title>
6
+
7
+ <meta
8
+ name="viewport"
9
+ content="width=device-width, initial-scale=1.0, user-scalable=no"
10
+ />
11
+
12
+ <link type="text/css" rel="stylesheet" href="https://xrblocks.github.io/css/xr.css" />
13
+
14
+ <script>
15
+ window.litDisableBundleWarning = true;
16
+ </script>
17
+ <script type="importmap">
18
+ {
19
+ "imports": {
20
+ "three": "https://cdn.jsdelivr.net/npm/three@0.182.0/build/three.module.js",
21
+ "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.182.0/examples/jsm/",
22
+ "troika-three-text": "https://cdn.jsdelivr.net/gh/protectwise/troika@028b81cf308f0f22e5aa8e78196be56ec1997af5/packages/troika-three-text/src/index.js",
23
+ "troika-three-utils": "https://cdn.jsdelivr.net/gh/protectwise/troika@v0.52.4/packages/troika-three-utils/src/index.js",
24
+ "troika-worker-utils": "https://cdn.jsdelivr.net/gh/protectwise/troika@v0.52.4/packages/troika-worker-utils/src/index.js",
25
+ "bidi-js": "https://esm.sh/bidi-js@%5E1.0.2?target=es2022",
26
+ "webgl-sdf-generator": "https://esm.sh/webgl-sdf-generator@1.1.1/es2022/webgl-sdf-generator.mjs",
27
+ "lit": "https://cdn.jsdelivr.net/gh/lit/dist@3/core/lit-core.min.js",
28
+ "lit/": "https://esm.run/lit@3/",
29
+ "xrblocks": "https://cdn.jsdelivr.net/npm/xrblocks@0.11.0/build/xrblocks.js",
30
+ "xrblocks/addons/": "https://cdn.jsdelivr.net/npm/xrblocks@0.11.0/build/addons/"
31
+ }
32
+ }
33
+ </script>
34
+ </head>
35
+
36
+ <body>
37
+ <div
38
+ class="background-image"
39
+ style="background-image: url('textures/background.webp')"
40
+ ></div>
41
+
42
+ <div
43
+ id="startButton"
44
+ style="
45
+ position: fixed;
46
+ top: 0;
47
+ left: 0;
48
+ width: 100%;
49
+ height: 100%;
50
+ background-color: black;
51
+ color: white;
52
+ display: flex;
53
+ justify-content: center;
54
+ align-items: center;
55
+ cursor: pointer;
56
+ z-index: 1000;
57
+ "
58
+ >
59
+ <p style="font-size: 24px">Click to Start Rain Experience</p>
60
+ </div>
61
+
62
+ <script type="module">
63
+ import 'xrblocks/addons/simulator/SimulatorAddons.js';
64
+
65
+ import * as THREE from 'three';
66
+ import * as xb from 'xrblocks';
67
+ import {VolumetricCloud} from 'xrblocks/addons/volumes/VolumetricCloud.js';
68
+
69
+ // --- RainParticles inlined ---
70
+ const kMaxAnimationFrames = 15;
71
+ const kAnimationSpeed = 2.0;
72
+ const DEBUG_SINGLE = false;
73
+
74
+ function clamp(x, a, b) {
75
+ return Math.min(Math.max(x, a), b);
76
+ }
77
+
78
+ class RainParticles extends THREE.Object3D {
79
+ constructor() {
80
+ super();
81
+ this.particleCount = DEBUG_SINGLE ? 1 : 200;
82
+ this.RANGE = 4;
83
+ this.raycaster = new THREE.Raycaster();
84
+
85
+ this.velocities = new Float32Array(this.particleCount);
86
+ this.particleWeights = new Float32Array(this.particleCount);
87
+ this.particleVisibility = new Float32Array(this.particleCount);
88
+
89
+ this.raindropMesh = null;
90
+ }
91
+
92
+ init() {
93
+ const textureLoader = new THREE.TextureLoader();
94
+ textureLoader.load('textures/rain_sprite_sheet.png', (raindropTexture) => {
95
+ const raindropMaterial = this.createRaindropMaterial(raindropTexture);
96
+ const raindropGeometry = new THREE.PlaneGeometry(0.1, 0.1);
97
+
98
+ this.raindropMesh = new THREE.InstancedMesh(
99
+ raindropGeometry,
100
+ raindropMaterial,
101
+ this.particleCount
102
+ );
103
+
104
+ this.initializeParticles();
105
+
106
+ this.raindropMesh.geometry.setAttribute(
107
+ 'aWeight',
108
+ new THREE.InstancedBufferAttribute(this.particleWeights, 1).setUsage(
109
+ THREE.DynamicDrawUsage
110
+ )
111
+ );
112
+ this.raindropMesh.geometry.setAttribute(
113
+ 'aVisibility',
114
+ new THREE.InstancedBufferAttribute(this.particleVisibility, 1).setUsage(
115
+ THREE.DynamicDrawUsage
116
+ )
117
+ );
118
+
119
+ this.raindropMesh.instanceMatrix.needsUpdate = true;
120
+ this.add(this.raindropMesh);
121
+ });
122
+ }
123
+
124
+ createRaindropMaterial(texture) {
125
+ return new THREE.ShaderMaterial({
126
+ uniforms: {
127
+ uTexture: {value: texture},
128
+ uCameraPosition: {value: new THREE.Vector3()},
129
+ uCameraRotationMatrix: {value: new THREE.Matrix4()},
130
+ },
131
+ vertexShader: `
132
+ attribute float aWeight;
133
+ attribute float aVisibility;
134
+ varying float vWeight;
135
+ varying float vVisibility;
136
+ varying vec2 vUv;
137
+ uniform vec3 uCameraPosition;
138
+ uniform mat4 uCameraRotationMatrix;
139
+
140
+ const float PI = 3.14159265359;
141
+
142
+
143
+ void main() {
144
+ vUv = uv;
145
+ vWeight = aWeight;
146
+ vVisibility = aVisibility;
147
+
148
+ // Get the world position of the instance
149
+ vec4 worldPosition = instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0);
150
+
151
+ vec3 rotatedPosition;
152
+
153
+ if (vWeight < 1.5) {
154
+ // Compute vector from particle to camera, projected onto XZ plane
155
+ vec3 toCamera = uCameraPosition - worldPosition.xyz;
156
+ toCamera.y = 0.0; // Ignore vertical component
157
+ toCamera = normalize(toCamera);
158
+
159
+ // Compute the angle to rotate around Y-axis
160
+ float angle = atan(toCamera.x, toCamera.z);
161
+
162
+ // Create rotation matrix around Y-axis
163
+ mat3 rotationMatrix = mat3(
164
+ cos(angle), 0.0, -sin(angle),
165
+ 0.0, 1.0, 0.0,
166
+ sin(angle), 0.0, cos(angle)
167
+ );
168
+
169
+ // Apply rotation to vertex position
170
+ rotatedPosition = rotationMatrix * position;
171
+ } else {
172
+ // Rotate the particle to face positive Y-axis
173
+ // This is a rotation of -90 degrees around X-axis
174
+ float angle = 0.5 * PI; // -90 degrees in radians
175
+
176
+ // Create rotation matrix around X-axis
177
+ mat3 rotationMatrix = mat3(
178
+ 1.0, 0.0, 0.0,
179
+ 0.0, cos(angle), -sin(angle),
180
+ 0.0, sin(angle), cos(angle)
181
+ );
182
+
183
+ // Apply rotation to vertex position
184
+ rotatedPosition = rotationMatrix * position;
185
+ }
186
+
187
+ // Apply instance transformations
188
+ vec4 finalPosition = instanceMatrix * vec4(rotatedPosition, 1.0);
189
+
190
+ // Transform to clip space
191
+ gl_Position = projectionMatrix * viewMatrix * finalPosition;
192
+ }
193
+
194
+ `,
195
+ fragmentShader: `
196
+ uniform sampler2D uTexture;
197
+ varying vec2 vUv;
198
+ varying float vWeight;
199
+ varying float vVisibility;
200
+
201
+ void main() {
202
+ const float kAnimationSpeed = 2.0;
203
+ vec2 uv = vUv * 0.25; // Assumes a 4x4 texture grid.
204
+ float frame = floor(vWeight / kAnimationSpeed);
205
+ float xIndex = mod(frame, 4.0);
206
+ float yIndex = floor(frame / 4.0);
207
+ uv += vec2(xIndex, 3.0 - yIndex) * 0.25; // Maps frame index to UV coordinates.
208
+ vec4 texColor = texture2D(uTexture, uv);
209
+ gl_FragColor = vec4(pow(texColor.rgb, vec3(0.5)), texColor.a * vVisibility * 0.8 - step(vWeight, 0.5) * 0.2); // Applies visibility factor.
210
+ }
211
+ `,
212
+ transparent: true,
213
+ });
214
+ }
215
+
216
+ initializeParticles() {
217
+ const dummy = new THREE.Object3D();
218
+ for (let i = 0; i < this.particleCount; i++) {
219
+ dummy.position.set(
220
+ Math.random() * this.RANGE * 2 - this.RANGE,
221
+ Math.random() * this.RANGE * 2,
222
+ Math.random() * this.RANGE * 2 - this.RANGE
223
+ );
224
+
225
+ if (DEBUG_SINGLE) {
226
+ dummy.position.set(0, 1.2, -1);
227
+ }
228
+
229
+ dummy.updateMatrix();
230
+ this.raindropMesh.setMatrixAt(i, dummy.matrix);
231
+
232
+ this.velocities[i] = Math.random() * 0.05 + 0.2;
233
+ this.particleWeights[i] = 0;
234
+ this.particleVisibility[i] = 1;
235
+ }
236
+ }
237
+
238
+ update(camera, xrDepth) {
239
+ if (!this.raindropMesh) return;
240
+ const depthMesh = xrDepth.depthMesh;
241
+
242
+ const dummy = new THREE.Object3D();
243
+ const particleWeightsAttribute =
244
+ this.raindropMesh.geometry.attributes.aWeight;
245
+ const particleVisibilityAttribute =
246
+ this.raindropMesh.geometry.attributes.aVisibility;
247
+
248
+ const cameraEuler = new THREE.Euler().setFromQuaternion(
249
+ camera.quaternion,
250
+ 'YXZ'
251
+ );
252
+ const cameraEulerNoYaw = new THREE.Euler(
253
+ cameraEuler.x,
254
+ 0,
255
+ cameraEuler.z,
256
+ 'YXZ'
257
+ );
258
+ const cameraRotationMatrix = new THREE.Matrix4().makeRotationFromEuler(
259
+ cameraEulerNoYaw
260
+ );
261
+ const inverseCameraRotationMatrix = cameraRotationMatrix.clone().invert();
262
+
263
+ this.raindropMesh.material.uniforms.uCameraRotationMatrix.value.copy(
264
+ inverseCameraRotationMatrix
265
+ );
266
+
267
+ for (let i = 0; i < this.raindropMesh.count; ++i) {
268
+ this.raindropMesh.getMatrixAt(i, dummy.matrix);
269
+ dummy.matrix.decompose(dummy.position, dummy.quaternion, dummy.scale);
270
+
271
+ if (this.particleWeights[i] < 0.5) {
272
+ dummy.position.y -= this.velocities[i];
273
+ }
274
+
275
+ const screenPos = dummy.position.clone().project(camera);
276
+
277
+ const isWithinFoV =
278
+ screenPos.x >= -0.8 &&
279
+ screenPos.x <= 0.6 &&
280
+ screenPos.y >= -1.0 &&
281
+ screenPos.y <= 1.0 &&
282
+ screenPos.z >= 0 &&
283
+ screenPos.z <= 1;
284
+
285
+ let isOccluded = false;
286
+ let maxVisibility = 1.0;
287
+ let deltaDepth = 0.0;
288
+
289
+ const isHigh = dummy.position.y > 2.0;
290
+
291
+ if (isWithinFoV) {
292
+ const depth = xrDepth.getDepth(
293
+ (screenPos.x + 1) / 2,
294
+ (screenPos.y + 1) / 2
295
+ );
296
+
297
+ const pointInCameraSpace = dummy.position
298
+ .clone()
299
+ .applyMatrix4(camera.matrixWorldInverse);
300
+
301
+ const distanceToCameraPlane = -pointInCameraSpace.z;
302
+
303
+ isOccluded = depth == 0 || depth < distanceToCameraPlane;
304
+ deltaDepth = Math.abs(distanceToCameraPlane - depth);
305
+
306
+ if (
307
+ this.particleWeights[i] == 0 &&
308
+ this.particleVisibility[i] > 0.5 &&
309
+ isOccluded &&
310
+ !isHigh
311
+ ) {
312
+ this.particleWeights[i] = 1;
313
+
314
+ if (depth < 0.3) {
315
+ maxVisibility = 0.0;
316
+ } else if (depth > 2.0) {
317
+ maxVisibility *= 0.5 + (4.0 - depth) / 4.0;
318
+ }
319
+ }
320
+ }
321
+
322
+ if (isWithinFoV) {
323
+ this.particleVisibility[i] =
324
+ isOccluded && !isHigh
325
+ ? clamp(0.6 - deltaDepth, 0.0, 0.6)
326
+ : maxVisibility;
327
+ } else {
328
+ this.particleVisibility[i] = 0.0;
329
+ }
330
+
331
+ if (dummy.position.y < 0) {
332
+ dummy.position.y = 0;
333
+ if (this.particleWeights[i] < 0.5) {
334
+ this.particleWeights[i] = 1;
335
+ }
336
+
337
+ this.particleVisibility[i] =
338
+ isOccluded && !isHigh ? 0.0 : maxVisibility;
339
+ }
340
+
341
+ if (this.particleWeights[i] > 0) {
342
+ this.particleWeights[i] += 1;
343
+ }
344
+
345
+ if (depthMesh.minDepth < 0.1) {
346
+ this.particleVisibility[i] = 0.0;
347
+ }
348
+
349
+ if (this.particleWeights[i] > kMaxAnimationFrames * kAnimationSpeed) {
350
+ this.respawnPrticle(dummy, i, camera, depthMesh);
351
+ }
352
+
353
+ particleVisibilityAttribute.setX(i, this.particleVisibility[i]);
354
+ particleWeightsAttribute.setX(i, this.particleWeights[i]);
355
+ dummy.updateMatrix();
356
+ this.raindropMesh.setMatrixAt(i, dummy.matrix);
357
+ }
358
+
359
+ this.raindropMesh.instanceMatrix.needsUpdate = true;
360
+ particleWeightsAttribute.needsUpdate = true;
361
+ particleVisibilityAttribute.needsUpdate = true;
362
+ this.raindropMesh.material.uniforms.uCameraPosition.value.copy(
363
+ camera.position
364
+ );
365
+ }
366
+
367
+ respawnPrticle(dummy, index, camera, depthMesh) {
368
+ let u = Math.random();
369
+ let v = Math.random();
370
+ const half = Math.random();
371
+ let vertex;
372
+ let inited = false;
373
+ let threshold = 0.05;
374
+ if (depthMesh.minDepth < 0.16) {
375
+ threshold = depthMesh.minDepth * 0.01;
376
+ }
377
+
378
+ threshold = 0.1;
379
+
380
+ if (Math.random() < threshold) {
381
+ u = u * 0.8 + 0.1;
382
+ v = v * 0.8 + 0.1;
383
+ this.raycaster.setFromCamera(
384
+ {x: u * 2.0 - 1.0, y: v * 2.0 - 1.0},
385
+ camera
386
+ );
387
+ const intersections = this.raycaster.intersectObject(depthMesh);
388
+ if (intersections.length > 0) {
389
+ vertex = intersections[0].point;
390
+ inited = true;
391
+ }
392
+ }
393
+
394
+ if (!inited) {
395
+ const theta = u * 2 * Math.PI;
396
+ let radius = Math.sqrt(v) * this.RANGE + 0.2;
397
+ if (half < 0.5) {
398
+ radius = Math.sqrt(v) * 0.7 + 0.3;
399
+ } else if (half < 0.7) {
400
+ radius = Math.sqrt(v) * 1.5 + 0.3;
401
+ }
402
+
403
+ vertex = {
404
+ x: radius * Math.cos(theta),
405
+ z: radius * Math.sin(theta),
406
+ y: 4.0,
407
+ };
408
+ }
409
+
410
+ vertex = DEBUG_SINGLE ? new THREE.Vector3(-1, 4, -1) : vertex;
411
+
412
+ dummy.position.set(vertex.x, vertex.y, vertex.z);
413
+ dummy.rotation.set(0, 0, 0);
414
+ this.particleWeights[index] = inited ? 1.0 : 0.0;
415
+ }
416
+ }
417
+
418
+ // --- RainScene inlined ---
419
+ const ASSETS_PATH = 'https://cdn.jsdelivr.net/gh/xrblocks/assets@main/';
420
+
421
+ class RainScene extends xb.Script {
422
+ rainParticles = new RainParticles();
423
+ cloud = new VolumetricCloud();
424
+
425
+ listener = null;
426
+ rainSound = null;
427
+
428
+ init() {
429
+ this.add(this.rainParticles);
430
+ this.rainParticles.init();
431
+ this.add(this.cloud);
432
+
433
+ this.listener = new THREE.AudioListener();
434
+ xb.core.camera.add(this.listener);
435
+
436
+ this.rainSound = new THREE.Audio(this.listener);
437
+ const audioLoader = new THREE.AudioLoader();
438
+ audioLoader.load(ASSETS_PATH + 'demos/rain/rain.opus', (buffer) => {
439
+ this.rainSound.setBuffer(buffer);
440
+ this.rainSound.setLoop(true);
441
+ this.rainSound.setVolume(0.5);
442
+ this.rainSound.play();
443
+ console.log('Rain audio loaded and playing.');
444
+ });
445
+
446
+ const startButton = document.getElementById('startButton');
447
+ if (startButton) {
448
+ startButton.addEventListener('click', () => {
449
+ this.startAudio();
450
+ startButton.remove();
451
+ });
452
+ }
453
+ }
454
+
455
+ startAudio() {
456
+ if (this.listener.context.state === 'suspended') {
457
+ this.listener.context.resume();
458
+ }
459
+
460
+ if (this.rainSound.buffer) {
461
+ this.rainSound.play();
462
+ console.log('Rain audio started by user gesture.');
463
+ }
464
+ }
465
+
466
+ update() {
467
+ const leftCamera = xb.getXrCameraLeft() || xb.core.camera;
468
+ this.rainParticles.update(leftCamera, xb.core.depth);
469
+ this.cloud.update(xb.core.camera, xb.core.depth);
470
+ }
471
+ }
472
+
473
+ const depthMeshColliderUpdateFps = xb.getUrlParamFloat(
474
+ 'depthMeshColliderUpdateFps',
475
+ 30
476
+ );
477
+
478
+ const options = new xb.Options();
479
+ options.simulator.instructions.enabled = false;
480
+ options.reticles.enabled = false;
481
+ options.depth = new xb.DepthOptions(xb.xrDepthMeshPhysicsOptions);
482
+ options.depth.depthMesh.colliderUpdateFps = depthMeshColliderUpdateFps;
483
+ options.xrButton.startText = '<i id="xrlogo"></i> LET IT RAIN';
484
+ options.xrButton.endText = '<i id="xrlogo"></i> MISSION COMPLETE';
485
+
486
+ async function start() {
487
+ const rainScene = new RainScene();
488
+ xb.add(rainScene);
489
+ await xb.init(options);
490
+ }
491
+
492
+ document.addEventListener('DOMContentLoaded', function () {
493
+ start();
494
+ });
495
+
496
+ </script>
497
+ </body>
498
+ </html>