brilliantsole 0.0.27 → 0.0.29

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 (202) hide show
  1. package/assets/3d/anchor.glb +0 -0
  2. package/assets/3d/coin.glb +0 -0
  3. package/assets/3d/glasses.glb +0 -0
  4. package/assets/audio/bounceMedium.wav +0 -0
  5. package/assets/audio/bounceStrong.wav +0 -0
  6. package/assets/audio/bounceWeak.wav +0 -0
  7. package/assets/audio/coin.wav +0 -0
  8. package/assets/audio/getUp.wav +0 -0
  9. package/assets/audio/grab.wav +0 -0
  10. package/assets/audio/kick.wav +0 -0
  11. package/assets/audio/platterFadeIn old.wav +0 -0
  12. package/assets/audio/platterFadeIn.wav +0 -0
  13. package/assets/audio/platterFadeOut.wav +0 -0
  14. package/assets/audio/punch.wav +0 -0
  15. package/assets/audio/punchSqueak.wav +0 -0
  16. package/assets/audio/purr.wav +0 -0
  17. package/assets/audio/purrFadeOut.wav +0 -0
  18. package/assets/audio/release.wav +0 -0
  19. package/assets/audio/splat.wav +0 -0
  20. package/assets/audio/stomp.wav +0 -0
  21. package/build/brilliantsole.cjs +3091 -741
  22. package/build/brilliantsole.cjs.map +1 -1
  23. package/build/brilliantsole.js +2759 -709
  24. package/build/brilliantsole.js.map +1 -1
  25. package/build/brilliantsole.ls.js +2602 -543
  26. package/build/brilliantsole.ls.js.map +1 -1
  27. package/build/brilliantsole.min.js +1 -1
  28. package/build/brilliantsole.min.js.map +1 -1
  29. package/build/brilliantsole.module.d.ts +295 -65
  30. package/build/brilliantsole.module.js +2749 -710
  31. package/build/brilliantsole.module.js.map +1 -1
  32. package/build/brilliantsole.module.min.d.ts +295 -65
  33. package/build/brilliantsole.module.min.js +1 -1
  34. package/build/brilliantsole.module.min.js.map +1 -1
  35. package/build/brilliantsole.node.module.d.ts +289 -62
  36. package/build/brilliantsole.node.module.js +3080 -742
  37. package/build/brilliantsole.node.module.js.map +1 -1
  38. package/build/dts/BS-output.d.ts +10 -0
  39. package/build/dts/BS.d.ts +21 -8
  40. package/build/dts/CameraManager.d.ts +72 -0
  41. package/build/dts/Device.d.ts +64 -13
  42. package/build/dts/DeviceInformationManager.d.ts +4 -4
  43. package/build/dts/DeviceManager.d.ts +2 -0
  44. package/build/dts/FileTransferManager.d.ts +18 -8
  45. package/build/dts/InformationManager.d.ts +2 -0
  46. package/build/dts/MicrophoneManager.d.ts +88 -0
  47. package/build/dts/TfliteManager.d.ts +22 -2
  48. package/build/dts/WifiManager.d.ts +61 -0
  49. package/build/dts/connection/BaseConnectionManager.d.ts +35 -3
  50. package/build/dts/connection/ClientConnectionManager.d.ts +7 -2
  51. package/build/dts/connection/bluetooth/NobleConnectionManager.d.ts +2 -1
  52. package/build/dts/connection/bluetooth/WebBluetoothConnectionManager.d.ts +1 -0
  53. package/build/dts/connection/bluetooth/bluetoothUUIDs.d.ts +2 -2
  54. package/build/dts/connection/udp/UDPConnectionManager.d.ts +28 -0
  55. package/build/dts/connection/webSocket/WebSocketConnectionManager.d.ts +25 -0
  56. package/build/dts/devicePair/DevicePair.d.ts +5 -5
  57. package/build/dts/scanner/BaseScanner.d.ts +4 -1
  58. package/build/dts/scanner/NobleScanner.d.ts +2 -1
  59. package/build/dts/sensor/MotionSensorDataManager.d.ts +5 -2
  60. package/build/dts/sensor/SensorDataManager.d.ts +5 -4
  61. package/build/dts/server/BaseClient.d.ts +5 -3
  62. package/build/dts/server/ServerUtils.d.ts +1 -1
  63. package/build/dts/server/websocket/WebSocketUtils.d.ts +1 -1
  64. package/build/dts/utils/AudioUtils.d.ts +2 -0
  65. package/build/dts/utils/Console.d.ts +2 -0
  66. package/build/dts/utils/ThrottleUtils.d.ts +2 -0
  67. package/build/dts/vibration/VibrationManager.d.ts +19 -2
  68. package/build/index.d.ts +292 -62
  69. package/build/index.node.d.ts +286 -59
  70. package/examples/3d/scene.html +19 -5
  71. package/examples/3d-generic/index.html +144 -0
  72. package/examples/3d-generic/script.js +266 -0
  73. package/examples/basic/index.html +267 -17
  74. package/examples/basic/script.js +958 -105
  75. package/examples/camera/barcode-detector.js +109 -0
  76. package/examples/camera/depth-estimation.js +71 -0
  77. package/examples/camera/face-detector.js +119 -0
  78. package/examples/camera/face-landmark.js +111 -0
  79. package/examples/camera/gesture-recognition.js +97 -0
  80. package/examples/camera/hand-landmark.js +74 -0
  81. package/examples/camera/image-segmentation.js +98 -0
  82. package/examples/camera/image-to-text.js +43 -0
  83. package/examples/camera/image-upscale.js +75 -0
  84. package/examples/camera/index.html +129 -0
  85. package/examples/camera/object-detection.js +98 -0
  86. package/examples/camera/pose-landmark.js +60 -0
  87. package/examples/camera/script.js +316 -0
  88. package/examples/camera/utils.js +165 -0
  89. package/examples/camera/yolo-tiny.js +54 -0
  90. package/examples/camera/yolo.js +119 -0
  91. package/examples/edge-impulse/script.js +157 -48
  92. package/examples/edge-impulse-test/README.md +11 -0
  93. package/examples/edge-impulse-test/edge-impulse-standalone.js +7228 -0
  94. package/examples/edge-impulse-test/edge-impulse-standalone.wasm +0 -0
  95. package/examples/edge-impulse-test/index.html +75 -0
  96. package/examples/edge-impulse-test/run-impulse.js +135 -0
  97. package/examples/edge-impulse-test/script.js +200 -0
  98. package/examples/glasses-gestures/README.md +11 -0
  99. package/examples/glasses-gestures/edge-impulse-standalone.js +7228 -0
  100. package/examples/glasses-gestures/edge-impulse-standalone.wasm +0 -0
  101. package/examples/glasses-gestures/index.html +69 -0
  102. package/examples/glasses-gestures/run-impulse.js +135 -0
  103. package/examples/glasses-gestures/script.js +226 -0
  104. package/examples/gloves/edge-impulse-standalone.js +7228 -0
  105. package/examples/gloves/edge-impulse-standalone.wasm +0 -0
  106. package/examples/gloves/index.html +4 -1
  107. package/examples/gloves/run-impulse.js +135 -0
  108. package/examples/gloves/script.js +367 -51
  109. package/examples/graph/script.js +94 -37
  110. package/examples/microphone/gender.js +54 -0
  111. package/examples/microphone/index.html +102 -0
  112. package/examples/microphone/script.js +394 -0
  113. package/examples/microphone/utils.js +45 -0
  114. package/examples/microphone/whisper-realtime.js +166 -0
  115. package/examples/microphone/whisper.js +132 -0
  116. package/examples/punch/index.html +135 -0
  117. package/examples/punch/punch.tflite +0 -0
  118. package/examples/punch/script.js +169 -0
  119. package/examples/server/index.html +98 -22
  120. package/examples/server/script.js +317 -109
  121. package/examples/ukaton-firmware-update/merged-firmware.bin +0 -0
  122. package/examples/utils/aframe/aframe-master.min.js +2 -0
  123. package/examples/utils/aframe/bs-vibration.js +150 -0
  124. package/examples/utils/aframe/force-pushable.js +80 -0
  125. package/examples/utils/aframe/grabbable-anchor.js +46 -0
  126. package/examples/utils/aframe/grabbable-listener.js +31 -0
  127. package/examples/utils/aframe/grabbable-physics-body.js +190 -0
  128. package/examples/utils/aframe/grow-shrink.js +25 -0
  129. package/examples/utils/aframe/hand-punch.js +119 -0
  130. package/examples/utils/aframe/my-obb-collider.js +293 -0
  131. package/examples/utils/aframe/occlude-hand-tracking-controls.js +47 -0
  132. package/examples/utils/aframe/occlude-mesh.js +42 -0
  133. package/examples/utils/aframe/palm-up-detector.js +47 -0
  134. package/examples/utils/aframe/shadow-material.js +20 -0
  135. package/examples/utils/aframe/soft-shadow-light.js +9 -0
  136. package/examples/webxr-2/assets/3d/soccerBall.glb +0 -0
  137. package/examples/webxr-2/assets/audio/shellBounce.wav +0 -0
  138. package/examples/webxr-2/assets/audio/shellHit.wav +0 -0
  139. package/examples/webxr-2/assets/audio/shellKick.wav +0 -0
  140. package/examples/webxr-2/assets/audio/soccerBounce.wav +0 -0
  141. package/examples/webxr-2/assets/audio/soccerKick.mp3 +0 -0
  142. package/examples/webxr-2/assets/images/shellTexture.png +0 -0
  143. package/examples/webxr-2/components/bs-ankle.js +337 -0
  144. package/examples/webxr-2/components/coin.js +84 -0
  145. package/examples/webxr-2/components/custom-wrap.js +17 -0
  146. package/examples/webxr-2/components/goomba.js +3250 -0
  147. package/examples/webxr-2/components/init-shell-material.js +215 -0
  148. package/examples/webxr-2/components/platter.js +172 -0
  149. package/examples/webxr-2/components/shell.js +374 -0
  150. package/examples/webxr-2/components/soccer-ball.js +250 -0
  151. package/examples/webxr-2/components/squashed-goomba.js +249 -0
  152. package/examples/webxr-2/edge-impulse-standalone.js +7228 -0
  153. package/examples/webxr-2/edge-impulse-standalone.wasm +0 -0
  154. package/examples/webxr-2/index.html +996 -0
  155. package/examples/webxr-2/kick.tflite +0 -0
  156. package/examples/webxr-2/kick2.tflite +0 -0
  157. package/examples/webxr-2/run-impulse.js +135 -0
  158. package/examples/webxr-2/script.js +384 -0
  159. package/examples/webxr-3/components/bs-camera.js +65 -0
  160. package/examples/webxr-3/index.html +134 -0
  161. package/examples/webxr-3/script.js +432 -0
  162. package/package.json +2 -1
  163. package/src/.prettierrc +4 -0
  164. package/src/BS.ts +79 -8
  165. package/src/CameraManager.ts +497 -0
  166. package/src/Device.ts +691 -86
  167. package/src/DeviceInformationManager.ts +19 -10
  168. package/src/DeviceManager.ts +85 -25
  169. package/src/FileTransferManager.ts +145 -20
  170. package/src/InformationManager.ts +40 -15
  171. package/src/MicrophoneManager.ts +599 -0
  172. package/src/TfliteManager.ts +171 -25
  173. package/src/WifiManager.ts +323 -0
  174. package/src/connection/BaseConnectionManager.ts +130 -30
  175. package/src/connection/ClientConnectionManager.ts +34 -10
  176. package/src/connection/bluetooth/BluetoothConnectionManager.ts +8 -2
  177. package/src/connection/bluetooth/NobleConnectionManager.ts +147 -41
  178. package/src/connection/bluetooth/WebBluetoothConnectionManager.ts +99 -34
  179. package/src/connection/bluetooth/bluetoothUUIDs.ts +40 -13
  180. package/src/connection/udp/UDPConnectionManager.ts +356 -0
  181. package/src/connection/websocket/WebSocketConnectionManager.ts +282 -0
  182. package/src/devicePair/DevicePair.ts +95 -25
  183. package/src/devicePair/DevicePairPressureSensorDataManager.ts +27 -7
  184. package/src/scanner/BaseScanner.ts +49 -11
  185. package/src/scanner/NobleScanner.ts +76 -14
  186. package/src/sensor/MotionSensorDataManager.ts +21 -6
  187. package/src/sensor/PressureSensorDataManager.ts +37 -8
  188. package/src/sensor/SensorConfigurationManager.ts +73 -22
  189. package/src/sensor/SensorDataManager.ts +109 -23
  190. package/src/server/BaseClient.ts +150 -36
  191. package/src/server/BaseServer.ts +50 -2
  192. package/src/server/ServerUtils.ts +39 -9
  193. package/src/server/udp/UDPServer.ts +73 -22
  194. package/src/server/udp/UDPUtils.ts +9 -2
  195. package/src/server/websocket/WebSocketClient.ts +27 -7
  196. package/src/server/websocket/WebSocketUtils.ts +4 -2
  197. package/src/utils/AudioUtils.ts +65 -0
  198. package/src/utils/Console.ts +62 -9
  199. package/src/utils/ParseUtils.ts +24 -5
  200. package/src/utils/ThrottleUtils.ts +62 -0
  201. package/src/utils/Timer.ts +1 -1
  202. package/src/vibration/VibrationManager.ts +166 -40
@@ -0,0 +1,150 @@
1
+ import * as BS from "../../../build/brilliantsole.module.js";
2
+
3
+ AFRAME.registerComponent("bs-vibration", {
4
+ schema: {
5
+ type: {
6
+ default: "insole",
7
+ oneOf: ["glove", "insole"],
8
+ },
9
+ side: {
10
+ default: "right",
11
+ oneOf: ["left", "right"],
12
+ },
13
+ },
14
+
15
+ dependencies: ["hand-tracking-controls"],
16
+
17
+ init() {
18
+ this.type = this.data.type;
19
+ this.side = this.data.side;
20
+
21
+ this.hand = this.el.components["hand-tracking-controls"];
22
+ if (this.hand) {
23
+ this.side = this.hand.data.hand;
24
+ this.type = "glove";
25
+ }
26
+
27
+ switch (this.type) {
28
+ case "glove":
29
+ this.devicePair = BS.DevicePair.gloves;
30
+
31
+ this.el.addEventListener("grabstarted", () =>
32
+ this.setGrabEnabled(true)
33
+ );
34
+ this.el.addEventListener("grabended", () => this.setGrabEnabled(false));
35
+
36
+ this.setGrabEnabled = AFRAME.utils.throttleLeadingAndTrailing(
37
+ this.setGrabEnabled.bind(this),
38
+ 70
39
+ );
40
+
41
+ this.el.sceneEl.addEventListener(
42
+ "startPetting",
43
+ this.onStartPetting.bind(this)
44
+ );
45
+ this.el.sceneEl.addEventListener(
46
+ "stopPetting",
47
+ this.onStopPetting.bind(this)
48
+ );
49
+ break;
50
+ case "insole":
51
+ this.devicePair = BS.DevicePair.insoles;
52
+ break;
53
+ }
54
+
55
+ this.el.sceneEl.addEventListener(
56
+ "bs-trigger-vibration",
57
+ this.onVibrate.bind(this)
58
+ );
59
+ },
60
+
61
+ setGrabEnabled: function (enabled) {
62
+ if (enabled) {
63
+ this.onGrabStarted();
64
+ } else {
65
+ this.onGrabEnded();
66
+ }
67
+ },
68
+
69
+ onGrabStarted: function (event) {
70
+ /** @type {BS.VibrationWaveformEffect} */
71
+ const waveformEffect = "sharpClick100";
72
+ this.vibrate(waveformEffect);
73
+ },
74
+ onGrabEnded: function (event) {
75
+ /** @type {BS.VibrationWaveformEffect} */
76
+ const waveformEffect = "shortDoubleSharpTick100";
77
+ this.vibrate(waveformEffect);
78
+ },
79
+
80
+ onStartPetting: function (event) {
81
+ const { side } = event.detail;
82
+ if (side != this.side) {
83
+ return;
84
+ }
85
+ /** @type {BS.VibrationWaveformEffect} */
86
+ const waveformEffect = "transitionHum40";
87
+ this.vibrate(waveformEffect, true);
88
+ },
89
+ onStopPetting: function (event) {
90
+ const { side } = event.detail;
91
+ if (side != this.side) {
92
+ return;
93
+ }
94
+ /** @type {BS.VibrationWaveformEffect} */
95
+ const waveformEffect = "none";
96
+ this.vibrate(waveformEffect);
97
+ },
98
+
99
+ onVibrate: function (event) {
100
+ const { side, type, waveformEffect } = event.detail;
101
+ if (side != this.side || type != this.type) {
102
+ return;
103
+ }
104
+ this.vibrate(waveformEffect);
105
+ },
106
+
107
+ vibrate: function (waveformEffect, loop = false) {
108
+ if (this.loopInterval) {
109
+ clearInterval(this.loopInterval);
110
+ }
111
+ if (!this.devicePair) {
112
+ console.log("devicePair not defined");
113
+ return;
114
+ }
115
+ /** @type {BS.Device?} */
116
+ const device = this.devicePair[this.side];
117
+ if (!device?.isConnected) {
118
+ // console.log(
119
+ // `${this.side} ${this.type} not connected`,
120
+ // device,
121
+ // this.devicePair
122
+ // );
123
+ return;
124
+ }
125
+
126
+ if (loop) {
127
+ const trigger = () => {
128
+ device.triggerVibration([
129
+ {
130
+ type: "waveformEffect",
131
+ locations: ["rear"],
132
+ segments: new Array(
133
+ BS.MaxNumberOfVibrationWaveformEffectSegments
134
+ ).fill({ effect: waveformEffect }),
135
+ },
136
+ ]);
137
+ };
138
+ this.loopInterval = setInterval(() => trigger(), 4000);
139
+ trigger();
140
+ } else {
141
+ device.triggerVibration([
142
+ {
143
+ type: "waveformEffect",
144
+ locations: ["rear"],
145
+ segments: [{ effect: waveformEffect }],
146
+ },
147
+ ]);
148
+ }
149
+ },
150
+ });
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Force Pushable component.
3
+ *
4
+ * Applies behavior to the current entity such that cursor clicks will apply a
5
+ * strong impulse, pushing the entity away from the viewer.
6
+ *
7
+ * Requires: physics
8
+ */
9
+ AFRAME.registerComponent("force-pushable", {
10
+ schema: {
11
+ force: { default: 100 },
12
+ },
13
+ init: function () {
14
+ if (this.el.sceneEl.getAttribute("physics").driver === "ammo") {
15
+ this.driver = "ammo";
16
+ } else {
17
+ this.driver = "cannon";
18
+ }
19
+
20
+ this.pStart = new THREE.Vector3();
21
+ this.sourceEl = this.el.sceneEl.querySelector("[camera]");
22
+
23
+ if (this.driver === "cannon") {
24
+ this.el.addEventListener("click", this.forcePushCannon.bind(this));
25
+ } else {
26
+ this.el.addEventListener("click", this.forcePushAmmo.bind(this));
27
+
28
+ this.force = new THREE.Vector3();
29
+ this.pos = new THREE.Vector3();
30
+
31
+ this.el.addEventListener("body-loaded", (e) => {
32
+ this.impulseBtVector = new Ammo.btVector3();
33
+ this.posBtVector = new Ammo.btVector3();
34
+ });
35
+ }
36
+ },
37
+
38
+ forcePushCannon: function () {
39
+ var force,
40
+ el = this.el,
41
+ pStart = this.pStart.copy(this.sourceEl.getAttribute("position"));
42
+
43
+ // Compute direction of force, normalize, then scale.
44
+ force = el.body.position.vsub(pStart);
45
+ force.normalize();
46
+ force.scale(this.data.force, force);
47
+
48
+ if (window.force) {
49
+ force = window.force;
50
+ }
51
+
52
+ el.body.applyImpulse(force, el.body.position);
53
+ },
54
+
55
+ forcePushAmmo: function (e) {
56
+ if (!this.impulseBtVector) return;
57
+
58
+ const el = this.el;
59
+ const force = this.force;
60
+ const impulseBt = this.impulseBtVector;
61
+ const pusher = e.detail.cursorEl.object3D;
62
+ force.copy(pusher.position);
63
+ pusher.localToWorld(force);
64
+ force.copy(el.object3D.position.sub(force));
65
+ force.normalize();
66
+
67
+ force.multiplyScalar(this.data.force);
68
+ impulseBt.setValue(force.x, force.y, force.z);
69
+
70
+ // use data from intersection to determine point at which to apply impulse.
71
+ const pos = this.pos;
72
+ const posBt = this.posBtVector;
73
+ pos.copy(e.detail.intersection.point);
74
+ el.object3D.worldToLocal(pos);
75
+ posBt.setValue(pos.x, pos.y, pos.z);
76
+
77
+ el.body.activate();
78
+ el.body.applyImpulse(impulseBt, posBt);
79
+ },
80
+ });
@@ -0,0 +1,46 @@
1
+ AFRAME.registerComponent("grabbable-anchor", {
2
+ schema: {},
3
+ dependencies: ["anchored", "grabbable"],
4
+
5
+ init: function () {
6
+ this.el.addEventListener("grabstarted", () => {
7
+ this.el.removeAttribute("anchored");
8
+ });
9
+
10
+ this.el.addEventListener("grabended", () => {
11
+ this.el.setAttribute("anchored", "persistent: true;");
12
+ this.shouldCreateAnchor = true;
13
+ });
14
+ },
15
+
16
+ deleteAnchor: async function () {
17
+ this.isDeletingAnchor = true;
18
+ const uuid = localStorage.getItem(this.el.id);
19
+ if (uuid) {
20
+ const frame = this.el.sceneEl.renderer.xr.getFrame();
21
+ console.log("removing persistant anchor");
22
+ try {
23
+ await frame.session.deletePersistentAnchor(uuid);
24
+ } catch (e) {
25
+ console.log(e);
26
+ }
27
+ localStorage.removeItem(this.el.id);
28
+ }
29
+ this.isDeletingAnchor = false;
30
+ },
31
+
32
+ tick: function () {
33
+ if (this.shouldCreateAnchor && this.el.components.anchored?.createAnchor) {
34
+ this.deleteAnchor();
35
+ if (this.isDeletingAnchor) {
36
+ return;
37
+ }
38
+ this.shouldCreateAnchor = false;
39
+ const position = new THREE.Vector3();
40
+ this.el.object3D.getWorldPosition(position);
41
+ const quaternion = new THREE.Quaternion();
42
+ this.el.object3D.getWorldQuaternion(quaternion);
43
+ this.el.components.anchored.createAnchor(position, quaternion);
44
+ }
45
+ },
46
+ });
@@ -0,0 +1,31 @@
1
+ AFRAME.registerSystem("grabbable-listener", {
2
+ schema: {},
3
+
4
+ init: function () {
5
+ this.allGrabControls = Array.from(
6
+ document.querySelectorAll("[hand-tracking-grab-controls]")
7
+ );
8
+ this.allGrabControls.forEach((grabControls) => {
9
+ grabControls.addEventListener("grabstarted", (event) => {
10
+ if (!event.detail?.grabbedEl) {
11
+ return;
12
+ }
13
+ const { grabbedEl } = event.detail;
14
+ grabbedEl.emit(event.type, {
15
+ hand: event.target.components["hand-tracking-controls"].data.hand,
16
+ grab: event.target.components["hand-tracking-grab-controls"],
17
+ });
18
+ });
19
+ grabControls.addEventListener("grabended", (event) => {
20
+ if (!event.detail?.grabbedEl) {
21
+ return;
22
+ }
23
+ const { grabbedEl } = event.detail;
24
+ grabbedEl.emit(event.type, {
25
+ hand: event.target.components["hand-tracking-controls"].data.hand,
26
+ grab: event.target.components["hand-tracking-grab-controls"],
27
+ });
28
+ });
29
+ });
30
+ },
31
+ });
@@ -0,0 +1,190 @@
1
+ AFRAME.registerComponent("grabbable-physics-body", {
2
+ dependencies: ["grabbable"],
3
+
4
+ schema: {
5
+ type: {
6
+ default: "static",
7
+ oneOf: ["static", "dynamic"],
8
+ },
9
+ staticBody: { default: "" },
10
+ dynamicBody: { default: "" },
11
+ enableAngularVelocity: { default: true },
12
+ },
13
+
14
+ init: function () {
15
+ this.velocityScalar = 1.5;
16
+ this.isGrabbed = false;
17
+ this.positionHistory = [];
18
+ this.velocity = new THREE.Vector3();
19
+
20
+ this.rotationHistory = [];
21
+ this.angularVelocityScalar = 1.0;
22
+ this.angularVelocity = new THREE.Vector3();
23
+
24
+ this.el.addEventListener("body-loaded", this.onBodyLoaded.bind(this));
25
+
26
+ this.el.addEventListener("grabstarted", () => {
27
+ this.grabStartTime = Date.now();
28
+ this.isGrabbed = true;
29
+
30
+ this.positionHistory = [];
31
+ this.velocity.set(0, 0, 0);
32
+
33
+ this.angularVelocity.set(0, 0, 0);
34
+ this.rotationHistory = [];
35
+
36
+ // console.log("removing physics");
37
+ this.el.removeAttribute("static-body");
38
+ this.el.removeAttribute("dynamic-body");
39
+ });
40
+
41
+ this.el.addEventListener("grabended", () => {
42
+ this.isGrabbed = false;
43
+ const now = Date.now();
44
+
45
+ // Compute velocity from position history
46
+ const history = this.positionHistory;
47
+ if (history.length >= 2) {
48
+ const first = history[0];
49
+ const last = history[history.length - 1];
50
+ const dt = (last.time - first.time) / 1000;
51
+ if (dt > 0) {
52
+ this.velocity.copy(last.pos).sub(first.pos).divideScalar(dt);
53
+ }
54
+ }
55
+
56
+ // Compute angular velocity
57
+ const rotHistory = this.rotationHistory;
58
+ if (rotHistory.length >= 2) {
59
+ const first = rotHistory[0];
60
+ const last = rotHistory[rotHistory.length - 1];
61
+ const dt = (last.time - first.time) / 1000;
62
+
63
+ this.angularVelocity = this.getAngularVelocityFromQuaternions(
64
+ first.rot,
65
+ last.rot,
66
+ dt
67
+ );
68
+ }
69
+
70
+ if (now - this.grabStartTime < 10) {
71
+ this.velocity.set(0, 0, 0);
72
+ this.angularVelocity.set(0, 0, 0);
73
+ }
74
+
75
+ this.el.removeAttribute("dynamic-body");
76
+ this.el.removeAttribute("static-body");
77
+ this.el.removeAttribute("shape__main");
78
+
79
+ // console.log("adding physics", this.data.type);
80
+ // Re-add physics and apply velocity
81
+ if (this.data.type === "static") {
82
+ this.el.setAttribute("static-body", this.data.staticBody);
83
+ this.el.setAttribute(
84
+ "shape__main",
85
+ `shape: box;
86
+ halfExtents: 0.1 0.091 0.09;
87
+ offset: 0 0 0;`
88
+ );
89
+ } else {
90
+ this.shouldSetVelocity = true;
91
+ //console.log("setting dynamic body", this.data.dynamicBody);
92
+ //this.el.setAttribute("dynamic-body", this.data.dynamicBody);
93
+ const shapeMain = this.el.shapeMain;
94
+ if (shapeMain) {
95
+ this.el.setAttribute("dynamic-body", "shape: none;");
96
+ // console.log("shape__main", shapeMain);
97
+ //this.el.setAttribute("shape__main", shapeMain);
98
+ // should wait for 'goomba' component to load
99
+ this.el.setAttribute("shape__main", shapeMain);
100
+ } else {
101
+ this.el.setAttribute("dynamic-body", "");
102
+ }
103
+ }
104
+ });
105
+ },
106
+
107
+ onBodyLoaded: function () {
108
+ if (!this.shouldSetVelocity) {
109
+ return;
110
+ }
111
+ // console.log("grabbable physics onBodyLoaded");
112
+ this.shouldSetVelocity = false;
113
+ const body = this.el.body;
114
+ if (body) {
115
+ body.wakeUp();
116
+ setTimeout(() => {
117
+ body.wakeUp();
118
+ // console.log("setting velocity", this.velocity);
119
+ body.velocity.set(
120
+ this.velocity.x * this.velocityScalar,
121
+ this.velocity.y * this.velocityScalar,
122
+ this.velocity.z * this.velocityScalar
123
+ );
124
+
125
+ if (this.data.enableAngularVelocity) {
126
+ // console.log("setting angularVelocity", this.angularVelocity);
127
+ body.angularVelocity.set(
128
+ this.angularVelocity.x * this.angularVelocityScalar,
129
+ this.angularVelocity.y * this.angularVelocityScalar,
130
+ this.angularVelocity.z * this.angularVelocityScalar
131
+ );
132
+ }
133
+
134
+ this.el.emit("toss", {
135
+ velocity: body.velocity.clone(),
136
+ angularVelocity: body.angularVelocity.clone(),
137
+ });
138
+ }, 1);
139
+ } else {
140
+ console.error("body not found");
141
+ }
142
+ },
143
+
144
+ getAngularVelocityFromQuaternions: function (q1, q2, deltaTime) {
145
+ const invQ1 = q1.clone().invert();
146
+ const deltaQ = q2.clone().multiply(invQ1);
147
+
148
+ // Convert delta quaternion to axis-angle
149
+ const axis = new THREE.Vector3();
150
+ let angle = 2 * Math.acos(deltaQ.w);
151
+
152
+ if (angle > Math.PI) {
153
+ angle -= 2 * Math.PI;
154
+ }
155
+
156
+ const s = Math.sqrt(1 - deltaQ.w * deltaQ.w);
157
+ if (s < 0.001) {
158
+ axis.set(1, 0, 0); // arbitrary
159
+ } else {
160
+ axis.set(deltaQ.x / s, deltaQ.y / s, deltaQ.z / s);
161
+ }
162
+
163
+ // Angular velocity = axis * angle / deltaTime
164
+ const angularVelocity = axis.multiplyScalar(angle / deltaTime);
165
+
166
+ return angularVelocity;
167
+ },
168
+
169
+ tick: function (time, delta) {
170
+ if (!this.isGrabbed) return;
171
+
172
+ // Track recent positions (with timestamp)
173
+ const pos = new THREE.Vector3();
174
+ this.el.object3D.getWorldPosition(pos);
175
+ this.positionHistory.push({ pos, time });
176
+
177
+ // Keep only recent entries (e.g. last 100ms or 10 positions)
178
+ while (this.positionHistory.length > 10) {
179
+ this.positionHistory.shift();
180
+ }
181
+
182
+ const rot = new THREE.Quaternion();
183
+ this.el.object3D.getWorldQuaternion(rot);
184
+ this.rotationHistory.push({ rot, time });
185
+
186
+ while (this.rotationHistory.length > 10) {
187
+ this.rotationHistory.shift();
188
+ }
189
+ },
190
+ });
@@ -0,0 +1,25 @@
1
+ AFRAME.registerComponent("grow-shrink", {
2
+ schema: {
3
+ duration: { type: "number", default: 200 }, // ms
4
+ targetScale: { type: "vec3", default: { x: 1, y: 1, z: 1 } },
5
+ },
6
+
7
+ init() {
8
+ this.el.addEventListener("grow", () => {
9
+ this.animateScale(this.data.targetScale, undefined, "easeOutBack");
10
+ });
11
+ this.el.addEventListener("shrink", () => {
12
+ this.animateScale({ x: 0, y: 0, z: 0 });
13
+ });
14
+ },
15
+
16
+ animateScale(to, duration, easing = "easeInOutQuad") {
17
+ this.el.removeAttribute("animation__scale"); // clear existing animation if any
18
+ this.el.setAttribute("animation__scale", {
19
+ property: "scale",
20
+ to: `${to.x} ${to.y} ${to.z}`,
21
+ dur: duration || this.data.duration,
22
+ easing,
23
+ });
24
+ },
25
+ });
@@ -0,0 +1,119 @@
1
+ import * as BS from "../../../build/brilliantsole.module.js";
2
+
3
+ AFRAME.registerComponent("hand-punch", {
4
+ schema: {
5
+ punchable: { default: ".punchable" },
6
+ velocityThreshold: { default: 1.2 },
7
+ velocityScalar: { default: 1 },
8
+ punchTimeout: { default: 50 },
9
+ },
10
+
11
+ dependencies: [
12
+ "hand-tracking-controls",
13
+ "hand-tracking-grab-controls",
14
+ "obb-collider",
15
+ ],
16
+
17
+ init() {
18
+ this.hand = this.el.components["hand-tracking-controls"];
19
+ this.side = this.hand.data.hand;
20
+
21
+ this.lastTimePunched = 0;
22
+ this.positionHistory = [];
23
+
24
+ if (true) {
25
+ this.collider = document.createElement("a-box");
26
+ this.collider.setAttribute("visible", "false");
27
+
28
+ let trackedObject3DVariable;
29
+ if (this.side === "right") {
30
+ trackedObject3DVariable =
31
+ "parentEl.components.hand-tracking-controls.bones.11";
32
+ } else {
33
+ trackedObject3DVariable =
34
+ "parentEl.components.hand-tracking-controls.bones.13";
35
+ }
36
+
37
+ this.collider.addEventListener("loaded", () => {
38
+ this.collider.setAttribute("obb-collider", {
39
+ trackedObject3D: trackedObject3DVariable,
40
+ size: 0.12,
41
+ });
42
+ });
43
+
44
+ this.el.appendChild(this.collider);
45
+ } else {
46
+ this.collider = this.el;
47
+ }
48
+ this.onCollisionStarted = this.onCollisionStarted.bind(this);
49
+ this.onCollisionEnded = this.onCollisionEnded.bind(this);
50
+ this.collider.addEventListener(
51
+ "obbcollisionstarted",
52
+ this.onCollisionStarted
53
+ );
54
+ this.collider.addEventListener("obbcollisionended", this.onCollisionEnded);
55
+ },
56
+
57
+ onCollisionStarted: function (event) {
58
+ // console.log(this, event);
59
+ const now = Date.now();
60
+ if (now - this.lastTimePunched < this.data.punchTimeout) {
61
+ //return;
62
+ }
63
+ this.lastTimePunched = now;
64
+ const { withEl, trackedObject3D } = event.detail;
65
+ if (!trackedObject3D) {
66
+ return;
67
+ }
68
+ const position = trackedObject3D.position.clone();
69
+ if (withEl.classList.contains("punchable")) {
70
+ // Compute velocity from position history
71
+ const velocity = new THREE.Vector3();
72
+ const history = this.positionHistory;
73
+ if (history.length >= 2) {
74
+ const first = history[0];
75
+ const last = history[history.length - 1];
76
+ const dt = (last.time - first.time) / 1000;
77
+ if (dt > 0) {
78
+ velocity.copy(last.pos).sub(first.pos).divideScalar(dt);
79
+ }
80
+ }
81
+
82
+ velocity.multiplyScalar(this.data.velocityScalar);
83
+
84
+ const length = velocity.length();
85
+ if (length < this.data.velocityThreshold) {
86
+ return;
87
+ }
88
+
89
+ withEl.emit("punch", { velocity, position });
90
+
91
+ /** @type {BS.VibrationWaveformEffect} */
92
+ let waveformEffect = "strongClick100";
93
+ this.el.sceneEl.emit("bs-trigger-vibration", {
94
+ side: this.side,
95
+ type: "glove",
96
+ waveformEffect,
97
+ });
98
+ }
99
+ },
100
+
101
+ onCollisionEnded: function () {},
102
+
103
+ tick: function (time, delta) {
104
+ const object = this.collider.object3D;
105
+ if (!object) {
106
+ return;
107
+ }
108
+ // Track recent positions (with timestamp)
109
+
110
+ const pos = new THREE.Vector3();
111
+ object.getWorldPosition(pos);
112
+ this.positionHistory.push({ pos, time });
113
+
114
+ // Keep only recent entries (e.g. last 100ms or 10 positions)
115
+ while (this.positionHistory.length > 10) {
116
+ this.positionHistory.shift();
117
+ }
118
+ },
119
+ });