janusweb 1.5.42 → 1.5.44

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 (34) hide show
  1. package/CHANGELOG +23 -0
  2. package/css/janusweb.css +7 -2
  3. package/media/assets/webui/apps/buttons/buttons.js +17 -3
  4. package/media/assets/webui/apps/comms/comms.css +1 -1
  5. package/media/assets/webui/apps/comms/comms.js +1 -1
  6. package/media/assets/webui/apps/comms/voip.css +12 -3
  7. package/media/assets/webui/apps/comms/voip.js +16 -6
  8. package/media/assets/webui/apps/editor/editor.css +1 -0
  9. package/media/assets/webui/apps/editor/editor.js +19 -12
  10. package/media/assets/webui/apps/locomotion/teleporter.js +11 -4
  11. package/media/assets/webui/apps/xrmenu/images/audio-settings.png +0 -0
  12. package/media/assets/webui/apps/xrmenu/xrmenu-assets.json +2 -1
  13. package/media/assets/webui/apps/xrmenu/xrmenu.js +142 -40
  14. package/media/assets/webui/themes/default.css +42 -0
  15. package/package.json +2 -2
  16. package/scripts/client.js +12 -1
  17. package/scripts/config.js +1 -1
  18. package/scripts/elements/outliner.js +7 -1
  19. package/scripts/external/JanusClientConnection.js +14 -8
  20. package/scripts/image.js +1 -1
  21. package/scripts/janusbase.js +49 -27
  22. package/scripts/janusghost.js +14 -10
  23. package/scripts/januslight.js +46 -4
  24. package/scripts/janusparticle.js +116 -13
  25. package/scripts/janusplayer.js +97 -22
  26. package/scripts/janusweb.js +18 -5
  27. package/scripts/janusxrplayer.js +117 -17
  28. package/scripts/object.js +75 -31
  29. package/scripts/parts.js +1 -1
  30. package/scripts/portal.js +21 -10
  31. package/scripts/remoteplayer.js +3 -2
  32. package/scripts/room.js +159 -49
  33. package/scripts/text.js +7 -4
  34. package/scripts/websurface.js +3 -3
@@ -426,12 +426,21 @@ ui-tooltip {
426
426
  ui-input {
427
427
  display: flex;
428
428
  }
429
+ ui-input>ui-label {
430
+ min-width: 5em;
431
+ }
429
432
  ui-input>input {
430
433
  flex: 1 1;
434
+ background: #999;
435
+ border: 1px solid black;
436
+ border-radius: 4px;
431
437
  }
438
+ ui-input>input:hover,
432
439
  ui-input>input[hover] {
440
+ background: #aaa;
433
441
  }
434
442
  ui-input>input:focus {
443
+ background: #bbb;
435
444
  }
436
445
  ui-input>input:active {
437
446
  }
@@ -675,6 +684,18 @@ ui-slider-handle {
675
684
  cursor: pointer;
676
685
  box-shadow: 0 0 5px rgba(0,0,0,.8);
677
686
  }
687
+ ui-slider-handle>ui-label {
688
+ pointer-events: none;
689
+ position: absolute;
690
+ left: 20px;
691
+ z-index: 100;
692
+ background: rgba(0,0,0,.5);
693
+ border-radius: 20px;
694
+ padding: 0 .4em;
695
+ }
696
+ ui-slider-track[hover] ui-slider-handle>ui-label {
697
+ display: block !important;
698
+ }
678
699
 
679
700
 
680
701
  /***********
@@ -881,6 +902,10 @@ ui-select>select {
881
902
  ui-select:hover>select {
882
903
  background: #555;
883
904
  }
905
+ ui-select>ui-label {
906
+ min-width: 5em;
907
+ }
908
+
884
909
 
885
910
  ui-formgroup {
886
911
  position: relative;
@@ -1242,3 +1267,20 @@ ui-spinner[full] {
1242
1267
  right: 0;
1243
1268
  background: rgba(0,0,0,.1);
1244
1269
  }
1270
+ ui-image-picker {
1271
+ display: block;
1272
+ }
1273
+ ui-image-picker ui-label {
1274
+ vertical-align: top;
1275
+ min-width: 5em;
1276
+ display: inline-block;
1277
+ }
1278
+ ui-image-picker canvas {
1279
+ width: 30px;
1280
+ height: 30px;
1281
+ border: 1px solid black;
1282
+ border-radius: 2px;
1283
+ padding: 2px;
1284
+ display: inline-block;
1285
+ vertical-align: top;
1286
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "janusweb",
3
3
  "description": "Web client for JanusVR worlds",
4
- "version": "1.5.42",
4
+ "version": "1.5.44",
5
5
  "main": "scripts/janusweb.js",
6
6
  "author": "James Baicoianu",
7
7
  "license": "MIT",
@@ -18,7 +18,7 @@
18
18
  "url": "https://github.com/jbaicoianu/janusweb"
19
19
  },
20
20
  "dependencies": {
21
- "elation-engine": ">=0.9.73",
21
+ "elation-engine": ">=0.9.114",
22
22
  "uglify-es": "*"
23
23
  },
24
24
  "keywords": [
package/scripts/client.js CHANGED
@@ -1,4 +1,4 @@
1
- elation.require(['elements.elements', 'elements', 'engine.engine', 'engine.assets', 'engine.things.light_ambient', 'engine.things.light_directional', 'engine.things.light_point', 'janusweb.janusweb', 'janusweb.chat', 'janusweb.janusplayer', 'janusweb.janusxrplayer', 'janusweb.external.document-register-element', 'janusweb.ui.main', 'elements.elements'], function() {
1
+ elation.require(['elements.elements', 'elements', 'engine.engine', 'engine.assets', 'engine.things.light_ambient', 'engine.things.light_directional', 'engine.things.light_point', 'janusweb.janusweb', 'janusweb.janusplayer', 'janusweb.janusxrplayer', 'janusweb.ui.main'], function() {
2
2
  // If getCurrentScript returns non-null here, then it means we're in release mode
3
3
  var clientScript = elation.utils.getCurrentScript();
4
4
 
@@ -133,6 +133,17 @@ elation.require(['elements.elements', 'elements', 'engine.engine', 'engine.asset
133
133
  this.startXR();
134
134
  });
135
135
  }
136
+ window.addEventListener('load', ev => {
137
+ window.scrollTo(0, 1);
138
+ });
139
+ window.addEventListener('touchend', ev => {
140
+ // FIXME - useragent hack isn't the best way of handling this, but it beats getting stuck in non-immersive fullscreen mode while in a VR headset
141
+ if (navigator.userAgent.indexOf('OculusBrowser') != -1) {
142
+ this.startXR();
143
+ } else if (!this.view.isFullscreen()) {
144
+ this.toggleFullscreen({value: 1});
145
+ }
146
+ });
136
147
  }
137
148
  initButtons() {
138
149
  this.sharebutton = elation.ui.button({classname: 'janusweb_sharing', label: 'Share'});
package/scripts/config.js CHANGED
@@ -26,7 +26,7 @@ elation.config.set('share.targets.yahoo.clientid', '374523350201-p566ctvssq49sa4
26
26
  elation.config.set('share.targets.facebook.clientid', '1197654320349894');
27
27
  elation.config.set('share.targets.file.enabled', true);
28
28
 
29
- elation.config.set('serviceworker.enabled', true);
29
+ elation.config.set('serviceworker.enabled', false);
30
30
 
31
31
  // FIXME - hack for dev, we should support role-based config
32
32
  if (typeof document != 'undefined' && document.location.origin == 'https://bai.dev.supcrit.com') {
@@ -59,7 +59,13 @@ elation.require(['janusweb.janusbase'], function() {
59
59
  this.outlinematerial.side = THREE.BackSide;
60
60
  //this.outlinematerial.blending = THREE.AdditiveBlending;
61
61
 
62
- if (this.target) this.updateTarget();
62
+ if (this.target) {
63
+ this.updateTarget();
64
+ } else {
65
+ setTimeout(() => {
66
+ this.select(this.children[0]);
67
+ }, 50);
68
+ }
63
69
  },
64
70
  select(object) {
65
71
  this.selected = object;
@@ -329,9 +329,7 @@ JanusClientConnection.prototype.connect = function() {
329
329
  this.status = 2;
330
330
  this._useridSuffix = '';
331
331
  this.sendLogon();
332
- while (this.msgQueue.length > 0) {
333
- this.send(this.msgQueue.shift());
334
- }
332
+ this.sendQueuedCommands()
335
333
  this.dispatchEvent({type: 'connect'});
336
334
  }.bind(this);
337
335
 
@@ -362,6 +360,15 @@ JanusClientConnection.prototype.disconnect = function() {
362
360
  this.dispatchEvent({type: 'disconnecting'});
363
361
  this._websocket.close();
364
362
  }
363
+ JanusClientConnection.prototype.sendQueuedCommands = function() {
364
+ if (this._websocket.readyState > 0) {
365
+ while (this.msgQueue.length > 0) {
366
+ this.send(this.msgQueue.shift());
367
+ }
368
+ } else {
369
+ setTimeout(() => this.sendQueuedCommands(), 100);
370
+ }
371
+ }
365
372
 
366
373
  JanusClientConnection.prototype.sendLogon = function() {
367
374
  var msgData = {
@@ -385,13 +392,12 @@ JanusClientConnection.prototype.setUserId = function(userId) {
385
392
  };
386
393
 
387
394
  JanusClientConnection.prototype.send = function(msg) {
388
- if (this._websocket.readyState == 0) {
389
- this.msgQueue.push(msg);
390
- } else if (this._websocket.readyState == 1) {
395
+ try {
391
396
  this._websocket.send(JSON.stringify(msg) + '\r\n');
392
- } else {
393
- //this.reconnect();
397
+ } catch (e) {
398
+ this.msgQueue.push(msg);
394
399
  }
400
+ //this.reconnect();
395
401
  };
396
402
 
397
403
  JanusClientConnection.prototype.onMessage = function(msg) {
package/scripts/image.js CHANGED
@@ -37,7 +37,7 @@ elation.require(['janusweb.janusbase'], function() {
37
37
  this.createGeometry = function() {
38
38
  var aspect = this.getAspect(),
39
39
  thickness = 0.1; //Math.max(this.scale.x, this.scale.z) / (10 * this.scale.z);
40
- var box = new THREE.BoxBufferGeometry(2, 2 * aspect, thickness);
40
+ var box = new THREE.BoxGeometry(2, 2 * aspect, thickness);
41
41
  box.applyMatrix4(new THREE.Matrix4().makeTranslation(0, 0, thickness / this.scale.z));
42
42
 
43
43
  // Flip the back face for images
@@ -178,7 +178,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
178
178
  collider.traverse(n => {
179
179
  // Ignore collider if it's too high-poly
180
180
  if (n instanceof THREE.Mesh && n.geometry instanceof THREE.BufferGeometry) {
181
- if (n.geometry.attributes.position.count > 65536) {
181
+ if (n.geometry.attributes.position.count > 65536 * 3) {
182
182
  console.warn('Collider mesh rejected, too many polys!', collision_id, this, n, collider);
183
183
  elation.events.fire({type: 'thing_collider_rejected', element: this, data: {root: collider, mesh: n}});
184
184
  remove.push(n);
@@ -231,7 +231,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
231
231
  }
232
232
  }
233
233
  this.createForces = function() {
234
- if (this.collidable && !this.collision_trigger) {
234
+ if (this.collidable || this.collision_trigger) {
235
235
  elation.events.add(this.objects.dynamics, 'physics_collide', elation.bind(this, this.handleCollision));
236
236
  }
237
237
  this.updateRotationSpeed();
@@ -564,7 +564,8 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
564
564
  hasalpha: args.hasalpha,
565
565
  maxsize: args.maxsize,
566
566
  preload: args.preload,
567
- baseurl: this.baseurl
567
+ baseurl: this.baseurl,
568
+ srgb: args.srgb
568
569
  };
569
570
  assetlist.push(assetargs);
570
571
  } else if (args.canvas) {
@@ -597,13 +598,16 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
597
598
  sbs3d: args.sbs3d,
598
599
  ou3d: args.ou3d,
599
600
  eac360: args.eac360,
601
+ vr180: args.vr180,
600
602
  hasalpha: args.hasalpha,
601
603
  auto_play: args.auto_play,
602
604
  type: args.type,
603
605
  format: args.format,
604
606
  hls: args.hls,
605
607
  preload: args.preload,
606
- baseurl: this.baseurl
608
+ baseurl: this.baseurl,
609
+ proxy: args.proxy,
610
+ extratracks: args.extratracks,
607
611
  });
608
612
  } else if (args.video) {
609
613
  assetlist.push({
@@ -613,12 +617,15 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
613
617
  loop: args.loop,
614
618
  sbs3d: args.sbs3d,
615
619
  ou3d: args.ou3d,
620
+ vr180: args.vr180,
616
621
  hasalpha: args.hasalpha,
617
622
  auto_play: args.auto_play,
618
623
  type: args.type,
619
624
  format: args.format,
620
625
  hls: args.hls,
621
- baseurl: this.baseurl
626
+ baseurl: this.baseurl,
627
+ proxy: args.proxy,
628
+ extratracks: args.extratracks,
622
629
  });
623
630
  }
624
631
  } else if (type == 'sound') {
@@ -760,8 +767,8 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
760
767
  dir = new THREE.Vector3(),
761
768
  up = new THREE.Vector3();
762
769
  return function(ev) {
763
- let parent = this.properties.parent;
764
- let billboard = this.properties.billboard;
770
+ const parent = this.properties.parent;
771
+ const billboard = this.properties.billboard;
765
772
  if (billboard && parent) {
766
773
  //player.camera.localToWorld(playerpos.set(0,0,0));
767
774
  //this.localToWorld(objpos.set(0,0,0));
@@ -789,14 +796,11 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
789
796
  */
790
797
  // TODO - Simple trig makes this much faster, but to get the same functionality as before we'll need to implement each dimension
791
798
  // For now, we only support billboarding with the Y axis locked (eg, doom sprites)
792
- let views = this.engine.systems.render.views;
793
- let camera = player.camera;
794
- if (views.xr && views.xr.enabled && views.xr.camera && views.xr.camera.userData.thing) {
795
- camera = views.xr.camera.userData.thing;
796
- }
797
- parent.worldToLocal(camera.getWorldPosition(playerpos)).sub(this.position);
798
- dir.copy(playerpos).normalize();
799
- if (billboard == 'y') {
799
+ if (billboard == 'y' || billboard === true || billboard == 'true') {
800
+ const views = this.engine.systems.render.views;
801
+ const camera = (views.xr && views.xr.enabled && views.xr.camera && views.xr.camera.userData.thing ? views.xr.camera.userData.thing : player.camera)
802
+ parent.worldToLocal(camera.getWorldPosition(playerpos)).sub(this.position);
803
+ dir.copy(playerpos).normalize();
800
804
  this.rotation.radians.set(0, Math.atan2(dir.x, dir.z), 0);
801
805
  this.frameupdates['rotation'] = true;
802
806
  }
@@ -818,10 +822,12 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
818
822
  this.refresh();
819
823
  }
820
824
 
825
+ /*
821
826
  let pos = this.position;
822
827
  if (isNaN(pos.x)) pos.x = 0;
823
828
  if (isNaN(pos.y)) pos.y = 0;
824
829
  if (isNaN(pos.z)) pos.z = 0;
830
+ */
825
831
 
826
832
  if (this.properties.color === this.defaultcolor && (this.properties.color.r != 1 || this.properties.color.g != 1 || this.properties.color.b != 1)) {
827
833
  this.updateColor();
@@ -829,8 +835,8 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
829
835
 
830
836
  this.resetFrameUpdates();
831
837
  this.dispatchEvent({type: 'update', data: ev.data, bubbles: false});
832
- var proxy = this.getProxyObject();
833
- if (typeof proxy.update == 'function' && this.created) {
838
+ const proxy = this.getProxyObject();
839
+ if (this.created && typeof proxy.update == 'function') {
834
840
  proxy.update(ev.data);
835
841
  }
836
842
  }
@@ -910,6 +916,8 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
910
916
  this.frameupdates['zdir'] = false;
911
917
  this.frameupdates['rotation'] = false;
912
918
  this.frameupdates['rotation_dir'] = false;
919
+ this.frameupdates['rotation_order'] = false;
920
+ this.frameupdates['fwd'] = false;
913
921
 
914
922
  for (var k in this.lastframevalues) {
915
923
  this.lastframevalues[k].copy(this.properties[k]);
@@ -979,13 +987,13 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
979
987
  if (other) {
980
988
  if (other.getProxyObject) {
981
989
  var proxy = other.getProxyObject();
982
- //console.log('I collided', proxy, this);
990
+ //console.log('I collided', this.collision_trigger, other.collision_trigger, proxy, this);
983
991
 
984
- if (this.collision_trigger || proxy.collision_trigger) {
992
+ if (this.collision_trigger || proxy.collision_trigger || other.collision_trigger) {
985
993
  this.dispatchEvent({type: 'trigger', data: { collision: ev.data, other: proxy }});
986
994
  ev.preventDefault();
987
995
  ev.stopPropagation();
988
- } else if (this.collidable) {
996
+ } else if (this.collidable && other.collidable) {
989
997
  this.dispatchEvent({type: 'collision', data: { collision: ev.data, other: proxy }});
990
998
  } else {
991
999
  ev.preventDefault();
@@ -1031,7 +1039,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
1031
1039
  }
1032
1040
  this.updateAnimation = function() {
1033
1041
  // Triggered whenever this.anim_id changes
1034
- if (this.anim_id) {
1042
+ if (this.anim_id || !this.activeanimation) {
1035
1043
  this.setAnimation(this.anim_id);
1036
1044
  } else if (this.activeanimation) {
1037
1045
  this.stopAnimation();
@@ -1052,7 +1060,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
1052
1060
  if (!this.fadetimers[clipname]) {
1053
1061
  // FIXME - for some reason, THREE.AnimationAction.fadeIn() / fadeOut() / etc are just causing the animations to stop, so we'll handle fading ourselves
1054
1062
  this.fadetimers[clipname] = setInterval(() => {
1055
- oldaction.weight *= .95;
1063
+ oldaction.weight *= .9;
1056
1064
  if (oldaction.weight <= .001) {
1057
1065
  oldaction.weight = 0;
1058
1066
  oldaction.stop();
@@ -1088,10 +1096,12 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
1088
1096
  if (!event.target) {
1089
1097
  event.target = target || event.element;
1090
1098
  }
1099
+
1091
1100
  var handlerfn = 'on' + event.type;
1092
1101
  if (handlerfn in this) {
1093
1102
  this.executeCallback(this[handlerfn], event);
1094
1103
  }
1104
+
1095
1105
  // Bubble event up to parents, unless the event was thrown with bubbling disabled or an event handler called stopPropagation()
1096
1106
  let firedev = elation.events.fire(event);
1097
1107
  let returnValue = true;
@@ -1172,7 +1182,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
1172
1182
  this.raycast = (function() {
1173
1183
  var _pos = new THREE.Vector3(),
1174
1184
  _dir = new THREE.Vector3(0,0,-1);
1175
- return function(dir, offset, classname, maxdist) {
1185
+ return function(dir, offset, classname, maxdist, colliderroot=null) {
1176
1186
  if (!this.room) return [];
1177
1187
  if (dir) {
1178
1188
  _dir.copy(dir);
@@ -1185,7 +1195,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
1185
1195
  }
1186
1196
  this.localToWorld(_pos);
1187
1197
  this.objects.dynamics.localToWorldDir(_dir);
1188
- return this.room.raycast(_dir, _pos, classname, maxdist);
1198
+ return this.room.raycast(_dir, _pos, classname, maxdist, colliderroot);
1189
1199
  };
1190
1200
  })();
1191
1201
  this.getElementsByTagName = function(tagname, elements) {
@@ -1282,9 +1292,9 @@ console.log('its null', k, this[k], prop);
1282
1292
  // Special handling for 'rotation' and 'color'
1283
1293
  if (realkey == 'rotation') {
1284
1294
  /*
1285
- props['rotation'][0] *= THREE.Math.RAD2DEG;
1286
- props['rotation'][1] *= THREE.Math.RAD2DEG;
1287
- props['rotation'][2] *= THREE.Math.RAD2DEG;
1295
+ props['rotation'][0] *= THREE.MathUtils.RAD2DEG;
1296
+ props['rotation'][1] *= THREE.MathUtils.RAD2DEG;
1297
+ props['rotation'][2] *= THREE.MathUtils.RAD2DEG;
1288
1298
  */
1289
1299
  } else if (realkey == 'color') {
1290
1300
  if (!this.colorIsDefault) {
@@ -1402,5 +1412,17 @@ console.log('clone', props);
1402
1412
  }
1403
1413
  return false;
1404
1414
  }
1415
+ this.physics_collide = function(ev) {
1416
+ let obj1 = ev.data.bodies[0].object, obj2 = ev.data.bodies[1].object,
1417
+ other = (obj1 == this ? obj2 : obj1);
1418
+
1419
+ let events = elation.events.fire({type: 'collide', element: this, data: {
1420
+ other: (typeof other.getProxyObject == 'function' ? other.getProxyObject() : other),
1421
+ collision: ev.data
1422
+ } });
1423
+ if (elation.events.wasDefaultPrevented(events)) {
1424
+ ev.preventDefault();
1425
+ }
1426
+ }
1405
1427
  }, elation.engine.things.generic);
1406
1428
  });
@@ -33,8 +33,8 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
33
33
  diffuseColor.rgb *= vColor;
34
34
  #endif
35
35
  float dist = length(vViewPosition);
36
- float mindist = .4;
37
- float maxdist = .6;
36
+ float mindist = .2;
37
+ float maxdist = .4;
38
38
  if (dist < maxdist) {
39
39
  diffuseColor.a = clamp(((dist - mindist) / (maxdist - mindist)), 0., 1.);
40
40
  }
@@ -131,13 +131,11 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
131
131
  this.ghostassets = assets;
132
132
  this.assetpack = elation.engine.assets.loadJSON(assets.assetlist);
133
133
  } else {
134
- console.log(this.ghostassets);
135
- this.assetpack.loadJSON(assets.assetlist);
134
+ this.assetpack.loadJSON(assets.assetlist, true);
136
135
  }
137
136
 
138
137
  let animnames = []; //'idle', 'walk', 'walk_left', 'walk_right', 'walk_back', 'run', 'jump', 'fly', 'speak', 'type', 'portal'];
139
138
  let animassets = assets.assetlist.filter(asset => animnames.indexOf(asset.name) != -1);
140
- console.log('some ghost animations', animassets, assets);
141
139
 
142
140
  if (!this.animationmixer) {
143
141
  // Set up our animation mixer with a simple bone mapper for our head. We'll add more animations to this ass other assets load
@@ -341,7 +339,7 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
341
339
  if (this.body.animationmixer) {
342
340
  this.cloneAnimations(animasset);
343
341
  }
344
- //this.body.setAnimation('idle');
342
+ this.body.setAnimation('idle');
345
343
  }
346
344
  });
347
345
  animasset.load();
@@ -664,9 +662,13 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
664
662
  }
665
663
  if (ghostdef.head_id) {
666
664
  this.setHead(ghostdef.head_id, headpos, ghostdef.scale);
665
+ } else if (this.head) {
666
+ this.setHead(false);
667
667
  }
668
668
  if (ghostdef.body_id) {
669
669
  this.setBody(ghostdef.body_id, ghostdef.scale, ghostdef.pos);
670
+ } else if (this.body) {
671
+ this.setBody(false);
670
672
  }
671
673
  if (ghostdef._children) {
672
674
  for (var type in ghostdef._children) {
@@ -826,10 +828,12 @@ return;
826
828
  let headaction = this.headaction || this._target.headaction;
827
829
  if (headaction && headaction._clip.tracks[0]) {
828
830
  let track = headaction._clip.tracks[0];
829
- track.values[0] = orientation.x * (invert ? -1 : 1);
830
- track.values[1] = orientation.y * (invert ? -1 : 1);
831
- track.values[2] = orientation.z * (invert ? -1 : 1);
832
- track.values[3] = orientation.w; // * (invert ? -1 : 1);
831
+ if (track) {
832
+ track.values[0] = orientation.x * (invert ? -1 : 1);
833
+ track.values[1] = orientation.y * (invert ? -1 : 1);
834
+ track.values[2] = orientation.z * (invert ? -1 : 1);
835
+ track.values[3] = orientation.w; // * (invert ? -1 : 1);
836
+ }
833
837
  }
834
838
  }
835
839
  this.blink = function() {
@@ -20,6 +20,7 @@ elation.require(['janusweb.janusbase'], function() {
20
20
  light_helper: { type: 'boolean', default: false, set: this.updateLightHelper },
21
21
  light_style: { type: 'string', default: '' },
22
22
  light_style_fps: { type: 'float', default: 10 },
23
+ color_temperature: { type: 'float', set: this.updateLight },
23
24
  collision_id: { type: 'string', default: 'sphere', set: this.updateCollider },
24
25
  collision_trigger: { type: 'boolean', default: true, set: this.updateCollider },
25
26
  });
@@ -73,14 +74,14 @@ elation.require(['janusweb.janusbase'], function() {
73
74
  this.getPlaceholderGeometry = function() {
74
75
  let placeholdergeo = null;
75
76
  if (this.light_cone_angle == 0) {
76
- placeholdergeo = new THREE.SphereBufferGeometry(.1);
77
+ placeholdergeo = new THREE.SphereGeometry(.1);
77
78
  } else if (this.light_cone_angle == 1) {
78
- placeholdergeo = new THREE.SphereBufferGeometry(.1);
79
+ placeholdergeo = new THREE.SphereGeometry(.1);
79
80
  } else {
80
81
  let angle = Math.acos(this.light_cone_angle),
81
82
  height = this.light_shadow_near,
82
83
  radius = Math.tan(angle) * height;
83
- placeholdergeo = new THREE.ConeBufferGeometry(radius, height);
84
+ placeholdergeo = new THREE.ConeGeometry(radius, height);
84
85
  placeholdergeo.applyMatrix4(new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(-Math.PI/2, 0, 0)).setPosition(0, 0, height / 2));
85
86
  }
86
87
  return placeholdergeo;
@@ -139,7 +140,11 @@ elation.require(['janusweb.janusbase'], function() {
139
140
  this.light.intensity = .1;
140
141
  this.light.penumbra = this.light_penumbra;
141
142
  this.light.decay = this.light_decay;
142
- this.light.color.copy(this.color);
143
+ if (this.color_temperature) {
144
+ this.light.color.copy(this.temperatureToRGB(this.color_temperature));
145
+ } else {
146
+ this.light.color.copy(this.color);
147
+ }
143
148
  this.light.color.multiplyScalar(this.light_intensity * avgscale * avgscale);
144
149
  this.light.distance = this.light_range * avgscale;
145
150
  if (this.light_cone_angle > 0 && this.light_cone_angle < 1) {
@@ -199,6 +204,42 @@ elation.require(['janusweb.janusbase'], function() {
199
204
  this.light.shadow.camera.top = d;
200
205
  this.light.shadow.camera.bottom = -d;
201
206
  }
207
+ this.temperatureToRGB = function(t) {
208
+ // From view-source:https://web.archive.org/web/20161108193229/https://tommitytom.co.uk/colourtemp/
209
+ let r = 0, g = 0, b = 0,
210
+ temp = Math.floor(t / 100 + 0.5),
211
+ rgb = null;
212
+
213
+ if (temp <= 66) {
214
+ r = 255;
215
+ } else {
216
+ r = temp - 60;
217
+ r = 329.698727446 * Math.pow(r, -0.1332047592);
218
+ }
219
+
220
+ if (temp <= 66) {
221
+ g = temp;
222
+ g = 99.4708025861 * Math.log(g) - 161.1195681661;
223
+ } else {
224
+ g = temp - 60;
225
+ g = 288.1221695283 * Math.pow(g, -0.0755148492);
226
+ }
227
+
228
+ if (temp >= 66) {
229
+ b = 255;
230
+ } else if (temp <= 19) {
231
+ b = 0;
232
+ } else {
233
+ b = temp - 10;
234
+ b = 138.5177312231 * Math.log(b) - 305.0447927307;
235
+ }
236
+
237
+ r = THREE.MathUtils.clamp(r, 0, 255) / 255;
238
+ g = THREE.MathUtils.clamp(g, 0, 255) / 255;
239
+ b = THREE.MathUtils.clamp(b, 0, 255) / 255;
240
+
241
+ return {r, g, b};
242
+ }
202
243
  this.getProxyObject = function(classdef) {
203
244
  if (!this._proxyobject) {
204
245
  this._proxyobject = elation.engine.things.janusobject.extendclass.getProxyObject.call(this, classdef);
@@ -215,6 +256,7 @@ elation.require(['janusweb.janusbase'], function() {
215
256
  light_shadow_far: [ 'property', 'light_shadow_far'],
216
257
  light_shadow_bias: [ 'property', 'light_shadow_bias'],
217
258
  light_shadow_radius: [ 'property', 'light_shadow_radius'],
259
+ color_temperature: [ 'property', 'color_temperature'],
218
260
  };
219
261
  }
220
262
  return this._proxyobject;