diff --git a/.eslintrc.js b/.eslintrc.js
index b4d88777f2..535abb807e 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -54,7 +54,8 @@ module.exports = {
"Window": false,
"XMLHttpRequest": false,
"location": false,
- "print": false
+ "print": false,
+ "module": false
},
"rules": {
"brace-style": ["error", "1tbs", { "allowSingleLine": false }],
diff --git a/interface/resources/icons/tablet-icons/clap-a.svg b/interface/resources/icons/tablet-icons/clap-a.svg
new file mode 100644
index 0000000000..10a8e3ea98
--- /dev/null
+++ b/interface/resources/icons/tablet-icons/clap-a.svg
@@ -0,0 +1,104 @@
+
+
+
+
diff --git a/interface/resources/icons/tablet-icons/clap-i.svg b/interface/resources/icons/tablet-icons/clap-i.svg
new file mode 100644
index 0000000000..3e4ecb0b64
--- /dev/null
+++ b/interface/resources/icons/tablet-icons/clap-i.svg
@@ -0,0 +1,104 @@
+
+
+
+
diff --git a/unpublishedScripts/marketplace/clap/animations/ClapAnimation.json b/unpublishedScripts/marketplace/clap/animations/ClapAnimation.json
new file mode 100644
index 0000000000..2dca45a0de
--- /dev/null
+++ b/unpublishedScripts/marketplace/clap/animations/ClapAnimation.json
@@ -0,0 +1,386 @@
+{
+ "RightShoulder": {
+ "rotations": {
+ "x": 0.5578474402427673,
+ "y": -0.44214877486228943,
+ "z": 0.4979960322380066,
+ "w": 0.4952884614467621
+ }
+ },
+ "RightArm": {
+ "rotations": {
+ "x": 0.6266362071037292,
+ "y": -0.02882515825331211,
+ "z": -0.3233867585659027,
+ "w": 0.7084611654281616
+ }
+ },
+ "RightForeArm": {
+ "rotations": {
+ "x": 0.00004018074105260894,
+ "y": 0.06418406218290329,
+ "z": -0.5193823575973511,
+ "w": 0.8521281480789185
+ }
+ },
+ "RightHand": {
+ "rotations": {
+ "x": -0.21368850767612457,
+ "y": 0.02043931558728218,
+ "z": -0.02227853797376156,
+ "w": 0.9764339923858643
+ }
+ },
+ "RightHandPinky1": {
+ "rotations": {
+ "x": -0.003497191471979022,
+ "y": -0.01721140556037426,
+ "z": 0.19736060500144958,
+ "w": 0.980173647403717
+ }
+ },
+ "RightHandPinky2": {
+ "rotations": {
+ "x": 0.000005483317181642633,
+ "y": -0.00008023700502235442,
+ "z": -0.06867633014917374,
+ "w": 0.997639000415802
+ }
+ },
+ "RightHandPinky3": {
+ "rotations": {
+ "x": 7.18885644346301e-8,
+ "y": -2.7131383717460267e-7,
+ "z": 0.007620905060321093,
+ "w": 0.9999709725379944
+ }
+ },
+ "RightHandPinky4": {
+ "rotations": {
+ "x": -5.719068774112657e-9,
+ "y": 5.142213126418937e-7,
+ "z": -0.0075718737207353115,
+ "w": 0.999971330165863
+ }
+ },
+ "RightHandRing1": {
+ "rotations": {
+ "x": -0.0013452530838549137,
+ "y": -0.017564140260219574,
+ "z": 0.0761696845293045,
+ "w": 0.9969393610954285
+ }
+ },
+ "RightHandRing2": {
+ "rotations": {
+ "x": 0.0000010375651982030831,
+ "y": -0.00002211921673733741,
+ "z": -0.04599710553884506,
+ "w": 0.9989416003227234
+ }
+ },
+ "RightHandRing3": {
+ "rotations": {
+ "x": -2.7102969868408877e-10,
+ "y": 1.9202734335976857e-7,
+ "z": 0.0016911650309339166,
+ "w": 0.9999985694885254
+ }
+ },
+ "RightHandRing4": {
+ "rotations": {
+ "x": 2.3246689018208144e-9,
+ "y": -3.364403156069784e-8,
+ "z": 0.0004951066803187132,
+ "w": 0.9999998807907104
+ }
+ },
+ "RightHandMiddle1": {
+ "rotations": {
+ "x": 0.0012630893616005778,
+ "y": -0.017612185329198837,
+ "z": -0.07168931514024734,
+ "w": 0.9972707033157349
+ }
+ },
+ "RightHandMiddle2": {
+ "rotations": {
+ "x": 2.3561028683616314e-7,
+ "y": 0.000020313073036959395,
+ "z": 0.011195243336260319,
+ "w": 0.9999373555183411
+ }
+ },
+ "RightHandMiddle3": {
+ "rotations": {
+ "x": 6.375214667286855e-8,
+ "y": 4.750924631480302e-7,
+ "z": 0.00237679248675704,
+ "w": 0.9999971985816956
+ }
+ },
+ "RightHandMiddle4": {
+ "rotations": {
+ "x": 6.717256439969788e-8,
+ "y": 3.876683507542111e-8,
+ "z": -0.005236906465142965,
+ "w": 0.9999862909317017
+ }
+ },
+ "RightHandIndex1": {
+ "rotations": {
+ "x": 0.002164300065487623,
+ "y": -0.017346171662211418,
+ "z": -0.12158434838056564,
+ "w": 0.9924271702766418
+ }
+ },
+ "RightHandIndex2": {
+ "rotations": {
+ "x": -0.00000143755482895358,
+ "y": -0.0001614764187252149,
+ "z": 0.008941099047660828,
+ "w": 0.9999601244926453
+ }
+ },
+ "RightHandIndex3": {
+ "rotations": {
+ "x": 7.458467621290765e-8,
+ "y": 5.365728839024086e-7,
+ "z": 0.03373909369111061,
+ "w": 0.999430775642395
+ }
+ },
+ "RightHandIndex4": {
+ "rotations": {
+ "x": 4.511302997833866e-10,
+ "y": -2.259726272768603e-7,
+ "z": -0.009632252156734467,
+ "w": 0.9999536275863647
+ }
+ },
+ "RightHandThumb1": {
+ "rotations": {
+ "x": -0.0783928632736206,
+ "y": -0.3033908009529114,
+ "z": -0.26653754711151123,
+ "w": 0.9114638566970825
+ }
+ },
+ "RightHandThumb2": {
+ "rotations": {
+ "x": 0.0031029442325234413,
+ "y": 0.07382386922836304,
+ "z": 0.005253761075437069,
+ "w": 0.9972526431083679
+ }
+ },
+ "RightHandThumb3": {
+ "rotations": {
+ "x": 0.0040440745651721954,
+ "y": -0.04943573474884033,
+ "z": 0.007246015593409538,
+ "w": 0.9987428188323975
+ }
+ },
+ "RightHandThumb4": {
+ "rotations": {
+ "x": -0.00009280416270485148,
+ "y": -0.01658034883439541,
+ "z": -0.00014316302258521318,
+ "w": 0.999862551689148
+ }
+ },
+ "LeftShoulder": {
+ "rotations": {
+ "x": 0.5578474402427673,
+ "y": 0.44214877486228943,
+ "z": -0.4979960322380066,
+ "w": 0.4952884614467621
+ }
+ },
+ "LeftArm": {
+ "rotations": {
+ "x": 0.626636266708374,
+ "y": 0.028824958950281143,
+ "z": 0.3233867585659027,
+ "w": 0.7084611654281616
+ }
+ },
+ "LeftForeArm": {
+ "rotations": {
+ "x": 0.00004015670492663048,
+ "y": -0.06418408453464508,
+ "z": 0.5193824768066406,
+ "w": 0.8521282076835632
+ }
+ },
+ "LeftHand": {
+ "rotations": {
+ "x": -0.21368853747844696,
+ "y": -0.02043931558728218,
+ "z": 0.02227853797376156,
+ "w": 0.9764339923858643
+ }
+ },
+ "LeftHandPinky1": {
+ "rotations": {
+ "x": -0.003497188910841942,
+ "y": 0.01721140556037426,
+ "z": -0.19736060500144958,
+ "w": 0.980173647403717
+ }
+ },
+ "LeftHandPinky2": {
+ "rotations": {
+ "x": 0.000005479304491018411,
+ "y": 0.00008023556438274682,
+ "z": 0.06867631524801254,
+ "w": 0.997639000415802
+ }
+ },
+ "LeftHandPinky3": {
+ "rotations": {
+ "x": 7.229602516645173e-8,
+ "y": 2.709063835482084e-7,
+ "z": -0.007620909716933966,
+ "w": 0.9999709725379944
+ }
+ },
+ "LeftHandPinky4": {
+ "rotations": {
+ "x": -5.52988677071653e-9,
+ "y": -5.13755651354586e-7,
+ "z": 0.007571868598461151,
+ "w": 0.999971330165863
+ }
+ },
+ "LeftHandRing1": {
+ "rotations": {
+ "x": -0.001345252152532339,
+ "y": 0.017564138397574425,
+ "z": -0.0761696845293045,
+ "w": 0.9969393610954285
+ }
+ },
+ "LeftHandRing2": {
+ "rotations": {
+ "x": 0.000001034482806971937,
+ "y": 0.000022119218556326814,
+ "z": 0.04599710553884506,
+ "w": 0.9989416003227234
+ }
+ },
+ "LeftHandRing3": {
+ "rotations": {
+ "x": -2.8012464570181805e-10,
+ "y": -1.923183816643359e-7,
+ "z": -0.0016911652637645602,
+ "w": 0.9999985694885254
+ }
+ },
+ "LeftHandRing4": {
+ "rotations": {
+ "x": -1.1168596047994583e-9,
+ "y": 3.33529932561305e-8,
+ "z": -0.0004951058072037995,
+ "w": 0.9999998807907104
+ }
+ },
+ "LeftHandMiddle1": {
+ "rotations": {
+ "x": 0.0012630895944312215,
+ "y": 0.01761218160390854,
+ "z": 0.07168931514024734,
+ "w": 0.9972707033157349
+ }
+ },
+ "LeftHandMiddle2": {
+ "rotations": {
+ "x": 2.37378529277521e-7,
+ "y": -0.00002031277836067602,
+ "z": -0.011195233091711998,
+ "w": 0.9999373555183411
+ }
+ },
+ "LeftHandMiddle3": {
+ "rotations": {
+ "x": 7.146466884933034e-8,
+ "y": -4.7555812443533796e-7,
+ "z": -0.0023767934180796146,
+ "w": 0.9999971985816956
+ }
+ },
+ "LeftHandMiddle4": {
+ "rotations": {
+ "x": 6.549178976911207e-8,
+ "y": -3.865041975359418e-8,
+ "z": 0.005236904136836529,
+ "w": 0.9999862909317017
+ }
+ },
+ "LeftHandIndex1": {
+ "rotations": {
+ "x": 0.002164299599826336,
+ "y": 0.017346171662211418,
+ "z": 0.12158433347940445,
+ "w": 0.9924271702766418
+ }
+ },
+ "LeftHandIndex2": {
+ "rotations": {
+ "x": -0.000001437780269952782,
+ "y": 0.00016147761198226362,
+ "z": -0.008941099047660828,
+ "w": 0.9999601244926453
+ }
+ },
+ "LeftHandIndex3": {
+ "rotations": {
+ "x": 7.61426193207626e-8,
+ "y": -5.373883027459669e-7,
+ "z": -0.03373908996582031,
+ "w": 0.999430775642395
+ }
+ },
+ "LeftHandIndex4": {
+ "rotations": {
+ "x": -5.311697748311417e-10,
+ "y": 2.26380109324964e-7,
+ "z": 0.009632255882024765,
+ "w": 0.9999536275863647
+ }
+ },
+ "LeftHandThumb1": {
+ "rotations": {
+ "x": -0.07839284837245941,
+ "y": 0.3033908009529114,
+ "z": 0.26653754711151123,
+ "w": 0.9114638566970825
+ }
+ },
+ "LeftHandThumb2": {
+ "rotations": {
+ "x": 0.0031029372476041317,
+ "y": -0.07382386922836304,
+ "z": -0.005253763869404793,
+ "w": 0.9972526431083679
+ }
+ },
+ "LeftHandThumb3": {
+ "rotations": {
+ "x": 0.004044072702527046,
+ "y": 0.049435727298259735,
+ "z": -0.0072460174560546875,
+ "w": 0.9987428188323975
+ }
+ },
+ "LeftHandThumb4": {
+ "rotations": {
+ "x": -0.00009280881931772456,
+ "y": 0.016580356284976006,
+ "z": 0.00014314628788270056,
+ "w": 0.999862551689148
+ }
+ }
+}
diff --git a/unpublishedScripts/marketplace/clap/animations/Clap_left.fbx b/unpublishedScripts/marketplace/clap/animations/Clap_left.fbx
new file mode 100644
index 0000000000..a3830b9838
Binary files /dev/null and b/unpublishedScripts/marketplace/clap/animations/Clap_left.fbx differ
diff --git a/unpublishedScripts/marketplace/clap/animations/Clap_right.fbx b/unpublishedScripts/marketplace/clap/animations/Clap_right.fbx
new file mode 100644
index 0000000000..1877e963f9
Binary files /dev/null and b/unpublishedScripts/marketplace/clap/animations/Clap_right.fbx differ
diff --git a/unpublishedScripts/marketplace/clap/clapApp.js b/unpublishedScripts/marketplace/clap/clapApp.js
new file mode 100644
index 0000000000..a32937d6dd
--- /dev/null
+++ b/unpublishedScripts/marketplace/clap/clapApp.js
@@ -0,0 +1,56 @@
+"use strict";
+
+/*
+ clapApp.js
+ unpublishedScripts/marketplace/clap/clapApp.js
+
+ Created by Matti 'Menithal' Lahtinen on 9/11/2017
+ Copyright 2017 High Fidelity, Inc.
+
+ Distributed under the Apache License, Version 2.0.
+ See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+*/
+
+// Entry Script for the clap app
+
+// Load up engine
+var APP_NAME = "CLAP";
+var ClapEngine = Script.require(Script.resolvePath("scripts/ClapEngine.js?v6"));
+var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
+
+// Define Menu
+var blackIcon = Script.resolvePath("icons/tablet-icons/clap-a.svg");
+var whiteIcon =Script.resolvePath("icons/tablet-icons/clap-i.svg");
+var isActive = true;
+
+var activeButton = tablet.addButton({
+ icon: whiteIcon,
+ activeIcon: blackIcon,
+ text: APP_NAME,
+ isActive: isActive,
+ sortOrder: 11
+});
+
+if (isActive) {
+ ClapEngine.connectEngine();
+}
+
+function onClick(enabled) {
+
+ isActive = !isActive;
+ activeButton.editProperties({
+ isActive: isActive
+ });
+ if (isActive) {
+ ClapEngine.connectEngine();
+ } else {
+ ClapEngine.disconnectEngine();
+ }
+}
+activeButton.clicked.connect(onClick);
+
+Script.scriptEnding.connect(function () {
+ ClapEngine.disconnectEngine();
+ activeButton.clicked.disconnect(onClick);
+ tablet.removeButton(activeButton);
+});
diff --git a/unpublishedScripts/marketplace/clap/entities/ClapParticle.json b/unpublishedScripts/marketplace/clap/entities/ClapParticle.json
new file mode 100644
index 0000000000..bf1b70665b
--- /dev/null
+++ b/unpublishedScripts/marketplace/clap/entities/ClapParticle.json
@@ -0,0 +1,58 @@
+{
+ "alpha": 0.01,
+ "alphaFinish": 0.0,
+ "alphaSpread": 1,
+ "alphaStart": 0.05,
+ "color": {
+ "blue": 200,
+ "green": 200,
+ "red": 200
+ },
+ "colorFinish": {
+ "blue": 200,
+ "green": 200,
+ "red": 200
+ },
+ "colorStart": {
+ "blue": 200,
+ "green": 200,
+ "red": 200
+ },
+ "created": "2017-09-09T16:01:38Z",
+ "dimensions": {
+ "x": 0.5,
+ "y": 0.5,
+ "z": 0.5
+ },
+ "emitAcceleration": {
+ "x": 0,
+ "y": 0,
+ "z": 0
+ },
+ "emitDimensions": {
+ "x": 0.25,
+ "y": 0.25,
+ "z": 0.25
+ },
+ "emitOrientation": {
+ "w": 1,
+ "x": 0,
+ "y": 0,
+ "z": 0
+ },
+ "emitRate": 100,
+ "emitSpeed": 0.125,
+ "lifespan": 0.5,
+ "lifetime": 2,
+ "script": "(function(){return{preload:function(id){Script.setTimeout(function(){Entities.editEntity(id,{isEmitting:false});},200);}}})",
+ "maxParticles": 100,
+ "particleRadius": 0.05,
+ "polarFinish": 1.4311699867248535,
+ "polarStart": 1.3962633609771729,
+ "radiusFinish": 0.01,
+ "radiusSpread": 0.2,
+ "radiusStart": 0.05,
+ "speedSpread": 0,
+ "emitShouldTrail": true,
+ "type": "ParticleEffect"
+}
diff --git a/unpublishedScripts/marketplace/clap/icons/clap-black-icon.svg b/unpublishedScripts/marketplace/clap/icons/clap-black-icon.svg
new file mode 100644
index 0000000000..10a8e3ea98
--- /dev/null
+++ b/unpublishedScripts/marketplace/clap/icons/clap-black-icon.svg
@@ -0,0 +1,104 @@
+
+
+
+
diff --git a/unpublishedScripts/marketplace/clap/icons/clap-white-icon.svg b/unpublishedScripts/marketplace/clap/icons/clap-white-icon.svg
new file mode 100644
index 0000000000..3e4ecb0b64
--- /dev/null
+++ b/unpublishedScripts/marketplace/clap/icons/clap-white-icon.svg
@@ -0,0 +1,104 @@
+
+
+
+
diff --git a/unpublishedScripts/marketplace/clap/scripts/ClapDebugger.js b/unpublishedScripts/marketplace/clap/scripts/ClapDebugger.js
new file mode 100644
index 0000000000..247664c157
--- /dev/null
+++ b/unpublishedScripts/marketplace/clap/scripts/ClapDebugger.js
@@ -0,0 +1,165 @@
+"use strict";
+
+/*
+ clapApp.js
+ unpublishedScripts/marketplace/clap/scripts/clapDebugger.js
+
+ Created by Matti 'Menithal' Lahtinen on 9/11/2017
+ Copyright 2017 High Fidelity, Inc.
+
+ Distributed under the Apache License, Version 2.0.
+ See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+*/
+
+var DEBUG_RIGHT_HAND;
+var DEBUG_LEFT_HAND;
+var DEBUG_CLAP_LEFT;
+var DEBUG_CLAP_RIGHT;
+var DEBUG_CLAP;
+var DEBUG_CLAP_DIRECTION;
+
+// Debug Values:
+var DEBUG_CORRECT = {
+ red: 0,
+ green: 255,
+ blue: 0
+};
+var DEBUG_WRONG = {
+ red: 255,
+ green: 0,
+ blue: 0
+};
+
+var DEBUG_VOLUME = {
+ red: 255,
+ green: 255,
+ blue: 128
+};
+
+module.exports = {
+ disableDebug: function () {
+ Overlays.deleteOverlay(DEBUG_RIGHT_HAND);
+ Overlays.deleteOverlay(DEBUG_LEFT_HAND);
+ Overlays.deleteOverlay(DEBUG_CLAP_LEFT);
+ Overlays.deleteOverlay(DEBUG_CLAP_RIGHT);
+ Overlays.deleteOverlay(DEBUG_CLAP);
+ Overlays.deleteOverlay(DEBUG_CLAP_DIRECTION);
+ },
+
+ debugPositions: function (leftAlignmentWorld, leftHandPositionOffset, leftHandDownWorld, rightAlignmentWorld, rightHandPositionOffset, rightHandDownWorld, tolerance) {
+
+ Overlays.editOverlay(DEBUG_CLAP_LEFT, {
+ color: leftAlignmentWorld > tolerance ? DEBUG_CORRECT : DEBUG_WRONG,
+ position: leftHandPositionOffset
+ });
+
+ Overlays.editOverlay(DEBUG_CLAP_RIGHT, {
+ color: rightAlignmentWorld > tolerance ? DEBUG_CORRECT : DEBUG_WRONG,
+ position: rightHandPositionOffset
+ });
+
+ Overlays.editOverlay(DEBUG_LEFT_HAND, {
+ color: leftAlignmentWorld > tolerance ? DEBUG_CORRECT : DEBUG_WRONG,
+ start: leftHandPositionOffset,
+ end: Vec3.sum(leftHandPositionOffset, Vec3.multiply(leftHandDownWorld, 0.2))
+ });
+
+ Overlays.editOverlay(DEBUG_RIGHT_HAND, {
+ color: rightAlignmentWorld > tolerance ? DEBUG_CORRECT : DEBUG_WRONG,
+ start: rightHandPositionOffset,
+ end: Vec3.sum(rightHandPositionOffset, Vec3.multiply(rightHandDownWorld, 0.2))
+ });
+ },
+
+ debugClapLine: function (start, end, visible) {
+ Overlays.editOverlay(DEBUG_CLAP_DIRECTION, {
+ start: start,
+ end: end,
+ visible: visible
+ });
+ },
+
+ clapSphere: function (pos, vol) {
+ Overlays.editOverlay(DEBUG_CLAP, {
+ position: pos,
+ scale: {
+ x: vol,
+ y: vol,
+ z: vol
+ }
+ });
+ },
+
+ enableDebug: function () {
+ DEBUG_RIGHT_HAND = Overlays.addOverlay("line3d", {
+ color: DEBUG_WRONG,
+ start: MyAvatar.position,
+ end: Vec3.sum(MyAvatar.position, {
+ x: 0,
+ y: 1,
+ z: 0
+ }),
+ dimensions: {
+ x: 2,
+ y: 2,
+ z: 2
+ }
+ });
+
+ DEBUG_LEFT_HAND = Overlays.addOverlay("line3d", {
+ color: DEBUG_WRONG,
+ start: MyAvatar.position,
+ end: Vec3.sum(MyAvatar.position, {
+ x: 0,
+ y: 1,
+ z: 0
+ }),
+ dimensions: {
+ x: 2,
+ y: 2,
+ z: 2
+ }
+ });
+
+ DEBUG_CLAP_LEFT = Overlays.addOverlay("sphere", {
+ position: MyAvatar.position,
+ color: DEBUG_WRONG,
+ scale: {
+ x: 0.05,
+ y: 0.05,
+ z: 0.05
+ }
+ });
+
+ DEBUG_CLAP_RIGHT = Overlays.addOverlay("sphere", {
+ position: MyAvatar.position,
+ color: DEBUG_WRONG,
+ scale: {
+ x: 0.05,
+ y: 0.05,
+ z: 0.05
+ }
+ });
+
+ DEBUG_CLAP = Overlays.addOverlay("sphere", {
+ position: MyAvatar.position,
+ color: DEBUG_VOLUME,
+ scale: {
+ x: 0.05,
+ y: 0.05,
+ z: 0.05
+ }
+ });
+
+ DEBUG_CLAP_DIRECTION = Overlays.addOverlay("line3d", {
+ color: DEBUG_VOLUME,
+ start: MyAvatar.position,
+ end: MyAvatar.position,
+ dimensions: {
+ x: 2,
+ y: 2,
+ z: 2
+ }
+ });
+ }
+};
diff --git a/unpublishedScripts/marketplace/clap/scripts/ClapEngine.js b/unpublishedScripts/marketplace/clap/scripts/ClapEngine.js
new file mode 100644
index 0000000000..f36aa9716b
--- /dev/null
+++ b/unpublishedScripts/marketplace/clap/scripts/ClapEngine.js
@@ -0,0 +1,318 @@
+"use strict";
+
+/*
+ clapEngine.js
+ unpublishedScripts/marketplace/clap/clapApp.js
+
+ Created by Matti 'Menithal' Lahtinen on 9/11/2017
+ Copyright 2017 High Fidelity, Inc.
+
+ Distributed under the Apache License, Version 2.0.
+ See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+
+
+ Main Heart of the clap script> Does both keyboard binding and tracking of the gear..
+
+*/
+var DEG_TO_RAD = Math.PI / 180;
+// If angle is closer to 0 from 25 degrees, then "clap" can happen;
+var COS_OF_TOLERANCE = Math.cos(25 * DEG_TO_RAD);
+
+var CONTROL_MAP_PACKAGE = "com.highfidelity.avatar.clap.active";
+
+var CLAP_MENU = "Clap";
+var ENABLE_PARTICLE_MENU = "Enable Clap Particles";
+var ENABLE_DEBUG_MENU = "Enable Clap Debug";
+
+var sounds = [
+ "clap1.wav",
+ "clap2.wav",
+ "clap3.wav",
+ "clap4.wav",
+ "clap5.wav",
+ "clap6.wav"
+];
+
+
+var ClapParticle = Script.require(Script.resolvePath("../entities/ClapParticle.json?V2"));
+var ClapAnimation = Script.require(Script.resolvePath("../animations/ClapAnimation.json?V2"));
+var ClapDebugger = Script.require(Script.resolvePath("ClapDebugger.js?V2"));
+
+var settingDebug = false;
+var settingParticlesOn = true;
+
+function setJointRotation(map) {
+ Object.keys(map).forEach(function (key, index) {
+ MyAvatar.setJointRotation(MyAvatar.getJointIndex(key), map[key].rotations);
+ });
+}
+// Load Sounds to Cache
+var cache = [];
+for (var index in sounds) {
+ cache.push(SoundCache.getSound(Script.resolvePath("../sounds/" + sounds[index])));
+}
+
+
+var previousIndex;
+var clapOn = false;
+var animClap = false;
+var animThrottle;
+
+function clap(volume, position, rotation) {
+ var index;
+ // Make sure one does not generate consequtive sounds
+ do {
+ index = Math.floor(Math.random() * cache.length);
+ } while (index === previousIndex);
+
+ previousIndex = index;
+
+ Audio.playSound(cache[index], {
+ position: position,
+ volume: volume / 4 + Math.random() * (volume / 3)
+ });
+
+ if (settingParticlesOn) {
+ ClapParticle.orientation = Quat.multiply(MyAvatar.orientation, rotation);
+ ClapParticle.position = position;
+ ClapParticle.emitSpeed = volume > 1 ? 1 : volume;
+ Entities.addEntity(ClapParticle, true);
+ }
+
+
+ if (settingDebug) {
+ ClapDebugger.clapSphere(position, volume);
+ }
+
+}
+// Helper Functions
+function getHandFingerAnim(side) {
+ return Script.resolvePath("../animations/Clap_" + side + '.fbx');
+}
+
+// Disable all role animations related to fingers for side
+function overrideFingerRoleAnimation(side) {
+ var anim = getHandFingerAnim(side);
+ MyAvatar.overrideRoleAnimation(side + "HandGraspOpen", anim, 30, true, 0, 0);
+ MyAvatar.overrideRoleAnimation(side + "HandGraspClosed", anim, 30, true, 0, 0);
+ if (HMD.active) {
+ MyAvatar.overrideRoleAnimation(side + "HandPointIntro", anim, 30, true, 0, 0);
+ MyAvatar.overrideRoleAnimation(side + "HandPointHold", anim, 30, true, 0, 0);
+ MyAvatar.overrideRoleAnimation(side + "HandPointOutro", anim, 30, true, 0, 0);
+
+ MyAvatar.overrideRoleAnimation(side + "IndexPointOpen", anim, 30, true, 0, 0);
+ MyAvatar.overrideRoleAnimation(side + "IndexPointClosed", anim, 30, true, 0, 0);
+ MyAvatar.overrideRoleAnimation(side + "IndexPointAndThumbRaiseOpen", anim, 30, true, 0, 0);
+ MyAvatar.overrideRoleAnimation(side + "IndexPointAndThumbRaiseClosed", anim, 30, true, 0, 0);
+
+ MyAvatar.overrideRoleAnimation(side + "ThumbRaiseOpen", anim, 30, true, 0, 0);
+ MyAvatar.overrideRoleAnimation(side + "ThumbRaiseClosed", anim, 30, true, 0, 0);
+ }
+}
+// Re-enable all role animations for fingers
+function restoreFingerRoleAnimation(side) {
+ MyAvatar.restoreRoleAnimation(side + "HandGraspOpen");
+ MyAvatar.restoreRoleAnimation(side + "HandGraspClosed");
+ if (HMD.active) {
+ MyAvatar.restoreRoleAnimation(side + "HandPointIntro");
+ MyAvatar.restoreRoleAnimation(side + "HandPointHold");
+ MyAvatar.restoreRoleAnimation(side + "HandPointOutro");
+ MyAvatar.restoreRoleAnimation(side + "IndexPointOpen");
+
+ MyAvatar.restoreRoleAnimation(side + "IndexPointClosed");
+ MyAvatar.restoreRoleAnimation(side + "IndexPointAndThumbRaiseOpen");
+ MyAvatar.restoreRoleAnimation(side + "IndexPointAndThumbRaiseClosed");
+ MyAvatar.restoreRoleAnimation(side + "ThumbRaiseOpen");
+ MyAvatar.restoreRoleAnimation(side + "ThumbRaiseClosed");
+ }
+}
+
+
+function menuListener(menuItem) {
+ if (menuItem === ENABLE_PARTICLE_MENU) {
+ settingParticlesOn = Menu.isOptionChecked(ENABLE_PARTICLE_MENU);
+ } else if (menuItem === ENABLE_DEBUG_MENU) {
+ var debugOn = Menu.isOptionChecked(ENABLE_DEBUG_MENU);
+
+ if (debugOn) {
+ settingDebug = true;
+ ClapDebugger.enableDebug();
+ } else {
+ settingDebug = false;
+ ClapDebugger.disableDebug();
+ }
+ }
+}
+
+function update(dt) {
+
+ // NOTICE: Someof this stuff is unnessary for the actual: But they are done for Debug Purposes!
+ // Forexample, the controller doesnt really need to know where it is in the world, only its relation to the other controller!
+
+ var leftHand = Controller.getPoseValue(Controller.Standard.LeftHand);
+ var rightHand = Controller.getPoseValue(Controller.Standard.RightHand);
+
+ // Get Offset position for palms, not the controllers that are at the wrists (7.5 cm up)
+
+ var leftWorldRotation = Quat.multiply(MyAvatar.orientation, leftHand.rotation);
+ var rightWorldRotation = Quat.multiply(MyAvatar.orientation, rightHand.rotation);
+
+ var leftWorldUpNormal = Quat.getUp(leftWorldRotation);
+ var rightWorldUpNormal = Quat.getUp(rightWorldRotation);
+
+ var leftHandDownWorld = Vec3.multiply(-1, Quat.getForward(leftWorldRotation));
+ var rightHandDownWorld = Vec3.multiply(-1, Quat.getForward(rightWorldRotation));
+
+ //
+ var leftHandWorldPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, leftHand.translation));
+ var rightHandWorldPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, rightHand.translation));
+
+ var rightHandPositionOffset = Vec3.sum(rightHandWorldPosition, Vec3.multiply(rightWorldUpNormal, 0.035));
+ var leftHandPositionOffset = Vec3.sum(leftHandWorldPosition, Vec3.multiply(leftWorldUpNormal, 0.035));
+
+ var leftToRightWorld = Vec3.subtract(leftHandPositionOffset, rightHandPositionOffset);
+ var rightToLeftWorld = Vec3.subtract(rightHandPositionOffset, leftHandPositionOffset);
+
+ var leftAlignmentWorld = -1 * Vec3.dot(Vec3.normalize(leftToRightWorld), leftHandDownWorld);
+ var rightAlignmentWorld = -1 * Vec3.dot(Vec3.normalize(rightToLeftWorld), rightHandDownWorld);
+
+ var distance = Vec3.distance(rightHandPositionOffset, leftHandPositionOffset);
+
+ var matchTolerance = leftAlignmentWorld > COS_OF_TOLERANCE && rightAlignmentWorld > COS_OF_TOLERANCE;
+
+ if (settingDebug) {
+ ClapDebugger.debugPositions(leftAlignmentWorld,
+ leftHandPositionOffset, leftHandDownWorld,
+ rightAlignmentWorld, rightHandPositionOffset,
+ rightHandDownWorld, COS_OF_TOLERANCE);
+ }
+ // Using subtract, because these will be heading to opposite directions
+ var angularVelocity = Vec3.length(Vec3.subtract(leftHand.angularVelocity, rightHand.angularVelocity));
+ var velocity = Vec3.length(Vec3.subtract(leftHand.velocity, rightHand.velocity));
+
+ if (matchTolerance && distance < 0.3 && !animClap) {
+ if (settingDebug) {
+ ClapDebugger.debugClapLine(leftHandPositionOffset, rightHandPositionOffset, true);
+ }
+ if (!animThrottle) {
+ overrideFingerRoleAnimation("left");
+ overrideFingerRoleAnimation("right");
+ animClap = true;
+ } else {
+ Script.clearTimeout(animThrottle);
+ animThrottle = false;
+ }
+ } else if (animClap && distance > 0.3) {
+ if (settingDebug) {
+ ClapDebugger.debugClapLine(leftHandPositionOffset, rightHandPositionOffset, false);
+ }
+ animThrottle = Script.setTimeout(function () {
+ restoreFingerRoleAnimation("left");
+ restoreFingerRoleAnimation("right");
+ animClap = false;
+ }, 500);
+ }
+
+ if (distance < 0.22 && matchTolerance && !clapOn) {
+ clapOn = true;
+
+ var midClap = Vec3.mix(rightHandPositionOffset, leftHandPositionOffset, 0.5);
+ var volume = velocity / 2 + angularVelocity / 5;
+
+ clap(volume, midClap, Quat.lookAtSimple(rightHandPositionOffset, leftHandPositionOffset));
+ } else if (distance > 0.22 && !matchTolerance) {
+ clapOn = false;
+ }
+}
+
+
+module.exports = {
+ connectEngine: function () {
+ if (!Menu.menuExists(CLAP_MENU)) {
+ Menu.addMenu(CLAP_MENU);
+ }
+
+ if (!Menu.menuItemExists(CLAP_MENU, ENABLE_PARTICLE_MENU)) {
+ Menu.addMenuItem({
+ menuName: CLAP_MENU,
+ menuItemName: ENABLE_PARTICLE_MENU,
+ isCheckable: true,
+ isChecked: settingParticlesOn
+ });
+ }
+ if (!Menu.menuItemExists(CLAP_MENU, ENABLE_DEBUG_MENU)) {
+ Menu.addMenuItem({
+ menuName: CLAP_MENU,
+ menuItemName: ENABLE_DEBUG_MENU,
+ isCheckable: true,
+ isChecked: settingDebug
+ });
+ }
+
+
+ Menu.menuItemEvent.connect(menuListener);
+
+ var controls = Controller.newMapping(CONTROL_MAP_PACKAGE);
+ var Keyboard = Controller.Hardware.Keyboard;
+
+ controls.from(Keyboard.K).to(function (down) {
+ if (down) {
+
+ setJointRotation(ClapAnimation);
+ Script.setTimeout(function () {
+ // As soon as an animation bug is fixed, this will kick and get fixed.s.
+ overrideFingerRoleAnimation("left");
+ overrideFingerRoleAnimation("right");
+
+ var lh = MyAvatar.getJointPosition("LeftHand");
+ var rh = MyAvatar.getJointPosition("RightHand");
+ var midClap = Vec3.mix(rh, lh, 0.5);
+ var volume = 0.5 + Math.random() * 0.5;
+ var position = midClap;
+
+ clap(volume, position, Quat.fromVec3Degrees(0, 0, 0));
+ }, 50); // delay is present to allow for frames to catch up.
+ } else {
+
+ restoreFingerRoleAnimation("left");
+
+ restoreFingerRoleAnimation("right");
+ MyAvatar.clearJointsData();
+ }
+ });
+ Controller.enableMapping(CONTROL_MAP_PACKAGE);
+
+ // settingDebug STUFF
+ if (settingDebug) {
+ ClapDebugger.enableDebug();
+ }
+
+
+ Script.update.connect(update);
+
+ Script.scriptEnding.connect(this.disconnectEngine);
+ },
+ disconnectEngine: function () {
+ if (settingDebug) {
+ ClapDebugger.disableDebug();
+ }
+ if (Menu.menuItemExists(CLAP_MENU, ENABLE_PARTICLE_MENU)) {
+ Menu.removeMenuItem(CLAP_MENU, ENABLE_PARTICLE_MENU);
+ }
+ if (Menu.menuItemExists(CLAP_MENU, ENABLE_DEBUG_MENU)) {
+ Menu.removeMenuItem(CLAP_MENU, ENABLE_DEBUG_MENU);
+ }
+
+ if (Menu.menuExists(CLAP_MENU)) {
+ Menu.removeMenu(CLAP_MENU);
+ }
+ restoreFingerRoleAnimation('left');
+ restoreFingerRoleAnimation('right');
+ Controller.disableMapping(CONTROL_MAP_PACKAGE);
+ try {
+ Script.update.disconnect(update);
+ } catch (e) {
+ print("Script.update connection did not exist on disconnection. Skipping")
+ }
+ }
+};
diff --git a/unpublishedScripts/marketplace/clap/sounds/clap1.wav b/unpublishedScripts/marketplace/clap/sounds/clap1.wav
new file mode 100644
index 0000000000..679cb7e732
Binary files /dev/null and b/unpublishedScripts/marketplace/clap/sounds/clap1.wav differ
diff --git a/unpublishedScripts/marketplace/clap/sounds/clap2.wav b/unpublishedScripts/marketplace/clap/sounds/clap2.wav
new file mode 100644
index 0000000000..b43c745e52
Binary files /dev/null and b/unpublishedScripts/marketplace/clap/sounds/clap2.wav differ
diff --git a/unpublishedScripts/marketplace/clap/sounds/clap3.wav b/unpublishedScripts/marketplace/clap/sounds/clap3.wav
new file mode 100644
index 0000000000..47a4a8d48f
Binary files /dev/null and b/unpublishedScripts/marketplace/clap/sounds/clap3.wav differ
diff --git a/unpublishedScripts/marketplace/clap/sounds/clap4.wav b/unpublishedScripts/marketplace/clap/sounds/clap4.wav
new file mode 100644
index 0000000000..4e8dfca1a0
Binary files /dev/null and b/unpublishedScripts/marketplace/clap/sounds/clap4.wav differ
diff --git a/unpublishedScripts/marketplace/clap/sounds/clap5.wav b/unpublishedScripts/marketplace/clap/sounds/clap5.wav
new file mode 100644
index 0000000000..1f38864db4
Binary files /dev/null and b/unpublishedScripts/marketplace/clap/sounds/clap5.wav differ
diff --git a/unpublishedScripts/marketplace/clap/sounds/clap6.wav b/unpublishedScripts/marketplace/clap/sounds/clap6.wav
new file mode 100644
index 0000000000..4591f79d9d
Binary files /dev/null and b/unpublishedScripts/marketplace/clap/sounds/clap6.wav differ