diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..6ab075b --- /dev/null +++ b/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "env" + ] +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 087ea75..53edff5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,5 @@ gh-pages node_modules/ npm-debug.log examples/build.js - +lib examples/build.js diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..444eb13 --- /dev/null +++ b/.npmignore @@ -0,0 +1,7 @@ +tests +examples +src +*.png +*.jpg +*.webm +*.mp4 \ No newline at end of file diff --git a/cubes_stereo.png b/cubes_stereo.png index 2603108..43cbc79 100644 Binary files a/cubes_stereo.png and b/cubes_stereo.png differ diff --git a/dist/aframe-stereo-component.js b/dist/aframe-stereo-component.js index fff8f8c..82100fd 100644 --- a/dist/aframe-stereo-component.js +++ b/dist/aframe-stereo-component.js @@ -1,297 +1,98 @@ /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; - +/******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { - +/******/ /******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) +/******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; - +/******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} /******/ }; - +/******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - +/******/ /******/ // Flag the module as loaded -/******/ module.loaded = true; - +/******/ module.l = true; +/******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } - - +/******/ +/******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; - +/******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; - +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; - +/******/ +/******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(0); +/******/ return __webpack_require__(__webpack_require__.s = "./browser.js"); /******/ }) /************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - - // Browser distrubution of the A-Frame component. - (function () { - if (!AFRAME) { - console.error('Component attempted to register before AFRAME was available.'); - return; - } - - // Register all components here. - var components = { - stereo: __webpack_require__(1).stereo_component, - stereocam: __webpack_require__(1).stereocam_component - }; - - Object.keys(components).forEach(function (name) { - if (AFRAME.aframeCore) { - AFRAME.aframeCore.registerComponent(name, components[name]); - } else { - AFRAME.registerComponent(name, components[name]); - } - }); - })(); +/******/ ({ +/***/ "./browser.js": +/*!********************!*\ + !*** ./browser.js ***! + \********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; +eval("\n\n// Browser distrubution of the A-Frame component.\n(function () {\n if (!AFRAME) {\n console.error('Component attempted to register before AFRAME was available.');\n return;\n }\n\n // Register all components here.\n var components = {\n stereo: __webpack_require__(/*! ./index */ \"./index.js\").stereo_component,\n stereocam: __webpack_require__(/*! ./index */ \"./index.js\").stereocam_component\n };\n\n Object.keys(components).forEach(function (name) {\n if (AFRAME.aframeCore) {\n AFRAME.aframeCore.registerComponent(name, components[name]);\n } else {\n AFRAME.registerComponent(name, components[name]);\n }\n });\n})();\n\n//# sourceURL=webpack:///./browser.js?"); /***/ }), -/* 1 */ -/***/ (function(module, exports) { - - module.exports = { - - // Put an object into left, right or both eyes. - // If it's a video sphere, take care of correct stereo mapping for both eyes (if full dome) - // or half the sphere (if half dome) - - 'stereo_component' : { - schema: { - eye: { type: 'string', default: "left"}, - mode: { type: 'string', default: "full"}, - split: { type: 'string', default: "horizontal"}, - playOnClick: { type: 'boolean', default: true }, - }, - init: function(){ - - // Flag to acknowledge if 'click' on video has been attached to canvas - // Keep in mind that canvas is the last thing initialized on a scene so have to wait for the event - // or just check in every tick if is not undefined - - this.video_click_event_added = false; - - this.material_is_a_video = false; - - // Check if material is a video from html tag (object3D.material.map instanceof THREE.VideoTexture does not - // always work - - if(this.el.getAttribute("material")!==null && 'src' in this.el.getAttribute("material") && this.el.getAttribute("material").src !== "") { - var src = this.el.getAttribute("material").src; - - // If src is an object and its tagName is video... - - if (typeof src === 'object' && ('tagName' in src && src.tagName === "VIDEO")) { - this.material_is_a_video = true; - } - } - - var object3D = this.el.object3D.children[0]; - - // In A-Frame 0.2.0, objects are all groups so sphere is the first children - // Check if it's a sphere w/ video material, and if so - // Note that in A-Frame 0.2.0, sphere entities are THREE.SphereBufferGeometry, while in A-Frame 0.3.0, - // sphere entities are THREE.BufferGeometry. - - var validGeometries = [THREE.SphereGeometry, THREE.SphereBufferGeometry, THREE.BufferGeometry]; - var isValidGeometry = validGeometries.some(function(geometry) { - return object3D.geometry instanceof geometry; - }); - - if (isValidGeometry && this.material_is_a_video) { - - // if half-dome mode, rebuild geometry (with default 100, radius, 64 width segments and 64 height segments) - - if (this.data.mode === "half") { - - var geo_def = this.el.getAttribute("geometry"); - var geometry = new THREE.SphereGeometry(geo_def.radius || 100, geo_def.segmentsWidth || 64, geo_def.segmentsHeight || 64, Math.PI / 2, Math.PI, 0, Math.PI); - - } - else { - var geo_def = this.el.getAttribute("geometry"); - var geometry = new THREE.SphereGeometry(geo_def.radius || 100, geo_def.segmentsWidth || 64, geo_def.segmentsHeight || 64); - } - - // Panorama in front - - object3D.rotation.y = Math.PI / 2; - - // If left eye is set, and the split is horizontal, take the left half of the video texture. If the split - // is set to vertical, take the top/upper half of the video texture. - - if (this.data.eye === "left") { - var uvs = geometry.faceVertexUvs[ 0 ]; - var axis = this.data.split === "vertical" ? "y" : "x"; - for (var i = 0; i < uvs.length; i++) { - for (var j = 0; j < 3; j++) { - if (axis == "x") { - uvs[ i ][ j ][ axis ] *= 0.5; - } - else { - uvs[ i ][ j ][ axis ] *= 0.5; - uvs[ i ][ j ][ axis ] += 0.5; - } - } - } - } - - // If right eye is set, and the split is horizontal, take the right half of the video texture. If the split - // is set to vertical, take the bottom/lower half of the video texture. - - if (this.data.eye === "right") { - var uvs = geometry.faceVertexUvs[ 0 ]; - var axis = this.data.split === "vertical" ? "y" : "x"; - for (var i = 0; i < uvs.length; i++) { - for (var j = 0; j < 3; j++) { - if (axis == "x") { - uvs[ i ][ j ][ axis ] *= 0.5; - uvs[ i ][ j ][ axis ] += 0.5; - } - else { - uvs[ i ][ j ][ axis ] *= 0.5; - } - } - } - } - - // As AFrame 0.2.0 builds bufferspheres from sphere entities, transform - // into buffergeometry for coherence - object3D.geometry = new THREE.BufferGeometry().fromGeometry(geometry); - - } - else{ - - // No need to attach video click if not a sphere and not a video, set this to true - - this.video_click_event_added = true; - - } - - - }, - - // On element update, put in the right layer, 0:both, 1:left, 2:right (spheres or not) - - update: function(oldData){ - - var object3D = this.el.object3D.children[0]; - var data = this.data; - - if(data.eye === "both"){ - object3D.layers.set(0); - } - else{ - object3D.layers.set(data.eye === 'left' ? 1:2); - } - - }, - - tick: function(time){ - - // If this value is false, it means that (a) this is a video on a sphere [see init method] - // and (b) of course, tick is not added - - if(!this.video_click_event_added && this.data.playOnClick){ - if(typeof(this.el.sceneEl.canvas) !== 'undefined'){ - - // Get video DOM - - this.videoEl = this.el.object3D.children[0].material.map.image; - - // On canvas click, play video element. Use self to not lose track of object into event handler - - var self = this; - - this.el.sceneEl.canvas.onclick = function () { - self.videoEl.play(); - }; - - // Signal that click event is added - this.video_click_event_added = true; - - } - } - - } - }, - - // Sets the 'default' eye viewed by camera in non-VR mode - - 'stereocam_component':{ - - schema: { - eye: { type: 'string', default: "left"} - }, - - // Cam is not attached on init, so use a flag to do this once at 'tick' - - // Use update every tick if flagged as 'not changed yet' - - init: function(){ - // Flag to register if cam layer has already changed - this.layer_changed = false; - }, - - tick: function(time){ - - var originalData = this.data; - - // If layer never changed - - if(!this.layer_changed){ - - // because stereocam component should be attached to an a-camera element - // need to get down to the root PerspectiveCamera before addressing layers - - // Gather the children of this a-camera and identify types - - var childrenTypes = []; - - this.el.object3D.children.forEach( function (item, index, array) { - childrenTypes[index] = item.type; - }); - - // Retrieve the PerspectiveCamera - var rootIndex = childrenTypes.indexOf("PerspectiveCamera"); - var rootCam = this.el.object3D.children[rootIndex]; - - if(originalData.eye === "both"){ - rootCam.layers.enable( 1 ); - rootCam.layers.enable( 2 ); - } - else{ - rootCam.layers.enable(originalData.eye === 'left' ? 1:2); - } - } - } - - } - }; +/***/ "./index.js": +/*!******************!*\ + !*** ./index.js ***! + \******************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; +eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\nexports.default = {\n\n // Put an object into left, right or both eyes.\n // If it's a video sphere, take care of correct stereo mapping for both eyes (if full dome)\n // or half the sphere (if half dome)\n\n 'stereo_component': {\n schema: {\n eye: { type: 'string', default: \"left\" },\n mode: { type: 'string', default: \"full\" },\n split: { type: 'string', default: \"\" },\n playOnClick: { type: 'boolean', default: true }\n },\n init: function init() {\n // Flag to acknowledge if 'click' on video has been attached to canvas\n // Keep in mind that canvas is the last thing initialized on a scene so have to wait for the event\n // or just check in every tick if is not undefined\n\n this.video_click_event_added = false;\n\n this.material_is_a_video = false;\n this.material_is_a_image = false;\n\n var object3D = this.el.object3D.children[0];\n\n transformGeometry(object3D, this.el, this.data);\n\n if (!this.material_is_a_video) {\n // No need to attach video click if not a sphere and not a video, set this to true\n this.video_click_event_added = true;\n }\n },\n\n // On element update, put in the right layer, 0:both, 1:left, 2:right (spheres or not)\n\n update: function update(oldData) {\n\n var object3D = this.el.object3D.children[0];\n var data = this.data;\n\n if (data.eye === \"both\") {\n object3D.layers.set(0);\n } else {\n object3D.layers.set(data.eye === 'left' ? 1 : 2);\n }\n\n if (data.split !== oldData.split) transformGeometry(object3D, this.el, this.data);\n },\n\n tick: function tick(time) {\n\n // If this value is false, it means that (a) this is a video on a sphere [see init method]\n // and (b) of course, tick is not added\n\n if (!this.video_click_event_added && this.data.playOnClick) {\n if (typeof this.el.sceneEl.canvas !== 'undefined') {\n\n // Get video DOM\n\n this.videoEl = this.el.object3D.children[0].material.map.image;\n\n // On canvas click, play video element. Use self to not lose track of object into event handler\n\n var self = this;\n\n this.el.sceneEl.canvas.onclick = function () {\n self.videoEl.play();\n };\n\n // Signal that click event is added\n this.video_click_event_added = true;\n }\n }\n }\n },\n\n // Sets the 'default' eye viewed by camera in non-VR mode\n\n 'stereocam_component': {\n\n schema: {\n eye: { type: 'string', default: \"left\" }\n },\n\n // Cam is not attached on init, so use a flag to do this once at 'tick'\n\n // Use update every tick if flagged as 'not changed yet'\n\n init: function init() {\n // Flag to register if cam layer has already changed\n this.layer_changed = false;\n },\n\n tick: function tick(time) {\n\n var originalData = this.data;\n\n // If layer never changed\n\n if (!this.layer_changed) {\n\n // because stereocam component should be attached to an a-camera element\n // need to get down to the root PerspectiveCamera before addressing layers\n\n // Gather the children of this a-camera and identify types\n\n var childrenTypes = [];\n\n this.el.object3D.children.forEach(function (item, index, array) {\n childrenTypes[index] = item.type;\n });\n\n // Retrieve the PerspectiveCamera\n var rootIndex = childrenTypes.indexOf(\"PerspectiveCamera\");\n var rootCam = this.el.object3D.children[rootIndex];\n\n if (originalData.eye === \"both\") {\n rootCam.layers.enable(1);\n rootCam.layers.enable(2);\n } else {\n rootCam.layers.enable(originalData.eye === 'left' ? 1 : 2);\n }\n }\n }\n\n }\n};\n\n\nvar transformGeometry = function transformGeometry(object3D, element, data) {\n\n var material_is_a_video = false;\n var material_is_a_image = false;\n\n if (element.getAttribute(\"material\") !== null && 'src' in element.getAttribute(\"material\") && element.getAttribute(\"material\").src !== \"\") {\n var src = element.getAttribute(\"material\").src;\n\n // If src is an object and its tagName is video...\n if ((typeof src === 'undefined' ? 'undefined' : _typeof(src)) === 'object' && 'tagName' in src && src.tagName === \"VIDEO\") {\n material_is_a_video = true;\n } else if ((typeof src === 'undefined' ? 'undefined' : _typeof(src)) === 'object' && 'tagName' in src && src.tagName === \"IMG\") {\n material_is_a_image = true;\n }\n }\n\n // In A-Frame 0.2.0, objects are all groups so sphere is the first children\n // Check if it's a sphere w/ video material, and if so\n // Note that in A-Frame 0.2.0, sphere entities are THREE.SphereBufferGeometry, while in A-Frame 0.3.0,\n // sphere entities are THREE.BufferGeometry.\n\n var validGeometries = [THREE.SphereGeometry, THREE.SphereBufferGeometry, THREE.BufferGeometry];\n var isValidGeometry = validGeometries.some(function (geometry) {\n return object3D.geometry instanceof geometry;\n });\n\n if (isValidGeometry && (material_is_a_video || material_is_a_image && !!data.split)) {\n\n // if half-dome mode, rebuild geometry (with default 100, radius, 64 width segments and 64 height segments)\n\n var geo_def = element.getAttribute(\"geometry\");\n var geometry = null;\n\n if (data.mode === \"half\") {\n geometry = new THREE.SphereGeometry(geo_def.radius || 100, geo_def.segmentsWidth || 64, geo_def.segmentsHeight || 64, Math.PI / 2, Math.PI, 0, Math.PI);\n } else {\n geometry = new THREE.SphereGeometry(geo_def.radius || 100, geo_def.segmentsWidth || 64, geo_def.segmentsHeight || 64);\n }\n\n // Panorama in front\n object3D.rotation.y = Math.PI / 2;\n\n // If left eye is set, and the split is horizontal, take the left half of the video texture. If the split\n // is set to vertical, take the top/upper half of the video texture.\n\n if (data.eye === \"left\") {\n var uvs = geometry.faceVertexUvs[0];\n var axis = data.split === \"vertical\" ? \"y\" : \"x\";\n for (var i = 0; i < uvs.length; i++) {\n for (var j = 0; j < 3; j++) {\n if (axis == \"x\") {\n uvs[i][j][axis] *= 0.5;\n } else {\n uvs[i][j][axis] *= 0.5;\n uvs[i][j][axis] += 0.5;\n }\n }\n }\n }\n\n // If right eye is set, and the split is horizontal, take the right half of the video texture. If the split\n // is set to vertical, take the bottom/lower half of the video texture.\n\n if (data.eye === \"right\") {\n var uvs = geometry.faceVertexUvs[0];\n var axis = data.split === \"vertical\" ? \"y\" : \"x\";\n for (var i = 0; i < uvs.length; i++) {\n for (var j = 0; j < 3; j++) {\n if (axis == \"x\") {\n uvs[i][j][axis] *= 0.5;\n uvs[i][j][axis] += 0.5;\n } else {\n uvs[i][j][axis] *= 0.5;\n }\n }\n }\n }\n\n // As AFrame 0.2.0 builds bufferspheres from sphere entities, transform\n // into buffergeometry for coherence\n\n object3D.geometry = new THREE.BufferGeometry().fromGeometry(geometry);\n }\n};\n\n//# sourceURL=webpack:///./index.js?"); /***/ }) -/******/ ]); \ No newline at end of file + +/******/ }); \ No newline at end of file diff --git a/dist/aframe-stereo-component.min.js b/dist/aframe-stereo-component.min.js index 55e944e..e32f449 100644 --- a/dist/aframe-stereo-component.min.js +++ b/dist/aframe-stereo-component.min.js @@ -1 +1 @@ -!function(e){function t(a){if(i[a])return i[a].exports;var r=i[a]={exports:{},id:a,loaded:!1};return e[a].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t,i){!function(){if(!AFRAME)return void console.error("Component attempted to register before AFRAME was available.");var e={stereo:i(1).stereo_component,stereocam:i(1).stereocam_component};Object.keys(e).forEach(function(t){AFRAME.aframeCore?AFRAME.aframeCore.registerComponent(t,e[t]):AFRAME.registerComponent(t,e[t])})}()},function(e,t){e.exports={stereo_component:{schema:{eye:{type:"string",default:"left"},mode:{type:"string",default:"full"},split:{type:"string",default:"horizontal"},playOnClick:{type:"boolean",default:!0}},init:function(){if(this.video_click_event_added=!1,this.material_is_a_video=!1,null!==this.el.getAttribute("material")&&"src"in this.el.getAttribute("material")&&""!==this.el.getAttribute("material").src){var e=this.el.getAttribute("material").src;"object"==typeof e&&"tagName"in e&&"VIDEO"===e.tagName&&(this.material_is_a_video=!0)}var t=this.el.object3D.children[0],i=[THREE.SphereGeometry,THREE.SphereBufferGeometry,THREE.BufferGeometry],a=i.some(function(e){return t.geometry instanceof e});if(a&&this.material_is_a_video){if("half"===this.data.mode)var r=this.el.getAttribute("geometry"),o=new THREE.SphereGeometry(r.radius||100,r.segmentsWidth||64,r.segmentsHeight||64,Math.PI/2,Math.PI,0,Math.PI);else var r=this.el.getAttribute("geometry"),o=new THREE.SphereGeometry(r.radius||100,r.segmentsWidth||64,r.segmentsHeight||64);if(t.rotation.y=Math.PI/2,"left"===this.data.eye)for(var n=o.faceVertexUvs[0],s="vertical"===this.data.split?"y":"x",l=0;l { + + let material_is_a_video = false; + let material_is_a_image = false; + + if(element.getAttribute("material")!==null && 'src' in element.getAttribute("material") && element.getAttribute("material").src !== "") { + const src = element.getAttribute("material").src; + + // If src is an object and its tagName is video... + if (typeof src === 'object' && ('tagName' in src && src.tagName === "VIDEO")) { + material_is_a_video = true; + } else if (typeof src === 'object' && ('tagName' in src && src.tagName === "IMG")) { + material_is_a_image = true; + } + } + + // In A-Frame 0.2.0, objects are all groups so sphere is the first children + // Check if it's a sphere w/ video material, and if so + // Note that in A-Frame 0.2.0, sphere entities are THREE.SphereBufferGeometry, while in A-Frame 0.3.0, + // sphere entities are THREE.BufferGeometry. + + const validGeometries = [THREE.SphereGeometry, THREE.SphereBufferGeometry, THREE.BufferGeometry]; + const isValidGeometry = validGeometries.some(function(geometry) { + return object3D.geometry instanceof geometry; + }); + + + if (isValidGeometry && (material_is_a_video || material_is_a_image && !!data.split)) { + + // if half-dome mode, rebuild geometry (with default 100, radius, 64 width segments and 64 height segments) + + const geo_def = element.getAttribute("geometry"); + let geometry = null; + + if (data.mode === "half") { + geometry = new THREE.SphereGeometry(geo_def.radius || 100, geo_def.segmentsWidth || 64, geo_def.segmentsHeight || 64, Math.PI / 2, Math.PI, 0, Math.PI); + } + else { + geometry = new THREE.SphereGeometry(geo_def.radius || 100, geo_def.segmentsWidth || 64, geo_def.segmentsHeight || 64); + } + + // Panorama in front + object3D.rotation.y = Math.PI / 2; + + // If left eye is set, and the split is horizontal, take the left half of the video texture. If the split + // is set to vertical, take the top/upper half of the video texture. + + if (data.eye === "left") { + var uvs = geometry.faceVertexUvs[ 0 ]; + var axis = data.split === "vertical" ? "y" : "x"; + for (var i = 0; i < uvs.length; i++) { + for (var j = 0; j < 3; j++) { + if (axis == "x") { + uvs[ i ][ j ][ axis ] *= 0.5; + } + else { + uvs[ i ][ j ][ axis ] *= 0.5; + uvs[ i ][ j ][ axis ] += 0.5; + } + } + } + } + + // If right eye is set, and the split is horizontal, take the right half of the video texture. If the split + // is set to vertical, take the bottom/lower half of the video texture. + + if (data.eye === "right") { + var uvs = geometry.faceVertexUvs[ 0 ]; + var axis = data.split === "vertical" ? "y" : "x"; + for (var i = 0; i < uvs.length; i++) { + for (var j = 0; j < 3; j++) { + if (axis == "x") { + uvs[ i ][ j ][ axis ] *= 0.5; + uvs[ i ][ j ][ axis ] += 0.5; + } + else { + uvs[ i ][ j ][ axis ] *= 0.5; + } + } + } + } + + // As AFrame 0.2.0 builds bufferspheres from sphere entities, transform + // into buffergeometry for coherence + + object3D.geometry = new THREE.BufferGeometry().fromGeometry(geometry); + } +} +},{}],3:[function(require,module,exports){ +(function (global){ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.AFRAME = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } + _repeatDelayTime = amount; + return this; - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0 -} + }; -function byteLength (b64) { - // base64 is 4/3 + up to two characters of the original data - return b64.length * 3 / 4 - placeHoldersCount(b64) -} + this.yoyo = function (yoyo) { -function toByteArray (b64) { - var i, j, l, tmp, placeHolders, arr - var len = b64.length - placeHolders = placeHoldersCount(b64) + _yoyo = yoyo; + return this; - arr = new Arr(len * 3 / 4 - placeHolders) + }; - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? len - 4 : len - var L = 0 + this.easing = function (easing) { - for (i = 0, j = 0; i < l; i += 4, j += 3) { - tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] - arr[L++] = (tmp >> 16) & 0xFF - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF - } + _easingFunction = easing; + return this; - if (placeHolders === 2) { - tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) - arr[L++] = tmp & 0xFF - } else if (placeHolders === 1) { - tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF - } + }; - return arr -} + this.interpolation = function (interpolation) { -function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] -} + _interpolationFunction = interpolation; + return this; -function encodeChunk (uint8, start, end) { - var tmp - var output = [] - for (var i = start; i < end; i += 3) { - tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) - output.push(tripletToBase64(tmp)) - } - return output.join('') -} + }; -function fromByteArray (uint8) { - var tmp - var len = uint8.length - var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - var output = '' - var parts = [] - var maxChunkLength = 16383 // must be multiple of 3 + this.chain = function () { - // go through the array every three bytes, we'll deal with trailing stuff later - for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) - } + _chainedTweens = arguments; + return this; - // pad the end with zeros, but make sure to not forget the extra bytes - if (extraBytes === 1) { - tmp = uint8[len - 1] - output += lookup[tmp >> 2] - output += lookup[(tmp << 4) & 0x3F] - output += '==' - } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + (uint8[len - 1]) - output += lookup[tmp >> 10] - output += lookup[(tmp >> 4) & 0x3F] - output += lookup[(tmp << 2) & 0x3F] - output += '=' - } + }; - parts.push(output) + this.onStart = function (callback) { - return parts.join('') -} + _onStartCallback = callback; + return this; -},{}],4:[function(_dereq_,module,exports){ -'use strict'; -// For more information about browser field, check out the browser field at https://github.com/substack/browserify-handbook#browser-field. + }; -module.exports = { - // Create a tag with optional data attributes - createLink: function(href, attributes) { - var head = document.head || document.getElementsByTagName('head')[0]; - var link = document.createElement('link'); + this.onUpdate = function (callback) { - link.href = href; - link.rel = 'stylesheet'; + _onUpdateCallback = callback; + return this; - for (var key in attributes) { - if ( ! attributes.hasOwnProperty(key)) { - continue; - } - var value = attributes[key]; - link.setAttribute('data-' + key, value); - } + }; - head.appendChild(link); - }, - // Create a