diff --git a/README.md b/README.md index 8770a1f..b57d400 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ This is a fully functional example of what A-Frame code looks like. - + - * + * * * * @@ -96,14 +96,14 @@ * */ AFRAME.registerComponent('altspace', { - version: '1.3.1', + version: '1.3.2', schema: { usePixelScale: { type: 'boolean', default: 'false'}, verticalAlign: { type: 'string', default: 'middle'}, enclosuresOnly:{ type: 'boolean', default: 'true'}, fullspace: { type: 'boolean', default: 'false'} }, - + /* * Called once when component is attached. Generally for initial setup. */ @@ -112,7 +112,7 @@ console.warn('aframe-altspace-component can only be attached to a-scene'); return; } - + if (window.altspace && window.altspace.inClient) { this.el.setAttribute('vr-mode-ui', {enabled: false}); this.initRenderer(); @@ -121,9 +121,9 @@ } else { console.warn('aframe-altspace-component only works inside of AltspaceVR'); } - + }, - + /* * Called on every single tick or render loop of the scene. */ @@ -131,38 +131,38 @@ if(this.el.object3D.updateAllBehaviors) this.el.object3D.updateAllBehaviors(); }, - + /* * Called when a component is removed (e.g., via removeAttribute). * Generally undoes all modifications to the entity. */ remove: function () { }, - + /* * Called on each scene tick. */ // tick: function (t) { }, - + /* * Called when entity pauses. * Use to stop or remove any dynamic or background behavior such as events. */ pause: function () { }, - + /* * Called when entity resumes. * Use to continue or add any dynamic or background behavior such as events. */ play: function () { }, - - + + /********** Helper Methods **********/ - + /* * Swap in Altspace renderer when running in AltspaceVR. */ initRenderer: function () { - + var scene = this.el.object3D; altspace.getEnclosure().then(function(e) { @@ -172,11 +172,11 @@ scene.scale.setScalar(e.pixelsPerMeter); }); } - + if (!this.data.usePixelScale || this.data.fullspace){ scene.scale.setScalar(e.pixelsPerMeter); } - + switch (this.data.verticalAlign) { case 'bottom': scene.position.y -= e.innerHeight / 2; @@ -189,14 +189,14 @@ default: console.warn('Unexpected value for verticalAlign: ', this.data.verticalAlign); } - + if(this.data.enclosuresOnly && e.innerDepth === 1){ this.el.renderer.render(new THREE.Scene()); this.el.renderer = this.el.effect = oldRenderer; - + } }.bind(this)); - + var oldRenderer = this.el.renderer; var renderer = this.el.renderer = this.el.effect = altspace.getThreeJSRenderer({ aframeComponentVersion: this.version @@ -214,14 +214,14 @@ renderer.setFaceCulling = noop; renderer.context = {canvas: {}}; renderer.shadowMap = {}; - + }, - + /* * Emulate A-Frame cursor events when running in altspaceVR. */ initCursorEvents: function() { - + var scene = this.el.object3D; var cursorEl = document.querySelector('a-cursor') || document.querySelector('a-entity[cursor]'); if (cursorEl) { @@ -229,20 +229,20 @@ cursorEl.setAttribute('material', 'transparent', true); cursorEl.setAttribute('material', 'opacity', 0.0); } - + var emit = function (eventName, event) { // Fire events on intersected object and A-Frame cursor. var targetEl = event.target.el; if (cursorEl) cursorEl.emit(eventName, { target: targetEl, ray: event.ray, point: event.point }); if (targetEl) targetEl.emit(eventName, { target: targetEl, ray: event.ray, point: event.point }); } ; - + var cursordownObj = null; scene.addEventListener('cursordown', function(event) { cursordownObj = event.target; emit('mousedown', event); }); - + scene.addEventListener('cursorup', function(event) { emit('mouseup', event); if (event.target.uuid === cursordownObj.uuid) { @@ -250,31 +250,31 @@ } cursordownObj = null; }); - + scene.addEventListener('cursorenter', function(event) { if (!event.target.el) { return; } event.target.el.addState('hovered'); if (cursorEl) cursorEl.addState('hovering'); emit('mouseenter', event); }); - + scene.addEventListener('cursorleave', function(event) { if (!event.target.el) { return; } event.target.el.removeState('hovered'); if (cursorEl) cursorEl.removeState('hovering'); emit('mouseleave', event); }); - + }, - + initCollisionEvents: function () { - + var scene = this.el.object3D; - + var emit = function (eventName, event) { var targetEl = event.target.el; if (!targetEl) return; - + //remap target and other from object3Ds to aframe element event.target = targetEl; if (event.other && event.other.el) { @@ -282,25 +282,25 @@ } targetEl.emit(eventName, event); }; - + scene.addEventListener('collisionenter', function (event) { emit('collisionenter', event); }); - + scene.addEventListener('collisionexit', function (event) { emit('collisionexit', event); }); - + scene.addEventListener('triggerenter', function (event) { emit('triggerenter', event); }); - + scene.addEventListener('triggerexit', function (event) { emit('triggerexit', event); }); - + } - + }); @@ -309,7 +309,7 @@ /***/ function(module, exports) { (function(){ - + function setColliderFlag(obj, state) { obj.userData.altspace = {collider: {enabled: state}}; obj.traverse(function (obj) { @@ -318,7 +318,7 @@ } }) } - + /** * Enable or disable cursor collision on the object. * @mixin altspace-cursor-collider @@ -337,7 +337,7 @@ setColliderFlag(this.el.object3D, this.data.enabled); } }); - + })(); @@ -406,7 +406,7 @@ removeNativeComponent: noop }; } - + var placeholderGeometry = new THREE.BoxGeometry(0.001, 0.001, 0.001); var placeholderMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 }); placeholderMaterial.visible = false; @@ -415,21 +415,21 @@ }; PlaceholderMesh.prototype = Object.create( THREE.Mesh.prototype ); PlaceholderMesh.prototype.constructor = THREE.PlaceholderMesh; - + function meshInit(mesh) { //If you attach native components to an entity, it will not use a default collider mesh.userData.altspace = mesh.userData.altspace || {}; mesh.userData.altspace.collider = mesh.userData.altspace.collider || {}; mesh.userData.altspace.collider.enabled = false; - + altspace.addNativeComponent(mesh, this.name); } - + function nativeComponentInit() { var mesh = this.el.getOrCreateObject3D('mesh', PlaceholderMesh); - + meshInit.call(this, mesh); - + //to pass defaults this.update(this.data); } @@ -440,11 +440,11 @@ function nativeComponentUpdate(oldData) { altspace.updateNativeComponent(this.el.object3DMap.mesh, this.name, this.data); } - + function callComponent(functionName, functionArguments) { altspace.callNativeComponent(this.el.object3DMap.mesh, this.name, functionName, functionArguments) } - + /** * Attach a given native object to this entity. * @mixin n-object @@ -461,7 +461,7 @@ update: nativeComponentUpdate, remove: nativeComponentRemove }); - + /** * Create an object that spawns additional copies of itself when grabbed by a user (the copies are not spawners themselves). * These copies will be physically interactive and automatically synchronized @@ -480,7 +480,7 @@ update: nativeComponentUpdate, remove: nativeComponentRemove }); - + /** * Creates dynamic 2D text on the entity. The text will wrap automatically based on the width and height provided. * This text will be clearer than texture-based text and more performant than geometry-based test. @@ -517,11 +517,11 @@ verticalAlign: { default: 'middle'} } }); - + //object: collides against: objects / enviroment / cursor //environment: can be teleported onto, and collides against: objects / environment / cursor //hologram: collides against: cursor / holograms - + /** * Abstract base class for {@link n.n-sphere-collider}, {@link n.n-box-collider}, * {@link n.n-capsule-collider}, and {@link n.n-mesh-collider}. You cannot use @@ -537,7 +537,7 @@ * teleport onto them. Hologram colliders only collide with other holograms and * the cursor. */ - + /** * Create a spherical collider on this entity. * @mixin n-sphere-collider @@ -556,8 +556,8 @@ type: {default: 'object'} } }); - - + + /** * Create a box-shaped collider on this entity. * @mixin n-box-collider @@ -576,7 +576,7 @@ type: {default: 'object'} } }); - + /** * Create a capsule-shaped collider on this entity. Capsules * are a union of a cylinder and two spheres on top and bottom. @@ -601,7 +601,7 @@ type: {default: 'object'} } }); - + /** * Enable collision for the entire attached mesh. This is expensive to evaluate, so should only be used on * low-poly meshes. @@ -629,7 +629,7 @@ _initObj: function () { this._forEachMesh(function (mesh) { meshInit.call(this, mesh); - + //to pass defaults altspace.updateNativeComponent(mesh, this.name, this.data); }.bind(this)); @@ -638,10 +638,10 @@ // Allow a-frame to create a PlaceholderMesh if there isn't already one, so that the native collider is // registered. this.el.getOrCreateObject3D('mesh', PlaceholderMesh); - + // Initialize the existing mesh this._initObj(); - + this.el.addEventListener('model-loaded', function () { // Re-initialize the collider if a new model is loaded this._initObj(); @@ -663,7 +663,7 @@ type: {default: 'object'} } }); - + /** * Make the object's +Z always face the viewer. Currently will only directly apply to main mesh or native component on the attached entity, not any children or submeshes. * @mixin n-billboard @@ -674,7 +674,7 @@ init:nativeComponentInit, remove: nativeComponentRemove, }); - + /** * A container keeps a running tally of how many objects are within * its bounds, and adds and removes the states `container-full` and @@ -688,10 +688,10 @@ AFRAME.registerComponent('n-container', { init: function(){ nativeComponentInit.call(this); - + var el = this.el; var component = this; - + el.addEventListener('stateadded', function(event){ if(event.detail.state === 'container-full'){ el.emit('container-full'); @@ -700,7 +700,7 @@ el.emit('container-empty'); } }); - + el.addEventListener('container-count-changed', function(event){ component.count = event.detail.count; }); @@ -711,7 +711,7 @@ capacity: { default: 4, type: 'number' }, } }); - + /** * Play the sound given by the `src` or `res` property from the location * of the entity. @@ -762,7 +762,7 @@ } nativeComponentInit.call(this); }, - + /** * Stop the playing sound, and preserve position in clip. * @method native.n-sound#pauseSound @@ -771,7 +771,7 @@ callComponent.call(this, 'pause'); this.el.emit('sound-paused'); }, - + /** * Start the sound playing. * @method native.n-sound#playSound @@ -780,7 +780,7 @@ callComponent.call(this, 'play'); this.el.emit('sound-played'); }, - + /** * Jump to a position in the clip. * @method native.n-sound#seek @@ -820,7 +820,7 @@ rolloff: { type: 'string', default: 'logarithmic' }, } }); - + })(); @@ -829,7 +829,7 @@ /***/ function(module, exports) { // this file is just for good measure. didn't want native-components getting too cluttered. - + /** * This namespace describes strings that are valid inputs to the various native * components. Some components can only take certain types of resources, i.e. @@ -837,7 +837,7 @@ * @namespace resources * @example */ - + /** * Generic modular building pieces. All pieces are aligned to one corner, such that * the piece extends out toward -X and +Z. @@ -904,7 +904,7 @@ * @prop architecture/wall-window-gap-end-r-2w-4h * @prop architecture/wall-window-gap-end-r-4w-4h */ - + /** * Particle systems and other native effects * @name effects @@ -921,7 +921,7 @@ * @prop effects/sparkler - Emits sparks in all directions * @prop effects/steam - Small white steam rising upwards */ - + /** * Objects that can be picked up, thrown, and otherwise interacted with. * @name interactables @@ -937,7 +937,7 @@ * @prop interactables/ring * @prop interactables/soccerball */ - + /** * Static models that you can place in your scene. * @name objects @@ -952,7 +952,7 @@ * @prop objects/ring * @prop objects/target-archery */ - + /** * A selection of pipes/chutes/etc. * @name pipes @@ -976,7 +976,7 @@ * @prop pipes/pipe-half-straight-1d-4l * @prop pipes/pipe-half-tee-1d */ - + /** * Common UI sounds can be used for a consistent UI experience. * @name sounds-ui @@ -993,7 +993,7 @@ * @prop ui/join * @prop ui/click */ - + /** * Foley sounds are real sounds designed for tangible, touchable objects as they are heard in the real world. * @name sounds-foley @@ -1007,7 +1007,7 @@ * @prop foley/paper-shuffle * @prop foley/explode */ - + /** * Effect sounds for a variety of use cases. * @name sounds-effects @@ -1038,9 +1038,9 @@ * * */ - - - + + + /** * Enables the synchronization of properties of the entity. Must be used in * conjuction with the {@link sync.sync-system} component and a component for a @@ -1060,21 +1060,21 @@ init: function () { var scene = document.querySelector('a-scene'); var syncSys = scene.systems['sync-system']; - + var ref; var key; var dataRef; var ownerRef; var ownerId; var isMine = false; - + var component = this; - + component.isConnected = false; - + if(syncSys.isConnected) start(); else scene.addEventListener('connected', start); - - + + if(component.data.ownOn) { var ownershipEvents = component.data.ownOn.split(/[ ,]+/); @@ -1086,38 +1086,38 @@ }); } } - + function start(){ //Make sure someone always owns an object. If the owner leaves and we are the master client, we will take it. //This ensures, for example, that synced animations keep playing scene.addEventListener('clientleft', function(event){ var shouldTakeOwnership = (!ownerId || ownerId === event.detail.id) && syncSys.isMasterClient; - + if(shouldTakeOwnership) component.takeOwnership(); }); - + if (component.data.mode === 'link') { var id = component.el.id; if (!id) { console.error('Entities cannot be synced using link mode without an id.'); return; } - + console.log('syncSys: ' + syncSys); console.log('syncSys.sceneRef: ' + syncSys.sceneRef); - + link(syncSys.sceneRef.child(id)); setupReceive(); - + } else { console.error('Unsupported sync mode: ' + component.data.mode); return; } - + component.isConnected = true; component.el.emit('connected', null, false); } - + function link(entityRef) { ref = entityRef; key = ref.key(); @@ -1125,40 +1125,40 @@ component.dataRef = dataRef; ownerRef = ref.child('owner'); } - + function setupReceive() { - + //if nobody has owned the object yet, we will. ownerRef.transaction(function (owner) { if (owner) return undefined; - + ownerRef.onDisconnect().set(null); return syncSys.clientId; }); - + ownerRef.on('value', function(snapshot) { var newOwnerId = snapshot.val(); - + var gained = newOwnerId === syncSys.clientId && !isMine; if (gained) component.el.emit('ownershipgained', null, false); - - + + //note this also fires when we start up without ownership var lost = newOwnerId !== syncSys.clientId && isMine; if (lost){ component.el.emit('ownershiplost', null, false); - + //we no longer have to clear our ownership when we disconnect ownerRef.onDisconnect().cancel(); } - + ownerId = newOwnerId; - + isMine = newOwnerId === syncSys.clientId; }); } - + /** * Tell sync to start pushing local property values instead of updating * local from remote values. @@ -1166,12 +1166,12 @@ */ component.takeOwnership = function() { ownerRef.set(syncSys.clientId); - + //clear our ownership if we disconnect //this is needed if we are the last user in the room, but we expect people to join later ownerRef.onDisconnect().set(null); } - + /** * Indicates whether the sync ownership is yours. * @member sync.sync#isMine @@ -1213,12 +1213,12 @@ }, init: function() { var component = this; - + if(!this.data || !this.data.app){ console.warn('The sync-system must be present on the scene and configured with required data.'); return; } - + component.isConnected = false; console.log(this.data); altspace.utilities.sync.connect({ @@ -1228,20 +1228,20 @@ baseRefUrl: this.data.refUrl }).then(function(connection) { this.connection = connection; - + this.sceneRef = this.connection.instance.child('scene'); this.clientsRef = this.connection.instance.child('clients'); - + // temporary way of having unique identifiers for each client this.clientId = this.sceneEl.object3D.uuid; var masterClientId; this.clientsRef.on("value", function (snapshot) { var clientIds = snapshot.val(); - + var masterClientKey = Object.keys(clientIds)[0]; masterClientId = clientIds[masterClientKey]; }); - + this.clientsRef.on('child_added', function(childSnapshot) { var joinedClientId = childSnapshot.val(); //let the master client flag get set first @@ -1249,7 +1249,7 @@ component.sceneEl.emit('clientjoined', {id: joinedClientId}, false); }, 0); }); - + this.clientsRef.on('child_removed', function(childSnapshot) { var leftClientId = childSnapshot.val(); //let the master client flag get set first @@ -1257,21 +1257,21 @@ component.sceneEl.emit('clientleft', {id: leftClientId}, false); }, 0); }); - + // add our client ID to the list of connected clients, // but have it be automatically removed by firebase if we disconnect for any reason this.clientsRef.push(this.clientId).onDisconnect().remove(); - - + + this.connection.instance.child('initialized').once('value', function (snapshot) { var shouldInitialize = !snapshot.val(); snapshot.ref().set(true); - + component.sceneEl.emit('connected', { shouldInitialize: shouldInitialize }, false); component.isConnected = true; }.bind(this)); - - + + Object.defineProperty(this, 'isMasterClient', { get: function () { return masterClientId === this.clientId; }.bind(this) }); @@ -1286,7 +1286,7 @@ //TODO: We need to figure out a way to recieve our first update without caring about ownership. // firstValue is probably not the right way to go, probably something about having sent yet. Need to change for both - + /** * Synchronize the position, rotation, and scale of this object with all clients. * Requires both a {@link sync.sync-system} component on the `a-scene`, and a @@ -1303,15 +1303,15 @@ var component = this; var sync = component.el.components.sync; if(sync.isConnected) start(); else component.el.addEventListener('connected', start); - + function start(){ - + var positionRef = sync.dataRef.child('position'); var rotationRef = sync.dataRef.child('rotation'); var scaleRef = sync.dataRef.child('scale'); - + component.updateRate = 100; - + var stoppedAnimations = []; //pause all animations on ownership loss component.el.addEventListener('ownershiplost', function() { @@ -1331,46 +1331,46 @@ } stoppedAnimations = []; }); - + function onTransform(snapshot, componentName) { if (sync.isMine) return; - + var value = snapshot.val(); if (!value) return; - + component.el.setAttribute(componentName, value); } - + positionRef.on('value', function (snapshot) { onTransform(snapshot, 'position'); }); - + rotationRef.on('value', function (snapshot) { onTransform(snapshot, 'rotation'); }); - + scaleRef.on('value', function (snapshot) { onTransform(snapshot, 'scale'); }); - + var sendPosition = throttle(function(value){ positionRef.set(value); }, component.updateRate); - + var sendRotation = throttle(function(value){ rotationRef.set(value); }, component.updateRate); - + var sendScale = throttle(function(value){ scaleRef.set(value); }, component.updateRate); - + function onComponentChanged(event){ if (!sync.isMine) return; - + var name = event.detail.name; var newData = event.detail.newData; - + if (name === 'position') { sendPosition(newData); } else if (name === 'rotation') { @@ -1380,22 +1380,22 @@ } else { return; } - + } - + //from underscore.js function throttle(func, wait, options) { var timeout, context, args, result; var previous = 0; if (!options) options = {}; - + var later = function() { previous = options.leading === false ? 0 : Date.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; - + var throttled = function() { var now = Date.now(); if (!previous && options.leading === false) previous = now; @@ -1415,17 +1415,17 @@ } return result; }; - + throttled.cancel = function() { clearTimeout(timeout); previous = 0; timeout = context = args = null; }; - + return throttled; }; - - + + component.el.addEventListener('componentchanged', onComponentChanged); } } @@ -1452,22 +1452,22 @@ var component = this; var sync = component.el.components.sync; if(sync.isConnected) start(); else component.el.addEventListener('connected', start); - + function start(){ var colorRef = sync.dataRef.child('material/color'); - + var refChangedLocked = false; - + var firstValue = true; - + component.el.addEventListener('componentchanged', function (event) { var name = event.detail.name; var oldData = event.detail.oldData; var newData = event.detail.newData; - + if (name !== 'material') return; if (refChangedLocked) return; - + if (oldData.color !== newData.color) { if(sync.isMine){ setTimeout(function() {//For some reason A-Frame has a misconfigured material reference if we do this too early @@ -1476,15 +1476,15 @@ } } }); - + colorRef.on('value', function (snapshot) { if (sync.isMine && !firstValue) return; var color = snapshot.val(); - + refChangedLocked = true; component.el.setAttribute('material', 'color', color); refChangedLocked = false; - + firstValue = false; }); } @@ -1513,11 +1513,11 @@ var scene = document.querySelector('a-scene'); var syncSys = scene.systems['sync-system']; if(sync.isConnected) start(); else component.el.addEventListener('connected', start); - + function start(){ component.soundStateRef = sync.dataRef.child('sound/state'); component.soundEventRef = sync.dataRef.child('sound/event'); - + function sendEvent(event) { if (!sync.isMine) return; var event = { @@ -1528,10 +1528,10 @@ }; component.soundEventRef.set(event); } - + component.el.addEventListener('sound-played', sendEvent); component.el.addEventListener('sound-paused', sendEvent); - + component.soundEventRef.on('value', function (snapshot) { if (sync.isMine) return; var event = snapshot.val(); @@ -1546,14 +1546,14 @@ } } }); - + component.el.addEventListener('componentchanged', function (event) { if (!sync.isMine) return; var name = event.detail.name; if (name !== 'n-sound') return; component.soundStateRef.set(event.detail.newData); }); - + component.soundStateRef.on('value', function (snapshot) { if (sync.isMine) return; var state = snapshot.val(); @@ -1608,7 +1608,7 @@ if (oldData.lost) { this.el.removeEventListener('stateremoved', this.actOnTargetsIfStateMatches); } - + this.actOnTargets = function () { function act(el) { if (this.data.emit) { @@ -1621,17 +1621,17 @@ el.removeState(this.data.lose); } } - this.data.targets.forEach(act.bind(this)); + if(this.data.targets) this.data.targets.forEach(act.bind(this)); if(this.data.target) act.call(this, this.data.target); }.bind(this); - + this.actOnTargetsIfStateMatches = function (event) { var state = event.detail.state; if (state === this.data.gained || state === this.data.lost) { this.actOnTargets(); } }.bind(this); - + if (this.data.on) { this.el.addEventListener(this.data.on, this.actOnTargets); } @@ -1651,4 +1651,5 @@ /***/ } -/******/ ]); \ No newline at end of file +/******/ ]); +//# sourceMappingURL=aframe-altspace-component.js.map \ No newline at end of file diff --git a/dist/aframe-altspace-component.js.map b/dist/aframe-altspace-component.js.map new file mode 100644 index 0000000..596b5ce --- /dev/null +++ b/dist/aframe-altspace-component.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///webpack/bootstrap 4d409d583224f60e7a34","webpack:///./src/index.js","webpack:///./src/altspace.js","webpack:///./src/altspace-cursor-collider.js","webpack:///./src/altspace-tracked-controls.js","webpack:///./src/native-components.js","webpack:///./src/native-resources.js","webpack:///./src/sync.js","webpack:///./src/sync-system.js","webpack:///./src/sync-transform.js","webpack:///./src/sync-color.js","webpack:///./src/sync-n-sound.js","webpack:///./src/wire.js"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;;;;;;ACtCA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;ACdA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,cAAa,QAAQ;AACrB;AACA,cAAa,OAAO;AACpB;AACA,cAAa,QAAQ;AACrB;AACA,cAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAiB,mCAAmC;AACpD,kBAAiB,oCAAoC;AACrD,kBAAiB,kCAAkC;AACnD,kBAAiB;AACjB,IAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,wCAAuC,eAAe;AACtD;AACA;AACA;AACA,GAAE;AACF;AACA;;AAEA,IAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA,IAAG;;AAEH;AACA;AACA;AACA;AACA,wBAAuB,EAAE;;AAEzB;AACA;AACA;AACA,0BAAyB,EAAE;;AAE3B;AACA;AACA;AACA;AACA,uBAAsB,EAAE;;AAExB;AACA;AACA;AACA;AACA,sBAAqB,EAAE;;;AAGvB;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAI;AACJ;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,GAAE;;AAEF;AACA;AACA;AACA,GAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAqB;AACrB;;AAEA,IAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,2CAA0C,uDAAuD;AACjG,2CAA0C,uDAAuD;AACjG,GAAE;;AAEF;AACA;AACA;AACA;AACA,GAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA,GAAE;;AAEF;AACA,2BAA0B,QAAQ;AAClC;AACA;AACA;AACA,GAAE;;AAEF;AACA,2BAA0B,QAAQ;AAClC;AACA;AACA;AACA,GAAE;;AAEF,IAAG;;AAEH;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAE;;AAEF;AACA;AACA,GAAE;;AAEF;AACA;AACA,GAAE;;AAEF;AACA;AACA,GAAE;;AAEF;;AAEA,EAAC;;;;;;;AC5OD;;AAEA;AACA,4BAA2B,WAAW;AACtC;AACA;AACA,8BAA6B,WAAW;AACxC;AACA,IAAG;AACH;;AAEA;AACA;AACA;AACA;AACA,WAAU,QAAQ;AAClB;AACA;AACA,YAAW,WAAW,gBAAgB,EAAE;AACxC;AACA;AACA;AACA;AACA,KAAI;AACJ,IAAG;AACH;AACA;AACA;AACA,GAAE;;AAEF,EAAC;;;;;;;AC9BD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAC;;;;;;;;ACpCD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,yDAAwD,kBAAkB;AAC1E;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAU,OAAO;AACjB;AACA;AACA;AACA;AACA;AACA,UAAS;AACT,IAAG;AACH;AACA;AACA;AACA,GAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA,WAAU,OAAO;AACjB;AACA;AACA;AACA;AACA;AACA,UAAS;AACT,IAAG;AACH;AACA;AACA;AACA,GAAE;;AAEF;AACA;AACA;AACA;AACA;AACA,WAAU,OAAO;AACjB,WAAU,OAAO;AACjB,WAAU,OAAO;AACjB;AACA,WAAU,OAAO;AACjB;AACA,WAAU,OAAO;AACjB;AACA,WAAU,OAAO;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAU,8BAA8B;AACxC,cAAa;AACb;AACA;AACA,MAAK;AACL;AACA;AACA,OAAM;AACN,eAAc,6BAA6B;AAC3C,YAAW,gCAAgC;AAC3C,aAAY,+BAA+B;AAC3C,sBAAqB,mBAAmB;AACxC,oBAAmB;AACnB;AACA,GAAE;;AAEF;AACA;AACA;;AAEA;AACA,6BAA4B,0BAA0B,GAAG,uBAAuB;AAChF,KAAI,2BAA2B,OAAO,wBAAwB;AAC9D;AACA;AACA;AACA;AACA;AACA,WAAU,KAAK;AACf,WAAU,OAAO;AACjB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAU,OAAO;AACjB;AACA;AACA;AACA;AACA;AACA;AACA,gBAAe,kCAAkC;AACjD,aAAY,eAAe;AAC3B,aAAY,+BAA+B;AAC3C,WAAU;AACV;AACA,GAAE;;;AAGF;AACA;AACA;AACA;AACA;AACA,WAAU,KAAK;AACf;AACA;AACA;AACA;AACA;AACA;AACA,gBAAe,kCAAkC;AACjD,aAAY,eAAe;AAC3B,WAAU,eAAe;AACzB,WAAU;AACV;AACA,GAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA,WAAU,OAAO;AACjB,WAAU,OAAO;AACjB,WAAU,OAAO;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAe,kCAAkC;AACjD,aAAY,eAAe;AAC3B,aAAY,+BAA+B;AAC3C,aAAY,+BAA+B;AAC3C,gBAAe,eAAe;AAC9B,WAAU;AACV;AACA,GAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAU,KAAK;AACf;AACA;AACA;AACA;AACA;AACA;AACA,eAAc,QAAQ;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAI;AACJ,IAAG;AACH;AACA;AACA;;AAEA;AACA;AACA,KAAI;AACJ,IAAG;AACH;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAI;AACJ,IAAG;AACH;AACA;AACA;AACA,KAAI;AACJ,IAAG;AACH;AACA;AACA;AACA,KAAI;AACJ,IAAG;AACH;AACA,gBAAe,kCAAkC;AACjD,aAAY,iCAAiC;AAC7C,WAAU;AACV;AACA,GAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAU,OAAO;AACjB;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAI;;AAEJ;AACA;AACA,KAAI;AACJ,IAAG;AACH;AACA;AACA;AACA,eAAc,6BAA6B;AAC3C;AACA,GAAE;;AAEF;AACA;AACA;AACA;AACA;AACA,WAAU,OAAO;AACjB,WAAU,OAAO;AACjB;AACA,WAAU,OAAO;AACjB,WAAU,QAAQ;AAClB;AACA,WAAU,QAAQ;AAClB;AACA,WAAU,QAAQ;AAClB;AACA,WAAU,OAAO;AACjB,WAAU,OAAO;AACjB;AACA;AACA;AACA,WAAU,OAAO;AACjB;AACA,WAAU,OAAO;AACjB;AACA,WAAU,OAAO;AACjB;AACA,WAAU,OAAO;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAG;;AAEH;AACA;AACA;AACA,aAAY,OAAO;AACnB;AACA;AACA,sCAAqC,WAAW;AAChD,IAAG;AACH;AACA;AACA;AACA;AACA;AACA,IAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAG;AACH;AACA,SAAQ,iBAAiB;AACzB,UAAS,iBAAiB;AAC1B,UAAS,iBAAiB;AAC1B,WAAU,kBAAkB;AAC5B,aAAY,6BAA6B;AACzC,eAAc,kBAAkB;AAChC,cAAa,kBAAkB;AAC/B,mBAAkB,4BAA4B;AAC9C,YAAW,4BAA4B;AACvC,kBAAiB,4BAA4B;AAC7C,kBAAiB,6BAA6B;AAC9C,cAAa,yCAAyC;AACtD;AACA,GAAE;;AAEF,EAAC;;;;;;;AChbD;;AAEA;AACA;AACA;AACA,IAAG,kBAAkB;AACrB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AChMA;AACA;AACA,mBAAkB,uBAAuB,sBAAsB;AAC/D;AACA;AACA;AACA;AACA,2CAA0C;AAC1C;AACA;AACA;;;;AAIA;AACA;AACA,wBAAuB,uBAAuB;AAC9C,4BAA2B,0BAA0B;AACrD;AACA;AACA,UAAS,OAAO;AAChB;AACA;AACA;AACA;AACA;AACA;AACA,UAAS,kBAAkB;AAC3B,WAAU,iBAAiB;AAC3B,GAAE;AACF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,mCAAkC;;;AAGlC;AACA;AACA;AACA,gDAA+C,SAAS;AACxD;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,KAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,KAAI;AACJ;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAI;;AAEJ;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA,MAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAkB;AAClB;AACA,IAAG;AACH;AACA,EAAC;;;;;;;AC5JD;AACA;AACA;AACA,qCAAoC,+FAA+F;AACnI;AACA;AACA;AACA,UAAS,OAAO;AAChB,UAAS,OAAO;AAChB,UAAS,OAAO;AAChB,UAAS,OAAO;AAChB;AACA;AACA;AACA;AACA;AACA,YAAW,gCAAgC;AAC3C,SAAQ,gCAAgC;AACxC,cAAa,gCAAgC;AAC7C,YAAW;AACX,GAAE;AACF;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAG;AACH;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAI;;AAEJ;AACA;AACA;AACA;AACA,8CAA6C,mBAAmB;AAChE,MAAK;AACL,KAAI;;AAEJ;AACA;AACA;AACA;AACA,4CAA2C,iBAAiB;AAC5D,MAAK;AACL,KAAI;;AAEJ;AACA;AACA;;;AAGA;AACA;AACA;;AAEA,0CAAyC,qCAAqC;AAC9E;AACA,KAAI;;;AAGJ;AACA,uBAAsB,yCAAyC,EAAE;AACjE,KAAI;AACJ,IAAG;AACH;AACA,EAAC;;;;;;;ACvFD;AACA;;AAEA;AACA;AACA,oBAAmB,uBAAuB;AAC1C,IAAG,gBAAgB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAE;AACF;AACA;AACA;AACA,gCAA+B;;AAE/B;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,oBAAmB,qBAAqB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA,KAAI;AACJ;AACA,oBAAmB,8BAA8B;AACjD;AACA;AACA;AACA;AACA,KAAI;;AAEJ;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAI;;AAEJ;AACA;AACA,KAAI;;AAEJ;AACA;AACA,KAAI;;AAEJ;AACA;AACA,KAAI;;AAEJ;AACA;AACA,KAAI;;AAEJ;AACA;AACA,KAAI;;AAEJ;AACA;;AAEA;AACA;;AAEA;AACA;AACA,MAAK;AACL;AACA,MAAK;AACL;AACA,MAAK;AACL;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;AACA;AACA,EAAC;;;;;;;ACjJD;AACA;AACA,oBAAmB,uBAAuB;AAC1C,IAAG,gBAAgB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAE;AACF;AACA;AACA;AACA,gCAA+B;;AAE/B;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,8BAA6B;AAC7B;AACA,QAAO;AACP;AACA;AACA,KAAI;;AAEJ;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,KAAI;AACJ;AACA;AACA,EAAC;;;;;;;ACrDD;AACA,yCAAwC,gBAAgB;AACxD,oBAAmB,uBAAuB;AAC1C,IAAG,gBAAgB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA,WAAU,EAAE;AACZ;AACA;AACA;AACA;AACA;AACA,gCAA+B;;AAE/B;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,KAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,KAAI;AACJ;AACA,GAAE;AACF;AACA;AACA;AACA;AACA,EAAC;;;;;;;ACtED;AACA;AACA;AACA,eAAc,OAAO;AACrB,eAAc,OAAO;AACrB,eAAc,OAAO;AACrB,eAAc,OAAO;AACrB,eAAc,OAAO;AACrB,eAAc,OAAO;AACrB,eAAc,SAAS;AACvB,eAAc,SAAS;AACvB;AACA;AACA;AACA;AACA;AACA,QAAO,eAAe;AACtB,UAAS,eAAe;AACxB,YAAW,eAAe;AAC1B,UAAS,eAAe;AACxB,UAAS,eAAe;AACxB,UAAS,eAAe;AACxB,aAAY,oBAAoB;AAChC,YAAW;AACX,GAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,IAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAE;AACF;AACA;AACA;AACA;AACA;AACA,EAAC","file":"aframe-altspace-component.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap 4d409d583224f60e7a34\n **/","if (typeof AFRAME === 'undefined') {\r\n throw new Error('Component attempted to register before AFRAME was available.');\r\n}\r\n\r\nrequire('./altspace');\r\nrequire('./altspace-cursor-collider');\r\nrequire('./altspace-tracked-controls');\r\nrequire('./native-components');\r\nrequire('./native-resources');\r\nrequire('./sync');\r\nrequire('./sync-system');\r\nrequire('./sync-transform');\r\nrequire('./sync-color');\r\nrequire('./sync-n-sound');\r\nrequire('./wire');\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/index.js\n ** module id = 0\n ** module chunks = 0\n **/","/**\r\n* @namespace altspace\r\n*/\r\n\r\n/**\r\n* The altspace component makes A-Frame apps compatible with AltspaceVR.\r\n*\r\n* **Note**: If you use the `embedded` A-Frame component on your scene, you must include it *before* the `altspace` component, or your app will silently fail.\r\n* @mixin altspace\r\n* @memberof altspace\r\n* @property {boolean} usePixelScale=`false` - Allows you to use A-Frame units as CSS pixels.\r\n* This is the default behavior for three.js apps, but not for A-Frame apps.\r\n* @property {string} verticalAlign=`middle` - Puts the origin at the `bottom`, `middle` (default),\r\n* or `top` of the Altspace enclosure.\r\n* @property {boolean} enclosuresOnly=`true` - Prevents the scene from being created if\r\n* enclosure is flat.\r\n* @property {boolean} fullspace=`false` - Puts the app into fullspace mode.\r\n*\r\n* @example\r\n* \r\n* My A-Frame Scene\r\n* \r\n* \r\n* \r\n* \r\n* \r\n* \r\n* \r\n* \r\n*/\r\nAFRAME.registerComponent('altspace', {\r\n version: '1.3.2',\r\n schema: {\r\n\tusePixelScale: { type: 'boolean', default: 'false'},\r\n\tverticalAlign: { type: 'string', default: 'middle'},\r\n\tenclosuresOnly:{ type: 'boolean', default: 'true'},\r\n\tfullspace: { type: 'boolean', default: 'false'}\r\n },\r\n\r\n /*\r\n * Called once when component is attached. Generally for initial setup.\r\n */\r\n init: function () {\r\n\tif (!(this.el.object3D instanceof THREE.Scene)) {\r\n\t console.warn('aframe-altspace-component can only be attached to a-scene');\r\n\t return;\r\n\t}\r\n\r\n\tif (window.altspace && window.altspace.inClient) {\r\n\t this.el.setAttribute('vr-mode-ui', {enabled: false});\r\n\t this.initRenderer();\r\n\t this.initCursorEvents();\r\n\t this.initCollisionEvents();\r\n\t} else {\r\n\t console.warn('aframe-altspace-component only works inside of AltspaceVR');\r\n\t}\r\n\r\n },\r\n\r\n /*\r\n * Called on every single tick or render loop of the scene.\r\n */\r\n tick: function (t, dt) {\r\n if(this.el.object3D.updateAllBehaviors)\r\n this.el.object3D.updateAllBehaviors();\r\n },\r\n\r\n /*\r\n * Called when a component is removed (e.g., via removeAttribute).\r\n * Generally undoes all modifications to the entity.\r\n */\r\n remove: function () { },\r\n\r\n /*\r\n * Called on each scene tick.\r\n */\r\n // tick: function (t) { },\r\n\r\n /*\r\n * Called when entity pauses.\r\n * Use to stop or remove any dynamic or background behavior such as events.\r\n */\r\n pause: function () { },\r\n\r\n /*\r\n * Called when entity resumes.\r\n * Use to continue or add any dynamic or background behavior such as events.\r\n */\r\n play: function () { },\r\n\r\n\r\n /********** Helper Methods **********/\r\n\r\n /*\r\n * Swap in Altspace renderer when running in AltspaceVR.\r\n */\r\n initRenderer: function () {\r\n\r\n\tvar scene = this.el.object3D;\r\n\taltspace.getEnclosure().then(function(e)\r\n\t{\r\n\t\tif(this.data.fullspace){\r\n\t\t\te.requestFullspace();\r\n\t\t\te.addEventListener('fullspacechange', function(){\r\n\t\t\t\tscene.scale.setScalar(e.pixelsPerMeter);\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tif (!this.data.usePixelScale || this.data.fullspace){\r\n\t\t\tscene.scale.setScalar(e.pixelsPerMeter);\r\n\t\t}\r\n\r\n\t switch (this.data.verticalAlign) {\r\n\t\tcase 'bottom':\r\n\t\t scene.position.y -= e.innerHeight / 2;\r\n\t\t break;\r\n\t\tcase 'top':\r\n\t\t scene.position.y += e.innerHeight / 2;\r\n\t\t break;\r\n\t\tcase 'middle':\r\n\t\t break;\r\n\t\tdefault:\r\n\t\t console.warn('Unexpected value for verticalAlign: ', this.data.verticalAlign);\r\n\t }\r\n\r\n\t if(this.data.enclosuresOnly && e.innerDepth === 1){\r\n\t\tthis.el.renderer.render(new THREE.Scene());\r\n\t\tthis.el.renderer = this.el.effect = oldRenderer;\r\n\r\n\t }\r\n\t}.bind(this));\r\n\r\n\tvar oldRenderer = this.el.renderer;\r\n\tvar renderer = this.el.renderer = this.el.effect = altspace.getThreeJSRenderer({\r\n\t aframeComponentVersion: this.version\r\n\t});\r\n\tvar noop = function() {};\r\n\trenderer.setSize = noop;\r\n\trenderer.setPixelRatio = noop;\r\n\trenderer.setClearColor = noop;\r\n\trenderer.clear = noop;\r\n\trenderer.enableScissorTest = noop;\r\n\trenderer.setScissor = noop;\r\n\trenderer.setViewport = noop;\r\n\trenderer.getPixelRatio = noop;\r\n\trenderer.getMaxAnisotropy = noop;\r\n\trenderer.setFaceCulling = noop;\r\n\trenderer.context = {canvas: {}};\r\n\trenderer.shadowMap = {};\r\n\r\n },\r\n\r\n /*\r\n * Emulate A-Frame cursor events when running in altspaceVR.\r\n */\r\n initCursorEvents: function() {\r\n\r\n\tvar scene = this.el.object3D;\r\n\tvar cursorEl = document.querySelector('a-cursor') || document.querySelector('a-entity[cursor]');\r\n\tif (cursorEl) {\r\n\t // Hide A-Frame cursor mesh.\r\n\t cursorEl.setAttribute('material', 'transparent', true);\r\n\t cursorEl.setAttribute('material', 'opacity', 0.0);\r\n\t}\r\n\r\n\tvar emit = function (eventName, event) {\r\n\t\t// Fire events on intersected object and A-Frame cursor.\r\n\t\tvar targetEl = event.target.el;\r\n\t\tif (cursorEl) cursorEl.emit(eventName, { target: targetEl, ray: event.ray, point: event.point });\r\n\t\tif (targetEl) targetEl.emit(eventName, { target: targetEl, ray: event.ray, point: event.point });\r\n\t} ;\r\n\r\n\tvar cursordownObj = null;\r\n\tscene.addEventListener('cursordown', function(event) {\r\n\t cursordownObj = event.target;\r\n\t emit('mousedown', event);\r\n\t});\r\n\r\n\tscene.addEventListener('cursorup', function(event) {\r\n\t emit('mouseup', event);\r\n\t if (event.target.uuid === cursordownObj.uuid) {\r\n\t\temit('click', event);\r\n\t }\r\n\t cursordownObj = null;\r\n\t});\r\n\r\n\tscene.addEventListener('cursorenter', function(event) {\r\n\t if (!event.target.el) { return; }\r\n\t event.target.el.addState('hovered');\r\n\t if (cursorEl) cursorEl.addState('hovering');\r\n\t emit('mouseenter', event);\r\n\t});\r\n\r\n\tscene.addEventListener('cursorleave', function(event) {\r\n\t if (!event.target.el) { return; }\r\n\t event.target.el.removeState('hovered');\r\n\t if (cursorEl) cursorEl.removeState('hovering');\r\n\t emit('mouseleave', event);\r\n\t});\r\n\r\n },\r\n\r\n initCollisionEvents: function () {\r\n\r\n\tvar scene = this.el.object3D;\r\n\r\n\tvar emit = function (eventName, event) {\r\n\t\tvar targetEl = event.target.el;\r\n\t\tif (!targetEl) return;\r\n\r\n\t\t//remap target and other from object3Ds to aframe element\r\n\t\tevent.target = targetEl;\r\n\t\tif (event.other && event.other.el) {\r\n\t\t\tevent.other = event.other.el;\r\n\t\t}\r\n\t\ttargetEl.emit(eventName, event);\r\n\t};\r\n\r\n\tscene.addEventListener('collisionenter', function (event) {\r\n\t\temit('collisionenter', event);\r\n\t});\r\n\r\n\tscene.addEventListener('collisionexit', function (event) {\r\n\t\temit('collisionexit', event);\r\n\t});\r\n\r\n\tscene.addEventListener('triggerenter', function (event) {\r\n\t\temit('triggerenter', event);\r\n\t});\r\n\r\n\tscene.addEventListener('triggerexit', function (event) {\r\n\t\temit('triggerexit', event);\r\n\t});\r\n\r\n }\r\n\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/altspace.js\n ** module id = 1\n ** module chunks = 0\n **/","(function(){\r\n\r\n\tfunction setColliderFlag(obj, state) {\r\n\t\tobj.userData.altspace = {collider: {enabled: state}};\r\n\t\tobj.traverse(function (obj) {\r\n\t\t\tif (obj instanceof THREE.Mesh) {\r\n\t\t\t\tobj.userData.altspace = {collider: {enabled: state}};\r\n\t\t\t}\r\n\t\t})\r\n\t}\r\n\r\n\t/**\r\n\t* Enable or disable cursor collision on the object.\r\n\t* @mixin altspace-cursor-collider\r\n\t* @memberof altspace\r\n\t* @prop {boolean} enabled=true - The state of the cursor collider.\r\n\t*/\r\n\tAFRAME.registerComponent('altspace-cursor-collider', {\r\n\t\tschema: { enabled: { default: true } },\r\n\t\tinit: function () {\r\n\t\t\tsetColliderFlag(this.el.object3D, this.data.enabled);\r\n\t\t\tthis.el.addEventListener('model-loaded', (function(){\r\n\t\t\t\tsetColliderFlag(this.el.object3D, this.data.enabled);\r\n\t\t\t}).bind(this));\r\n\t\t},\r\n\t\tupdate: function () {\r\n\t\t\tsetColliderFlag(this.el.object3D, this.data.enabled);\r\n\t\t}\r\n\t});\r\n\r\n})();\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/altspace-cursor-collider.js\n ** module id = 2\n ** module chunks = 0\n **/","/**\r\n* Enables tracked control support for A-Frame applications that use the built-in\r\n* `tracked-controls`, `vive-controls` or `hand-controls` components.\r\n* @mixin altspace-tracked-controls\r\n* @memberof altspace\r\n*/\r\nAFRAME.registerComponent('altspace-tracked-controls', {\r\n init: function () {\r\n\tthis.gamepadIndex = null;\r\n\tthis.trackedControlsSystem = document.querySelector('a-scene').systems['tracked-controls'];\r\n\tthis.systemGamepads = 0;\r\n\taltspace.getGamepads();\r\n },\r\n tick: function () {\r\n\t if (\r\n\t\tthis.trackedControlsSystem &&\r\n\t\tthis.systemGamepads !== this.trackedControlsSystem.controllers.length &&\r\n\t\twindow.altspace && altspace.getGamepads && altspace.getGamepads().length\r\n\t ) {\r\n\t\tvar components = this.el.components;\r\n\t\tif (components['paint-controls']) {\r\n\t\t this.gamepadIndex = components['paint-controls'].data.hand === 'left' ? 2 : 1;\r\n\t\t}\r\n\t\tif (this.gamepadIndex === null && components['hand-controls']) {\r\n\t\t this.gamepadIndex = components['hand-controls'].data === 'left' ? 2 : 1;\r\n\t\t}\r\n\t\tif (this.gamepadIndex === null && components['vive-controls']) {\r\n\t\t this.gamepadIndex = components['vive-controls'].data.hand === 'left' ? 2 : 1;\r\n\t\t}\r\n\t\tif (this.gamepadIndex === null && components['tracked-controls']) {\r\n\t\t this.gamepadIndex = components['tracked-controls'].data.controller;\r\n\t\t}\r\n\t\tthis.el.setAttribute('tracked-controls', 'id', altspace.getGamepads()[this.gamepadIndex].id);\r\n\t\tthis.el.setAttribute('tracked-controls', 'controller', 0);\r\n\t\tthis.systemGamepads = this.trackedControlsSystem.controllers.length;\r\n\t }\r\n }\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/altspace-tracked-controls.js\n ** module id = 3\n ** module chunks = 0\n **/","\r\n/**\r\n* This set of components map to various objects and effects that are provided\r\n* natively by AltspaceVR. Your management of these objects may be limited to\r\n* some degree, but they will tend to be more performant than SDK equivalents,\r\n* or may provide some functionality not otherwise available to the SDK.\r\n* @namespace native\r\n*/\r\n(function () {\r\n\tif (!window.altspace || !altspace.inClient) {\r\n\t\tvar noop = function () {};\r\n\t\twindow.altspace = {\r\n\t\t\taddNativeComponent: noop,\r\n\t\t\tupdateNativeComponent: noop,\r\n\t\t\tremoveNativeComponent: noop\r\n\t\t};\r\n\t}\r\n\r\n\tvar placeholderGeometry = new THREE.BoxGeometry(0.001, 0.001, 0.001);\r\n\tvar placeholderMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 });\r\n\tplaceholderMaterial.visible = false;\r\n\tvar PlaceholderMesh = function () {\r\n\t\tTHREE.Mesh.call( this, placeholderGeometry, placeholderMaterial );\r\n\t};\r\n\tPlaceholderMesh.prototype = Object.create( THREE.Mesh.prototype );\r\n\tPlaceholderMesh.prototype.constructor = THREE.PlaceholderMesh;\r\n\r\n\tfunction meshInit(mesh) {\r\n\t\t//If you attach native components to an entity, it will not use a default collider\r\n\t\tmesh.userData.altspace = mesh.userData.altspace || {};\r\n\t\tmesh.userData.altspace.collider = mesh.userData.altspace.collider || {};\r\n\t\tmesh.userData.altspace.collider.enabled = false;\r\n\r\n\t\taltspace.addNativeComponent(mesh, this.name);\r\n\t}\r\n\r\n\tfunction nativeComponentInit() {\r\n\t\tvar mesh = this.el.getOrCreateObject3D('mesh', PlaceholderMesh);\r\n\r\n\t\tmeshInit.call(this, mesh);\r\n\r\n\t\t//to pass defaults\r\n\t\tthis.update(this.data);\r\n\t}\r\n\tfunction nativeComponentRemove() {\r\n\t\tvar mesh = this.el.getObject3D('mesh');\r\n\t\taltspace.removeNativeComponent(mesh, this.name);\r\n\t}\r\n\tfunction nativeComponentUpdate(oldData) {\r\n\t\taltspace.updateNativeComponent(this.el.object3DMap.mesh, this.name, this.data);\r\n\t}\r\n\r\n\tfunction callComponent(functionName, functionArguments) {\r\n\t\taltspace.callNativeComponent(this.el.object3DMap.mesh, this.name, functionName, functionArguments)\r\n\t}\r\n\r\n\t/**\r\n\t* Attach a given native object to this entity.\r\n\t* @mixin n-object\r\n\t* @memberof native\r\n\t* @prop {string} res - The identifier for the resource you want. This component\r\n\t* can accept all resources except for `interactables`.\r\n\t* @example \r\n\t*/\r\n\tAFRAME.registerComponent('n-object', {\r\n\t\tschema: {\r\n\t\t\tres: {type: 'string'}\r\n\t\t},\r\n\t\tinit: nativeComponentInit,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tremove: nativeComponentRemove\r\n\t});\r\n\r\n\t/**\r\n\t* Create an object that spawns additional copies of itself when grabbed by a user (the copies are not spawners themselves).\r\n\t* These copies will be physically interactive and automatically synchronized\r\n\t* between users.\r\n\t* @mixin n-spawner\r\n\t* @memberof native\r\n\t* @prop {string} res - The identifier for the resource you want. This component\r\n\t* can only accept resources of type `interactables`.\r\n\t* @example \r\n\t*/\r\n\tAFRAME.registerComponent('n-spawner', {\r\n\t\tschema: {\r\n\t\t\tres: {type: 'string'}\r\n\t\t},\r\n\t\tinit: nativeComponentInit,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tremove: nativeComponentRemove\r\n\t});\r\n\r\n\t/**\r\n\t* Creates dynamic 2D text on the entity. The text will wrap automatically based on the width and height provided.\r\n\t* This text will be clearer than texture-based text and more performant than geometry-based test.\r\n\t* @mixin n-text\r\n\t* @memberof native\r\n\t* @prop {string} text - The text to be drawn.\r\n\t* @prop {number} fontSize=10 - The height of the letters. 10pt ~= 1m\r\n\t* @prop {number} width=10 - The width of the text area in meters. If the\r\n\t* text is wider than this value, the overflow will be wrapped to the next line.\r\n\t* @prop {number} height=1 - The height of the text area in meters. If the\r\n\t* text is taller than this value, the overflow will be cut off.\r\n\t* @prop {string} horizontalAlign=middle - The horizontal anchor point for\r\n\t* the text. Can be `left`, `middle`, or `right`.\r\n\t* @prop {string} verticalAlign=middle - The vertical anchor point for the\r\n\t* text. Can be `top`, `middle`, or `bottom`.\r\n\t*/\r\n\tAFRAME.registerComponent('n-text', {\r\n\t\tinit: nativeComponentInit,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tremove: nativeComponentRemove,\r\n\t\tschema: {\r\n\t\t\ttext: { default: '', type: 'string' },\r\n\t\t\t/*color: { default: 'white',\r\n\t\t\t\tparse: function(value) {\r\n\t\t\t\t\treturn parseFloat(value, 10);\r\n\t\t\t\t},\r\n\t\t\t\tstringify: function(value) {\r\n\t\t\t\t\treturn value.toString();\r\n\t\t\t\t}},*/\r\n\t\t\tfontSize: { default: '10', type: 'int' },//roughly a meter tall\r\n\t\t\twidth: { default: '10', type: 'number' },//in meters\r\n\t\t\theight: { default: '1', type: 'number' },//in meters\r\n\t\t\thorizontalAlign: { default: 'middle'},\r\n\t\t\tverticalAlign: { default: 'middle'}\r\n\t\t}\r\n\t});\r\n\r\n\t//object: collides against: objects / enviroment / cursor\r\n\t//environment: can be teleported onto, and collides against: objects / environment / cursor\r\n\t//hologram: collides against: cursor / holograms\r\n\r\n\t/**\r\n\t* Abstract base class for {@link n.n-sphere-collider}, {@link n.n-box-collider},\r\n\t* {@link n.n-capsule-collider}, and {@link n.n-mesh-collider}. You cannot use\r\n\t* this class directly, but instead you should add one of those components\r\n\t* to your objects.\r\n\t* @name n-collider\r\n\t* @mixin n-collider\r\n\t* @memberof native\r\n\t* @prop {vec3} center=0,0,0 - The offset of the collider in local space.\r\n\t* @prop {string} type=hologram - The type of collider, one of: `object` | `environment` | `hologram`.\r\n\t* Object colliders collide with other objects, the environment, and the cursor.\r\n\t* Environment colliders collide with everything objects do, but you can also\r\n\t* teleport onto them. Hologram colliders only collide with other holograms and\r\n\t* the cursor.\r\n\t*/\r\n\r\n\t/**\r\n\t* Create a spherical collider on this entity.\r\n\t* @mixin n-sphere-collider\r\n\t* @memberof native\r\n\t* @extends native.n-collider\r\n\t* @prop {number} radius=1 - The size of the collider in meters.\r\n\t*/\r\n\tAFRAME.registerComponent('n-sphere-collider', {\r\n\t\tinit:nativeComponentInit,\r\n\t\tremove: nativeComponentRemove,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tschema: {\r\n\t\t\tisTrigger: { default: false, type: 'boolean' },\r\n\t\t\tcenter: { type: 'vec3' },\r\n\t\t\tradius: { default: '0', type: 'number' },\r\n\t\t\ttype: {default: 'object'}\r\n\t\t}\r\n\t});\r\n\r\n\r\n\t/**\r\n\t* Create a box-shaped collider on this entity.\r\n\t* @mixin n-box-collider\r\n\t* @memberof native\r\n\t* @extends native.n-collider\r\n\t* @prop {vec3} size=1,1,1 - The dimensions of the collider.\r\n\t*/\r\n\tAFRAME.registerComponent('n-box-collider', {\r\n\t\tinit:nativeComponentInit,\r\n\t\tremove: nativeComponentRemove,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tschema: {\r\n\t\t\tisTrigger: { default: false, type: 'boolean' },\r\n\t\t\tcenter: { type: 'vec3' },\r\n\t\t\tsize: { type: 'vec3' },\r\n\t\t\ttype: {default: 'object'}\r\n\t\t}\r\n\t});\r\n\r\n\t/**\r\n\t* Create a capsule-shaped collider on this entity. Capsules\r\n\t* are a union of a cylinder and two spheres on top and bottom.\r\n\t* @mixin n-capsule-collider\r\n\t* @memberof native\r\n\t* @extends native.n-collider\r\n\t* @prop {number} radius=1 - The radius of the capsule in meters.\r\n\t* @prop {number} height=1 - The height of the shaft of the capsule in meters.\r\n\t* @prop {string} direction=y - The axis with which the capsule is aligned.\r\n\t* One of `x`, `y`, or `z`.\r\n\t*/\r\n\tAFRAME.registerComponent('n-capsule-collider', {\r\n\t\tinit:nativeComponentInit,\r\n\t\tremove: nativeComponentRemove,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tschema: {\r\n\t\t\tisTrigger: { default: false, type: 'boolean' },\r\n\t\t\tcenter: { type: 'vec3' },\r\n\t\t\tradius: { default: '0', type: 'number' },\r\n\t\t\theight: { default: '0', type: 'number' },\r\n\t\t\tdirection: { default: 'y' },\r\n\t\t\ttype: {default: 'object'}\r\n\t\t}\r\n\t});\r\n\r\n\t/**\r\n\t* Enable collision for the entire attached mesh. This is expensive to evaluate, so should only be used on\r\n\t* low-poly meshes.\r\n\t* @mixin n-mesh-collider\r\n\t* @memberof native\r\n\t* @extends native.n-collider\r\n\t* @example \r\n\t* @prop {bool} convex=true - Whether the collider should be convex or concave. Set this to false if you have holes\r\n\t* in your mesh. Convex colliders are limited to 255 triangles. Note: concave colliders can be significantly more\r\n\t* expensive comparet to conves colliders.\r\n\t*/\r\n\tAFRAME.registerComponent('n-mesh-collider', {\r\n\t\t_forEachMesh: function (func) {\r\n\t\t\tvar obj = this.el.object3DMap.mesh;\r\n\t\t\tif (!obj) { return; }\r\n\t\t\tif (obj instanceof THREE.Mesh) {\r\n\t\t\t\tfunc(obj);\r\n\t\t\t}\r\n\t\t\tobj.traverse(function (childObj) {\r\n\t\t\t\tif (childObj instanceof THREE.Mesh) {\r\n\t\t\t\t\tfunc(childObj);\r\n\t\t\t\t}\r\n\t\t\t}.bind(this));\r\n\t\t},\r\n\t\t_initObj: function () {\r\n\t\t\tthis._forEachMesh(function (mesh) {\r\n\t\t\t\tmeshInit.call(this, mesh);\r\n\r\n\t\t\t\t//to pass defaults\r\n\t\t\t\taltspace.updateNativeComponent(mesh, this.name, this.data);\r\n\t\t\t}.bind(this));\r\n\t\t},\r\n\t\tinit: function () {\r\n\t\t\t// Allow a-frame to create a PlaceholderMesh if there isn't already one, so that the native collider is\r\n\t\t\t// registered.\r\n\t\t\tthis.el.getOrCreateObject3D('mesh', PlaceholderMesh);\r\n\r\n\t\t\t// Initialize the existing mesh\r\n\t\t\tthis._initObj();\r\n\r\n\t\t\tthis.el.addEventListener('model-loaded', function () {\r\n\t\t\t\t// Re-initialize the collider if a new model is loaded\r\n\t\t\t\tthis._initObj();\r\n\t\t\t}.bind(this));\r\n\t\t},\r\n\t\tremove: function () {\r\n\t\t\tthis._forEachMesh(function (mesh) {\r\n\t\t\t\taltspace.removeNativeComponent(mesh, this.name);\r\n\t\t\t}.bind(this));\r\n\t\t},\r\n\t\tupdate: function (oldData) {\r\n\t\t\tthis._forEachMesh(function (mesh) {\r\n\t\t\t\taltspace.updateNativeComponent(mesh, this.name, this.data);\r\n\t\t\t}.bind(this));\r\n\t\t},\r\n\t\tschema: {\r\n\t\t\tisTrigger: { default: false, type: 'boolean' },\r\n\t\t\tconvex: { default: true, type: 'boolean' },\r\n\t\t\ttype: {default: 'object'}\r\n\t\t}\r\n\t});\r\n\r\n\t/**\r\n\t* Make the object's +Z always face the viewer. Currently will only directly apply to main mesh or native component on the attached entity, not any children or submeshes.\r\n\t* @mixin n-billboard\r\n\t* @memberof native\r\n\t* @example \r\n\t*/\r\n\tAFRAME.registerComponent('n-billboard', {\r\n\t\tinit:nativeComponentInit,\r\n\t\tremove: nativeComponentRemove,\r\n\t});\r\n\r\n\t/**\r\n\t* A container keeps a running tally of how many objects are within\r\n\t* its bounds, and adds and removes the states `container-full` and\r\n\t* `container-empty` based on the current count of objects. Can fire three\r\n\t* special events: `container-full`, `container-empty`, and `container-count-changed`.\r\n\t* @mixin n-container\r\n\t* @memberof native\r\n\t* @prop {number} capacity=4 - The value at which the container will fire the\r\n\t* `container-full` event.\r\n\t*/\r\n\tAFRAME.registerComponent('n-container', {\r\n\t\tinit: function(){\r\n\t\t\tnativeComponentInit.call(this);\r\n\r\n\t\t\tvar el = this.el;\r\n\t\t\tvar component = this;\r\n\r\n\t\t\tel.addEventListener('stateadded', function(event){\r\n\t\t\t\tif(event.detail.state === 'container-full'){\r\n\t\t\t\t\tel.emit('container-full');\r\n\t\t\t\t}\r\n\t\t\t\tif(event.detail.state === 'container-empty'){\r\n\t\t\t\t\tel.emit('container-empty');\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\tel.addEventListener('container-count-changed', function(event){\r\n\t\t\t\tcomponent.count = event.detail.count;\r\n\t\t\t});\r\n\t\t},\r\n\t\tremove: nativeComponentRemove,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tschema: {\r\n\t\t\tcapacity: { default: 4, type: 'number' },\r\n\t\t}\r\n\t});\r\n\r\n\t/**\r\n\t* Play the sound given by the `src` or `res` property from the location\r\n\t* of the entity.\r\n\t* @mixin n-sound\r\n\t* @memberof native\r\n\t* @prop {string} res - The resource identifier for a built-in sound clip.\r\n\t* @prop {string} src - A URL to an external sound clip. The sound can be in WAV, OGG or MP3 format. However. only\r\n\t* WAV is supported on all platforms. MP3 is supported on Gear VR and OGG is supported on desktop.\r\n\t* @prop {string} on - The name of the event that will play this sound clip.\r\n\t* @prop {boolean} loop=false - Tells the clip to loop back to the beginning of the clip\r\n\t* once it's finished.\r\n\t* @prop {boolean} autoplay=false - Tells the clip to start automatically when\r\n\t* the scene loads, instead of waiting for `playSound()`.\r\n\t* @prop {boolean} oneshot=false - Tells the clip to clean itself up when it\r\n\t* finishes playing. Allows for overlapping instances of the sound.\r\n\t* @prop {number} volume=1 - The volume of the clip, from [0,1].\r\n\t* @prop {number} spatialBlend=1 - How spatialized a sound is, from [0,1].\r\n\t* A value of 1 will be fully localized, and the sound will pan left and\r\n\t* right as you turn your head. A value of 0 makes it non-spatialized, and\r\n\t* it will always be heard in both ears.\r\n\t* @prop {number} pitch=1 - The speed multiplier for the sound. 0.5 is one\r\n\t* octave down, and 2 is one octave up.\r\n\t* @prop {number} minDistance=1 - Inside this distance in meters,\r\n\t* the sound volume is at full volume.\r\n\t* @prop {number} maxDistance=12 - If rolloff is 'logarithmic', the sound will stop attenuating at this distance.\r\n\t* If rolloff is 'linear' or 'cosine', the sound will be silent at this distance.\r\n\t* @prop {string} rolloff='logarithmic' - Set this to 'linear' or 'cosine' if you want to cut sounds off at a\r\n\t* maxDistance.\r\n\t*/\r\n\t/**\r\n\t* Fired when a sound has loaded and is ready to be played\r\n\t* @event native.n-sound#n-sound-loaded\r\n\t*/\r\n\tAFRAME.registerComponent('n-sound', {\r\n\t\tinit: function () {\r\n\t\t\tvar src = this.data.src;\r\n\t\t\tif (src && !src.startsWith('http')) {\r\n\t\t\t\tif (src.startsWith('/')) {\r\n\t\t\t\t\tthis.data.src = location.origin + src;\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tvar currPath = location.pathname;\r\n\t\t\t\t\tif (!currPath.endsWith('/')) {\r\n\t\t\t\t\t\tcurrPath = location.pathname.split('/').slice(0, -1).join('/') + '/';\r\n\t\t\t\t\t}\r\n\t\t\t\t\tthis.data.src = location.origin + currPath + src;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tnativeComponentInit.call(this);\r\n\t\t},\r\n\r\n\t\t/**\r\n\t\t* Stop the playing sound, and preserve position in clip.\r\n\t\t* @method native.n-sound#pauseSound\r\n\t\t*/\r\n\t\tpauseSound: function () {\r\n\t\t\tcallComponent.call(this, 'pause');\r\n\t\t\tthis.el.emit('sound-paused');\r\n\t\t},\r\n\r\n\t\t/**\r\n\t\t* Start the sound playing.\r\n\t\t* @method native.n-sound#playSound\r\n\t\t*/\r\n\t\tplaySound: function () {\r\n\t\t\tcallComponent.call(this, 'play');\r\n\t\t\tthis.el.emit('sound-played');\r\n\t\t},\r\n\r\n\t\t/**\r\n\t\t* Jump to a position in the clip.\r\n\t\t* @method native.n-sound#seek\r\n\t\t* @param {number} time - The time in milliseconds to jump to.\r\n\t\t*/\r\n\t\tseek: function (time) {\r\n\t\t\tcallComponent.call(this, 'seek', {time: time});\r\n\t\t},\r\n\t\tremove: function () {\r\n\t\t\tnativeComponentRemove.call(this);\r\n\t\t\tif (this.playHandler) {\r\n\t\t\t this.el.removeEventListener(oldData.on, this.playHandler);\r\n\t\t\t}\r\n\t\t},\r\n\t\tupdate: function (oldData) {\r\n\t\t\tnativeComponentUpdate.call(this, oldData);\r\n\t\t\tif (this.playHandler) {\r\n\t\t\t this.el.removeEventListener(oldData.on, this.playHandler);\r\n\t\t\t}\r\n\t\t\tif (this.data.on) {\r\n\t\t\t this.playHandler = this.playSound.bind(this);\r\n\t\t\t this.el.addEventListener(this.data.on, this.playHandler);\r\n\t\t\t}\r\n\t\t},\r\n\t\tschema: {\r\n\t\t\ton: { type: 'string' },\r\n\t\t\tres: { type: 'string' },\r\n\t\t\tsrc: { type: 'string' },\r\n\t\t\tloop: { type: 'boolean' },\r\n\t\t\tvolume: { type: 'number', default: 1 },\r\n\t\t\tautoplay: { type: 'boolean' },\r\n\t\t\toneshot: { type: 'boolean' },\r\n\t\t\tspatialBlend: { type: 'float', default: 1 },\r\n\t\t\tpitch: { type: 'float', default: 1 },\r\n\t\t\tminDistance: { type: 'float', default: 1 },\r\n\t\t\tmaxDistance: { type: 'float', default: 12 },\r\n\t\t\trolloff: { type: 'string', default: 'logarithmic' },\r\n\t\t}\r\n\t});\r\n\r\n})();\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/native-components.js\n ** module id = 4\n ** module chunks = 0\n **/","// this file is just for good measure. didn't want native-components getting too cluttered.\r\n\r\n/**\r\n* This namespace describes strings that are valid inputs to the various native\r\n* components. Some components can only take certain types of resources, i.e.\r\n* {@link n.n-spawner} can only accept `interactables`.\r\n* @namespace resources\r\n* @example \r\n*/\r\n\r\n/**\r\n* Generic modular building pieces. All pieces are aligned to one corner, such that\r\n* the piece extends out toward -X and +Z.\r\n* @name architecture\r\n* @enum architecture\r\n* @memberof resources\r\n*\r\n* @prop architecture/ceiling-2w-2l\r\n* @prop architecture/ceiling-4w-4l\r\n* @prop architecture/ceiling-4w-4l\r\n* @prop architecture/ceiling-skylight-4w-4l\r\n* @prop architecture/ceiling-skylight-corner-2w-2l\r\n* @prop architecture/ceiling-skylight-edge-2w\r\n* @prop architecture/ceiling-skylight-edge-4w\r\n* @prop architecture/ceiling-skylight-filler-4w-4l-2\r\n* @prop architecture/ceiling-skylight-filler-4w-4l\r\n* @prop architecture/ceiling-slice-concave-2r\r\n* @prop architecture/ceiling-slice-concave-4r\r\n* @prop architecture/ceiling-slice-convex-2r\r\n* @prop architecture/ceiling-slice-convex-4r\r\n* @prop architecture/door-4w-4h\r\n* @prop architecture/floor-2w-2l\r\n* @prop architecture/floor-2w-4l\r\n* @prop architecture/floor-4w-2l\r\n* @prop architecture/floor-4w-4l\r\n* @prop architecture/floor-slice-concave-2r\r\n* @prop architecture/floor-slice-concave-4r\r\n* @prop architecture/floor-slice-convex-2r\r\n* @prop architecture/floor-slice-convex-4r\r\n* @prop architecture/railing-2l\r\n* @prop architecture/railing-4l\r\n* @prop architecture/railing-curve-concave-2r\r\n* @prop architecture/wall-2w-4h\r\n* @prop architecture/wall-4w-4h\r\n* @prop architecture/wall-base-2w\r\n* @prop architecture/wall-base-4w\r\n* @prop architecture/wall-base-curve-concave-2r\r\n* @prop architecture/wall-base-curve-concave-4r\r\n* @prop architecture/wall-base-curve-convex-2r\r\n* @prop architecture/wall-base-curve-convex-4r\r\n* @prop architecture/wall-bulkhead-2w\r\n* @prop architecture/wall-bulkhead-4w\r\n* @prop architecture/wall-bulkhead-curve-concave-2r\r\n* @prop architecture/wall-bulkhead-curve-concave-4r\r\n* @prop architecture/wall-bulkhead-curve-convex-2r\r\n* @prop architecture/wall-bulkhead-curve-convex-4r\r\n* @prop architecture/wall-curve-concave-2r-4h\r\n* @prop architecture/wall-curve-concave-4r-4h\r\n* @prop architecture/wall-curve-convex-2r-4h\r\n* @prop architecture/wall-curve-convex-4r-4h\r\n* @prop architecture/wall-curve-window-concave-4r-4h\r\n* @prop architecture/wall-curve-window-concave-filler-4r-4h\r\n* @prop architecture/wall-curve-window-gap-concave-4r-4h\r\n* @prop architecture/wall-curve-window-gap-end-l-concave-4r-4h\r\n* @prop architecture/wall-curve-window-gap-end-r-concave-4r-4h\r\n* @prop architecture/wall-filler-corner-inner-4h\r\n* @prop architecture/wall-filler-corner-outer-4h\r\n* @prop architecture/wall-window-4w-4h\r\n* @prop architecture/wall-window-filler-2\r\n* @prop architecture/wall-window-gap-2w-4h\r\n* @prop architecture/wall-window-gap-4w-4h\r\n* @prop architecture/wall-window-gap-end-l-2w-4h\r\n* @prop architecture/wall-window-gap-end-l-4w-4h\r\n* @prop architecture/wall-window-gap-end-r-2w-4h\r\n* @prop architecture/wall-window-gap-end-r-4w-4h\r\n*/\r\n\r\n/**\r\n* Particle systems and other native effects\r\n* @name effects\r\n* @enum effects\r\n* @memberof resources\r\n*\r\n* @prop effects/explosion - A particle system with a central flash, then debris flying outward.\r\n* This is a non-looping effect.\r\n* @prop effects/fire - An animated fire particle, suitable for a torch.\r\n* @prop effects/fire-trail - Fire that trails the entity through space as it moves. Only is visible while an object is in motion\r\n* @prop effects/fireworks - A compound particle system that shoots up from the entity,\r\n* explodes into colored sparks, then transitions to gold streamers.\r\n* @prop effects/smoke - Billowing smoke particle system.\r\n* @prop effects/sparkler - Emits sparks in all directions\r\n* @prop effects/steam - Small white steam rising upwards\r\n*/\r\n\r\n/**\r\n* Objects that can be picked up, thrown, and otherwise interacted with.\r\n* @name interactables\r\n* @enum interactables\r\n* @memberof resources\r\n*\r\n* @prop interactables/basketball\r\n* @prop interactables/bowlingball\r\n* @prop interactables/bowling-pin\r\n* @prop interactables/box\r\n* @prop interactables/coin\r\n* @prop interactables/gem\r\n* @prop interactables/ring\r\n* @prop interactables/soccerball\r\n*/\r\n\r\n/**\r\n* Static models that you can place in your scene.\r\n* @name objects\r\n* @enum objects\r\n* @memberof resources\r\n*\r\n* @prop objects/basketball-hoop\r\n* @prop objects/coin\r\n* @prop objects/cup\r\n* @prop objects/gem\r\n* @prop objects/hoop\r\n* @prop objects/ring\r\n* @prop objects/target-archery\r\n*/\r\n\r\n/**\r\n* A selection of pipes/chutes/etc.\r\n* @name pipes\r\n* @enum pipes\r\n* @memberof resources\r\n*\r\n* @prop pipes/pipe-full-cap-1d\r\n* @prop pipes/pipe-full-cross-1d\r\n* @prop pipes/pipe-full-elbow-1d\r\n* @prop pipes/pipe-full-fork-1d\r\n* @prop pipes/pipe-full-straight-1d-1l\r\n* @prop pipes/pipe-full-straight-1d-2l\r\n* @prop pipes/pipe-full-straight-1d-4l\r\n* @prop pipes/pipe-full-tee-1d\r\n* @prop pipes/pipe-half-cap-1d\r\n* @prop pipes/pipe-half-cross-1d\r\n* @prop pipes/pipe-half-elbow-1d\r\n* @prop pipes/pipe-half-fork-1d\r\n* @prop pipes/pipe-half-straight-1d-1l\r\n* @prop pipes/pipe-half-straight-1d-2l\r\n* @prop pipes/pipe-half-straight-1d-4l\r\n* @prop pipes/pipe-half-tee-1d\r\n*/\r\n\r\n/**\r\n* Common UI sounds can be used for a consistent UI experience.\r\n* @name sounds-ui\r\n* @enum sounds-ui\r\n* @memberof resources\r\n*\r\n* @prop ui/select\r\n* @prop ui/toggle\r\n* @prop ui/notify\r\n* @prop ui/error\r\n* @prop ui/complete\r\n* @prop ui/succeed\r\n* @prop ui/over\r\n* @prop ui/join\r\n* @prop ui/click\r\n*/\r\n\r\n/**\r\n* Foley sounds are real sounds designed for tangible, touchable objects as they are heard in the real world.\r\n* @name sounds-foley\r\n* @enum sounds-foley\r\n* @memberof resources\r\n*\r\n* @prop foley/metal-scrape\r\n* @prop foley/metal-clack\r\n* @prop foley/metal-rattle\r\n* @prop foley/coin-jingle\r\n* @prop foley/paper-shuffle\r\n* @prop foley/explode\r\n*/\r\n\r\n/**\r\n* Effect sounds for a variety of use cases.\r\n* @name sounds-effects\r\n* @enum sounds-effects\r\n* @memberof resources\r\n*\r\n* @prop effects/fanfare-succeed - The \"success!\" sound from Holograms Against Humanity.\r\n* @prop effects/fanfare-start - The \"Game has started!\" sound from HaH.\r\n* @prop effects/fanfare-fail\r\n* @prop effects/timer-10s - a 10 second timer that triggers a bell at exactly 10 seconds.\r\n* The bell lasts for 2 seconds. This allows for timer length changes.\r\n* @prop effects/gain-coin\r\n*/\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/native-resources.js\n ** module id = 5\n ** module chunks = 0\n **/","/**\r\n* Enables the synchronization of properties of entities. All property sync components\r\n* require both a {@link sync.sync-system} on `a-scene`, and a {@link sync.sync}\r\n* on the entity to be synced.\r\n* @name sync\r\n* @namespace sync\r\n* @example\r\n* \r\n* \r\n* \r\n*/\r\n\r\n\r\n\r\n/**\r\n* Enables the synchronization of properties of the entity. Must be used in\r\n* conjuction with the {@link sync.sync-system} component and a component for a\r\n* specific property (e.g. {@link sync.sync-transform}).\r\n* @memberof sync\r\n* @mixin sync\r\n* @prop {string} ownOn - The name of the event, or a list of events, that\r\n* will cause the local client to take ownership of this object. This field\r\n* cannot be updated after initialization.\r\n*/\r\nAFRAME.registerComponent('sync',\r\n{\r\n\tschema: {\r\n\t\tmode: { default: 'link' },\r\n\t\townOn: { type: 'string' } //cannot be changed after creation\r\n\t},\r\n\tinit: function () {\r\n\t\tvar scene = document.querySelector('a-scene');\r\n\t\tvar syncSys = scene.systems['sync-system'];\r\n\r\n\t\tvar ref;\r\n\t\tvar key;\r\n\t\tvar dataRef;\r\n\t\tvar ownerRef;\r\n\t\tvar ownerId;\r\n\t\tvar isMine = false;\r\n\r\n\t\tvar component = this;\r\n\r\n\t\tcomponent.isConnected = false;\r\n\r\n\t\tif(syncSys.isConnected) start(); else scene.addEventListener('connected', start);\r\n\r\n\r\n\t\tif(component.data.ownOn)\r\n\t\t{\r\n\t\t\tvar ownershipEvents = component.data.ownOn.split(/[ ,]+/);\r\n\t\t\tfor(var i = 0, max = ownershipEvents.length; i < max; i++){\r\n\t\t\t\tcomponent.el.addEventListener(ownershipEvents[i], function(){\r\n\t\t\t\t\tif(component.isConnected){\r\n\t\t\t\t\t\tcomponent.takeOwnership();\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfunction start(){\r\n\t\t\t//Make sure someone always owns an object. If the owner leaves and we are the master client, we will take it.\r\n\t\t\t//This ensures, for example, that synced animations keep playing\r\n\t\t\tscene.addEventListener('clientleft', function(event){\r\n\t\t\t\tvar shouldTakeOwnership = (!ownerId || ownerId === event.detail.id) && syncSys.isMasterClient;\r\n\r\n\t\t\t\tif(shouldTakeOwnership) component.takeOwnership();\r\n\t\t\t});\r\n\r\n\t\t\tif (component.data.mode === 'link') {\r\n\t\t\t\tvar id = component.el.id;\r\n\t\t\t\tif (!id) {\r\n\t\t\t\t\tconsole.error('Entities cannot be synced using link mode without an id.');\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconsole.log('syncSys: ' + syncSys);\r\n\t\t\t\tconsole.log('syncSys.sceneRef: ' + syncSys.sceneRef);\r\n\r\n\t\t\t\tlink(syncSys.sceneRef.child(id));\r\n\t\t\t\tsetupReceive();\r\n\r\n\t\t\t} else {\r\n\t\t\t\tconsole.error('Unsupported sync mode: ' + component.data.mode);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tcomponent.isConnected = true;\r\n\t\t\tcomponent.el.emit('connected', null, false);\r\n\t\t}\r\n\r\n\t\tfunction link(entityRef) {\r\n\t\t\tref = entityRef;\r\n\t\t\tkey = ref.key();\r\n\t\t\tdataRef = ref.child('data');\r\n\t\t\tcomponent.dataRef = dataRef;\r\n\t\t\townerRef = ref.child('owner');\r\n\t\t}\r\n\r\n\t\tfunction setupReceive() {\r\n\r\n\t\t\t//if nobody has owned the object yet, we will.\r\n\t\t\townerRef.transaction(function (owner) {\r\n\t\t\t\tif (owner) return undefined;\r\n\r\n\t\t\t\townerRef.onDisconnect().set(null);\r\n\t\t\t\treturn syncSys.clientId;\r\n\t\t\t});\r\n\r\n\t\t\townerRef.on('value',\r\n\t\t\t\tfunction(snapshot) {\r\n\t\t\t\t\tvar newOwnerId = snapshot.val();\r\n\r\n\t\t\t\t\tvar gained = newOwnerId === syncSys.clientId && !isMine;\r\n\t\t\t\t\tif (gained) component.el.emit('ownershipgained', null, false);\r\n\r\n\r\n\t\t\t\t\t//note this also fires when we start up without ownership\r\n\t\t\t\t\tvar lost = newOwnerId !== syncSys.clientId && isMine;\r\n\t\t\t\t\tif (lost){\r\n\t\t\t\t\t\tcomponent.el.emit('ownershiplost', null, false);\r\n\r\n\t\t\t\t\t\t//we no longer have to clear our ownership when we disconnect\r\n\t\t\t\t\t\townerRef.onDisconnect().cancel();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\townerId = newOwnerId;\r\n\r\n\t\t\t\t\tisMine = newOwnerId === syncSys.clientId;\r\n\t\t\t\t});\r\n\t\t}\r\n\r\n\t\t/**\r\n\t\t* Tell sync to start pushing local property values instead of updating\r\n\t\t* local from remote values.\r\n\t\t* @method sync.sync#takeOwnership\r\n\t\t*/\r\n\t\tcomponent.takeOwnership = function() {\r\n\t\t\townerRef.set(syncSys.clientId);\r\n\r\n\t\t\t//clear our ownership if we disconnect\r\n\t\t\t//this is needed if we are the last user in the room, but we expect people to join later\r\n\t\t\townerRef.onDisconnect().set(null);\r\n\t\t}\r\n\r\n\t\t/**\r\n\t\t* Indicates whether the sync ownership is yours.\r\n\t\t* @member sync.sync#isMine\r\n\t\t* @readonly\r\n\t\t*/\r\n\t\tObject.defineProperty(component, 'isMine', {\r\n\t\t\tget: function () {\r\n\t\t\t\treturn isMine;//TODO: Should this be state instead?\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/sync.js\n ** module id = 6\n ** module chunks = 0\n **/","/**\r\n* Connect to a remote Firebase server, and facilitate synchronization. These\r\n* options correspond exactly with the configuration options for\r\n* [altspace.utilities.sync.connect]{@link http://altspacevr.github.io/AltspaceSDK/doc/module-altspace_utilities_sync.html#.connect}.\r\n* This component must be present on `a-scene` for any other sync components to work.\r\n* @memberof sync\r\n* @mixin sync-system\r\n* @prop {string} author - A unique identifier for you or your organization.\r\n* @prop {string} app - The name of the app.\r\n* @prop {string} refUrl - Override the base reference. Set this to use your own Firebase.\r\n* @prop {string} instance - Override the instance ID. Can also be overridden with\r\n* a URL parameter.\r\n*/\r\nAFRAME.registerSystem('sync-system',\r\n{\r\n\tschema: {\r\n\t\tauthor: { type: 'string', default: null },\r\n\t\tapp: { type: 'string', default: null },\r\n\t\tinstance: { type: 'string', default: null },\r\n\t\trefUrl: { type: 'string', default: null }\r\n\t},\r\n\tinit: function() {\r\n\t\tvar component = this;\r\n\r\n\t\tif(!this.data || !this.data.app){\r\n\t\t\tconsole.warn('The sync-system must be present on the scene and configured with required data.');\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tcomponent.isConnected = false;\r\n\t\tconsole.log(this.data);\r\n\t\taltspace.utilities.sync.connect({\r\n\t\t\tauthorId: this.data.author,\r\n\t\t\tappId: this.data.app,\r\n\t\t\tinstanceId: this.data.instance,\r\n\t\t\tbaseRefUrl: this.data.refUrl\r\n\t\t}).then(function(connection) {\r\n\t\t\tthis.connection = connection;\r\n\r\n\t\t\tthis.sceneRef = this.connection.instance.child('scene');\r\n\t\t\tthis.clientsRef = this.connection.instance.child('clients');\r\n\r\n\t\t\t// temporary way of having unique identifiers for each client\r\n\t\t\tthis.clientId = this.sceneEl.object3D.uuid;\r\n\t\t\tvar masterClientId;\r\n\t\t\tthis.clientsRef.on(\"value\", function (snapshot) {\r\n\t\t\t\tvar clientIds = snapshot.val();\r\n\r\n\t\t\t\tvar masterClientKey = Object.keys(clientIds)[0];\r\n\t\t\t\tmasterClientId = clientIds[masterClientKey];\r\n\t\t\t});\r\n\r\n\t\t\tthis.clientsRef.on('child_added', function(childSnapshot) {\r\n\t\t\t\tvar joinedClientId = childSnapshot.val();\r\n\t\t\t\t//let the master client flag get set first\r\n\t\t\t\tsetTimeout(function(){\r\n\t\t\t\t\tcomponent.sceneEl.emit('clientjoined', {id: joinedClientId}, false);\r\n\t\t\t\t}, 0);\r\n\t\t\t});\r\n\r\n\t\t\tthis.clientsRef.on('child_removed', function(childSnapshot) {\r\n\t\t\t\tvar leftClientId = childSnapshot.val();\r\n\t\t\t\t//let the master client flag get set first\r\n\t\t\t\tsetTimeout(function(){\r\n\t\t\t\t\tcomponent.sceneEl.emit('clientleft', {id: leftClientId}, false);\r\n\t\t\t\t}, 0);\r\n\t\t\t});\r\n\r\n\t\t\t// add our client ID to the list of connected clients,\r\n\t\t\t// but have it be automatically removed by firebase if we disconnect for any reason\r\n\t\t\tthis.clientsRef.push(this.clientId).onDisconnect().remove();\r\n\r\n\r\n\t\t\tthis.connection.instance.child('initialized').once('value', function (snapshot) {\r\n\t\t\t\tvar shouldInitialize = !snapshot.val();\r\n\t\t\t\tsnapshot.ref().set(true);\r\n\r\n\t\t\t\tcomponent.sceneEl.emit('connected', { shouldInitialize: shouldInitialize }, false);\r\n\t\t\t\tcomponent.isConnected = true;\r\n\t\t\t}.bind(this));\r\n\r\n\r\n\t\t\tObject.defineProperty(this, 'isMasterClient', {\r\n\t\t\t\tget: function () { return masterClientId === this.clientId; }.bind(this)\r\n\t\t\t});\r\n\t\t}.bind(this));\r\n\t}\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/sync-system.js\n ** module id = 7\n ** module chunks = 0\n **/","//TODO: We need to figure out a way to recieve our first update without caring about ownership.\r\n// firstValue is probably not the right way to go, probably something about having sent yet. Need to change for both\r\n\r\n/**\r\n* Synchronize the position, rotation, and scale of this object with all clients.\r\n* Requires both a {@link sync.sync-system} component on the `a-scene`, and a\r\n* {@link sync.sync} component on the target entity.\r\n* @mixin sync-transform\r\n* @memberof sync\r\n*/\r\nAFRAME.registerComponent('sync-transform',\r\n{\r\n\tdependencies: ['sync'],\r\n\tschema: {\r\n\t},\r\n\tinit: function () {\r\n\t\tvar component = this;\r\n\t\tvar sync = component.el.components.sync;\r\n\t\tif(sync.isConnected) start(); else component.el.addEventListener('connected', start);\r\n\r\n\t\tfunction start(){\r\n\r\n\t\t\tvar positionRef = sync.dataRef.child('position');\r\n\t\t\tvar rotationRef = sync.dataRef.child('rotation');\r\n\t\t\tvar scaleRef = sync.dataRef.child('scale');\r\n\r\n\t\t\tcomponent.updateRate = 100;\r\n\r\n\t\t\tvar stoppedAnimations = [];\r\n\t\t\t//pause all animations on ownership loss\r\n\t\t\tcomponent.el.addEventListener('ownershiplost', function() {\r\n\t\t\t\tvar children = component.el.children;\r\n\t\t\t\tfor (var i = 0; i < children.length; i++) {\r\n\t\t\t\t\tvar tagName = children[i].tagName.toLowerCase();\r\n\t\t\t\t\tif (tagName === \"a-animation\") {\r\n\t\t\t\t\t\tstoppedAnimations.push(children[i]);\r\n\t\t\t\t\t\tchildren[i].stop();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t\tcomponent.el.addEventListener('ownershipgained', function () {\r\n\t\t\t\tfor (var i = 0; i < stoppedAnimations.length; i++) {\r\n\t\t\t\t\tvar animation = stoppedAnimations[i];\r\n\t\t\t\t\tanimation.start();\r\n\t\t\t\t}\r\n\t\t\t\tstoppedAnimations = [];\r\n\t\t\t});\r\n\r\n\t\t\tfunction onTransform(snapshot, componentName) {\r\n\t\t\t\tif (sync.isMine) return;\r\n\r\n\t\t\t\tvar value = snapshot.val();\r\n\t\t\t\tif (!value) return;\r\n\r\n\t\t\t\tcomponent.el.setAttribute(componentName, value);\r\n\t\t\t}\r\n\r\n\t\t\tpositionRef.on('value', function (snapshot) {\r\n\t\t\t\tonTransform(snapshot, 'position');\r\n\t\t\t});\r\n\r\n\t\t\trotationRef.on('value', function (snapshot) {\r\n\t\t\t\tonTransform(snapshot, 'rotation');\r\n\t\t\t});\r\n\r\n\t\t\tscaleRef.on('value', function (snapshot) {\r\n\t\t\t\tonTransform(snapshot, 'scale');\r\n\t\t\t});\r\n\r\n\t\t\tvar sendPosition = throttle(function(value){\r\n\t\t\t\tpositionRef.set(value);\r\n\t\t\t}, component.updateRate);\r\n\r\n\t\t\tvar sendRotation = throttle(function(value){\r\n\t\t\t\trotationRef.set(value);\r\n\t\t\t}, component.updateRate);\r\n\r\n\t\t\tvar sendScale = throttle(function(value){\r\n\t\t\t\tscaleRef.set(value);\r\n\t\t\t}, component.updateRate);\r\n\r\n\t\t\tfunction onComponentChanged(event){\r\n\t\t\t\tif (!sync.isMine) return;\r\n\r\n\t\t\t\tvar name = event.detail.name;\r\n\t\t\t\tvar newData = event.detail.newData;\r\n\r\n\t\t\t\tif (name === 'position') {\r\n\t\t\t\t\tsendPosition(newData);\r\n\t\t\t\t} else if (name === 'rotation') {\r\n\t\t\t\t\tsendRotation(newData);\r\n\t\t\t\t} else if (name === 'scale') {\r\n\t\t\t\t\tsendScale(newData);\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t//from underscore.js\r\n\t\t\tfunction throttle(func, wait, options) {\r\n\t\t\t\tvar timeout, context, args, result;\r\n\t\t\t\tvar previous = 0;\r\n\t\t\t\tif (!options) options = {};\r\n\r\n\t\t\t\tvar later = function() {\r\n\t\t\t\t previous = options.leading === false ? 0 : Date.now();\r\n\t\t\t\t timeout = null;\r\n\t\t\t\t result = func.apply(context, args);\r\n\t\t\t\t if (!timeout) context = args = null;\r\n\t\t\t\t};\r\n\r\n\t\t\t\tvar throttled = function() {\r\n\t\t\t\t var now = Date.now();\r\n\t\t\t\t if (!previous && options.leading === false) previous = now;\r\n\t\t\t\t var remaining = wait - (now - previous);\r\n\t\t\t\t context = this;\r\n\t\t\t\t args = arguments;\r\n\t\t\t\t if (remaining <= 0 || remaining > wait) {\r\n\t\t\t\t\tif (timeout) {\r\n\t\t\t\t\t clearTimeout(timeout);\r\n\t\t\t\t\t timeout = null;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tprevious = now;\r\n\t\t\t\t\tresult = func.apply(context, args);\r\n\t\t\t\t\tif (!timeout) context = args = null;\r\n\t\t\t\t } else if (!timeout && options.trailing !== false) {\r\n\t\t\t\t\ttimeout = setTimeout(later, remaining);\r\n\t\t\t\t }\r\n\t\t\t\t return result;\r\n\t\t\t\t};\r\n\r\n\t\t\t\tthrottled.cancel = function() {\r\n\t\t\t\t clearTimeout(timeout);\r\n\t\t\t\t previous = 0;\r\n\t\t\t\t timeout = context = args = null;\r\n\t\t\t\t};\r\n\r\n\t\t\t\treturn throttled;\r\n\t\t\t };\r\n\r\n\r\n\t\t\tcomponent.el.addEventListener('componentchanged', onComponentChanged);\r\n\t\t}\r\n\t}\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/sync-transform.js\n ** module id = 8\n ** module chunks = 0\n **/","/**\r\n* Sync the color property of the object between clients.\r\n* Requires both a {@link sync.sync-system} component on the `a-scene`, and a\r\n* {@link sync.sync} component on the target entity.\r\n* @mixin sync-color\r\n* @memberof sync\r\n*/\r\nAFRAME.registerComponent('sync-color',\r\n{\r\n\tdependencies: ['sync'],\r\n\tschema: {\r\n\t},\r\n\tinit: function () {\r\n\t\tvar component = this;\r\n\t\tvar sync = component.el.components.sync;\r\n\t\tif(sync.isConnected) start(); else component.el.addEventListener('connected', start);\r\n\r\n\t\tfunction start(){\r\n\t\t\tvar colorRef = sync.dataRef.child('material/color');\r\n\r\n\t\t\tvar refChangedLocked = false;\r\n\r\n\t\t\tvar firstValue = true;\r\n\r\n\t\t\tcomponent.el.addEventListener('componentchanged', function (event) {\r\n\t\t\t\tvar name = event.detail.name;\r\n\t\t\t\tvar oldData = event.detail.oldData;\r\n\t\t\t\tvar newData = event.detail.newData;\r\n\r\n\t\t\t\tif (name !== 'material') return;\r\n\t\t\t\tif (refChangedLocked) return;\r\n\r\n\t\t\t\tif (oldData.color !== newData.color) {\r\n\t\t\t\t\tif(sync.isMine){\r\n\t\t\t\t\t\tsetTimeout(function() {//For some reason A-Frame has a misconfigured material reference if we do this too early\r\n\t\t\t\t\t\t\tcolorRef.set(newData.color);\r\n\t\t\t\t\t\t}, 0);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\tcolorRef.on('value', function (snapshot) {\r\n\t\t\t\tif (sync.isMine && !firstValue) return;\r\n\t\t\t\tvar color = snapshot.val();\r\n\r\n\t\t\t\trefChangedLocked = true;\r\n\t\t\t\tcomponent.el.setAttribute('material', 'color', color);\r\n\t\t\t\trefChangedLocked = false;\r\n\r\n\t\t\t\tfirstValue = false;\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/sync-color.js\n ** module id = 9\n ** module chunks = 0\n **/","/**\r\n* Synchronize the playback state of an {@link n.n-sound} component between clients.\r\n* Requires both a {@link sync.sync-system} component on the `a-scene`, and a\r\n* {@link sync.sync} component on the target entity.\r\n* @mixin sync-n-sound\r\n* @memberof sync\r\n*/\r\nAFRAME.registerComponent('sync-n-sound',\r\n{\r\n\tdependencies: ['sync'],\r\n\tschema: { },\r\n\tinit: function () {\r\n\t\tvar component = this;\r\n\t\tvar sync = component.el.components.sync;\r\n\t\tvar scene = document.querySelector('a-scene');\r\n\t\tvar syncSys = scene.systems['sync-system'];\r\n\t\tif(sync.isConnected) start(); else component.el.addEventListener('connected', start);\r\n\r\n\t\tfunction start(){\r\n\t\t\tcomponent.soundStateRef = sync.dataRef.child('sound/state');\r\n\t\t\tcomponent.soundEventRef = sync.dataRef.child('sound/event');\r\n\r\n\t\t\tfunction sendEvent(event) {\r\n\t\t\t\tif (!sync.isMine) return;\r\n\t\t\t\tvar event = {\r\n\t\t\t\t\ttype: event.type,\r\n\t\t\t\t\tsender: syncSys.clientId,\r\n\t\t\t\t\tel: component.el.id,\r\n\t\t\t\t\ttime: Date.now()\r\n\t\t\t\t};\r\n\t\t\t\tcomponent.soundEventRef.set(event);\r\n\t\t\t}\r\n\r\n\t\t\tcomponent.el.addEventListener('sound-played', sendEvent);\r\n\t\t\tcomponent.el.addEventListener('sound-paused', sendEvent);\r\n\r\n\t\t\tcomponent.soundEventRef.on('value', function (snapshot) {\r\n\t\t\t\tif (sync.isMine) return;\r\n\t\t\t\tvar event = snapshot.val();\r\n\t\t\t\tif (!event) return;\r\n\t\t\t\tif (event.el === component.el.id) {\r\n\t\t\t\t\tvar sound = component.el.components['n-sound'];\r\n\t\t\t\t\tif (event.type === 'sound-played') {\r\n\t\t\t\t\t\tsound.playSound();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tsound.pauseSound();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\tcomponent.el.addEventListener('componentchanged', function (event) {\r\n\t\t\t\tif (!sync.isMine) return;\r\n\t\t\t\tvar name = event.detail.name;\r\n\t\t\t\tif (name !== 'n-sound') return;\r\n\t\t\t\tcomponent.soundStateRef.set(event.detail.newData);\r\n\t\t\t});\r\n\r\n\t\t\tcomponent.soundStateRef.on('value', function (snapshot) {\r\n\t\t\t\tif (sync.isMine) return;\r\n\t\t\t\tvar state = snapshot.val();\r\n\t\t\t\tif (!state) return;\r\n\t\t\t\tcomponent.el.setAttribute('n-sound', state);\r\n\t\t\t});\r\n\t\t}\r\n\t},\r\n\tremove: function () {\r\n\t\tthis.soundStateRef.off('value');\r\n\t\tthis.soundEventRef.off('value');\r\n\t}\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/sync-n-sound.js\n ** module id = 10\n ** module chunks = 0\n **/","/**\r\n * The wire component allows you to trigger an event on another entity when an event occurs on an entity\r\n * @mixin wire\r\n * @property {string} on Name of an event to listen to\r\n * @property {string} gained Name of a state to watch for\r\n * @property {string} lost Name of a state to watch for\r\n * @property {string} emit Name of an event to trigger on the targets\r\n * @property {string} gain Name of a state to add on the target\r\n * @property {string} lose Name of a state to remove on the target\r\n * @property {selector} targets A selector to pick which objects to wire to\r\n * @property {selector} target - A selector to pick a single object to wire to\r\n **/\r\nAFRAME.registerComponent('wire',\r\n{\r\n\tmultiple: true,\r\n\tschema: {\r\n\t\ton: {type: 'string'},\r\n\t\temit: {type: 'string'},\r\n\t\tgained: {type: 'string'},\r\n\t\tlost: {type: 'string'},\r\n\t\tgain: {type: 'string'},\r\n\t\tlose: {type: 'string'},\r\n\t\ttargets: {type: 'selectorAll'},\r\n\t\ttarget: {type: 'selector'}\r\n\t},\r\n\tupdate: function (oldData) {\r\n\t\tif (oldData.on) {\r\n\t\t\tthis.el.removeEventListener(oldData.on, this.actOnTargets);\r\n\t\t}\r\n\t\tif (oldData.gained) {\r\n\t\t\tthis.el.removeEventListener('stateadded', this.actOnTargetsIfStateMatches);\r\n\t\t}\r\n\t\tif (oldData.lost) {\r\n\t\t\tthis.el.removeEventListener('stateremoved', this.actOnTargetsIfStateMatches);\r\n\t\t}\r\n\r\n\t\tthis.actOnTargets = function () {\r\n\t\t\tfunction act(el) {\r\n\t\t\t\tif (this.data.emit) {\r\n\t\t\t\t\tel.emit(this.data.emit);\r\n\t\t\t\t}\r\n\t\t\t\tif (this.data.gain) {\r\n\t\t\t\t\tel.addState(this.data.gain);\r\n\t\t\t\t}\r\n\t\t\t\tif (this.data.lose) {\r\n\t\t\t\t\tel.removeState(this.data.lose);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif(this.data.targets) this.data.targets.forEach(act.bind(this));\r\n\t\t\tif(this.data.target) act.call(this, this.data.target);\r\n\t\t}.bind(this);\r\n\r\n\t\tthis.actOnTargetsIfStateMatches = function (event) {\r\n\t\t\tvar state = event.detail.state;\r\n\t\t\tif (state === this.data.gained || state === this.data.lost) {\r\n\t\t\t\tthis.actOnTargets();\r\n\t\t\t}\r\n\t\t}.bind(this);\r\n\r\n\t\tif (this.data.on) {\r\n\t\t\tthis.el.addEventListener(this.data.on, this.actOnTargets);\r\n\t\t}\r\n\t\tif (this.data.gained) {\r\n\t\t\tthis.el.addEventListener('stateadded', this.actOnTargetsIfStateMatches);\r\n\t\t}\r\n\t\tif (this.data.lost) {\r\n\t\t\tthis.el.addEventListener('stateremoved', this.actOnTargetsIfStateMatches);\r\n\t\t}\r\n\t},\r\n\tremove: function () {\r\n\t\tthis.el.removeEventListener(this.data.on, this.actOnTargets);\r\n\t\tthis.el.removeEventListener('stateadded', this.actOnTargetsIfStateMatches);\r\n\t\tthis.el.removeEventListener('stateremoved', this.actOnTargetsIfStateMatches);\r\n\t}\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/wire.js\n ** module id = 11\n ** module chunks = 0\n **/"],"sourceRoot":""} \ No newline at end of file diff --git a/dist/aframe-altspace-component.min.js b/dist/aframe-altspace-component.min.js index 10c7459..d2b2c28 100755 --- a/dist/aframe-altspace-component.min.js +++ b/dist/aframe-altspace-component.min.js @@ -1 +1,2 @@ -!function(e){function t(i){if(n[i])return n[i].exports;var a=n[i]={exports:{},id:i,loaded:!1};return e[i].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){if("undefined"==typeof AFRAME)throw new Error("Component attempted to register before AFRAME was available.");n(3),n(1),n(2),n(4),n(5),n(10),n(8),n(9),n(6),n(7),n(11)},function(e,t){!function(){function e(e,t){e.userData.altspace={collider:{enabled:t}},e.traverse(function(e){e instanceof THREE.Mesh&&(e.userData.altspace={collider:{enabled:t}})})}AFRAME.registerComponent("altspace-cursor-collider",{schema:{enabled:{"default":!0}},init:function(){e(this.el.object3D,this.data.enabled),this.el.addEventListener("model-loaded",function(){e(this.el.object3D,this.data.enabled)}.bind(this))},update:function(){e(this.el.object3D,this.data.enabled)}})}()},function(e,t){AFRAME.registerComponent("altspace-tracked-controls",{init:function(){this.gamepadIndex=null,this.trackedControlsSystem=document.querySelector("a-scene").systems["tracked-controls"],this.systemGamepads=0,altspace.getGamepads()},tick:function(){if(this.trackedControlsSystem&&this.systemGamepads!==this.trackedControlsSystem.controllers.length&&window.altspace&&altspace.getGamepads&&altspace.getGamepads().length){var e=this.el.components;e["paint-controls"]&&(this.gamepadIndex="left"===e["paint-controls"].data.hand?2:1),null===this.gamepadIndex&&e["hand-controls"]&&(this.gamepadIndex="left"===e["hand-controls"].data?2:1),null===this.gamepadIndex&&e["vive-controls"]&&(this.gamepadIndex="left"===e["vive-controls"].data.hand?2:1),null===this.gamepadIndex&&e["tracked-controls"]&&(this.gamepadIndex=e["tracked-controls"].data.controller),this.el.setAttribute("tracked-controls","id",altspace.getGamepads()[this.gamepadIndex].id),this.el.setAttribute("tracked-controls","controller",0),this.systemGamepads=this.trackedControlsSystem.controllers.length}}})},function(e,t){AFRAME.registerComponent("altspace",{version:"1.3.1",schema:{usePixelScale:{type:"boolean","default":"false"},verticalAlign:{type:"string","default":"middle"},enclosuresOnly:{type:"boolean","default":"true"},fullspace:{type:"boolean","default":"false"}},init:function(){return this.el.object3D instanceof THREE.Scene?void(window.altspace&&window.altspace.inClient?(this.el.setAttribute("vr-mode-ui",{enabled:!1}),this.initRenderer(),this.initCursorEvents(),this.initCollisionEvents()):console.warn("aframe-altspace-component only works inside of AltspaceVR")):void console.warn("aframe-altspace-component can only be attached to a-scene")},tick:function(e,t){this.el.object3D.updateAllBehaviors&&this.el.object3D.updateAllBehaviors()},remove:function(){},pause:function(){},play:function(){},initRenderer:function(){var e=this.el.object3D;altspace.getEnclosure().then(function(n){switch(this.data.fullspace&&(n.requestFullspace(),n.addEventListener("fullspacechange",function(){e.scale.setScalar(n.pixelsPerMeter)})),this.data.usePixelScale&&!this.data.fullspace||e.scale.setScalar(n.pixelsPerMeter),this.data.verticalAlign){case"bottom":e.position.y-=n.innerHeight/2;break;case"top":e.position.y+=n.innerHeight/2;break;case"middle":break;default:console.warn("Unexpected value for verticalAlign: ",this.data.verticalAlign)}this.data.enclosuresOnly&&1===n.innerDepth&&(this.el.renderer.render(new THREE.Scene),this.el.renderer=this.el.effect=t)}.bind(this));var t=this.el.renderer,n=this.el.renderer=this.el.effect=altspace.getThreeJSRenderer({aframeComponentVersion:this.version}),i=function(){};n.setSize=i,n.setPixelRatio=i,n.setClearColor=i,n.clear=i,n.enableScissorTest=i,n.setScissor=i,n.setViewport=i,n.getPixelRatio=i,n.getMaxAnisotropy=i,n.setFaceCulling=i,n.context={canvas:{}},n.shadowMap={}},initCursorEvents:function(){var e=this.el.object3D,t=document.querySelector("a-cursor")||document.querySelector("a-entity[cursor]");t&&(t.setAttribute("material","transparent",!0),t.setAttribute("material","opacity",0));var n=function(e,n){var i=n.target.el;t&&t.emit(e,{target:i,ray:n.ray,point:n.point}),i&&i.emit(e,{target:i,ray:n.ray,point:n.point})},i=null;e.addEventListener("cursordown",function(e){i=e.target,n("mousedown",e)}),e.addEventListener("cursorup",function(e){n("mouseup",e),e.target.uuid===i.uuid&&n("click",e),i=null}),e.addEventListener("cursorenter",function(e){e.target.el&&(e.target.el.addState("hovered"),t&&t.addState("hovering"),n("mouseenter",e))}),e.addEventListener("cursorleave",function(e){e.target.el&&(e.target.el.removeState("hovered"),t&&t.removeState("hovering"),n("mouseleave",e))})},initCollisionEvents:function(){var e=this.el.object3D,t=function(e,t){var n=t.target.el;n&&(t.target=n,t.other&&t.other.el&&(t.other=t.other.el),n.emit(e,t))};e.addEventListener("collisionenter",function(e){t("collisionenter",e)}),e.addEventListener("collisionexit",function(e){t("collisionexit",e)}),e.addEventListener("triggerenter",function(e){t("triggerenter",e)}),e.addEventListener("triggerexit",function(e){t("triggerexit",e)})}})},function(e,t){!function(){function e(e){e.userData.altspace=e.userData.altspace||{},e.userData.altspace.collider=e.userData.altspace.collider||{},e.userData.altspace.collider.enabled=!1,altspace.addNativeComponent(e,this.name)}function t(){var t=this.el.getOrCreateObject3D("mesh",l);e.call(this,t),this.update(this.data)}function n(){var e=this.el.getObject3D("mesh");altspace.removeNativeComponent(e,this.name)}function i(e){altspace.updateNativeComponent(this.el.object3DMap.mesh,this.name,this.data)}function a(e,t){altspace.callNativeComponent(this.el.object3DMap.mesh,this.name,e,t)}if(!window.altspace||!altspace.inClient){var s=function(){};window.altspace={addNativeComponent:s,updateNativeComponent:s,removeNativeComponent:s}}var o=new THREE.BoxGeometry(.001,.001,.001),r=new THREE.MeshBasicMaterial({color:0});r.visible=!1;var l=function(){THREE.Mesh.call(this,o,r)};l.prototype=Object.create(THREE.Mesh.prototype),l.prototype.constructor=THREE.PlaceholderMesh,AFRAME.registerComponent("n-object",{schema:{res:{type:"string"}},init:t,update:i,remove:n}),AFRAME.registerComponent("n-spawner",{schema:{res:{type:"string"}},init:t,update:i,remove:n}),AFRAME.registerComponent("n-text",{init:t,update:i,remove:n,schema:{text:{"default":"",type:"string"},fontSize:{"default":"10",type:"int"},width:{"default":"10",type:"number"},height:{"default":"1",type:"number"},horizontalAlign:{"default":"middle"},verticalAlign:{"default":"middle"}}}),AFRAME.registerComponent("n-sphere-collider",{init:t,remove:n,update:i,schema:{isTrigger:{"default":!1,type:"boolean"},center:{type:"vec3"},radius:{"default":"0",type:"number"},type:{"default":"object"}}}),AFRAME.registerComponent("n-box-collider",{init:t,remove:n,update:i,schema:{isTrigger:{"default":!1,type:"boolean"},center:{type:"vec3"},size:{type:"vec3"},type:{"default":"object"}}}),AFRAME.registerComponent("n-capsule-collider",{init:t,remove:n,update:i,schema:{isTrigger:{"default":!1,type:"boolean"},center:{type:"vec3"},radius:{"default":"0",type:"number"},height:{"default":"0",type:"number"},direction:{"default":"y"},type:{"default":"object"}}}),AFRAME.registerComponent("n-mesh-collider",{_forEachMesh:function(e){var t=this.el.object3DMap.mesh;t&&(t instanceof THREE.Mesh&&e(t),t.traverse(function(t){t instanceof THREE.Mesh&&e(t)}.bind(this)))},_initObj:function(){this._forEachMesh(function(t){e.call(this,t),altspace.updateNativeComponent(t,this.name,this.data)}.bind(this))},init:function(){this.el.getOrCreateObject3D("mesh",l),this._initObj(),this.el.addEventListener("model-loaded",function(){this._initObj()}.bind(this))},remove:function(){this._forEachMesh(function(e){altspace.removeNativeComponent(e,this.name)}.bind(this))},update:function(e){this._forEachMesh(function(e){altspace.updateNativeComponent(e,this.name,this.data)}.bind(this))},schema:{isTrigger:{"default":!1,type:"boolean"},convex:{"default":!0,type:"boolean"},type:{"default":"object"}}}),AFRAME.registerComponent("n-billboard",{init:t,remove:n}),AFRAME.registerComponent("n-container",{init:function(){t.call(this);var e=this.el,n=this;e.addEventListener("stateadded",function(t){"container-full"===t.detail.state&&e.emit("container-full"),"container-empty"===t.detail.state&&e.emit("container-empty")}),e.addEventListener("container-count-changed",function(e){n.count=e.detail.count})},remove:n,update:i,schema:{capacity:{"default":4,type:"number"}}}),AFRAME.registerComponent("n-sound",{init:function(){var e=this.data.src;if(e&&!e.startsWith("http"))if(e.startsWith("/"))this.data.src=location.origin+e;else{var n=location.pathname;n.endsWith("/")||(n=location.pathname.split("/").slice(0,-1).join("/")+"/"),this.data.src=location.origin+n+e}t.call(this)},pauseSound:function(){a.call(this,"pause"),this.el.emit("sound-paused")},playSound:function(){a.call(this,"play"),this.el.emit("sound-played")},seek:function(e){a.call(this,"seek",{time:e})},remove:function(){n.call(this),this.playHandler&&this.el.removeEventListener(oldData.on,this.playHandler)},update:function(e){i.call(this,e),this.playHandler&&this.el.removeEventListener(e.on,this.playHandler),this.data.on&&(this.playHandler=this.playSound.bind(this),this.el.addEventListener(this.data.on,this.playHandler))},schema:{on:{type:"string"},res:{type:"string"},src:{type:"string"},loop:{type:"boolean"},volume:{type:"number","default":1},autoplay:{type:"boolean"},oneshot:{type:"boolean"},spatialBlend:{type:"float","default":1},pitch:{type:"float","default":1},minDistance:{type:"float","default":1},maxDistance:{type:"float","default":12},rolloff:{type:"string","default":"logarithmic"}}})}()},function(e,t){},function(e,t){AFRAME.registerComponent("sync-color",{dependencies:["sync"],schema:{},init:function(){function e(){var e=n.dataRef.child("material/color"),i=!1,a=!0;t.el.addEventListener("componentchanged",function(t){var a=t.detail.name,s=t.detail.oldData,o=t.detail.newData;"material"===a&&(i||s.color!==o.color&&n.isMine&&setTimeout(function(){e.set(o.color)},0))}),e.on("value",function(e){if(!n.isMine||a){var s=e.val();i=!0,t.el.setAttribute("material","color",s),i=!1,a=!1}})}var t=this,n=t.el.components.sync;n.isConnected?e():t.el.addEventListener("connected",e)}})},function(e,t){AFRAME.registerComponent("sync-n-sound",{dependencies:["sync"],schema:{},init:function(){function e(){function e(e){if(n.isMine){var e={type:e.type,sender:a.clientId,el:t.el.id,time:Date.now()};t.soundEventRef.set(e)}}t.soundStateRef=n.dataRef.child("sound/state"),t.soundEventRef=n.dataRef.child("sound/event"),t.el.addEventListener("sound-played",e),t.el.addEventListener("sound-paused",e),t.soundEventRef.on("value",function(e){if(!n.isMine){var i=e.val();if(i&&i.el===t.el.id){var a=t.el.components["n-sound"];"sound-played"===i.type?a.playSound():a.pauseSound()}}}),t.el.addEventListener("componentchanged",function(e){if(n.isMine){var i=e.detail.name;"n-sound"===i&&t.soundStateRef.set(e.detail.newData)}}),t.soundStateRef.on("value",function(e){if(!n.isMine){var i=e.val();i&&t.el.setAttribute("n-sound",i)}})}var t=this,n=t.el.components.sync,i=document.querySelector("a-scene"),a=i.systems["sync-system"];n.isConnected?e():t.el.addEventListener("connected",e)},remove:function(){this.soundStateRef.off("value"),this.soundEventRef.off("value")}})},function(e,t){AFRAME.registerSystem("sync-system",{schema:{author:{type:"string","default":null},app:{type:"string","default":null},instance:{type:"string","default":null},refUrl:{type:"string","default":null}},init:function(){var e=this;return this.data&&this.data.app?(e.isConnected=!1,console.log(this.data),void altspace.utilities.sync.connect({authorId:this.data.author,appId:this.data.app,instanceId:this.data.instance,baseRefUrl:this.data.refUrl}).then(function(t){this.connection=t,this.sceneRef=this.connection.instance.child("scene"),this.clientsRef=this.connection.instance.child("clients"),this.clientId=this.sceneEl.object3D.uuid;var n;this.clientsRef.on("value",function(e){var t=e.val(),i=Object.keys(t)[0];n=t[i]}),this.clientsRef.on("child_added",function(t){var n=t.val();setTimeout(function(){e.sceneEl.emit("clientjoined",{id:n},!1)},0)}),this.clientsRef.on("child_removed",function(t){var n=t.val();setTimeout(function(){e.sceneEl.emit("clientleft",{id:n},!1)},0)}),this.clientsRef.push(this.clientId).onDisconnect().remove(),this.connection.instance.child("initialized").once("value",function(t){var n=!t.val();t.ref().set(!0),e.sceneEl.emit("connected",{shouldInitialize:n},!1),e.isConnected=!0}.bind(this)),Object.defineProperty(this,"isMasterClient",{get:function(){return n===this.clientId}.bind(this)})}.bind(this))):void console.warn("The sync-system must be present on the scene and configured with required data.")}})},function(e,t){AFRAME.registerComponent("sync-transform",{dependencies:["sync"],schema:{},init:function(){function e(){function e(e,i){if(!n.isMine){var a=e.val();a&&t.el.setAttribute(i,a)}}function i(e){if(n.isMine){var t=e.detail.name,i=e.detail.newData;if("position"===t)c(i);else if("rotation"===t)d(i);else{if("scale"!==t)return;u(i)}}}function a(e,t,n){var i,a,s,o,r=0;n||(n={});var l=function(){r=n.leading===!1?0:Date.now(),i=null,o=e.apply(a,s),i||(a=s=null)},c=function(){var c=Date.now();r||n.leading!==!1||(r=c);var d=t-(c-r);return a=this,s=arguments,d<=0||d>t?(i&&(clearTimeout(i),i=null),r=c,o=e.apply(a,s),i||(a=s=null)):i||n.trailing===!1||(i=setTimeout(l,d)),o};return c.cancel=function(){clearTimeout(i),r=0,i=a=s=null},c}var s=n.dataRef.child("position"),o=n.dataRef.child("rotation"),r=n.dataRef.child("scale");t.updateRate=100;var l=[];t.el.addEventListener("ownershiplost",function(){for(var e=t.el.children,n=0;nt?(i&&(clearTimeout(i),i=null),r=c,o=e.apply(a,s),i||(a=s=null)):i||n.trailing===!1||(i=setTimeout(l,d)),o};return c.cancel=function(){clearTimeout(i),r=0,i=a=s=null},c}var s=n.dataRef.child("position"),o=n.dataRef.child("rotation"),r=n.dataRef.child("scale");t.updateRate=100;var l=[];t.el.addEventListener("ownershiplost",function(){for(var e=t.el.children,n=0;n\r\n\t* My A-Frame Scene\r\n\t* \r\n\t* \r\n\t* \r\n\t* \r\n\t* \r\n\t* \r\n\t* \r\n\t* \r\n\t*/\r\n\tAFRAME.registerComponent('altspace', {\r\n\t version: '1.3.2',\r\n\t schema: {\r\n\t\tusePixelScale: { type: 'boolean', default: 'false'},\r\n\t\tverticalAlign: { type: 'string', default: 'middle'},\r\n\t\tenclosuresOnly:{ type: 'boolean', default: 'true'},\r\n\t\tfullspace: { type: 'boolean', default: 'false'}\r\n\t },\r\n\t\r\n\t /*\r\n\t * Called once when component is attached. Generally for initial setup.\r\n\t */\r\n\t init: function () {\r\n\t\tif (!(this.el.object3D instanceof THREE.Scene)) {\r\n\t\t console.warn('aframe-altspace-component can only be attached to a-scene');\r\n\t\t return;\r\n\t\t}\r\n\t\r\n\t\tif (window.altspace && window.altspace.inClient) {\r\n\t\t this.el.setAttribute('vr-mode-ui', {enabled: false});\r\n\t\t this.initRenderer();\r\n\t\t this.initCursorEvents();\r\n\t\t this.initCollisionEvents();\r\n\t\t} else {\r\n\t\t console.warn('aframe-altspace-component only works inside of AltspaceVR');\r\n\t\t}\r\n\t\r\n\t },\r\n\t\r\n\t /*\r\n\t * Called on every single tick or render loop of the scene.\r\n\t */\r\n\t tick: function (t, dt) {\r\n\t if(this.el.object3D.updateAllBehaviors)\r\n\t this.el.object3D.updateAllBehaviors();\r\n\t },\r\n\t\r\n\t /*\r\n\t * Called when a component is removed (e.g., via removeAttribute).\r\n\t * Generally undoes all modifications to the entity.\r\n\t */\r\n\t remove: function () { },\r\n\t\r\n\t /*\r\n\t * Called on each scene tick.\r\n\t */\r\n\t // tick: function (t) { },\r\n\t\r\n\t /*\r\n\t * Called when entity pauses.\r\n\t * Use to stop or remove any dynamic or background behavior such as events.\r\n\t */\r\n\t pause: function () { },\r\n\t\r\n\t /*\r\n\t * Called when entity resumes.\r\n\t * Use to continue or add any dynamic or background behavior such as events.\r\n\t */\r\n\t play: function () { },\r\n\t\r\n\t\r\n\t /********** Helper Methods **********/\r\n\t\r\n\t /*\r\n\t * Swap in Altspace renderer when running in AltspaceVR.\r\n\t */\r\n\t initRenderer: function () {\r\n\t\r\n\t\tvar scene = this.el.object3D;\r\n\t\taltspace.getEnclosure().then(function(e)\r\n\t\t{\r\n\t\t\tif(this.data.fullspace){\r\n\t\t\t\te.requestFullspace();\r\n\t\t\t\te.addEventListener('fullspacechange', function(){\r\n\t\t\t\t\tscene.scale.setScalar(e.pixelsPerMeter);\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\r\n\t\t\tif (!this.data.usePixelScale || this.data.fullspace){\r\n\t\t\t\tscene.scale.setScalar(e.pixelsPerMeter);\r\n\t\t\t}\r\n\t\r\n\t\t switch (this.data.verticalAlign) {\r\n\t\t\tcase 'bottom':\r\n\t\t\t scene.position.y -= e.innerHeight / 2;\r\n\t\t\t break;\r\n\t\t\tcase 'top':\r\n\t\t\t scene.position.y += e.innerHeight / 2;\r\n\t\t\t break;\r\n\t\t\tcase 'middle':\r\n\t\t\t break;\r\n\t\t\tdefault:\r\n\t\t\t console.warn('Unexpected value for verticalAlign: ', this.data.verticalAlign);\r\n\t\t }\r\n\t\r\n\t\t if(this.data.enclosuresOnly && e.innerDepth === 1){\r\n\t\t\tthis.el.renderer.render(new THREE.Scene());\r\n\t\t\tthis.el.renderer = this.el.effect = oldRenderer;\r\n\t\r\n\t\t }\r\n\t\t}.bind(this));\r\n\t\r\n\t\tvar oldRenderer = this.el.renderer;\r\n\t\tvar renderer = this.el.renderer = this.el.effect = altspace.getThreeJSRenderer({\r\n\t\t aframeComponentVersion: this.version\r\n\t\t});\r\n\t\tvar noop = function() {};\r\n\t\trenderer.setSize = noop;\r\n\t\trenderer.setPixelRatio = noop;\r\n\t\trenderer.setClearColor = noop;\r\n\t\trenderer.clear = noop;\r\n\t\trenderer.enableScissorTest = noop;\r\n\t\trenderer.setScissor = noop;\r\n\t\trenderer.setViewport = noop;\r\n\t\trenderer.getPixelRatio = noop;\r\n\t\trenderer.getMaxAnisotropy = noop;\r\n\t\trenderer.setFaceCulling = noop;\r\n\t\trenderer.context = {canvas: {}};\r\n\t\trenderer.shadowMap = {};\r\n\t\r\n\t },\r\n\t\r\n\t /*\r\n\t * Emulate A-Frame cursor events when running in altspaceVR.\r\n\t */\r\n\t initCursorEvents: function() {\r\n\t\r\n\t\tvar scene = this.el.object3D;\r\n\t\tvar cursorEl = document.querySelector('a-cursor') || document.querySelector('a-entity[cursor]');\r\n\t\tif (cursorEl) {\r\n\t\t // Hide A-Frame cursor mesh.\r\n\t\t cursorEl.setAttribute('material', 'transparent', true);\r\n\t\t cursorEl.setAttribute('material', 'opacity', 0.0);\r\n\t\t}\r\n\t\r\n\t\tvar emit = function (eventName, event) {\r\n\t\t\t// Fire events on intersected object and A-Frame cursor.\r\n\t\t\tvar targetEl = event.target.el;\r\n\t\t\tif (cursorEl) cursorEl.emit(eventName, { target: targetEl, ray: event.ray, point: event.point });\r\n\t\t\tif (targetEl) targetEl.emit(eventName, { target: targetEl, ray: event.ray, point: event.point });\r\n\t\t} ;\r\n\t\r\n\t\tvar cursordownObj = null;\r\n\t\tscene.addEventListener('cursordown', function(event) {\r\n\t\t cursordownObj = event.target;\r\n\t\t emit('mousedown', event);\r\n\t\t});\r\n\t\r\n\t\tscene.addEventListener('cursorup', function(event) {\r\n\t\t emit('mouseup', event);\r\n\t\t if (event.target.uuid === cursordownObj.uuid) {\r\n\t\t\temit('click', event);\r\n\t\t }\r\n\t\t cursordownObj = null;\r\n\t\t});\r\n\t\r\n\t\tscene.addEventListener('cursorenter', function(event) {\r\n\t\t if (!event.target.el) { return; }\r\n\t\t event.target.el.addState('hovered');\r\n\t\t if (cursorEl) cursorEl.addState('hovering');\r\n\t\t emit('mouseenter', event);\r\n\t\t});\r\n\t\r\n\t\tscene.addEventListener('cursorleave', function(event) {\r\n\t\t if (!event.target.el) { return; }\r\n\t\t event.target.el.removeState('hovered');\r\n\t\t if (cursorEl) cursorEl.removeState('hovering');\r\n\t\t emit('mouseleave', event);\r\n\t\t});\r\n\t\r\n\t },\r\n\t\r\n\t initCollisionEvents: function () {\r\n\t\r\n\t\tvar scene = this.el.object3D;\r\n\t\r\n\t\tvar emit = function (eventName, event) {\r\n\t\t\tvar targetEl = event.target.el;\r\n\t\t\tif (!targetEl) return;\r\n\t\r\n\t\t\t//remap target and other from object3Ds to aframe element\r\n\t\t\tevent.target = targetEl;\r\n\t\t\tif (event.other && event.other.el) {\r\n\t\t\t\tevent.other = event.other.el;\r\n\t\t\t}\r\n\t\t\ttargetEl.emit(eventName, event);\r\n\t\t};\r\n\t\r\n\t\tscene.addEventListener('collisionenter', function (event) {\r\n\t\t\temit('collisionenter', event);\r\n\t\t});\r\n\t\r\n\t\tscene.addEventListener('collisionexit', function (event) {\r\n\t\t\temit('collisionexit', event);\r\n\t\t});\r\n\t\r\n\t\tscene.addEventListener('triggerenter', function (event) {\r\n\t\t\temit('triggerenter', event);\r\n\t\t});\r\n\t\r\n\t\tscene.addEventListener('triggerexit', function (event) {\r\n\t\t\temit('triggerexit', event);\r\n\t\t});\r\n\t\r\n\t }\r\n\t\r\n\t});\r\n\n\n/***/ },\n/* 4 */\n/***/ function(module, exports) {\n\n\t\r\n\t/**\r\n\t* This set of components map to various objects and effects that are provided\r\n\t* natively by AltspaceVR. Your management of these objects may be limited to\r\n\t* some degree, but they will tend to be more performant than SDK equivalents,\r\n\t* or may provide some functionality not otherwise available to the SDK.\r\n\t* @namespace native\r\n\t*/\r\n\t(function () {\r\n\t\tif (!window.altspace || !altspace.inClient) {\r\n\t\t\tvar noop = function () {};\r\n\t\t\twindow.altspace = {\r\n\t\t\t\taddNativeComponent: noop,\r\n\t\t\t\tupdateNativeComponent: noop,\r\n\t\t\t\tremoveNativeComponent: noop\r\n\t\t\t};\r\n\t\t}\r\n\t\r\n\t\tvar placeholderGeometry = new THREE.BoxGeometry(0.001, 0.001, 0.001);\r\n\t\tvar placeholderMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 });\r\n\t\tplaceholderMaterial.visible = false;\r\n\t\tvar PlaceholderMesh = function () {\r\n\t\t\tTHREE.Mesh.call( this, placeholderGeometry, placeholderMaterial );\r\n\t\t};\r\n\t\tPlaceholderMesh.prototype = Object.create( THREE.Mesh.prototype );\r\n\t\tPlaceholderMesh.prototype.constructor = THREE.PlaceholderMesh;\r\n\t\r\n\t\tfunction meshInit(mesh) {\r\n\t\t\t//If you attach native components to an entity, it will not use a default collider\r\n\t\t\tmesh.userData.altspace = mesh.userData.altspace || {};\r\n\t\t\tmesh.userData.altspace.collider = mesh.userData.altspace.collider || {};\r\n\t\t\tmesh.userData.altspace.collider.enabled = false;\r\n\t\r\n\t\t\taltspace.addNativeComponent(mesh, this.name);\r\n\t\t}\r\n\t\r\n\t\tfunction nativeComponentInit() {\r\n\t\t\tvar mesh = this.el.getOrCreateObject3D('mesh', PlaceholderMesh);\r\n\t\r\n\t\t\tmeshInit.call(this, mesh);\r\n\t\r\n\t\t\t//to pass defaults\r\n\t\t\tthis.update(this.data);\r\n\t\t}\r\n\t\tfunction nativeComponentRemove() {\r\n\t\t\tvar mesh = this.el.getObject3D('mesh');\r\n\t\t\taltspace.removeNativeComponent(mesh, this.name);\r\n\t\t}\r\n\t\tfunction nativeComponentUpdate(oldData) {\r\n\t\t\taltspace.updateNativeComponent(this.el.object3DMap.mesh, this.name, this.data);\r\n\t\t}\r\n\t\r\n\t\tfunction callComponent(functionName, functionArguments) {\r\n\t\t\taltspace.callNativeComponent(this.el.object3DMap.mesh, this.name, functionName, functionArguments)\r\n\t\t}\r\n\t\r\n\t\t/**\r\n\t\t* Attach a given native object to this entity.\r\n\t\t* @mixin n-object\r\n\t\t* @memberof native\r\n\t\t* @prop {string} res - The identifier for the resource you want. This component\r\n\t\t* can accept all resources except for `interactables`.\r\n\t\t* @example \r\n\t\t*/\r\n\t\tAFRAME.registerComponent('n-object', {\r\n\t\t\tschema: {\r\n\t\t\t\tres: {type: 'string'}\r\n\t\t\t},\r\n\t\t\tinit: nativeComponentInit,\r\n\t\t\tupdate: nativeComponentUpdate,\r\n\t\t\tremove: nativeComponentRemove\r\n\t\t});\r\n\t\r\n\t\t/**\r\n\t\t* Create an object that spawns additional copies of itself when grabbed by a user (the copies are not spawners themselves).\r\n\t\t* These copies will be physically interactive and automatically synchronized\r\n\t\t* between users.\r\n\t\t* @mixin n-spawner\r\n\t\t* @memberof native\r\n\t\t* @prop {string} res - The identifier for the resource you want. This component\r\n\t\t* can only accept resources of type `interactables`.\r\n\t\t* @example \r\n\t\t*/\r\n\t\tAFRAME.registerComponent('n-spawner', {\r\n\t\t\tschema: {\r\n\t\t\t\tres: {type: 'string'}\r\n\t\t\t},\r\n\t\t\tinit: nativeComponentInit,\r\n\t\t\tupdate: nativeComponentUpdate,\r\n\t\t\tremove: nativeComponentRemove\r\n\t\t});\r\n\t\r\n\t\t/**\r\n\t\t* Creates dynamic 2D text on the entity. The text will wrap automatically based on the width and height provided.\r\n\t\t* This text will be clearer than texture-based text and more performant than geometry-based test.\r\n\t\t* @mixin n-text\r\n\t\t* @memberof native\r\n\t\t* @prop {string} text - The text to be drawn.\r\n\t\t* @prop {number} fontSize=10 - The height of the letters. 10pt ~= 1m\r\n\t\t* @prop {number} width=10 - The width of the text area in meters. If the\r\n\t\t* text is wider than this value, the overflow will be wrapped to the next line.\r\n\t\t* @prop {number} height=1 - The height of the text area in meters. If the\r\n\t\t* text is taller than this value, the overflow will be cut off.\r\n\t\t* @prop {string} horizontalAlign=middle - The horizontal anchor point for\r\n\t\t* the text. Can be `left`, `middle`, or `right`.\r\n\t\t* @prop {string} verticalAlign=middle - The vertical anchor point for the\r\n\t\t* text. Can be `top`, `middle`, or `bottom`.\r\n\t\t*/\r\n\t\tAFRAME.registerComponent('n-text', {\r\n\t\t\tinit: nativeComponentInit,\r\n\t\t\tupdate: nativeComponentUpdate,\r\n\t\t\tremove: nativeComponentRemove,\r\n\t\t\tschema: {\r\n\t\t\t\ttext: { default: '', type: 'string' },\r\n\t\t\t\t/*color: { default: 'white',\r\n\t\t\t\t\tparse: function(value) {\r\n\t\t\t\t\t\treturn parseFloat(value, 10);\r\n\t\t\t\t\t},\r\n\t\t\t\t\tstringify: function(value) {\r\n\t\t\t\t\t\treturn value.toString();\r\n\t\t\t\t\t}},*/\r\n\t\t\t\tfontSize: { default: '10', type: 'int' },//roughly a meter tall\r\n\t\t\t\twidth: { default: '10', type: 'number' },//in meters\r\n\t\t\t\theight: { default: '1', type: 'number' },//in meters\r\n\t\t\t\thorizontalAlign: { default: 'middle'},\r\n\t\t\t\tverticalAlign: { default: 'middle'}\r\n\t\t\t}\r\n\t\t});\r\n\t\r\n\t\t//object: collides against: objects / enviroment / cursor\r\n\t\t//environment: can be teleported onto, and collides against: objects / environment / cursor\r\n\t\t//hologram: collides against: cursor / holograms\r\n\t\r\n\t\t/**\r\n\t\t* Abstract base class for {@link n.n-sphere-collider}, {@link n.n-box-collider},\r\n\t\t* {@link n.n-capsule-collider}, and {@link n.n-mesh-collider}. You cannot use\r\n\t\t* this class directly, but instead you should add one of those components\r\n\t\t* to your objects.\r\n\t\t* @name n-collider\r\n\t\t* @mixin n-collider\r\n\t\t* @memberof native\r\n\t\t* @prop {vec3} center=0,0,0 - The offset of the collider in local space.\r\n\t\t* @prop {string} type=hologram - The type of collider, one of: `object` | `environment` | `hologram`.\r\n\t\t* Object colliders collide with other objects, the environment, and the cursor.\r\n\t\t* Environment colliders collide with everything objects do, but you can also\r\n\t\t* teleport onto them. Hologram colliders only collide with other holograms and\r\n\t\t* the cursor.\r\n\t\t*/\r\n\t\r\n\t\t/**\r\n\t\t* Create a spherical collider on this entity.\r\n\t\t* @mixin n-sphere-collider\r\n\t\t* @memberof native\r\n\t\t* @extends native.n-collider\r\n\t\t* @prop {number} radius=1 - The size of the collider in meters.\r\n\t\t*/\r\n\t\tAFRAME.registerComponent('n-sphere-collider', {\r\n\t\t\tinit:nativeComponentInit,\r\n\t\t\tremove: nativeComponentRemove,\r\n\t\t\tupdate: nativeComponentUpdate,\r\n\t\t\tschema: {\r\n\t\t\t\tisTrigger: { default: false, type: 'boolean' },\r\n\t\t\t\tcenter: { type: 'vec3' },\r\n\t\t\t\tradius: { default: '0', type: 'number' },\r\n\t\t\t\ttype: {default: 'object'}\r\n\t\t\t}\r\n\t\t});\r\n\t\r\n\t\r\n\t\t/**\r\n\t\t* Create a box-shaped collider on this entity.\r\n\t\t* @mixin n-box-collider\r\n\t\t* @memberof native\r\n\t\t* @extends native.n-collider\r\n\t\t* @prop {vec3} size=1,1,1 - The dimensions of the collider.\r\n\t\t*/\r\n\t\tAFRAME.registerComponent('n-box-collider', {\r\n\t\t\tinit:nativeComponentInit,\r\n\t\t\tremove: nativeComponentRemove,\r\n\t\t\tupdate: nativeComponentUpdate,\r\n\t\t\tschema: {\r\n\t\t\t\tisTrigger: { default: false, type: 'boolean' },\r\n\t\t\t\tcenter: { type: 'vec3' },\r\n\t\t\t\tsize: { type: 'vec3' },\r\n\t\t\t\ttype: {default: 'object'}\r\n\t\t\t}\r\n\t\t});\r\n\t\r\n\t\t/**\r\n\t\t* Create a capsule-shaped collider on this entity. Capsules\r\n\t\t* are a union of a cylinder and two spheres on top and bottom.\r\n\t\t* @mixin n-capsule-collider\r\n\t\t* @memberof native\r\n\t\t* @extends native.n-collider\r\n\t\t* @prop {number} radius=1 - The radius of the capsule in meters.\r\n\t\t* @prop {number} height=1 - The height of the shaft of the capsule in meters.\r\n\t\t* @prop {string} direction=y - The axis with which the capsule is aligned.\r\n\t\t* One of `x`, `y`, or `z`.\r\n\t\t*/\r\n\t\tAFRAME.registerComponent('n-capsule-collider', {\r\n\t\t\tinit:nativeComponentInit,\r\n\t\t\tremove: nativeComponentRemove,\r\n\t\t\tupdate: nativeComponentUpdate,\r\n\t\t\tschema: {\r\n\t\t\t\tisTrigger: { default: false, type: 'boolean' },\r\n\t\t\t\tcenter: { type: 'vec3' },\r\n\t\t\t\tradius: { default: '0', type: 'number' },\r\n\t\t\t\theight: { default: '0', type: 'number' },\r\n\t\t\t\tdirection: { default: 'y' },\r\n\t\t\t\ttype: {default: 'object'}\r\n\t\t\t}\r\n\t\t});\r\n\t\r\n\t\t/**\r\n\t\t* Enable collision for the entire attached mesh. This is expensive to evaluate, so should only be used on\r\n\t\t* low-poly meshes.\r\n\t\t* @mixin n-mesh-collider\r\n\t\t* @memberof native\r\n\t\t* @extends native.n-collider\r\n\t\t* @example \r\n\t\t* @prop {bool} convex=true - Whether the collider should be convex or concave. Set this to false if you have holes\r\n\t\t* in your mesh. Convex colliders are limited to 255 triangles. Note: concave colliders can be significantly more\r\n\t\t* expensive comparet to conves colliders.\r\n\t\t*/\r\n\t\tAFRAME.registerComponent('n-mesh-collider', {\r\n\t\t\t_forEachMesh: function (func) {\r\n\t\t\t\tvar obj = this.el.object3DMap.mesh;\r\n\t\t\t\tif (!obj) { return; }\r\n\t\t\t\tif (obj instanceof THREE.Mesh) {\r\n\t\t\t\t\tfunc(obj);\r\n\t\t\t\t}\r\n\t\t\t\tobj.traverse(function (childObj) {\r\n\t\t\t\t\tif (childObj instanceof THREE.Mesh) {\r\n\t\t\t\t\t\tfunc(childObj);\r\n\t\t\t\t\t}\r\n\t\t\t\t}.bind(this));\r\n\t\t\t},\r\n\t\t\t_initObj: function () {\r\n\t\t\t\tthis._forEachMesh(function (mesh) {\r\n\t\t\t\t\tmeshInit.call(this, mesh);\r\n\t\r\n\t\t\t\t\t//to pass defaults\r\n\t\t\t\t\taltspace.updateNativeComponent(mesh, this.name, this.data);\r\n\t\t\t\t}.bind(this));\r\n\t\t\t},\r\n\t\t\tinit: function () {\r\n\t\t\t\t// Allow a-frame to create a PlaceholderMesh if there isn't already one, so that the native collider is\r\n\t\t\t\t// registered.\r\n\t\t\t\tthis.el.getOrCreateObject3D('mesh', PlaceholderMesh);\r\n\t\r\n\t\t\t\t// Initialize the existing mesh\r\n\t\t\t\tthis._initObj();\r\n\t\r\n\t\t\t\tthis.el.addEventListener('model-loaded', function () {\r\n\t\t\t\t\t// Re-initialize the collider if a new model is loaded\r\n\t\t\t\t\tthis._initObj();\r\n\t\t\t\t}.bind(this));\r\n\t\t\t},\r\n\t\t\tremove: function () {\r\n\t\t\t\tthis._forEachMesh(function (mesh) {\r\n\t\t\t\t\taltspace.removeNativeComponent(mesh, this.name);\r\n\t\t\t\t}.bind(this));\r\n\t\t\t},\r\n\t\t\tupdate: function (oldData) {\r\n\t\t\t\tthis._forEachMesh(function (mesh) {\r\n\t\t\t\t\taltspace.updateNativeComponent(mesh, this.name, this.data);\r\n\t\t\t\t}.bind(this));\r\n\t\t\t},\r\n\t\t\tschema: {\r\n\t\t\t\tisTrigger: { default: false, type: 'boolean' },\r\n\t\t\t\tconvex: { default: true, type: 'boolean' },\r\n\t\t\t\ttype: {default: 'object'}\r\n\t\t\t}\r\n\t\t});\r\n\t\r\n\t\t/**\r\n\t\t* Make the object's +Z always face the viewer. Currently will only directly apply to main mesh or native component on the attached entity, not any children or submeshes.\r\n\t\t* @mixin n-billboard\r\n\t\t* @memberof native\r\n\t\t* @example \r\n\t\t*/\r\n\t\tAFRAME.registerComponent('n-billboard', {\r\n\t\t\tinit:nativeComponentInit,\r\n\t\t\tremove: nativeComponentRemove,\r\n\t\t});\r\n\t\r\n\t\t/**\r\n\t\t* A container keeps a running tally of how many objects are within\r\n\t\t* its bounds, and adds and removes the states `container-full` and\r\n\t\t* `container-empty` based on the current count of objects. Can fire three\r\n\t\t* special events: `container-full`, `container-empty`, and `container-count-changed`.\r\n\t\t* @mixin n-container\r\n\t\t* @memberof native\r\n\t\t* @prop {number} capacity=4 - The value at which the container will fire the\r\n\t\t* `container-full` event.\r\n\t\t*/\r\n\t\tAFRAME.registerComponent('n-container', {\r\n\t\t\tinit: function(){\r\n\t\t\t\tnativeComponentInit.call(this);\r\n\t\r\n\t\t\t\tvar el = this.el;\r\n\t\t\t\tvar component = this;\r\n\t\r\n\t\t\t\tel.addEventListener('stateadded', function(event){\r\n\t\t\t\t\tif(event.detail.state === 'container-full'){\r\n\t\t\t\t\t\tel.emit('container-full');\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif(event.detail.state === 'container-empty'){\r\n\t\t\t\t\t\tel.emit('container-empty');\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\tel.addEventListener('container-count-changed', function(event){\r\n\t\t\t\t\tcomponent.count = event.detail.count;\r\n\t\t\t\t});\r\n\t\t\t},\r\n\t\t\tremove: nativeComponentRemove,\r\n\t\t\tupdate: nativeComponentUpdate,\r\n\t\t\tschema: {\r\n\t\t\t\tcapacity: { default: 4, type: 'number' },\r\n\t\t\t}\r\n\t\t});\r\n\t\r\n\t\t/**\r\n\t\t* Play the sound given by the `src` or `res` property from the location\r\n\t\t* of the entity.\r\n\t\t* @mixin n-sound\r\n\t\t* @memberof native\r\n\t\t* @prop {string} res - The resource identifier for a built-in sound clip.\r\n\t\t* @prop {string} src - A URL to an external sound clip. The sound can be in WAV, OGG or MP3 format. However. only\r\n\t\t* WAV is supported on all platforms. MP3 is supported on Gear VR and OGG is supported on desktop.\r\n\t\t* @prop {string} on - The name of the event that will play this sound clip.\r\n\t\t* @prop {boolean} loop=false - Tells the clip to loop back to the beginning of the clip\r\n\t\t* once it's finished.\r\n\t\t* @prop {boolean} autoplay=false - Tells the clip to start automatically when\r\n\t\t* the scene loads, instead of waiting for `playSound()`.\r\n\t\t* @prop {boolean} oneshot=false - Tells the clip to clean itself up when it\r\n\t\t* finishes playing. Allows for overlapping instances of the sound.\r\n\t\t* @prop {number} volume=1 - The volume of the clip, from [0,1].\r\n\t\t* @prop {number} spatialBlend=1 - How spatialized a sound is, from [0,1].\r\n\t\t* A value of 1 will be fully localized, and the sound will pan left and\r\n\t\t* right as you turn your head. A value of 0 makes it non-spatialized, and\r\n\t\t* it will always be heard in both ears.\r\n\t\t* @prop {number} pitch=1 - The speed multiplier for the sound. 0.5 is one\r\n\t\t* octave down, and 2 is one octave up.\r\n\t\t* @prop {number} minDistance=1 - Inside this distance in meters,\r\n\t\t* the sound volume is at full volume.\r\n\t\t* @prop {number} maxDistance=12 - If rolloff is 'logarithmic', the sound will stop attenuating at this distance.\r\n\t\t* If rolloff is 'linear' or 'cosine', the sound will be silent at this distance.\r\n\t\t* @prop {string} rolloff='logarithmic' - Set this to 'linear' or 'cosine' if you want to cut sounds off at a\r\n\t\t* maxDistance.\r\n\t\t*/\r\n\t\t/**\r\n\t\t* Fired when a sound has loaded and is ready to be played\r\n\t\t* @event native.n-sound#n-sound-loaded\r\n\t\t*/\r\n\t\tAFRAME.registerComponent('n-sound', {\r\n\t\t\tinit: function () {\r\n\t\t\t\tvar src = this.data.src;\r\n\t\t\t\tif (src && !src.startsWith('http')) {\r\n\t\t\t\t\tif (src.startsWith('/')) {\r\n\t\t\t\t\t\tthis.data.src = location.origin + src;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tvar currPath = location.pathname;\r\n\t\t\t\t\t\tif (!currPath.endsWith('/')) {\r\n\t\t\t\t\t\t\tcurrPath = location.pathname.split('/').slice(0, -1).join('/') + '/';\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tthis.data.src = location.origin + currPath + src;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tnativeComponentInit.call(this);\r\n\t\t\t},\r\n\t\r\n\t\t\t/**\r\n\t\t\t* Stop the playing sound, and preserve position in clip.\r\n\t\t\t* @method native.n-sound#pauseSound\r\n\t\t\t*/\r\n\t\t\tpauseSound: function () {\r\n\t\t\t\tcallComponent.call(this, 'pause');\r\n\t\t\t\tthis.el.emit('sound-paused');\r\n\t\t\t},\r\n\t\r\n\t\t\t/**\r\n\t\t\t* Start the sound playing.\r\n\t\t\t* @method native.n-sound#playSound\r\n\t\t\t*/\r\n\t\t\tplaySound: function () {\r\n\t\t\t\tcallComponent.call(this, 'play');\r\n\t\t\t\tthis.el.emit('sound-played');\r\n\t\t\t},\r\n\t\r\n\t\t\t/**\r\n\t\t\t* Jump to a position in the clip.\r\n\t\t\t* @method native.n-sound#seek\r\n\t\t\t* @param {number} time - The time in milliseconds to jump to.\r\n\t\t\t*/\r\n\t\t\tseek: function (time) {\r\n\t\t\t\tcallComponent.call(this, 'seek', {time: time});\r\n\t\t\t},\r\n\t\t\tremove: function () {\r\n\t\t\t\tnativeComponentRemove.call(this);\r\n\t\t\t\tif (this.playHandler) {\r\n\t\t\t\t this.el.removeEventListener(oldData.on, this.playHandler);\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\tupdate: function (oldData) {\r\n\t\t\t\tnativeComponentUpdate.call(this, oldData);\r\n\t\t\t\tif (this.playHandler) {\r\n\t\t\t\t this.el.removeEventListener(oldData.on, this.playHandler);\r\n\t\t\t\t}\r\n\t\t\t\tif (this.data.on) {\r\n\t\t\t\t this.playHandler = this.playSound.bind(this);\r\n\t\t\t\t this.el.addEventListener(this.data.on, this.playHandler);\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\tschema: {\r\n\t\t\t\ton: { type: 'string' },\r\n\t\t\t\tres: { type: 'string' },\r\n\t\t\t\tsrc: { type: 'string' },\r\n\t\t\t\tloop: { type: 'boolean' },\r\n\t\t\t\tvolume: { type: 'number', default: 1 },\r\n\t\t\t\tautoplay: { type: 'boolean' },\r\n\t\t\t\toneshot: { type: 'boolean' },\r\n\t\t\t\tspatialBlend: { type: 'float', default: 1 },\r\n\t\t\t\tpitch: { type: 'float', default: 1 },\r\n\t\t\t\tminDistance: { type: 'float', default: 1 },\r\n\t\t\t\tmaxDistance: { type: 'float', default: 12 },\r\n\t\t\t\trolloff: { type: 'string', default: 'logarithmic' },\r\n\t\t\t}\r\n\t\t});\r\n\t\r\n\t})();\r\n\n\n/***/ },\n/* 5 */\n/***/ function(module, exports) {\n\n\t// this file is just for good measure. didn't want native-components getting too cluttered.\r\n\t\r\n\t/**\r\n\t* This namespace describes strings that are valid inputs to the various native\r\n\t* components. Some components can only take certain types of resources, i.e.\r\n\t* {@link n.n-spawner} can only accept `interactables`.\r\n\t* @namespace resources\r\n\t* @example \r\n\t*/\r\n\t\r\n\t/**\r\n\t* Generic modular building pieces. All pieces are aligned to one corner, such that\r\n\t* the piece extends out toward -X and +Z.\r\n\t* @name architecture\r\n\t* @enum architecture\r\n\t* @memberof resources\r\n\t*\r\n\t* @prop architecture/ceiling-2w-2l\r\n\t* @prop architecture/ceiling-4w-4l\r\n\t* @prop architecture/ceiling-4w-4l\r\n\t* @prop architecture/ceiling-skylight-4w-4l\r\n\t* @prop architecture/ceiling-skylight-corner-2w-2l\r\n\t* @prop architecture/ceiling-skylight-edge-2w\r\n\t* @prop architecture/ceiling-skylight-edge-4w\r\n\t* @prop architecture/ceiling-skylight-filler-4w-4l-2\r\n\t* @prop architecture/ceiling-skylight-filler-4w-4l\r\n\t* @prop architecture/ceiling-slice-concave-2r\r\n\t* @prop architecture/ceiling-slice-concave-4r\r\n\t* @prop architecture/ceiling-slice-convex-2r\r\n\t* @prop architecture/ceiling-slice-convex-4r\r\n\t* @prop architecture/door-4w-4h\r\n\t* @prop architecture/floor-2w-2l\r\n\t* @prop architecture/floor-2w-4l\r\n\t* @prop architecture/floor-4w-2l\r\n\t* @prop architecture/floor-4w-4l\r\n\t* @prop architecture/floor-slice-concave-2r\r\n\t* @prop architecture/floor-slice-concave-4r\r\n\t* @prop architecture/floor-slice-convex-2r\r\n\t* @prop architecture/floor-slice-convex-4r\r\n\t* @prop architecture/railing-2l\r\n\t* @prop architecture/railing-4l\r\n\t* @prop architecture/railing-curve-concave-2r\r\n\t* @prop architecture/wall-2w-4h\r\n\t* @prop architecture/wall-4w-4h\r\n\t* @prop architecture/wall-base-2w\r\n\t* @prop architecture/wall-base-4w\r\n\t* @prop architecture/wall-base-curve-concave-2r\r\n\t* @prop architecture/wall-base-curve-concave-4r\r\n\t* @prop architecture/wall-base-curve-convex-2r\r\n\t* @prop architecture/wall-base-curve-convex-4r\r\n\t* @prop architecture/wall-bulkhead-2w\r\n\t* @prop architecture/wall-bulkhead-4w\r\n\t* @prop architecture/wall-bulkhead-curve-concave-2r\r\n\t* @prop architecture/wall-bulkhead-curve-concave-4r\r\n\t* @prop architecture/wall-bulkhead-curve-convex-2r\r\n\t* @prop architecture/wall-bulkhead-curve-convex-4r\r\n\t* @prop architecture/wall-curve-concave-2r-4h\r\n\t* @prop architecture/wall-curve-concave-4r-4h\r\n\t* @prop architecture/wall-curve-convex-2r-4h\r\n\t* @prop architecture/wall-curve-convex-4r-4h\r\n\t* @prop architecture/wall-curve-window-concave-4r-4h\r\n\t* @prop architecture/wall-curve-window-concave-filler-4r-4h\r\n\t* @prop architecture/wall-curve-window-gap-concave-4r-4h\r\n\t* @prop architecture/wall-curve-window-gap-end-l-concave-4r-4h\r\n\t* @prop architecture/wall-curve-window-gap-end-r-concave-4r-4h\r\n\t* @prop architecture/wall-filler-corner-inner-4h\r\n\t* @prop architecture/wall-filler-corner-outer-4h\r\n\t* @prop architecture/wall-window-4w-4h\r\n\t* @prop architecture/wall-window-filler-2\r\n\t* @prop architecture/wall-window-gap-2w-4h\r\n\t* @prop architecture/wall-window-gap-4w-4h\r\n\t* @prop architecture/wall-window-gap-end-l-2w-4h\r\n\t* @prop architecture/wall-window-gap-end-l-4w-4h\r\n\t* @prop architecture/wall-window-gap-end-r-2w-4h\r\n\t* @prop architecture/wall-window-gap-end-r-4w-4h\r\n\t*/\r\n\t\r\n\t/**\r\n\t* Particle systems and other native effects\r\n\t* @name effects\r\n\t* @enum effects\r\n\t* @memberof resources\r\n\t*\r\n\t* @prop effects/explosion - A particle system with a central flash, then debris flying outward.\r\n\t* This is a non-looping effect.\r\n\t* @prop effects/fire - An animated fire particle, suitable for a torch.\r\n\t* @prop effects/fire-trail - Fire that trails the entity through space as it moves. Only is visible while an object is in motion\r\n\t* @prop effects/fireworks - A compound particle system that shoots up from the entity,\r\n\t* explodes into colored sparks, then transitions to gold streamers.\r\n\t* @prop effects/smoke - Billowing smoke particle system.\r\n\t* @prop effects/sparkler - Emits sparks in all directions\r\n\t* @prop effects/steam - Small white steam rising upwards\r\n\t*/\r\n\t\r\n\t/**\r\n\t* Objects that can be picked up, thrown, and otherwise interacted with.\r\n\t* @name interactables\r\n\t* @enum interactables\r\n\t* @memberof resources\r\n\t*\r\n\t* @prop interactables/basketball\r\n\t* @prop interactables/bowlingball\r\n\t* @prop interactables/bowling-pin\r\n\t* @prop interactables/box\r\n\t* @prop interactables/coin\r\n\t* @prop interactables/gem\r\n\t* @prop interactables/ring\r\n\t* @prop interactables/soccerball\r\n\t*/\r\n\t\r\n\t/**\r\n\t* Static models that you can place in your scene.\r\n\t* @name objects\r\n\t* @enum objects\r\n\t* @memberof resources\r\n\t*\r\n\t* @prop objects/basketball-hoop\r\n\t* @prop objects/coin\r\n\t* @prop objects/cup\r\n\t* @prop objects/gem\r\n\t* @prop objects/hoop\r\n\t* @prop objects/ring\r\n\t* @prop objects/target-archery\r\n\t*/\r\n\t\r\n\t/**\r\n\t* A selection of pipes/chutes/etc.\r\n\t* @name pipes\r\n\t* @enum pipes\r\n\t* @memberof resources\r\n\t*\r\n\t* @prop pipes/pipe-full-cap-1d\r\n\t* @prop pipes/pipe-full-cross-1d\r\n\t* @prop pipes/pipe-full-elbow-1d\r\n\t* @prop pipes/pipe-full-fork-1d\r\n\t* @prop pipes/pipe-full-straight-1d-1l\r\n\t* @prop pipes/pipe-full-straight-1d-2l\r\n\t* @prop pipes/pipe-full-straight-1d-4l\r\n\t* @prop pipes/pipe-full-tee-1d\r\n\t* @prop pipes/pipe-half-cap-1d\r\n\t* @prop pipes/pipe-half-cross-1d\r\n\t* @prop pipes/pipe-half-elbow-1d\r\n\t* @prop pipes/pipe-half-fork-1d\r\n\t* @prop pipes/pipe-half-straight-1d-1l\r\n\t* @prop pipes/pipe-half-straight-1d-2l\r\n\t* @prop pipes/pipe-half-straight-1d-4l\r\n\t* @prop pipes/pipe-half-tee-1d\r\n\t*/\r\n\t\r\n\t/**\r\n\t* Common UI sounds can be used for a consistent UI experience.\r\n\t* @name sounds-ui\r\n\t* @enum sounds-ui\r\n\t* @memberof resources\r\n\t*\r\n\t* @prop ui/select\r\n\t* @prop ui/toggle\r\n\t* @prop ui/notify\r\n\t* @prop ui/error\r\n\t* @prop ui/complete\r\n\t* @prop ui/succeed\r\n\t* @prop ui/over\r\n\t* @prop ui/join\r\n\t* @prop ui/click\r\n\t*/\r\n\t\r\n\t/**\r\n\t* Foley sounds are real sounds designed for tangible, touchable objects as they are heard in the real world.\r\n\t* @name sounds-foley\r\n\t* @enum sounds-foley\r\n\t* @memberof resources\r\n\t*\r\n\t* @prop foley/metal-scrape\r\n\t* @prop foley/metal-clack\r\n\t* @prop foley/metal-rattle\r\n\t* @prop foley/coin-jingle\r\n\t* @prop foley/paper-shuffle\r\n\t* @prop foley/explode\r\n\t*/\r\n\t\r\n\t/**\r\n\t* Effect sounds for a variety of use cases.\r\n\t* @name sounds-effects\r\n\t* @enum sounds-effects\r\n\t* @memberof resources\r\n\t*\r\n\t* @prop effects/fanfare-succeed - The \"success!\" sound from Holograms Against Humanity.\r\n\t* @prop effects/fanfare-start - The \"Game has started!\" sound from HaH.\r\n\t* @prop effects/fanfare-fail\r\n\t* @prop effects/timer-10s - a 10 second timer that triggers a bell at exactly 10 seconds.\r\n\t* The bell lasts for 2 seconds. This allows for timer length changes.\r\n\t* @prop effects/gain-coin\r\n\t*/\r\n\n\n/***/ },\n/* 6 */\n/***/ function(module, exports) {\n\n\t/**\r\n\t* Sync the color property of the object between clients.\r\n\t* Requires both a {@link sync.sync-system} component on the `a-scene`, and a\r\n\t* {@link sync.sync} component on the target entity.\r\n\t* @mixin sync-color\r\n\t* @memberof sync\r\n\t*/\r\n\tAFRAME.registerComponent('sync-color',\r\n\t{\r\n\t\tdependencies: ['sync'],\r\n\t\tschema: {\r\n\t\t},\r\n\t\tinit: function () {\r\n\t\t\tvar component = this;\r\n\t\t\tvar sync = component.el.components.sync;\r\n\t\t\tif(sync.isConnected) start(); else component.el.addEventListener('connected', start);\r\n\t\r\n\t\t\tfunction start(){\r\n\t\t\t\tvar colorRef = sync.dataRef.child('material/color');\r\n\t\r\n\t\t\t\tvar refChangedLocked = false;\r\n\t\r\n\t\t\t\tvar firstValue = true;\r\n\t\r\n\t\t\t\tcomponent.el.addEventListener('componentchanged', function (event) {\r\n\t\t\t\t\tvar name = event.detail.name;\r\n\t\t\t\t\tvar oldData = event.detail.oldData;\r\n\t\t\t\t\tvar newData = event.detail.newData;\r\n\t\r\n\t\t\t\t\tif (name !== 'material') return;\r\n\t\t\t\t\tif (refChangedLocked) return;\r\n\t\r\n\t\t\t\t\tif (oldData.color !== newData.color) {\r\n\t\t\t\t\t\tif(sync.isMine){\r\n\t\t\t\t\t\t\tsetTimeout(function() {//For some reason A-Frame has a misconfigured material reference if we do this too early\r\n\t\t\t\t\t\t\t\tcolorRef.set(newData.color);\r\n\t\t\t\t\t\t\t}, 0);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\tcolorRef.on('value', function (snapshot) {\r\n\t\t\t\t\tif (sync.isMine && !firstValue) return;\r\n\t\t\t\t\tvar color = snapshot.val();\r\n\t\r\n\t\t\t\t\trefChangedLocked = true;\r\n\t\t\t\t\tcomponent.el.setAttribute('material', 'color', color);\r\n\t\t\t\t\trefChangedLocked = false;\r\n\t\r\n\t\t\t\t\tfirstValue = false;\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t});\r\n\n\n/***/ },\n/* 7 */\n/***/ function(module, exports) {\n\n\t/**\r\n\t* Synchronize the playback state of an {@link n.n-sound} component between clients.\r\n\t* Requires both a {@link sync.sync-system} component on the `a-scene`, and a\r\n\t* {@link sync.sync} component on the target entity.\r\n\t* @mixin sync-n-sound\r\n\t* @memberof sync\r\n\t*/\r\n\tAFRAME.registerComponent('sync-n-sound',\r\n\t{\r\n\t\tdependencies: ['sync'],\r\n\t\tschema: { },\r\n\t\tinit: function () {\r\n\t\t\tvar component = this;\r\n\t\t\tvar sync = component.el.components.sync;\r\n\t\t\tvar scene = document.querySelector('a-scene');\r\n\t\t\tvar syncSys = scene.systems['sync-system'];\r\n\t\t\tif(sync.isConnected) start(); else component.el.addEventListener('connected', start);\r\n\t\r\n\t\t\tfunction start(){\r\n\t\t\t\tcomponent.soundStateRef = sync.dataRef.child('sound/state');\r\n\t\t\t\tcomponent.soundEventRef = sync.dataRef.child('sound/event');\r\n\t\r\n\t\t\t\tfunction sendEvent(event) {\r\n\t\t\t\t\tif (!sync.isMine) return;\r\n\t\t\t\t\tvar event = {\r\n\t\t\t\t\t\ttype: event.type,\r\n\t\t\t\t\t\tsender: syncSys.clientId,\r\n\t\t\t\t\t\tel: component.el.id,\r\n\t\t\t\t\t\ttime: Date.now()\r\n\t\t\t\t\t};\r\n\t\t\t\t\tcomponent.soundEventRef.set(event);\r\n\t\t\t\t}\r\n\t\r\n\t\t\t\tcomponent.el.addEventListener('sound-played', sendEvent);\r\n\t\t\t\tcomponent.el.addEventListener('sound-paused', sendEvent);\r\n\t\r\n\t\t\t\tcomponent.soundEventRef.on('value', function (snapshot) {\r\n\t\t\t\t\tif (sync.isMine) return;\r\n\t\t\t\t\tvar event = snapshot.val();\r\n\t\t\t\t\tif (!event) return;\r\n\t\t\t\t\tif (event.el === component.el.id) {\r\n\t\t\t\t\t\tvar sound = component.el.components['n-sound'];\r\n\t\t\t\t\t\tif (event.type === 'sound-played') {\r\n\t\t\t\t\t\t\tsound.playSound();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tsound.pauseSound();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\tcomponent.el.addEventListener('componentchanged', function (event) {\r\n\t\t\t\t\tif (!sync.isMine) return;\r\n\t\t\t\t\tvar name = event.detail.name;\r\n\t\t\t\t\tif (name !== 'n-sound') return;\r\n\t\t\t\t\tcomponent.soundStateRef.set(event.detail.newData);\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\tcomponent.soundStateRef.on('value', function (snapshot) {\r\n\t\t\t\t\tif (sync.isMine) return;\r\n\t\t\t\t\tvar state = snapshot.val();\r\n\t\t\t\t\tif (!state) return;\r\n\t\t\t\t\tcomponent.el.setAttribute('n-sound', state);\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t},\r\n\t\tremove: function () {\r\n\t\t\tthis.soundStateRef.off('value');\r\n\t\t\tthis.soundEventRef.off('value');\r\n\t\t}\r\n\t});\r\n\n\n/***/ },\n/* 8 */\n/***/ function(module, exports) {\n\n\t/**\r\n\t* Connect to a remote Firebase server, and facilitate synchronization. These\r\n\t* options correspond exactly with the configuration options for\r\n\t* [altspace.utilities.sync.connect]{@link http://altspacevr.github.io/AltspaceSDK/doc/module-altspace_utilities_sync.html#.connect}.\r\n\t* This component must be present on `a-scene` for any other sync components to work.\r\n\t* @memberof sync\r\n\t* @mixin sync-system\r\n\t* @prop {string} author - A unique identifier for you or your organization.\r\n\t* @prop {string} app - The name of the app.\r\n\t* @prop {string} refUrl - Override the base reference. Set this to use your own Firebase.\r\n\t* @prop {string} instance - Override the instance ID. Can also be overridden with\r\n\t* a URL parameter.\r\n\t*/\r\n\tAFRAME.registerSystem('sync-system',\r\n\t{\r\n\t\tschema: {\r\n\t\t\tauthor: { type: 'string', default: null },\r\n\t\t\tapp: { type: 'string', default: null },\r\n\t\t\tinstance: { type: 'string', default: null },\r\n\t\t\trefUrl: { type: 'string', default: null }\r\n\t\t},\r\n\t\tinit: function() {\r\n\t\t\tvar component = this;\r\n\t\r\n\t\t\tif(!this.data || !this.data.app){\r\n\t\t\t\tconsole.warn('The sync-system must be present on the scene and configured with required data.');\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\r\n\t\t\tcomponent.isConnected = false;\r\n\t\t\tconsole.log(this.data);\r\n\t\t\taltspace.utilities.sync.connect({\r\n\t\t\t\tauthorId: this.data.author,\r\n\t\t\t\tappId: this.data.app,\r\n\t\t\t\tinstanceId: this.data.instance,\r\n\t\t\t\tbaseRefUrl: this.data.refUrl\r\n\t\t\t}).then(function(connection) {\r\n\t\t\t\tthis.connection = connection;\r\n\t\r\n\t\t\t\tthis.sceneRef = this.connection.instance.child('scene');\r\n\t\t\t\tthis.clientsRef = this.connection.instance.child('clients');\r\n\t\r\n\t\t\t\t// temporary way of having unique identifiers for each client\r\n\t\t\t\tthis.clientId = this.sceneEl.object3D.uuid;\r\n\t\t\t\tvar masterClientId;\r\n\t\t\t\tthis.clientsRef.on(\"value\", function (snapshot) {\r\n\t\t\t\t\tvar clientIds = snapshot.val();\r\n\t\r\n\t\t\t\t\tvar masterClientKey = Object.keys(clientIds)[0];\r\n\t\t\t\t\tmasterClientId = clientIds[masterClientKey];\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\tthis.clientsRef.on('child_added', function(childSnapshot) {\r\n\t\t\t\t\tvar joinedClientId = childSnapshot.val();\r\n\t\t\t\t\t//let the master client flag get set first\r\n\t\t\t\t\tsetTimeout(function(){\r\n\t\t\t\t\t\tcomponent.sceneEl.emit('clientjoined', {id: joinedClientId}, false);\r\n\t\t\t\t\t}, 0);\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\tthis.clientsRef.on('child_removed', function(childSnapshot) {\r\n\t\t\t\t\tvar leftClientId = childSnapshot.val();\r\n\t\t\t\t\t//let the master client flag get set first\r\n\t\t\t\t\tsetTimeout(function(){\r\n\t\t\t\t\t\tcomponent.sceneEl.emit('clientleft', {id: leftClientId}, false);\r\n\t\t\t\t\t}, 0);\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\t// add our client ID to the list of connected clients,\r\n\t\t\t\t// but have it be automatically removed by firebase if we disconnect for any reason\r\n\t\t\t\tthis.clientsRef.push(this.clientId).onDisconnect().remove();\r\n\t\r\n\t\r\n\t\t\t\tthis.connection.instance.child('initialized').once('value', function (snapshot) {\r\n\t\t\t\t\tvar shouldInitialize = !snapshot.val();\r\n\t\t\t\t\tsnapshot.ref().set(true);\r\n\t\r\n\t\t\t\t\tcomponent.sceneEl.emit('connected', { shouldInitialize: shouldInitialize }, false);\r\n\t\t\t\t\tcomponent.isConnected = true;\r\n\t\t\t\t}.bind(this));\r\n\t\r\n\t\r\n\t\t\t\tObject.defineProperty(this, 'isMasterClient', {\r\n\t\t\t\t\tget: function () { return masterClientId === this.clientId; }.bind(this)\r\n\t\t\t\t});\r\n\t\t\t}.bind(this));\r\n\t\t}\r\n\t});\r\n\n\n/***/ },\n/* 9 */\n/***/ function(module, exports) {\n\n\t//TODO: We need to figure out a way to recieve our first update without caring about ownership.\r\n\t// firstValue is probably not the right way to go, probably something about having sent yet. Need to change for both\r\n\t\r\n\t/**\r\n\t* Synchronize the position, rotation, and scale of this object with all clients.\r\n\t* Requires both a {@link sync.sync-system} component on the `a-scene`, and a\r\n\t* {@link sync.sync} component on the target entity.\r\n\t* @mixin sync-transform\r\n\t* @memberof sync\r\n\t*/\r\n\tAFRAME.registerComponent('sync-transform',\r\n\t{\r\n\t\tdependencies: ['sync'],\r\n\t\tschema: {\r\n\t\t},\r\n\t\tinit: function () {\r\n\t\t\tvar component = this;\r\n\t\t\tvar sync = component.el.components.sync;\r\n\t\t\tif(sync.isConnected) start(); else component.el.addEventListener('connected', start);\r\n\t\r\n\t\t\tfunction start(){\r\n\t\r\n\t\t\t\tvar positionRef = sync.dataRef.child('position');\r\n\t\t\t\tvar rotationRef = sync.dataRef.child('rotation');\r\n\t\t\t\tvar scaleRef = sync.dataRef.child('scale');\r\n\t\r\n\t\t\t\tcomponent.updateRate = 100;\r\n\t\r\n\t\t\t\tvar stoppedAnimations = [];\r\n\t\t\t\t//pause all animations on ownership loss\r\n\t\t\t\tcomponent.el.addEventListener('ownershiplost', function() {\r\n\t\t\t\t\tvar children = component.el.children;\r\n\t\t\t\t\tfor (var i = 0; i < children.length; i++) {\r\n\t\t\t\t\t\tvar tagName = children[i].tagName.toLowerCase();\r\n\t\t\t\t\t\tif (tagName === \"a-animation\") {\r\n\t\t\t\t\t\t\tstoppedAnimations.push(children[i]);\r\n\t\t\t\t\t\t\tchildren[i].stop();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t\tcomponent.el.addEventListener('ownershipgained', function () {\r\n\t\t\t\t\tfor (var i = 0; i < stoppedAnimations.length; i++) {\r\n\t\t\t\t\t\tvar animation = stoppedAnimations[i];\r\n\t\t\t\t\t\tanimation.start();\r\n\t\t\t\t\t}\r\n\t\t\t\t\tstoppedAnimations = [];\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\tfunction onTransform(snapshot, componentName) {\r\n\t\t\t\t\tif (sync.isMine) return;\r\n\t\r\n\t\t\t\t\tvar value = snapshot.val();\r\n\t\t\t\t\tif (!value) return;\r\n\t\r\n\t\t\t\t\tcomponent.el.setAttribute(componentName, value);\r\n\t\t\t\t}\r\n\t\r\n\t\t\t\tpositionRef.on('value', function (snapshot) {\r\n\t\t\t\t\tonTransform(snapshot, 'position');\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\trotationRef.on('value', function (snapshot) {\r\n\t\t\t\t\tonTransform(snapshot, 'rotation');\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\tscaleRef.on('value', function (snapshot) {\r\n\t\t\t\t\tonTransform(snapshot, 'scale');\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\tvar sendPosition = throttle(function(value){\r\n\t\t\t\t\tpositionRef.set(value);\r\n\t\t\t\t}, component.updateRate);\r\n\t\r\n\t\t\t\tvar sendRotation = throttle(function(value){\r\n\t\t\t\t\trotationRef.set(value);\r\n\t\t\t\t}, component.updateRate);\r\n\t\r\n\t\t\t\tvar sendScale = throttle(function(value){\r\n\t\t\t\t\tscaleRef.set(value);\r\n\t\t\t\t}, component.updateRate);\r\n\t\r\n\t\t\t\tfunction onComponentChanged(event){\r\n\t\t\t\t\tif (!sync.isMine) return;\r\n\t\r\n\t\t\t\t\tvar name = event.detail.name;\r\n\t\t\t\t\tvar newData = event.detail.newData;\r\n\t\r\n\t\t\t\t\tif (name === 'position') {\r\n\t\t\t\t\t\tsendPosition(newData);\r\n\t\t\t\t\t} else if (name === 'rotation') {\r\n\t\t\t\t\t\tsendRotation(newData);\r\n\t\t\t\t\t} else if (name === 'scale') {\r\n\t\t\t\t\t\tsendScale(newData);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\r\n\t\t\t\t}\r\n\t\r\n\t\t\t\t//from underscore.js\r\n\t\t\t\tfunction throttle(func, wait, options) {\r\n\t\t\t\t\tvar timeout, context, args, result;\r\n\t\t\t\t\tvar previous = 0;\r\n\t\t\t\t\tif (!options) options = {};\r\n\t\r\n\t\t\t\t\tvar later = function() {\r\n\t\t\t\t\t previous = options.leading === false ? 0 : Date.now();\r\n\t\t\t\t\t timeout = null;\r\n\t\t\t\t\t result = func.apply(context, args);\r\n\t\t\t\t\t if (!timeout) context = args = null;\r\n\t\t\t\t\t};\r\n\t\r\n\t\t\t\t\tvar throttled = function() {\r\n\t\t\t\t\t var now = Date.now();\r\n\t\t\t\t\t if (!previous && options.leading === false) previous = now;\r\n\t\t\t\t\t var remaining = wait - (now - previous);\r\n\t\t\t\t\t context = this;\r\n\t\t\t\t\t args = arguments;\r\n\t\t\t\t\t if (remaining <= 0 || remaining > wait) {\r\n\t\t\t\t\t\tif (timeout) {\r\n\t\t\t\t\t\t clearTimeout(timeout);\r\n\t\t\t\t\t\t timeout = null;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tprevious = now;\r\n\t\t\t\t\t\tresult = func.apply(context, args);\r\n\t\t\t\t\t\tif (!timeout) context = args = null;\r\n\t\t\t\t\t } else if (!timeout && options.trailing !== false) {\r\n\t\t\t\t\t\ttimeout = setTimeout(later, remaining);\r\n\t\t\t\t\t }\r\n\t\t\t\t\t return result;\r\n\t\t\t\t\t};\r\n\t\r\n\t\t\t\t\tthrottled.cancel = function() {\r\n\t\t\t\t\t clearTimeout(timeout);\r\n\t\t\t\t\t previous = 0;\r\n\t\t\t\t\t timeout = context = args = null;\r\n\t\t\t\t\t};\r\n\t\r\n\t\t\t\t\treturn throttled;\r\n\t\t\t\t };\r\n\t\r\n\t\r\n\t\t\t\tcomponent.el.addEventListener('componentchanged', onComponentChanged);\r\n\t\t\t}\r\n\t\t}\r\n\t});\r\n\n\n/***/ },\n/* 10 */\n/***/ function(module, exports) {\n\n\t/**\r\n\t* Enables the synchronization of properties of entities. All property sync components\r\n\t* require both a {@link sync.sync-system} on `a-scene`, and a {@link sync.sync}\r\n\t* on the entity to be synced.\r\n\t* @name sync\r\n\t* @namespace sync\r\n\t* @example\r\n\t* \r\n\t* \r\n\t* \r\n\t*/\r\n\t\r\n\t\r\n\t\r\n\t/**\r\n\t* Enables the synchronization of properties of the entity. Must be used in\r\n\t* conjuction with the {@link sync.sync-system} component and a component for a\r\n\t* specific property (e.g. {@link sync.sync-transform}).\r\n\t* @memberof sync\r\n\t* @mixin sync\r\n\t* @prop {string} ownOn - The name of the event, or a list of events, that\r\n\t* will cause the local client to take ownership of this object. This field\r\n\t* cannot be updated after initialization.\r\n\t*/\r\n\tAFRAME.registerComponent('sync',\r\n\t{\r\n\t\tschema: {\r\n\t\t\tmode: { default: 'link' },\r\n\t\t\townOn: { type: 'string' } //cannot be changed after creation\r\n\t\t},\r\n\t\tinit: function () {\r\n\t\t\tvar scene = document.querySelector('a-scene');\r\n\t\t\tvar syncSys = scene.systems['sync-system'];\r\n\t\r\n\t\t\tvar ref;\r\n\t\t\tvar key;\r\n\t\t\tvar dataRef;\r\n\t\t\tvar ownerRef;\r\n\t\t\tvar ownerId;\r\n\t\t\tvar isMine = false;\r\n\t\r\n\t\t\tvar component = this;\r\n\t\r\n\t\t\tcomponent.isConnected = false;\r\n\t\r\n\t\t\tif(syncSys.isConnected) start(); else scene.addEventListener('connected', start);\r\n\t\r\n\t\r\n\t\t\tif(component.data.ownOn)\r\n\t\t\t{\r\n\t\t\t\tvar ownershipEvents = component.data.ownOn.split(/[ ,]+/);\r\n\t\t\t\tfor(var i = 0, max = ownershipEvents.length; i < max; i++){\r\n\t\t\t\t\tcomponent.el.addEventListener(ownershipEvents[i], function(){\r\n\t\t\t\t\t\tif(component.isConnected){\r\n\t\t\t\t\t\t\tcomponent.takeOwnership();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\r\n\t\t\tfunction start(){\r\n\t\t\t\t//Make sure someone always owns an object. If the owner leaves and we are the master client, we will take it.\r\n\t\t\t\t//This ensures, for example, that synced animations keep playing\r\n\t\t\t\tscene.addEventListener('clientleft', function(event){\r\n\t\t\t\t\tvar shouldTakeOwnership = (!ownerId || ownerId === event.detail.id) && syncSys.isMasterClient;\r\n\t\r\n\t\t\t\t\tif(shouldTakeOwnership) component.takeOwnership();\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\tif (component.data.mode === 'link') {\r\n\t\t\t\t\tvar id = component.el.id;\r\n\t\t\t\t\tif (!id) {\r\n\t\t\t\t\t\tconsole.error('Entities cannot be synced using link mode without an id.');\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\r\n\t\t\t\t\tconsole.log('syncSys: ' + syncSys);\r\n\t\t\t\t\tconsole.log('syncSys.sceneRef: ' + syncSys.sceneRef);\r\n\t\r\n\t\t\t\t\tlink(syncSys.sceneRef.child(id));\r\n\t\t\t\t\tsetupReceive();\r\n\t\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconsole.error('Unsupported sync mode: ' + component.data.mode);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\r\n\t\t\t\tcomponent.isConnected = true;\r\n\t\t\t\tcomponent.el.emit('connected', null, false);\r\n\t\t\t}\r\n\t\r\n\t\t\tfunction link(entityRef) {\r\n\t\t\t\tref = entityRef;\r\n\t\t\t\tkey = ref.key();\r\n\t\t\t\tdataRef = ref.child('data');\r\n\t\t\t\tcomponent.dataRef = dataRef;\r\n\t\t\t\townerRef = ref.child('owner');\r\n\t\t\t}\r\n\t\r\n\t\t\tfunction setupReceive() {\r\n\t\r\n\t\t\t\t//if nobody has owned the object yet, we will.\r\n\t\t\t\townerRef.transaction(function (owner) {\r\n\t\t\t\t\tif (owner) return undefined;\r\n\t\r\n\t\t\t\t\townerRef.onDisconnect().set(null);\r\n\t\t\t\t\treturn syncSys.clientId;\r\n\t\t\t\t});\r\n\t\r\n\t\t\t\townerRef.on('value',\r\n\t\t\t\t\tfunction(snapshot) {\r\n\t\t\t\t\t\tvar newOwnerId = snapshot.val();\r\n\t\r\n\t\t\t\t\t\tvar gained = newOwnerId === syncSys.clientId && !isMine;\r\n\t\t\t\t\t\tif (gained) component.el.emit('ownershipgained', null, false);\r\n\t\r\n\t\r\n\t\t\t\t\t\t//note this also fires when we start up without ownership\r\n\t\t\t\t\t\tvar lost = newOwnerId !== syncSys.clientId && isMine;\r\n\t\t\t\t\t\tif (lost){\r\n\t\t\t\t\t\t\tcomponent.el.emit('ownershiplost', null, false);\r\n\t\r\n\t\t\t\t\t\t\t//we no longer have to clear our ownership when we disconnect\r\n\t\t\t\t\t\t\townerRef.onDisconnect().cancel();\r\n\t\t\t\t\t\t}\r\n\t\r\n\t\t\t\t\t\townerId = newOwnerId;\r\n\t\r\n\t\t\t\t\t\tisMine = newOwnerId === syncSys.clientId;\r\n\t\t\t\t\t});\r\n\t\t\t}\r\n\t\r\n\t\t\t/**\r\n\t\t\t* Tell sync to start pushing local property values instead of updating\r\n\t\t\t* local from remote values.\r\n\t\t\t* @method sync.sync#takeOwnership\r\n\t\t\t*/\r\n\t\t\tcomponent.takeOwnership = function() {\r\n\t\t\t\townerRef.set(syncSys.clientId);\r\n\t\r\n\t\t\t\t//clear our ownership if we disconnect\r\n\t\t\t\t//this is needed if we are the last user in the room, but we expect people to join later\r\n\t\t\t\townerRef.onDisconnect().set(null);\r\n\t\t\t}\r\n\t\r\n\t\t\t/**\r\n\t\t\t* Indicates whether the sync ownership is yours.\r\n\t\t\t* @member sync.sync#isMine\r\n\t\t\t* @readonly\r\n\t\t\t*/\r\n\t\t\tObject.defineProperty(component, 'isMine', {\r\n\t\t\t\tget: function () {\r\n\t\t\t\t\treturn isMine;//TODO: Should this be state instead?\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t});\r\n\n\n/***/ },\n/* 11 */\n/***/ function(module, exports) {\n\n\t/**\r\n\t * The wire component allows you to trigger an event on another entity when an event occurs on an entity\r\n\t * @mixin wire\r\n\t * @property {string} on Name of an event to listen to\r\n\t * @property {string} gained Name of a state to watch for\r\n\t * @property {string} lost Name of a state to watch for\r\n\t * @property {string} emit Name of an event to trigger on the targets\r\n\t * @property {string} gain Name of a state to add on the target\r\n\t * @property {string} lose Name of a state to remove on the target\r\n\t * @property {selector} targets A selector to pick which objects to wire to\r\n\t * @property {selector} target - A selector to pick a single object to wire to\r\n\t **/\r\n\tAFRAME.registerComponent('wire',\r\n\t{\r\n\t\tmultiple: true,\r\n\t\tschema: {\r\n\t\t\ton: {type: 'string'},\r\n\t\t\temit: {type: 'string'},\r\n\t\t\tgained: {type: 'string'},\r\n\t\t\tlost: {type: 'string'},\r\n\t\t\tgain: {type: 'string'},\r\n\t\t\tlose: {type: 'string'},\r\n\t\t\ttargets: {type: 'selectorAll'},\r\n\t\t\ttarget: {type: 'selector'}\r\n\t\t},\r\n\t\tupdate: function (oldData) {\r\n\t\t\tif (oldData.on) {\r\n\t\t\t\tthis.el.removeEventListener(oldData.on, this.actOnTargets);\r\n\t\t\t}\r\n\t\t\tif (oldData.gained) {\r\n\t\t\t\tthis.el.removeEventListener('stateadded', this.actOnTargetsIfStateMatches);\r\n\t\t\t}\r\n\t\t\tif (oldData.lost) {\r\n\t\t\t\tthis.el.removeEventListener('stateremoved', this.actOnTargetsIfStateMatches);\r\n\t\t\t}\r\n\t\r\n\t\t\tthis.actOnTargets = function () {\r\n\t\t\t\tfunction act(el) {\r\n\t\t\t\t\tif (this.data.emit) {\r\n\t\t\t\t\t\tel.emit(this.data.emit);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (this.data.gain) {\r\n\t\t\t\t\t\tel.addState(this.data.gain);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (this.data.lose) {\r\n\t\t\t\t\t\tel.removeState(this.data.lose);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif(this.data.targets) this.data.targets.forEach(act.bind(this));\r\n\t\t\t\tif(this.data.target) act.call(this, this.data.target);\r\n\t\t\t}.bind(this);\r\n\t\r\n\t\t\tthis.actOnTargetsIfStateMatches = function (event) {\r\n\t\t\t\tvar state = event.detail.state;\r\n\t\t\t\tif (state === this.data.gained || state === this.data.lost) {\r\n\t\t\t\t\tthis.actOnTargets();\r\n\t\t\t\t}\r\n\t\t\t}.bind(this);\r\n\t\r\n\t\t\tif (this.data.on) {\r\n\t\t\t\tthis.el.addEventListener(this.data.on, this.actOnTargets);\r\n\t\t\t}\r\n\t\t\tif (this.data.gained) {\r\n\t\t\t\tthis.el.addEventListener('stateadded', this.actOnTargetsIfStateMatches);\r\n\t\t\t}\r\n\t\t\tif (this.data.lost) {\r\n\t\t\t\tthis.el.addEventListener('stateremoved', this.actOnTargetsIfStateMatches);\r\n\t\t\t}\r\n\t\t},\r\n\t\tremove: function () {\r\n\t\t\tthis.el.removeEventListener(this.data.on, this.actOnTargets);\r\n\t\t\tthis.el.removeEventListener('stateadded', this.actOnTargetsIfStateMatches);\r\n\t\t\tthis.el.removeEventListener('stateremoved', this.actOnTargetsIfStateMatches);\r\n\t\t}\r\n\t});\r\n\n\n/***/ }\n/******/ ]);\n\n\n/** WEBPACK FOOTER **\n ** aframe-altspace-component.min.js\n **/"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap 4c5d887d65f9da9ef80d\n **/","if (typeof AFRAME === 'undefined') {\r\n throw new Error('Component attempted to register before AFRAME was available.');\r\n}\r\n\r\nrequire('./altspace');\r\nrequire('./altspace-cursor-collider');\r\nrequire('./altspace-tracked-controls');\r\nrequire('./native-components');\r\nrequire('./native-resources');\r\nrequire('./sync');\r\nrequire('./sync-system');\r\nrequire('./sync-transform');\r\nrequire('./sync-color');\r\nrequire('./sync-n-sound');\r\nrequire('./wire');\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/index.js\n ** module id = 0\n ** module chunks = 0\n **/","(function(){\r\n\r\n\tfunction setColliderFlag(obj, state) {\r\n\t\tobj.userData.altspace = {collider: {enabled: state}};\r\n\t\tobj.traverse(function (obj) {\r\n\t\t\tif (obj instanceof THREE.Mesh) {\r\n\t\t\t\tobj.userData.altspace = {collider: {enabled: state}};\r\n\t\t\t}\r\n\t\t})\r\n\t}\r\n\r\n\t/**\r\n\t* Enable or disable cursor collision on the object.\r\n\t* @mixin altspace-cursor-collider\r\n\t* @memberof altspace\r\n\t* @prop {boolean} enabled=true - The state of the cursor collider.\r\n\t*/\r\n\tAFRAME.registerComponent('altspace-cursor-collider', {\r\n\t\tschema: { enabled: { default: true } },\r\n\t\tinit: function () {\r\n\t\t\tsetColliderFlag(this.el.object3D, this.data.enabled);\r\n\t\t\tthis.el.addEventListener('model-loaded', (function(){\r\n\t\t\t\tsetColliderFlag(this.el.object3D, this.data.enabled);\r\n\t\t\t}).bind(this));\r\n\t\t},\r\n\t\tupdate: function () {\r\n\t\t\tsetColliderFlag(this.el.object3D, this.data.enabled);\r\n\t\t}\r\n\t});\r\n\r\n})();\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/altspace-cursor-collider.js\n ** module id = 1\n ** module chunks = 0\n **/","/**\r\n* Enables tracked control support for A-Frame applications that use the built-in\r\n* `tracked-controls`, `vive-controls` or `hand-controls` components.\r\n* @mixin altspace-tracked-controls\r\n* @memberof altspace\r\n*/\r\nAFRAME.registerComponent('altspace-tracked-controls', {\r\n init: function () {\r\n\tthis.gamepadIndex = null;\r\n\tthis.trackedControlsSystem = document.querySelector('a-scene').systems['tracked-controls'];\r\n\tthis.systemGamepads = 0;\r\n\taltspace.getGamepads();\r\n },\r\n tick: function () {\r\n\t if (\r\n\t\tthis.trackedControlsSystem &&\r\n\t\tthis.systemGamepads !== this.trackedControlsSystem.controllers.length &&\r\n\t\twindow.altspace && altspace.getGamepads && altspace.getGamepads().length\r\n\t ) {\r\n\t\tvar components = this.el.components;\r\n\t\tif (components['paint-controls']) {\r\n\t\t this.gamepadIndex = components['paint-controls'].data.hand === 'left' ? 2 : 1;\r\n\t\t}\r\n\t\tif (this.gamepadIndex === null && components['hand-controls']) {\r\n\t\t this.gamepadIndex = components['hand-controls'].data === 'left' ? 2 : 1;\r\n\t\t}\r\n\t\tif (this.gamepadIndex === null && components['vive-controls']) {\r\n\t\t this.gamepadIndex = components['vive-controls'].data.hand === 'left' ? 2 : 1;\r\n\t\t}\r\n\t\tif (this.gamepadIndex === null && components['tracked-controls']) {\r\n\t\t this.gamepadIndex = components['tracked-controls'].data.controller;\r\n\t\t}\r\n\t\tthis.el.setAttribute('tracked-controls', 'id', altspace.getGamepads()[this.gamepadIndex].id);\r\n\t\tthis.el.setAttribute('tracked-controls', 'controller', 0);\r\n\t\tthis.systemGamepads = this.trackedControlsSystem.controllers.length;\r\n\t }\r\n }\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/altspace-tracked-controls.js\n ** module id = 2\n ** module chunks = 0\n **/","/**\r\n* @namespace altspace\r\n*/\r\n\r\n/**\r\n* The altspace component makes A-Frame apps compatible with AltspaceVR.\r\n*\r\n* **Note**: If you use the `embedded` A-Frame component on your scene, you must include it *before* the `altspace` component, or your app will silently fail.\r\n* @mixin altspace\r\n* @memberof altspace\r\n* @property {boolean} usePixelScale=`false` - Allows you to use A-Frame units as CSS pixels.\r\n* This is the default behavior for three.js apps, but not for A-Frame apps.\r\n* @property {string} verticalAlign=`middle` - Puts the origin at the `bottom`, `middle` (default),\r\n* or `top` of the Altspace enclosure.\r\n* @property {boolean} enclosuresOnly=`true` - Prevents the scene from being created if\r\n* enclosure is flat.\r\n* @property {boolean} fullspace=`false` - Puts the app into fullspace mode.\r\n*\r\n* @example\r\n* \r\n* My A-Frame Scene\r\n* \r\n* \r\n* \r\n* \r\n* \r\n* \r\n* \r\n* \r\n*/\r\nAFRAME.registerComponent('altspace', {\r\n version: '1.3.2',\r\n schema: {\r\n\tusePixelScale: { type: 'boolean', default: 'false'},\r\n\tverticalAlign: { type: 'string', default: 'middle'},\r\n\tenclosuresOnly:{ type: 'boolean', default: 'true'},\r\n\tfullspace: { type: 'boolean', default: 'false'}\r\n },\r\n\r\n /*\r\n * Called once when component is attached. Generally for initial setup.\r\n */\r\n init: function () {\r\n\tif (!(this.el.object3D instanceof THREE.Scene)) {\r\n\t console.warn('aframe-altspace-component can only be attached to a-scene');\r\n\t return;\r\n\t}\r\n\r\n\tif (window.altspace && window.altspace.inClient) {\r\n\t this.el.setAttribute('vr-mode-ui', {enabled: false});\r\n\t this.initRenderer();\r\n\t this.initCursorEvents();\r\n\t this.initCollisionEvents();\r\n\t} else {\r\n\t console.warn('aframe-altspace-component only works inside of AltspaceVR');\r\n\t}\r\n\r\n },\r\n\r\n /*\r\n * Called on every single tick or render loop of the scene.\r\n */\r\n tick: function (t, dt) {\r\n if(this.el.object3D.updateAllBehaviors)\r\n this.el.object3D.updateAllBehaviors();\r\n },\r\n\r\n /*\r\n * Called when a component is removed (e.g., via removeAttribute).\r\n * Generally undoes all modifications to the entity.\r\n */\r\n remove: function () { },\r\n\r\n /*\r\n * Called on each scene tick.\r\n */\r\n // tick: function (t) { },\r\n\r\n /*\r\n * Called when entity pauses.\r\n * Use to stop or remove any dynamic or background behavior such as events.\r\n */\r\n pause: function () { },\r\n\r\n /*\r\n * Called when entity resumes.\r\n * Use to continue or add any dynamic or background behavior such as events.\r\n */\r\n play: function () { },\r\n\r\n\r\n /********** Helper Methods **********/\r\n\r\n /*\r\n * Swap in Altspace renderer when running in AltspaceVR.\r\n */\r\n initRenderer: function () {\r\n\r\n\tvar scene = this.el.object3D;\r\n\taltspace.getEnclosure().then(function(e)\r\n\t{\r\n\t\tif(this.data.fullspace){\r\n\t\t\te.requestFullspace();\r\n\t\t\te.addEventListener('fullspacechange', function(){\r\n\t\t\t\tscene.scale.setScalar(e.pixelsPerMeter);\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tif (!this.data.usePixelScale || this.data.fullspace){\r\n\t\t\tscene.scale.setScalar(e.pixelsPerMeter);\r\n\t\t}\r\n\r\n\t switch (this.data.verticalAlign) {\r\n\t\tcase 'bottom':\r\n\t\t scene.position.y -= e.innerHeight / 2;\r\n\t\t break;\r\n\t\tcase 'top':\r\n\t\t scene.position.y += e.innerHeight / 2;\r\n\t\t break;\r\n\t\tcase 'middle':\r\n\t\t break;\r\n\t\tdefault:\r\n\t\t console.warn('Unexpected value for verticalAlign: ', this.data.verticalAlign);\r\n\t }\r\n\r\n\t if(this.data.enclosuresOnly && e.innerDepth === 1){\r\n\t\tthis.el.renderer.render(new THREE.Scene());\r\n\t\tthis.el.renderer = this.el.effect = oldRenderer;\r\n\r\n\t }\r\n\t}.bind(this));\r\n\r\n\tvar oldRenderer = this.el.renderer;\r\n\tvar renderer = this.el.renderer = this.el.effect = altspace.getThreeJSRenderer({\r\n\t aframeComponentVersion: this.version\r\n\t});\r\n\tvar noop = function() {};\r\n\trenderer.setSize = noop;\r\n\trenderer.setPixelRatio = noop;\r\n\trenderer.setClearColor = noop;\r\n\trenderer.clear = noop;\r\n\trenderer.enableScissorTest = noop;\r\n\trenderer.setScissor = noop;\r\n\trenderer.setViewport = noop;\r\n\trenderer.getPixelRatio = noop;\r\n\trenderer.getMaxAnisotropy = noop;\r\n\trenderer.setFaceCulling = noop;\r\n\trenderer.context = {canvas: {}};\r\n\trenderer.shadowMap = {};\r\n\r\n },\r\n\r\n /*\r\n * Emulate A-Frame cursor events when running in altspaceVR.\r\n */\r\n initCursorEvents: function() {\r\n\r\n\tvar scene = this.el.object3D;\r\n\tvar cursorEl = document.querySelector('a-cursor') || document.querySelector('a-entity[cursor]');\r\n\tif (cursorEl) {\r\n\t // Hide A-Frame cursor mesh.\r\n\t cursorEl.setAttribute('material', 'transparent', true);\r\n\t cursorEl.setAttribute('material', 'opacity', 0.0);\r\n\t}\r\n\r\n\tvar emit = function (eventName, event) {\r\n\t\t// Fire events on intersected object and A-Frame cursor.\r\n\t\tvar targetEl = event.target.el;\r\n\t\tif (cursorEl) cursorEl.emit(eventName, { target: targetEl, ray: event.ray, point: event.point });\r\n\t\tif (targetEl) targetEl.emit(eventName, { target: targetEl, ray: event.ray, point: event.point });\r\n\t} ;\r\n\r\n\tvar cursordownObj = null;\r\n\tscene.addEventListener('cursordown', function(event) {\r\n\t cursordownObj = event.target;\r\n\t emit('mousedown', event);\r\n\t});\r\n\r\n\tscene.addEventListener('cursorup', function(event) {\r\n\t emit('mouseup', event);\r\n\t if (event.target.uuid === cursordownObj.uuid) {\r\n\t\temit('click', event);\r\n\t }\r\n\t cursordownObj = null;\r\n\t});\r\n\r\n\tscene.addEventListener('cursorenter', function(event) {\r\n\t if (!event.target.el) { return; }\r\n\t event.target.el.addState('hovered');\r\n\t if (cursorEl) cursorEl.addState('hovering');\r\n\t emit('mouseenter', event);\r\n\t});\r\n\r\n\tscene.addEventListener('cursorleave', function(event) {\r\n\t if (!event.target.el) { return; }\r\n\t event.target.el.removeState('hovered');\r\n\t if (cursorEl) cursorEl.removeState('hovering');\r\n\t emit('mouseleave', event);\r\n\t});\r\n\r\n },\r\n\r\n initCollisionEvents: function () {\r\n\r\n\tvar scene = this.el.object3D;\r\n\r\n\tvar emit = function (eventName, event) {\r\n\t\tvar targetEl = event.target.el;\r\n\t\tif (!targetEl) return;\r\n\r\n\t\t//remap target and other from object3Ds to aframe element\r\n\t\tevent.target = targetEl;\r\n\t\tif (event.other && event.other.el) {\r\n\t\t\tevent.other = event.other.el;\r\n\t\t}\r\n\t\ttargetEl.emit(eventName, event);\r\n\t};\r\n\r\n\tscene.addEventListener('collisionenter', function (event) {\r\n\t\temit('collisionenter', event);\r\n\t});\r\n\r\n\tscene.addEventListener('collisionexit', function (event) {\r\n\t\temit('collisionexit', event);\r\n\t});\r\n\r\n\tscene.addEventListener('triggerenter', function (event) {\r\n\t\temit('triggerenter', event);\r\n\t});\r\n\r\n\tscene.addEventListener('triggerexit', function (event) {\r\n\t\temit('triggerexit', event);\r\n\t});\r\n\r\n }\r\n\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/altspace.js\n ** module id = 3\n ** module chunks = 0\n **/","\r\n/**\r\n* This set of components map to various objects and effects that are provided\r\n* natively by AltspaceVR. Your management of these objects may be limited to\r\n* some degree, but they will tend to be more performant than SDK equivalents,\r\n* or may provide some functionality not otherwise available to the SDK.\r\n* @namespace native\r\n*/\r\n(function () {\r\n\tif (!window.altspace || !altspace.inClient) {\r\n\t\tvar noop = function () {};\r\n\t\twindow.altspace = {\r\n\t\t\taddNativeComponent: noop,\r\n\t\t\tupdateNativeComponent: noop,\r\n\t\t\tremoveNativeComponent: noop\r\n\t\t};\r\n\t}\r\n\r\n\tvar placeholderGeometry = new THREE.BoxGeometry(0.001, 0.001, 0.001);\r\n\tvar placeholderMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 });\r\n\tplaceholderMaterial.visible = false;\r\n\tvar PlaceholderMesh = function () {\r\n\t\tTHREE.Mesh.call( this, placeholderGeometry, placeholderMaterial );\r\n\t};\r\n\tPlaceholderMesh.prototype = Object.create( THREE.Mesh.prototype );\r\n\tPlaceholderMesh.prototype.constructor = THREE.PlaceholderMesh;\r\n\r\n\tfunction meshInit(mesh) {\r\n\t\t//If you attach native components to an entity, it will not use a default collider\r\n\t\tmesh.userData.altspace = mesh.userData.altspace || {};\r\n\t\tmesh.userData.altspace.collider = mesh.userData.altspace.collider || {};\r\n\t\tmesh.userData.altspace.collider.enabled = false;\r\n\r\n\t\taltspace.addNativeComponent(mesh, this.name);\r\n\t}\r\n\r\n\tfunction nativeComponentInit() {\r\n\t\tvar mesh = this.el.getOrCreateObject3D('mesh', PlaceholderMesh);\r\n\r\n\t\tmeshInit.call(this, mesh);\r\n\r\n\t\t//to pass defaults\r\n\t\tthis.update(this.data);\r\n\t}\r\n\tfunction nativeComponentRemove() {\r\n\t\tvar mesh = this.el.getObject3D('mesh');\r\n\t\taltspace.removeNativeComponent(mesh, this.name);\r\n\t}\r\n\tfunction nativeComponentUpdate(oldData) {\r\n\t\taltspace.updateNativeComponent(this.el.object3DMap.mesh, this.name, this.data);\r\n\t}\r\n\r\n\tfunction callComponent(functionName, functionArguments) {\r\n\t\taltspace.callNativeComponent(this.el.object3DMap.mesh, this.name, functionName, functionArguments)\r\n\t}\r\n\r\n\t/**\r\n\t* Attach a given native object to this entity.\r\n\t* @mixin n-object\r\n\t* @memberof native\r\n\t* @prop {string} res - The identifier for the resource you want. This component\r\n\t* can accept all resources except for `interactables`.\r\n\t* @example \r\n\t*/\r\n\tAFRAME.registerComponent('n-object', {\r\n\t\tschema: {\r\n\t\t\tres: {type: 'string'}\r\n\t\t},\r\n\t\tinit: nativeComponentInit,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tremove: nativeComponentRemove\r\n\t});\r\n\r\n\t/**\r\n\t* Create an object that spawns additional copies of itself when grabbed by a user (the copies are not spawners themselves).\r\n\t* These copies will be physically interactive and automatically synchronized\r\n\t* between users.\r\n\t* @mixin n-spawner\r\n\t* @memberof native\r\n\t* @prop {string} res - The identifier for the resource you want. This component\r\n\t* can only accept resources of type `interactables`.\r\n\t* @example \r\n\t*/\r\n\tAFRAME.registerComponent('n-spawner', {\r\n\t\tschema: {\r\n\t\t\tres: {type: 'string'}\r\n\t\t},\r\n\t\tinit: nativeComponentInit,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tremove: nativeComponentRemove\r\n\t});\r\n\r\n\t/**\r\n\t* Creates dynamic 2D text on the entity. The text will wrap automatically based on the width and height provided.\r\n\t* This text will be clearer than texture-based text and more performant than geometry-based test.\r\n\t* @mixin n-text\r\n\t* @memberof native\r\n\t* @prop {string} text - The text to be drawn.\r\n\t* @prop {number} fontSize=10 - The height of the letters. 10pt ~= 1m\r\n\t* @prop {number} width=10 - The width of the text area in meters. If the\r\n\t* text is wider than this value, the overflow will be wrapped to the next line.\r\n\t* @prop {number} height=1 - The height of the text area in meters. If the\r\n\t* text is taller than this value, the overflow will be cut off.\r\n\t* @prop {string} horizontalAlign=middle - The horizontal anchor point for\r\n\t* the text. Can be `left`, `middle`, or `right`.\r\n\t* @prop {string} verticalAlign=middle - The vertical anchor point for the\r\n\t* text. Can be `top`, `middle`, or `bottom`.\r\n\t*/\r\n\tAFRAME.registerComponent('n-text', {\r\n\t\tinit: nativeComponentInit,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tremove: nativeComponentRemove,\r\n\t\tschema: {\r\n\t\t\ttext: { default: '', type: 'string' },\r\n\t\t\t/*color: { default: 'white',\r\n\t\t\t\tparse: function(value) {\r\n\t\t\t\t\treturn parseFloat(value, 10);\r\n\t\t\t\t},\r\n\t\t\t\tstringify: function(value) {\r\n\t\t\t\t\treturn value.toString();\r\n\t\t\t\t}},*/\r\n\t\t\tfontSize: { default: '10', type: 'int' },//roughly a meter tall\r\n\t\t\twidth: { default: '10', type: 'number' },//in meters\r\n\t\t\theight: { default: '1', type: 'number' },//in meters\r\n\t\t\thorizontalAlign: { default: 'middle'},\r\n\t\t\tverticalAlign: { default: 'middle'}\r\n\t\t}\r\n\t});\r\n\r\n\t//object: collides against: objects / enviroment / cursor\r\n\t//environment: can be teleported onto, and collides against: objects / environment / cursor\r\n\t//hologram: collides against: cursor / holograms\r\n\r\n\t/**\r\n\t* Abstract base class for {@link n.n-sphere-collider}, {@link n.n-box-collider},\r\n\t* {@link n.n-capsule-collider}, and {@link n.n-mesh-collider}. You cannot use\r\n\t* this class directly, but instead you should add one of those components\r\n\t* to your objects.\r\n\t* @name n-collider\r\n\t* @mixin n-collider\r\n\t* @memberof native\r\n\t* @prop {vec3} center=0,0,0 - The offset of the collider in local space.\r\n\t* @prop {string} type=hologram - The type of collider, one of: `object` | `environment` | `hologram`.\r\n\t* Object colliders collide with other objects, the environment, and the cursor.\r\n\t* Environment colliders collide with everything objects do, but you can also\r\n\t* teleport onto them. Hologram colliders only collide with other holograms and\r\n\t* the cursor.\r\n\t*/\r\n\r\n\t/**\r\n\t* Create a spherical collider on this entity.\r\n\t* @mixin n-sphere-collider\r\n\t* @memberof native\r\n\t* @extends native.n-collider\r\n\t* @prop {number} radius=1 - The size of the collider in meters.\r\n\t*/\r\n\tAFRAME.registerComponent('n-sphere-collider', {\r\n\t\tinit:nativeComponentInit,\r\n\t\tremove: nativeComponentRemove,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tschema: {\r\n\t\t\tisTrigger: { default: false, type: 'boolean' },\r\n\t\t\tcenter: { type: 'vec3' },\r\n\t\t\tradius: { default: '0', type: 'number' },\r\n\t\t\ttype: {default: 'object'}\r\n\t\t}\r\n\t});\r\n\r\n\r\n\t/**\r\n\t* Create a box-shaped collider on this entity.\r\n\t* @mixin n-box-collider\r\n\t* @memberof native\r\n\t* @extends native.n-collider\r\n\t* @prop {vec3} size=1,1,1 - The dimensions of the collider.\r\n\t*/\r\n\tAFRAME.registerComponent('n-box-collider', {\r\n\t\tinit:nativeComponentInit,\r\n\t\tremove: nativeComponentRemove,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tschema: {\r\n\t\t\tisTrigger: { default: false, type: 'boolean' },\r\n\t\t\tcenter: { type: 'vec3' },\r\n\t\t\tsize: { type: 'vec3' },\r\n\t\t\ttype: {default: 'object'}\r\n\t\t}\r\n\t});\r\n\r\n\t/**\r\n\t* Create a capsule-shaped collider on this entity. Capsules\r\n\t* are a union of a cylinder and two spheres on top and bottom.\r\n\t* @mixin n-capsule-collider\r\n\t* @memberof native\r\n\t* @extends native.n-collider\r\n\t* @prop {number} radius=1 - The radius of the capsule in meters.\r\n\t* @prop {number} height=1 - The height of the shaft of the capsule in meters.\r\n\t* @prop {string} direction=y - The axis with which the capsule is aligned.\r\n\t* One of `x`, `y`, or `z`.\r\n\t*/\r\n\tAFRAME.registerComponent('n-capsule-collider', {\r\n\t\tinit:nativeComponentInit,\r\n\t\tremove: nativeComponentRemove,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tschema: {\r\n\t\t\tisTrigger: { default: false, type: 'boolean' },\r\n\t\t\tcenter: { type: 'vec3' },\r\n\t\t\tradius: { default: '0', type: 'number' },\r\n\t\t\theight: { default: '0', type: 'number' },\r\n\t\t\tdirection: { default: 'y' },\r\n\t\t\ttype: {default: 'object'}\r\n\t\t}\r\n\t});\r\n\r\n\t/**\r\n\t* Enable collision for the entire attached mesh. This is expensive to evaluate, so should only be used on\r\n\t* low-poly meshes.\r\n\t* @mixin n-mesh-collider\r\n\t* @memberof native\r\n\t* @extends native.n-collider\r\n\t* @example \r\n\t* @prop {bool} convex=true - Whether the collider should be convex or concave. Set this to false if you have holes\r\n\t* in your mesh. Convex colliders are limited to 255 triangles. Note: concave colliders can be significantly more\r\n\t* expensive comparet to conves colliders.\r\n\t*/\r\n\tAFRAME.registerComponent('n-mesh-collider', {\r\n\t\t_forEachMesh: function (func) {\r\n\t\t\tvar obj = this.el.object3DMap.mesh;\r\n\t\t\tif (!obj) { return; }\r\n\t\t\tif (obj instanceof THREE.Mesh) {\r\n\t\t\t\tfunc(obj);\r\n\t\t\t}\r\n\t\t\tobj.traverse(function (childObj) {\r\n\t\t\t\tif (childObj instanceof THREE.Mesh) {\r\n\t\t\t\t\tfunc(childObj);\r\n\t\t\t\t}\r\n\t\t\t}.bind(this));\r\n\t\t},\r\n\t\t_initObj: function () {\r\n\t\t\tthis._forEachMesh(function (mesh) {\r\n\t\t\t\tmeshInit.call(this, mesh);\r\n\r\n\t\t\t\t//to pass defaults\r\n\t\t\t\taltspace.updateNativeComponent(mesh, this.name, this.data);\r\n\t\t\t}.bind(this));\r\n\t\t},\r\n\t\tinit: function () {\r\n\t\t\t// Allow a-frame to create a PlaceholderMesh if there isn't already one, so that the native collider is\r\n\t\t\t// registered.\r\n\t\t\tthis.el.getOrCreateObject3D('mesh', PlaceholderMesh);\r\n\r\n\t\t\t// Initialize the existing mesh\r\n\t\t\tthis._initObj();\r\n\r\n\t\t\tthis.el.addEventListener('model-loaded', function () {\r\n\t\t\t\t// Re-initialize the collider if a new model is loaded\r\n\t\t\t\tthis._initObj();\r\n\t\t\t}.bind(this));\r\n\t\t},\r\n\t\tremove: function () {\r\n\t\t\tthis._forEachMesh(function (mesh) {\r\n\t\t\t\taltspace.removeNativeComponent(mesh, this.name);\r\n\t\t\t}.bind(this));\r\n\t\t},\r\n\t\tupdate: function (oldData) {\r\n\t\t\tthis._forEachMesh(function (mesh) {\r\n\t\t\t\taltspace.updateNativeComponent(mesh, this.name, this.data);\r\n\t\t\t}.bind(this));\r\n\t\t},\r\n\t\tschema: {\r\n\t\t\tisTrigger: { default: false, type: 'boolean' },\r\n\t\t\tconvex: { default: true, type: 'boolean' },\r\n\t\t\ttype: {default: 'object'}\r\n\t\t}\r\n\t});\r\n\r\n\t/**\r\n\t* Make the object's +Z always face the viewer. Currently will only directly apply to main mesh or native component on the attached entity, not any children or submeshes.\r\n\t* @mixin n-billboard\r\n\t* @memberof native\r\n\t* @example \r\n\t*/\r\n\tAFRAME.registerComponent('n-billboard', {\r\n\t\tinit:nativeComponentInit,\r\n\t\tremove: nativeComponentRemove,\r\n\t});\r\n\r\n\t/**\r\n\t* A container keeps a running tally of how many objects are within\r\n\t* its bounds, and adds and removes the states `container-full` and\r\n\t* `container-empty` based on the current count of objects. Can fire three\r\n\t* special events: `container-full`, `container-empty`, and `container-count-changed`.\r\n\t* @mixin n-container\r\n\t* @memberof native\r\n\t* @prop {number} capacity=4 - The value at which the container will fire the\r\n\t* `container-full` event.\r\n\t*/\r\n\tAFRAME.registerComponent('n-container', {\r\n\t\tinit: function(){\r\n\t\t\tnativeComponentInit.call(this);\r\n\r\n\t\t\tvar el = this.el;\r\n\t\t\tvar component = this;\r\n\r\n\t\t\tel.addEventListener('stateadded', function(event){\r\n\t\t\t\tif(event.detail.state === 'container-full'){\r\n\t\t\t\t\tel.emit('container-full');\r\n\t\t\t\t}\r\n\t\t\t\tif(event.detail.state === 'container-empty'){\r\n\t\t\t\t\tel.emit('container-empty');\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\tel.addEventListener('container-count-changed', function(event){\r\n\t\t\t\tcomponent.count = event.detail.count;\r\n\t\t\t});\r\n\t\t},\r\n\t\tremove: nativeComponentRemove,\r\n\t\tupdate: nativeComponentUpdate,\r\n\t\tschema: {\r\n\t\t\tcapacity: { default: 4, type: 'number' },\r\n\t\t}\r\n\t});\r\n\r\n\t/**\r\n\t* Play the sound given by the `src` or `res` property from the location\r\n\t* of the entity.\r\n\t* @mixin n-sound\r\n\t* @memberof native\r\n\t* @prop {string} res - The resource identifier for a built-in sound clip.\r\n\t* @prop {string} src - A URL to an external sound clip. The sound can be in WAV, OGG or MP3 format. However. only\r\n\t* WAV is supported on all platforms. MP3 is supported on Gear VR and OGG is supported on desktop.\r\n\t* @prop {string} on - The name of the event that will play this sound clip.\r\n\t* @prop {boolean} loop=false - Tells the clip to loop back to the beginning of the clip\r\n\t* once it's finished.\r\n\t* @prop {boolean} autoplay=false - Tells the clip to start automatically when\r\n\t* the scene loads, instead of waiting for `playSound()`.\r\n\t* @prop {boolean} oneshot=false - Tells the clip to clean itself up when it\r\n\t* finishes playing. Allows for overlapping instances of the sound.\r\n\t* @prop {number} volume=1 - The volume of the clip, from [0,1].\r\n\t* @prop {number} spatialBlend=1 - How spatialized a sound is, from [0,1].\r\n\t* A value of 1 will be fully localized, and the sound will pan left and\r\n\t* right as you turn your head. A value of 0 makes it non-spatialized, and\r\n\t* it will always be heard in both ears.\r\n\t* @prop {number} pitch=1 - The speed multiplier for the sound. 0.5 is one\r\n\t* octave down, and 2 is one octave up.\r\n\t* @prop {number} minDistance=1 - Inside this distance in meters,\r\n\t* the sound volume is at full volume.\r\n\t* @prop {number} maxDistance=12 - If rolloff is 'logarithmic', the sound will stop attenuating at this distance.\r\n\t* If rolloff is 'linear' or 'cosine', the sound will be silent at this distance.\r\n\t* @prop {string} rolloff='logarithmic' - Set this to 'linear' or 'cosine' if you want to cut sounds off at a\r\n\t* maxDistance.\r\n\t*/\r\n\t/**\r\n\t* Fired when a sound has loaded and is ready to be played\r\n\t* @event native.n-sound#n-sound-loaded\r\n\t*/\r\n\tAFRAME.registerComponent('n-sound', {\r\n\t\tinit: function () {\r\n\t\t\tvar src = this.data.src;\r\n\t\t\tif (src && !src.startsWith('http')) {\r\n\t\t\t\tif (src.startsWith('/')) {\r\n\t\t\t\t\tthis.data.src = location.origin + src;\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tvar currPath = location.pathname;\r\n\t\t\t\t\tif (!currPath.endsWith('/')) {\r\n\t\t\t\t\t\tcurrPath = location.pathname.split('/').slice(0, -1).join('/') + '/';\r\n\t\t\t\t\t}\r\n\t\t\t\t\tthis.data.src = location.origin + currPath + src;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tnativeComponentInit.call(this);\r\n\t\t},\r\n\r\n\t\t/**\r\n\t\t* Stop the playing sound, and preserve position in clip.\r\n\t\t* @method native.n-sound#pauseSound\r\n\t\t*/\r\n\t\tpauseSound: function () {\r\n\t\t\tcallComponent.call(this, 'pause');\r\n\t\t\tthis.el.emit('sound-paused');\r\n\t\t},\r\n\r\n\t\t/**\r\n\t\t* Start the sound playing.\r\n\t\t* @method native.n-sound#playSound\r\n\t\t*/\r\n\t\tplaySound: function () {\r\n\t\t\tcallComponent.call(this, 'play');\r\n\t\t\tthis.el.emit('sound-played');\r\n\t\t},\r\n\r\n\t\t/**\r\n\t\t* Jump to a position in the clip.\r\n\t\t* @method native.n-sound#seek\r\n\t\t* @param {number} time - The time in milliseconds to jump to.\r\n\t\t*/\r\n\t\tseek: function (time) {\r\n\t\t\tcallComponent.call(this, 'seek', {time: time});\r\n\t\t},\r\n\t\tremove: function () {\r\n\t\t\tnativeComponentRemove.call(this);\r\n\t\t\tif (this.playHandler) {\r\n\t\t\t this.el.removeEventListener(oldData.on, this.playHandler);\r\n\t\t\t}\r\n\t\t},\r\n\t\tupdate: function (oldData) {\r\n\t\t\tnativeComponentUpdate.call(this, oldData);\r\n\t\t\tif (this.playHandler) {\r\n\t\t\t this.el.removeEventListener(oldData.on, this.playHandler);\r\n\t\t\t}\r\n\t\t\tif (this.data.on) {\r\n\t\t\t this.playHandler = this.playSound.bind(this);\r\n\t\t\t this.el.addEventListener(this.data.on, this.playHandler);\r\n\t\t\t}\r\n\t\t},\r\n\t\tschema: {\r\n\t\t\ton: { type: 'string' },\r\n\t\t\tres: { type: 'string' },\r\n\t\t\tsrc: { type: 'string' },\r\n\t\t\tloop: { type: 'boolean' },\r\n\t\t\tvolume: { type: 'number', default: 1 },\r\n\t\t\tautoplay: { type: 'boolean' },\r\n\t\t\toneshot: { type: 'boolean' },\r\n\t\t\tspatialBlend: { type: 'float', default: 1 },\r\n\t\t\tpitch: { type: 'float', default: 1 },\r\n\t\t\tminDistance: { type: 'float', default: 1 },\r\n\t\t\tmaxDistance: { type: 'float', default: 12 },\r\n\t\t\trolloff: { type: 'string', default: 'logarithmic' },\r\n\t\t}\r\n\t});\r\n\r\n})();\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/native-components.js\n ** module id = 4\n ** module chunks = 0\n **/","/**\r\n* Sync the color property of the object between clients.\r\n* Requires both a {@link sync.sync-system} component on the `a-scene`, and a\r\n* {@link sync.sync} component on the target entity.\r\n* @mixin sync-color\r\n* @memberof sync\r\n*/\r\nAFRAME.registerComponent('sync-color',\r\n{\r\n\tdependencies: ['sync'],\r\n\tschema: {\r\n\t},\r\n\tinit: function () {\r\n\t\tvar component = this;\r\n\t\tvar sync = component.el.components.sync;\r\n\t\tif(sync.isConnected) start(); else component.el.addEventListener('connected', start);\r\n\r\n\t\tfunction start(){\r\n\t\t\tvar colorRef = sync.dataRef.child('material/color');\r\n\r\n\t\t\tvar refChangedLocked = false;\r\n\r\n\t\t\tvar firstValue = true;\r\n\r\n\t\t\tcomponent.el.addEventListener('componentchanged', function (event) {\r\n\t\t\t\tvar name = event.detail.name;\r\n\t\t\t\tvar oldData = event.detail.oldData;\r\n\t\t\t\tvar newData = event.detail.newData;\r\n\r\n\t\t\t\tif (name !== 'material') return;\r\n\t\t\t\tif (refChangedLocked) return;\r\n\r\n\t\t\t\tif (oldData.color !== newData.color) {\r\n\t\t\t\t\tif(sync.isMine){\r\n\t\t\t\t\t\tsetTimeout(function() {//For some reason A-Frame has a misconfigured material reference if we do this too early\r\n\t\t\t\t\t\t\tcolorRef.set(newData.color);\r\n\t\t\t\t\t\t}, 0);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\tcolorRef.on('value', function (snapshot) {\r\n\t\t\t\tif (sync.isMine && !firstValue) return;\r\n\t\t\t\tvar color = snapshot.val();\r\n\r\n\t\t\t\trefChangedLocked = true;\r\n\t\t\t\tcomponent.el.setAttribute('material', 'color', color);\r\n\t\t\t\trefChangedLocked = false;\r\n\r\n\t\t\t\tfirstValue = false;\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/sync-color.js\n ** module id = 6\n ** module chunks = 0\n **/","/**\r\n* Synchronize the playback state of an {@link n.n-sound} component between clients.\r\n* Requires both a {@link sync.sync-system} component on the `a-scene`, and a\r\n* {@link sync.sync} component on the target entity.\r\n* @mixin sync-n-sound\r\n* @memberof sync\r\n*/\r\nAFRAME.registerComponent('sync-n-sound',\r\n{\r\n\tdependencies: ['sync'],\r\n\tschema: { },\r\n\tinit: function () {\r\n\t\tvar component = this;\r\n\t\tvar sync = component.el.components.sync;\r\n\t\tvar scene = document.querySelector('a-scene');\r\n\t\tvar syncSys = scene.systems['sync-system'];\r\n\t\tif(sync.isConnected) start(); else component.el.addEventListener('connected', start);\r\n\r\n\t\tfunction start(){\r\n\t\t\tcomponent.soundStateRef = sync.dataRef.child('sound/state');\r\n\t\t\tcomponent.soundEventRef = sync.dataRef.child('sound/event');\r\n\r\n\t\t\tfunction sendEvent(event) {\r\n\t\t\t\tif (!sync.isMine) return;\r\n\t\t\t\tvar event = {\r\n\t\t\t\t\ttype: event.type,\r\n\t\t\t\t\tsender: syncSys.clientId,\r\n\t\t\t\t\tel: component.el.id,\r\n\t\t\t\t\ttime: Date.now()\r\n\t\t\t\t};\r\n\t\t\t\tcomponent.soundEventRef.set(event);\r\n\t\t\t}\r\n\r\n\t\t\tcomponent.el.addEventListener('sound-played', sendEvent);\r\n\t\t\tcomponent.el.addEventListener('sound-paused', sendEvent);\r\n\r\n\t\t\tcomponent.soundEventRef.on('value', function (snapshot) {\r\n\t\t\t\tif (sync.isMine) return;\r\n\t\t\t\tvar event = snapshot.val();\r\n\t\t\t\tif (!event) return;\r\n\t\t\t\tif (event.el === component.el.id) {\r\n\t\t\t\t\tvar sound = component.el.components['n-sound'];\r\n\t\t\t\t\tif (event.type === 'sound-played') {\r\n\t\t\t\t\t\tsound.playSound();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tsound.pauseSound();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\tcomponent.el.addEventListener('componentchanged', function (event) {\r\n\t\t\t\tif (!sync.isMine) return;\r\n\t\t\t\tvar name = event.detail.name;\r\n\t\t\t\tif (name !== 'n-sound') return;\r\n\t\t\t\tcomponent.soundStateRef.set(event.detail.newData);\r\n\t\t\t});\r\n\r\n\t\t\tcomponent.soundStateRef.on('value', function (snapshot) {\r\n\t\t\t\tif (sync.isMine) return;\r\n\t\t\t\tvar state = snapshot.val();\r\n\t\t\t\tif (!state) return;\r\n\t\t\t\tcomponent.el.setAttribute('n-sound', state);\r\n\t\t\t});\r\n\t\t}\r\n\t},\r\n\tremove: function () {\r\n\t\tthis.soundStateRef.off('value');\r\n\t\tthis.soundEventRef.off('value');\r\n\t}\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/sync-n-sound.js\n ** module id = 7\n ** module chunks = 0\n **/","/**\r\n* Connect to a remote Firebase server, and facilitate synchronization. These\r\n* options correspond exactly with the configuration options for\r\n* [altspace.utilities.sync.connect]{@link http://altspacevr.github.io/AltspaceSDK/doc/module-altspace_utilities_sync.html#.connect}.\r\n* This component must be present on `a-scene` for any other sync components to work.\r\n* @memberof sync\r\n* @mixin sync-system\r\n* @prop {string} author - A unique identifier for you or your organization.\r\n* @prop {string} app - The name of the app.\r\n* @prop {string} refUrl - Override the base reference. Set this to use your own Firebase.\r\n* @prop {string} instance - Override the instance ID. Can also be overridden with\r\n* a URL parameter.\r\n*/\r\nAFRAME.registerSystem('sync-system',\r\n{\r\n\tschema: {\r\n\t\tauthor: { type: 'string', default: null },\r\n\t\tapp: { type: 'string', default: null },\r\n\t\tinstance: { type: 'string', default: null },\r\n\t\trefUrl: { type: 'string', default: null }\r\n\t},\r\n\tinit: function() {\r\n\t\tvar component = this;\r\n\r\n\t\tif(!this.data || !this.data.app){\r\n\t\t\tconsole.warn('The sync-system must be present on the scene and configured with required data.');\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tcomponent.isConnected = false;\r\n\t\tconsole.log(this.data);\r\n\t\taltspace.utilities.sync.connect({\r\n\t\t\tauthorId: this.data.author,\r\n\t\t\tappId: this.data.app,\r\n\t\t\tinstanceId: this.data.instance,\r\n\t\t\tbaseRefUrl: this.data.refUrl\r\n\t\t}).then(function(connection) {\r\n\t\t\tthis.connection = connection;\r\n\r\n\t\t\tthis.sceneRef = this.connection.instance.child('scene');\r\n\t\t\tthis.clientsRef = this.connection.instance.child('clients');\r\n\r\n\t\t\t// temporary way of having unique identifiers for each client\r\n\t\t\tthis.clientId = this.sceneEl.object3D.uuid;\r\n\t\t\tvar masterClientId;\r\n\t\t\tthis.clientsRef.on(\"value\", function (snapshot) {\r\n\t\t\t\tvar clientIds = snapshot.val();\r\n\r\n\t\t\t\tvar masterClientKey = Object.keys(clientIds)[0];\r\n\t\t\t\tmasterClientId = clientIds[masterClientKey];\r\n\t\t\t});\r\n\r\n\t\t\tthis.clientsRef.on('child_added', function(childSnapshot) {\r\n\t\t\t\tvar joinedClientId = childSnapshot.val();\r\n\t\t\t\t//let the master client flag get set first\r\n\t\t\t\tsetTimeout(function(){\r\n\t\t\t\t\tcomponent.sceneEl.emit('clientjoined', {id: joinedClientId}, false);\r\n\t\t\t\t}, 0);\r\n\t\t\t});\r\n\r\n\t\t\tthis.clientsRef.on('child_removed', function(childSnapshot) {\r\n\t\t\t\tvar leftClientId = childSnapshot.val();\r\n\t\t\t\t//let the master client flag get set first\r\n\t\t\t\tsetTimeout(function(){\r\n\t\t\t\t\tcomponent.sceneEl.emit('clientleft', {id: leftClientId}, false);\r\n\t\t\t\t}, 0);\r\n\t\t\t});\r\n\r\n\t\t\t// add our client ID to the list of connected clients,\r\n\t\t\t// but have it be automatically removed by firebase if we disconnect for any reason\r\n\t\t\tthis.clientsRef.push(this.clientId).onDisconnect().remove();\r\n\r\n\r\n\t\t\tthis.connection.instance.child('initialized').once('value', function (snapshot) {\r\n\t\t\t\tvar shouldInitialize = !snapshot.val();\r\n\t\t\t\tsnapshot.ref().set(true);\r\n\r\n\t\t\t\tcomponent.sceneEl.emit('connected', { shouldInitialize: shouldInitialize }, false);\r\n\t\t\t\tcomponent.isConnected = true;\r\n\t\t\t}.bind(this));\r\n\r\n\r\n\t\t\tObject.defineProperty(this, 'isMasterClient', {\r\n\t\t\t\tget: function () { return masterClientId === this.clientId; }.bind(this)\r\n\t\t\t});\r\n\t\t}.bind(this));\r\n\t}\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/sync-system.js\n ** module id = 8\n ** module chunks = 0\n **/","//TODO: We need to figure out a way to recieve our first update without caring about ownership.\r\n// firstValue is probably not the right way to go, probably something about having sent yet. Need to change for both\r\n\r\n/**\r\n* Synchronize the position, rotation, and scale of this object with all clients.\r\n* Requires both a {@link sync.sync-system} component on the `a-scene`, and a\r\n* {@link sync.sync} component on the target entity.\r\n* @mixin sync-transform\r\n* @memberof sync\r\n*/\r\nAFRAME.registerComponent('sync-transform',\r\n{\r\n\tdependencies: ['sync'],\r\n\tschema: {\r\n\t},\r\n\tinit: function () {\r\n\t\tvar component = this;\r\n\t\tvar sync = component.el.components.sync;\r\n\t\tif(sync.isConnected) start(); else component.el.addEventListener('connected', start);\r\n\r\n\t\tfunction start(){\r\n\r\n\t\t\tvar positionRef = sync.dataRef.child('position');\r\n\t\t\tvar rotationRef = sync.dataRef.child('rotation');\r\n\t\t\tvar scaleRef = sync.dataRef.child('scale');\r\n\r\n\t\t\tcomponent.updateRate = 100;\r\n\r\n\t\t\tvar stoppedAnimations = [];\r\n\t\t\t//pause all animations on ownership loss\r\n\t\t\tcomponent.el.addEventListener('ownershiplost', function() {\r\n\t\t\t\tvar children = component.el.children;\r\n\t\t\t\tfor (var i = 0; i < children.length; i++) {\r\n\t\t\t\t\tvar tagName = children[i].tagName.toLowerCase();\r\n\t\t\t\t\tif (tagName === \"a-animation\") {\r\n\t\t\t\t\t\tstoppedAnimations.push(children[i]);\r\n\t\t\t\t\t\tchildren[i].stop();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t\tcomponent.el.addEventListener('ownershipgained', function () {\r\n\t\t\t\tfor (var i = 0; i < stoppedAnimations.length; i++) {\r\n\t\t\t\t\tvar animation = stoppedAnimations[i];\r\n\t\t\t\t\tanimation.start();\r\n\t\t\t\t}\r\n\t\t\t\tstoppedAnimations = [];\r\n\t\t\t});\r\n\r\n\t\t\tfunction onTransform(snapshot, componentName) {\r\n\t\t\t\tif (sync.isMine) return;\r\n\r\n\t\t\t\tvar value = snapshot.val();\r\n\t\t\t\tif (!value) return;\r\n\r\n\t\t\t\tcomponent.el.setAttribute(componentName, value);\r\n\t\t\t}\r\n\r\n\t\t\tpositionRef.on('value', function (snapshot) {\r\n\t\t\t\tonTransform(snapshot, 'position');\r\n\t\t\t});\r\n\r\n\t\t\trotationRef.on('value', function (snapshot) {\r\n\t\t\t\tonTransform(snapshot, 'rotation');\r\n\t\t\t});\r\n\r\n\t\t\tscaleRef.on('value', function (snapshot) {\r\n\t\t\t\tonTransform(snapshot, 'scale');\r\n\t\t\t});\r\n\r\n\t\t\tvar sendPosition = throttle(function(value){\r\n\t\t\t\tpositionRef.set(value);\r\n\t\t\t}, component.updateRate);\r\n\r\n\t\t\tvar sendRotation = throttle(function(value){\r\n\t\t\t\trotationRef.set(value);\r\n\t\t\t}, component.updateRate);\r\n\r\n\t\t\tvar sendScale = throttle(function(value){\r\n\t\t\t\tscaleRef.set(value);\r\n\t\t\t}, component.updateRate);\r\n\r\n\t\t\tfunction onComponentChanged(event){\r\n\t\t\t\tif (!sync.isMine) return;\r\n\r\n\t\t\t\tvar name = event.detail.name;\r\n\t\t\t\tvar newData = event.detail.newData;\r\n\r\n\t\t\t\tif (name === 'position') {\r\n\t\t\t\t\tsendPosition(newData);\r\n\t\t\t\t} else if (name === 'rotation') {\r\n\t\t\t\t\tsendRotation(newData);\r\n\t\t\t\t} else if (name === 'scale') {\r\n\t\t\t\t\tsendScale(newData);\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t//from underscore.js\r\n\t\t\tfunction throttle(func, wait, options) {\r\n\t\t\t\tvar timeout, context, args, result;\r\n\t\t\t\tvar previous = 0;\r\n\t\t\t\tif (!options) options = {};\r\n\r\n\t\t\t\tvar later = function() {\r\n\t\t\t\t previous = options.leading === false ? 0 : Date.now();\r\n\t\t\t\t timeout = null;\r\n\t\t\t\t result = func.apply(context, args);\r\n\t\t\t\t if (!timeout) context = args = null;\r\n\t\t\t\t};\r\n\r\n\t\t\t\tvar throttled = function() {\r\n\t\t\t\t var now = Date.now();\r\n\t\t\t\t if (!previous && options.leading === false) previous = now;\r\n\t\t\t\t var remaining = wait - (now - previous);\r\n\t\t\t\t context = this;\r\n\t\t\t\t args = arguments;\r\n\t\t\t\t if (remaining <= 0 || remaining > wait) {\r\n\t\t\t\t\tif (timeout) {\r\n\t\t\t\t\t clearTimeout(timeout);\r\n\t\t\t\t\t timeout = null;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tprevious = now;\r\n\t\t\t\t\tresult = func.apply(context, args);\r\n\t\t\t\t\tif (!timeout) context = args = null;\r\n\t\t\t\t } else if (!timeout && options.trailing !== false) {\r\n\t\t\t\t\ttimeout = setTimeout(later, remaining);\r\n\t\t\t\t }\r\n\t\t\t\t return result;\r\n\t\t\t\t};\r\n\r\n\t\t\t\tthrottled.cancel = function() {\r\n\t\t\t\t clearTimeout(timeout);\r\n\t\t\t\t previous = 0;\r\n\t\t\t\t timeout = context = args = null;\r\n\t\t\t\t};\r\n\r\n\t\t\t\treturn throttled;\r\n\t\t\t };\r\n\r\n\r\n\t\t\tcomponent.el.addEventListener('componentchanged', onComponentChanged);\r\n\t\t}\r\n\t}\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/sync-transform.js\n ** module id = 9\n ** module chunks = 0\n **/","/**\r\n* Enables the synchronization of properties of entities. All property sync components\r\n* require both a {@link sync.sync-system} on `a-scene`, and a {@link sync.sync}\r\n* on the entity to be synced.\r\n* @name sync\r\n* @namespace sync\r\n* @example\r\n* \r\n* \r\n* \r\n*/\r\n\r\n\r\n\r\n/**\r\n* Enables the synchronization of properties of the entity. Must be used in\r\n* conjuction with the {@link sync.sync-system} component and a component for a\r\n* specific property (e.g. {@link sync.sync-transform}).\r\n* @memberof sync\r\n* @mixin sync\r\n* @prop {string} ownOn - The name of the event, or a list of events, that\r\n* will cause the local client to take ownership of this object. This field\r\n* cannot be updated after initialization.\r\n*/\r\nAFRAME.registerComponent('sync',\r\n{\r\n\tschema: {\r\n\t\tmode: { default: 'link' },\r\n\t\townOn: { type: 'string' } //cannot be changed after creation\r\n\t},\r\n\tinit: function () {\r\n\t\tvar scene = document.querySelector('a-scene');\r\n\t\tvar syncSys = scene.systems['sync-system'];\r\n\r\n\t\tvar ref;\r\n\t\tvar key;\r\n\t\tvar dataRef;\r\n\t\tvar ownerRef;\r\n\t\tvar ownerId;\r\n\t\tvar isMine = false;\r\n\r\n\t\tvar component = this;\r\n\r\n\t\tcomponent.isConnected = false;\r\n\r\n\t\tif(syncSys.isConnected) start(); else scene.addEventListener('connected', start);\r\n\r\n\r\n\t\tif(component.data.ownOn)\r\n\t\t{\r\n\t\t\tvar ownershipEvents = component.data.ownOn.split(/[ ,]+/);\r\n\t\t\tfor(var i = 0, max = ownershipEvents.length; i < max; i++){\r\n\t\t\t\tcomponent.el.addEventListener(ownershipEvents[i], function(){\r\n\t\t\t\t\tif(component.isConnected){\r\n\t\t\t\t\t\tcomponent.takeOwnership();\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfunction start(){\r\n\t\t\t//Make sure someone always owns an object. If the owner leaves and we are the master client, we will take it.\r\n\t\t\t//This ensures, for example, that synced animations keep playing\r\n\t\t\tscene.addEventListener('clientleft', function(event){\r\n\t\t\t\tvar shouldTakeOwnership = (!ownerId || ownerId === event.detail.id) && syncSys.isMasterClient;\r\n\r\n\t\t\t\tif(shouldTakeOwnership) component.takeOwnership();\r\n\t\t\t});\r\n\r\n\t\t\tif (component.data.mode === 'link') {\r\n\t\t\t\tvar id = component.el.id;\r\n\t\t\t\tif (!id) {\r\n\t\t\t\t\tconsole.error('Entities cannot be synced using link mode without an id.');\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconsole.log('syncSys: ' + syncSys);\r\n\t\t\t\tconsole.log('syncSys.sceneRef: ' + syncSys.sceneRef);\r\n\r\n\t\t\t\tlink(syncSys.sceneRef.child(id));\r\n\t\t\t\tsetupReceive();\r\n\r\n\t\t\t} else {\r\n\t\t\t\tconsole.error('Unsupported sync mode: ' + component.data.mode);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tcomponent.isConnected = true;\r\n\t\t\tcomponent.el.emit('connected', null, false);\r\n\t\t}\r\n\r\n\t\tfunction link(entityRef) {\r\n\t\t\tref = entityRef;\r\n\t\t\tkey = ref.key();\r\n\t\t\tdataRef = ref.child('data');\r\n\t\t\tcomponent.dataRef = dataRef;\r\n\t\t\townerRef = ref.child('owner');\r\n\t\t}\r\n\r\n\t\tfunction setupReceive() {\r\n\r\n\t\t\t//if nobody has owned the object yet, we will.\r\n\t\t\townerRef.transaction(function (owner) {\r\n\t\t\t\tif (owner) return undefined;\r\n\r\n\t\t\t\townerRef.onDisconnect().set(null);\r\n\t\t\t\treturn syncSys.clientId;\r\n\t\t\t});\r\n\r\n\t\t\townerRef.on('value',\r\n\t\t\t\tfunction(snapshot) {\r\n\t\t\t\t\tvar newOwnerId = snapshot.val();\r\n\r\n\t\t\t\t\tvar gained = newOwnerId === syncSys.clientId && !isMine;\r\n\t\t\t\t\tif (gained) component.el.emit('ownershipgained', null, false);\r\n\r\n\r\n\t\t\t\t\t//note this also fires when we start up without ownership\r\n\t\t\t\t\tvar lost = newOwnerId !== syncSys.clientId && isMine;\r\n\t\t\t\t\tif (lost){\r\n\t\t\t\t\t\tcomponent.el.emit('ownershiplost', null, false);\r\n\r\n\t\t\t\t\t\t//we no longer have to clear our ownership when we disconnect\r\n\t\t\t\t\t\townerRef.onDisconnect().cancel();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\townerId = newOwnerId;\r\n\r\n\t\t\t\t\tisMine = newOwnerId === syncSys.clientId;\r\n\t\t\t\t});\r\n\t\t}\r\n\r\n\t\t/**\r\n\t\t* Tell sync to start pushing local property values instead of updating\r\n\t\t* local from remote values.\r\n\t\t* @method sync.sync#takeOwnership\r\n\t\t*/\r\n\t\tcomponent.takeOwnership = function() {\r\n\t\t\townerRef.set(syncSys.clientId);\r\n\r\n\t\t\t//clear our ownership if we disconnect\r\n\t\t\t//this is needed if we are the last user in the room, but we expect people to join later\r\n\t\t\townerRef.onDisconnect().set(null);\r\n\t\t}\r\n\r\n\t\t/**\r\n\t\t* Indicates whether the sync ownership is yours.\r\n\t\t* @member sync.sync#isMine\r\n\t\t* @readonly\r\n\t\t*/\r\n\t\tObject.defineProperty(component, 'isMine', {\r\n\t\t\tget: function () {\r\n\t\t\t\treturn isMine;//TODO: Should this be state instead?\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/sync.js\n ** module id = 10\n ** module chunks = 0\n **/","/**\r\n * The wire component allows you to trigger an event on another entity when an event occurs on an entity\r\n * @mixin wire\r\n * @property {string} on Name of an event to listen to\r\n * @property {string} gained Name of a state to watch for\r\n * @property {string} lost Name of a state to watch for\r\n * @property {string} emit Name of an event to trigger on the targets\r\n * @property {string} gain Name of a state to add on the target\r\n * @property {string} lose Name of a state to remove on the target\r\n * @property {selector} targets A selector to pick which objects to wire to\r\n * @property {selector} target - A selector to pick a single object to wire to\r\n **/\r\nAFRAME.registerComponent('wire',\r\n{\r\n\tmultiple: true,\r\n\tschema: {\r\n\t\ton: {type: 'string'},\r\n\t\temit: {type: 'string'},\r\n\t\tgained: {type: 'string'},\r\n\t\tlost: {type: 'string'},\r\n\t\tgain: {type: 'string'},\r\n\t\tlose: {type: 'string'},\r\n\t\ttargets: {type: 'selectorAll'},\r\n\t\ttarget: {type: 'selector'}\r\n\t},\r\n\tupdate: function (oldData) {\r\n\t\tif (oldData.on) {\r\n\t\t\tthis.el.removeEventListener(oldData.on, this.actOnTargets);\r\n\t\t}\r\n\t\tif (oldData.gained) {\r\n\t\t\tthis.el.removeEventListener('stateadded', this.actOnTargetsIfStateMatches);\r\n\t\t}\r\n\t\tif (oldData.lost) {\r\n\t\t\tthis.el.removeEventListener('stateremoved', this.actOnTargetsIfStateMatches);\r\n\t\t}\r\n\r\n\t\tthis.actOnTargets = function () {\r\n\t\t\tfunction act(el) {\r\n\t\t\t\tif (this.data.emit) {\r\n\t\t\t\t\tel.emit(this.data.emit);\r\n\t\t\t\t}\r\n\t\t\t\tif (this.data.gain) {\r\n\t\t\t\t\tel.addState(this.data.gain);\r\n\t\t\t\t}\r\n\t\t\t\tif (this.data.lose) {\r\n\t\t\t\t\tel.removeState(this.data.lose);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif(this.data.targets) this.data.targets.forEach(act.bind(this));\r\n\t\t\tif(this.data.target) act.call(this, this.data.target);\r\n\t\t}.bind(this);\r\n\r\n\t\tthis.actOnTargetsIfStateMatches = function (event) {\r\n\t\t\tvar state = event.detail.state;\r\n\t\t\tif (state === this.data.gained || state === this.data.lost) {\r\n\t\t\t\tthis.actOnTargets();\r\n\t\t\t}\r\n\t\t}.bind(this);\r\n\r\n\t\tif (this.data.on) {\r\n\t\t\tthis.el.addEventListener(this.data.on, this.actOnTargets);\r\n\t\t}\r\n\t\tif (this.data.gained) {\r\n\t\t\tthis.el.addEventListener('stateadded', this.actOnTargetsIfStateMatches);\r\n\t\t}\r\n\t\tif (this.data.lost) {\r\n\t\t\tthis.el.addEventListener('stateremoved', this.actOnTargetsIfStateMatches);\r\n\t\t}\r\n\t},\r\n\tremove: function () {\r\n\t\tthis.el.removeEventListener(this.data.on, this.actOnTargets);\r\n\t\tthis.el.removeEventListener('stateadded', this.actOnTargetsIfStateMatches);\r\n\t\tthis.el.removeEventListener('stateremoved', this.actOnTargetsIfStateMatches);\r\n\t}\r\n});\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/wire.js\n ** module id = 11\n ** module chunks = 0\n **/"],"sourceRoot":""} \ No newline at end of file diff --git a/doc/altspace.altspace.html b/doc/altspace.altspace.html index cd1ecc1..86a4588 100644 --- a/doc/altspace.altspace.html +++ b/doc/altspace.altspace.html @@ -1,302 +1,293 @@ - - - - - altspace - Documentation - - - - - - - - - - - - - - - - - -
- -

altspace

- - - - - - - -
- -
- -

- altspace. - - altspace -

- - -
- -
-
- - + + + + + altspace - Documentation + + + + + + + + + + + + + + + + + +
+ +

altspace

+ + + + + + + +
+ +
+ +

+ altspace. + + altspace +

+ + +
+ +
+
+ +

The altspace component makes A-Frame apps compatible with AltspaceVR.

-

Note: If you use the embedded A-Frame component on your scene, you must include it before the altspace component, or your app will silently fail.

- - - - - -
Properties:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +

Note: If you use the embedded A-Frame component on your scene, you must include it before the altspace component, or your app will silently fail.

+ + + + + +
Properties:
+ + + +
NameTypeDefaultDescription
usePixelScale - - -boolean - - - - - - `false` - -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - +This is the default behavior for three.js apps, but not for A-Frame apps.

+ + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - +or top of the Altspace enclosure.

+ + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
usePixelScale + + +boolean + + + + + + `false` + +

Allows you to use A-Frame units as CSS pixels. -This is the default behavior for three.js apps, but not for A-Frame apps.

verticalAlign - - -string - - - - - - `middle` - -
verticalAlign + + +string + + + + + + `middle` + +

Puts the origin at the bottom, middle (default), -or top of the Altspace enclosure.

enclosuresOnly - - -boolean - - - - - - `true` - -
enclosuresOnly + + +boolean + + + + + + `true` + +

Prevents the scene from being created if -enclosure is flat.

fullspace - - -boolean - - - - - - `false` - -

Puts the app into fullspace mode.

- - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -

Example

- -
<head>
-  <title>My A-Frame Scene</title>
-  <script src="https://aframe.io/releases/0.3.0/aframe.min.js"></script>
-  <script src="https://cdn.rawgit.com/AltspaceVR/aframe-altspace-component/vAFRAME_ALTSPACE_VERSION/dist/aframe-altspace-component.min.js"></script>
-</head>
-<body>
-  <a-scene altspace>
-    <a-entity geometry="primitive: box" material="color: #C03546"></a-entity>
-  </a-scene>
-</body>
- - - -
- - - - - - - - - - - - - - - - - - -
- -
- - - - -
- -
- -
- Documentation generated by JSDoc 3.4.3 using the Minami theme. -
- - - - +enclosure is flat.

+ + + + + + + fullspace + + + + + +boolean + + + + + + + + + + + `false` + + + + +

Puts the app into fullspace mode.

+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +

Example

+ +
<head>
  <title>My A-Frame Scene</title>
  <script src="https://aframe.io/releases/0.3.0/aframe.min.js"></script>
  <script src="https://cdn.rawgit.com/AltspaceVR/aframe-altspace-component/vAFRAME_ALTSPACE_VERSION/dist/aframe-altspace-component.min.js"></script>
</head>
<body>
  <a-scene altspace>
    <a-entity geometry="primitive: box" material="color: #C03546"></a-entity>
  </a-scene>
</body>
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ +
+ Documentation generated by JSDoc 3.4.3 using the Minami theme. +
+ + + + \ No newline at end of file diff --git a/doc/index.html b/doc/index.html index 3dada89..85ffd17 100644 --- a/doc/index.html +++ b/doc/index.html @@ -63,7 +63,7 @@

Quick Start

This is a fully functional example of what A-Frame code l

<!DOCTYPE html>
 <html><head>
 <script src="https://aframe.io/releases/0.3.0/aframe.min.js"></script>
-<script src="https://cdn.rawgit.com/AltspaceVR/aframe-altspace-component/v1.3.1/dist/aframe-altspace-component.min.js"></script>
+<script src="https://cdn.rawgit.com/AltspaceVR/aframe-altspace-component/v1.3.2/dist/aframe-altspace-component.min.js"></script>
 <script>
 
 // an example custom component, that will change the color when clicked
diff --git a/doc/sync.html b/doc/sync.html
index 17ccd13..32ad3b0 100644
--- a/doc/sync.html
+++ b/doc/sync.html
@@ -1,163 +1,161 @@
-
-
-
-    
-    sync - Documentation
-
-    
-    
-    
-    
-    
-    
-
-
-
-
-
-
-
-
-
-
-
- -

sync

- - - - - - - -
- -
- -

- sync -

- - -
- -
-
- - + + + + + sync - Documentation + + + + + + + + + + + + + + + + + +
+ +

sync

+ + + + + + + +
+ +
+ +

+ sync +

+ + +
+ +
+
+ +

Enables the synchronization of properties of entities. All property sync components require both a sync.sync-system on a-scene, and a sync.sync -on the entity to be synced.

- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -

Example

- -
<a-scene sync-system='app: example sync; author: altspacevr'>
-  <a-entity sync='ownOn: cursordown' sync-color></a-entity>
-</a-scene>
- - - -
- - - - - - - - -

Mixins

- -
-
sync
-
- -
sync-color
-
- -
sync-n-sound
-
- -
sync-system
-
- -
sync-transform
-
-
- - - - - - - - - - - -
- -
- - - - -
- -
- -
- Documentation generated by JSDoc 3.4.3 using the Minami theme. -
- - - - +on the entity to be synced.

+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +

Example

+ +
<a-scene sync-system='app: example sync; author: altspacevr'>
  <a-entity sync='ownOn: cursordown' sync-color></a-entity>
</a-scene>
+ + + +
+ + + + + + + + +

Mixins

+ +
+
sync
+
+ +
sync-color
+
+ +
sync-n-sound
+
+ +
sync-system
+
+ +
sync-transform
+
+
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ Documentation generated by JSDoc 3.4.3 using the Minami theme. +
+ + + + \ No newline at end of file diff --git a/examples/wire/index.html b/examples/wire/index.html index 8b77fd4..9dc7a88 100644 --- a/examples/wire/index.html +++ b/examples/wire/index.html @@ -10,8 +10,8 @@ + wire__high="on: mouseup; gain: mouse-off; target: #error" + wire__spin="gained: hovered; emit: spin; target: #pop"> - diff --git a/gulpfile.js b/gulpfile.js index a842857..89beade 100755 --- a/gulpfile.js +++ b/gulpfile.js @@ -12,7 +12,8 @@ function versionAndPack(filename, webpackPlugins) { output: { filename: filename }, - plugins: webpackPlugins + plugins: webpackPlugins, + devtool: 'source-map' })) .pipe(replace('AFRAME_ALTSPACE_VERSION', version)) .pipe(gulp.dest('./dist/')); diff --git a/package.json b/package.json index b266918..a429b43 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aframe-altspace-component", - "version": "1.3.1", + "version": "1.3.2", "description": "aframe-altspace-component makes A-frame apps compatible with AltspaceVR.", "main": "src/index.js", "scripts": { diff --git a/src/wire.js b/src/wire.js index 0ce6ea5..4860201 100644 --- a/src/wire.js +++ b/src/wire.js @@ -46,7 +46,7 @@ AFRAME.registerComponent('wire', el.removeState(this.data.lose); } } - this.data.targets.forEach(act.bind(this)); + if(this.data.targets) this.data.targets.forEach(act.bind(this)); if(this.data.target) act.call(this, this.data.target); }.bind(this);