├── assets ├── visual1.png ├── visual2.png ├── visual1_zoom.png └── visual2_zoom.png ├── notes.js ├── cors.json ├── css ├── main.css └── dat.gui.css ├── js ├── utils │ ├── StereoEffect.js │ ├── tween.min.js │ ├── ParametricGeometries.js │ ├── TweenLite.min.js │ ├── OrbitControls.js │ └── dat.gui.min.js ├── main.web.js └── main.js ├── web.html ├── README.md └── index.html /assets/visual1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KanteLabs/Music-Visualizer/HEAD/assets/visual1.png -------------------------------------------------------------------------------- /assets/visual2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KanteLabs/Music-Visualizer/HEAD/assets/visual2.png -------------------------------------------------------------------------------- /notes.js: -------------------------------------------------------------------------------- 1 | //Three js is capable of having multiple scenes and each one can have different objects -------------------------------------------------------------------------------- /assets/visual1_zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KanteLabs/Music-Visualizer/HEAD/assets/visual1_zoom.png -------------------------------------------------------------------------------- /assets/visual2_zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KanteLabs/Music-Visualizer/HEAD/assets/visual2_zoom.png -------------------------------------------------------------------------------- /cors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "origin": ["*"], 4 | "method": ["GET"], 5 | "maxAgeSeconds": 3600 6 | } 7 | ] -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | div#past-songs { 2 | background: black; 3 | width: 250px; 4 | position: absolute; 5 | top: 2em; 6 | opacity: 0.8; 7 | left: -2em; 8 | height: 60vh; 9 | overflow: auto; 10 | } 11 | body::-webkit-scrollbar { 12 | width: 1em; 13 | } 14 | ul#prevSongs { 15 | list-style: none; 16 | text-transform: capitalize; 17 | letter-spacing: 1px; 18 | opacity: 1; 19 | color: #eee; 20 | font-family: cursive; 21 | } 22 | 23 | ul li { 24 | cursor: pointer; 25 | } -------------------------------------------------------------------------------- /js/utils/StereoEffect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * @authod mrdoob / http://mrdoob.com/ 4 | * @authod arodic / http://aleksandarrodic.com/ 5 | * @authod fonserbc / http://fonserbc.github.io/ 6 | */ 7 | 8 | THREE.StereoEffect = function ( renderer ) { 9 | 10 | var _stereo = new THREE.StereoCamera(); 11 | _stereo.aspect = 0.5; 12 | 13 | this.setEyeSeparation = function ( eyeSep ) { 14 | 15 | _stereo.eyeSep = eyeSep; 16 | 17 | }; 18 | 19 | this.setSize = function ( width, height ) { 20 | 21 | renderer.setSize( width, height ); 22 | 23 | }; 24 | 25 | this.render = function ( scene, camera ) { 26 | 27 | scene.updateMatrixWorld(); 28 | 29 | if ( camera.parent === null ) camera.updateMatrixWorld(); 30 | 31 | _stereo.update( camera ); 32 | 33 | var size = renderer.getSize(); 34 | 35 | if ( renderer.autoClear ) renderer.clear(); 36 | renderer.setScissorTest( true ); 37 | 38 | renderer.setScissor( 0, 0, size.width / 2, size.height ); 39 | renderer.setViewport( 0, 0, size.width / 2, size.height ); 40 | renderer.render( scene, _stereo.cameraL ); 41 | 42 | renderer.setScissor( size.width / 2, 0, size.width / 2, size.height ); 43 | renderer.setViewport( size.width / 2, 0, size.width / 2, size.height ); 44 | renderer.render( scene, _stereo.cameraR ); 45 | 46 | renderer.setScissorTest( false ); 47 | 48 | }; 49 | 50 | }; 51 | -------------------------------------------------------------------------------- /web.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ThreeJs Demo 1 5 | 6 | 7 | 36 | 37 | 38 | 51 | 52 |
53 | Default
54 | Cube Matrix
55 | Web
56 |
57 | 58 |
59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Music Visualizer 2 | User's can either upload a song or choose one that has been uploaded by other users and then see the visualizations for it on their screen. Once a song is uploaded visualizations are created by analyzing the frequency data and waveform with the Web Audio Api. The data is then render with THREE.js. GUI controls are also included to control the camera rotation and positioning. Different songs create different colors and affect how high each bar goes in the visualization. 3 | 4 | [View Live Demo Here](https://kantelabs.github.io/Music-Visualizer/) 5 | 6 | ### Bars - Main Visualizer 7 | ![Bars](/assets/visual1_zoom.png) 8 | ### Experimental Web Visualizer 9 | ![Web](/assets/visual2_zoom.png) 10 | [Link to Web](https://kantelabs.github.io/Music-Visualizer/web.html) 11 | 12 | ### Technical Details 13 | The core of this project was built using THREE.js in order to render the visualizers in canvas. When a user uploads a song to visual it also gets stored in Google Firebase so that the song can be reused by other people. This is also useful for people that do not want to upload a song. Web Audio Api analyzes the song data so that it could be visualized by THREE.js. 14 | 15 | ### Sample Code 16 | This sample code was how I generated the random floating shapes around the scene. 17 | 18 | ```javascript 19 | var asteroidMesh = new Array() 20 | var asteroidGeometry = new THREE.TetrahedronGeometry((Math.random() + 0.5 ), 2); 21 | var asteroidMaterial = new THREE.MeshPhongMaterial({ 22 | color: (Math.random() * 0xffffff), 23 | flatShading: true 24 | }); 25 | 26 | var i = 0; 27 | for(var x = 0; x < 1; x++){ 28 | var j = 0; 29 | asteroidMesh[i] = new Array(); 30 | for(var y = 0; y < 1000; y++){ 31 | asteroidMesh[i][j] = new THREE.Mesh(asteroidGeometry, asteroidMaterial); 32 | asteroidMesh[i][j].position.x = ( Math.random() - 0.5 ) * 300; 33 | asteroidMesh[i][j].position.y = ( Math.random() - 0.5 ) * 300; 34 | asteroidMesh[i][j].position.z = ( Math.random() - 0.5 ) * 300; 35 | asteroidMesh[i][j].scale.z = (Math.random() * 2, Math.random() * 2, Math.random() * 2); 36 | asteroidMesh[i][j].rotation.set(Math.random() * 4, Math.random() * 4, Math.random() * 4) 37 | scene.add(asteroidMesh[x][j]) 38 | j++; 39 | } 40 | i++; 41 | } 42 | ``` 43 | 44 | ### Future Improvements 45 | - Incorporate AFrame for VR & smoother interactions [] 46 | - Basic VR using Google Cardboard [] 47 | - Include at least 3 music visualizers [] 48 | - Can generate random shapes around the visualizer [] 49 | - have certain features determined by song data 50 | - color [] 51 | - size [] 52 | - shape type? [] 53 | - option to choose different scenes [] -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Music Visualizer 5 | 6 | 7 | 39 | 40 | 41 | 42 | 43 | 44 | 56 | 57 | 58 |
59 |
60 | 63 |
64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /js/utils/tween.min.js: -------------------------------------------------------------------------------- 1 | // tween.js - http://github.com/sole/tween.js - Licensed under the MIT License 2 | 'use strict';void 0===Date.now&&(Date.now=function(){return(new Date).valueOf()}); 3 | var TWEEN=TWEEN||function(){var a=[];return{REVISION:"14",getAll:function(){return a},removeAll:function(){a=[]},add:function(c){a.push(c)},remove:function(c){c=a.indexOf(c);-1!==c&&a.splice(c,1)},update:function(c){if(0===a.length)return!1;for(var b=0,c=void 0!==c?c:"undefined"!==typeof window&&void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();b(a*=2)?0.5*a*a:-0.5*(--a*(a-2)-1)}},Cubic:{In:function(a){return a*a*a},Out:function(a){return--a*a*a+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*a:0.5*((a-=2)*a*a+2)}},Quartic:{In:function(a){return a*a*a*a},Out:function(a){return 1- --a*a*a*a},InOut:function(a){return 1>(a*=2)?0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)}},Quintic:{In:function(a){return a*a*a* 9 | a*a},Out:function(a){return--a*a*a*a*a+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)}},Sinusoidal:{In:function(a){return 1-Math.cos(a*Math.PI/2)},Out:function(a){return Math.sin(a*Math.PI/2)},InOut:function(a){return 0.5*(1-Math.cos(Math.PI*a))}},Exponential:{In:function(a){return 0===a?0:Math.pow(1024,a-1)},Out:function(a){return 1===a?1:1-Math.pow(2,-10*a)},InOut:function(a){return 0===a?0:1===a?1:1>(a*=2)?0.5*Math.pow(1024,a-1):0.5*(-Math.pow(2,-10*(a-1))+2)}},Circular:{In:function(a){return 1- 10 | Math.sqrt(1-a*a)},Out:function(a){return Math.sqrt(1- --a*a)},InOut:function(a){return 1>(a*=2)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)}},Elastic:{In:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return-(b*Math.pow(2,10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4))},Out:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return b*Math.pow(2,-10*a)*Math.sin((a-c)* 11 | 2*Math.PI/0.4)+1},InOut:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return 1>(a*=2)?-0.5*b*Math.pow(2,10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4):0.5*b*Math.pow(2,-10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4)+1}},Back:{In:function(a){return a*a*(2.70158*a-1.70158)},Out:function(a){return--a*a*(2.70158*a+1.70158)+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*(3.5949095*a-2.5949095):0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)}},Bounce:{In:function(a){return 1- 12 | TWEEN.Easing.Bounce.Out(1-a)},Out:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375},InOut:function(a){return 0.5>a?0.5*TWEEN.Easing.Bounce.In(2*a):0.5*TWEEN.Easing.Bounce.Out(2*a-1)+0.5}}}; 13 | TWEEN.Interpolation={Linear:function(a,c){var b=a.length-1,d=b*c,e=Math.floor(d),g=TWEEN.Interpolation.Utils.Linear;return 0>c?g(a[0],a[1],d):1b?b:e+1],d-e)},Bezier:function(a,c){var b=0,d=a.length-1,e=Math.pow,g=TWEEN.Interpolation.Utils.Bernstein,h;for(h=0;h<=d;h++)b+=e(1-c,d-h)*e(c,h)*a[h]*g(d,h);return b},CatmullRom:function(a,c){var b=a.length-1,d=b*c,e=Math.floor(d),g=TWEEN.Interpolation.Utils.CatmullRom;return a[0]===a[b]?(0>c&&(e=Math.floor(d=b*(1+c))),g(a[(e- 14 | 1+b)%b],a[e],a[(e+1)%b],a[(e+2)%b],d-e)):0>c?a[0]-(g(a[0],a[0],a[1],a[1],-d)-a[0]):1 { 11 | audioFile = event.target.files; 12 | var songName = audioFile[0].name; 13 | console.log(`Now playing ${songName}, with shape ${pickedShape}`) 14 | //Creates a temporary url for the file that was uploaded so that it could be played the audio element 15 | var audioPlayer = new Audio(URL.createObjectURL(audioFile[0])) 16 | var audioDiv = document.querySelector('.audio-container'); 17 | 18 | //Prevents local memory of audio files so you can create a new instance on upload 19 | audioDiv.firstChild !== null ? (audioDiv.firstElementChild.remove(), (audioDiv.appendChild(audioPlayer))) : audioDiv.appendChild(audioPlayer); 20 | audioPlayer.controls = true; 21 | audioPlayer.load(); 22 | /*audioPlayer.play(),*/ 23 | 24 | analyzeAudio(audioPlayer); 25 | } 26 | 27 | form.onchange = (event) => { 28 | console.log(event.target.value) 29 | } 30 | } 31 | 32 | analyzeAudio = (audioPlayer) => { 33 | console.log(`Received ${audioPlayer}`) 34 | // AnalyserNode is necessary to provide real-time frequency and time-domain analysis information. It is an AudioNode that passes the audio stream unchanged from the input to the output, but allows you to take the generated data, process it, and create audio visualizations. 35 | 36 | source = audioCtx.createMediaElementSource(audioPlayer) // Uploaded audio becomes the source for the media stream 37 | source.connect(analyser) 38 | analyser.connect(audioCtx.destination) 39 | 40 | analyser.fftSize = 256; // 256 for analyser.getByteFrequencyData(dataArray) and 2048 for analyser.getByteTimeDomainData(dataArray) 41 | var bufferLength = analyser.frequencyBinCount; 42 | console.log(bufferLength) 43 | var dataArray = new Uint8Array(bufferLength) 44 | 45 | //Scene Details 46 | var scene = new THREE.Scene(); //new scene instance 47 | scene.background = new THREE.Color( 0x000000); 48 | scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 ); 49 | 50 | var renderer = new THREE.WebGLRenderer(); 51 | renderer.setSize( window.innerWidth, window.innerHeight); 52 | document.querySelector('canvas') != undefined ? (document.querySelector('canvas').remove(), document.body.appendChild(renderer.domElement)) : document.body.appendChild(renderer.domElement) 53 | 54 | //Lighting Details 55 | var light = new THREE.AmbientLight(0x505050); 56 | scene.add(light); 57 | 58 | var directionalLight1 = new THREE.DirectionalLight(0xffffff, 0.7); 59 | directionalLight1.position.set(0, 1, 1); 60 | scene.add(directionalLight1); 61 | 62 | directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.7); 63 | directionalLight2.position.set(1, 1, 0); 64 | scene.add(directionalLight2); 65 | 66 | 67 | directionalLight3 = new THREE.DirectionalLight(0xffffff, 0.7); 68 | directionalLight3.position.set(0, -1, -1); 69 | scene.add(directionalLight3); 70 | 71 | directionalLight4 = new THREE.DirectionalLight(0xffffff, 0.7); 72 | directionalLight4.position.set(-1, -1, 0); 73 | scene.add(directionalLight4); 74 | 75 | //Camera Details 76 | var camera = new THREE.PerspectiveCamera( 65, window.innerWidth/window.innerHeight, 1, 1000 ); 77 | camera.position.x = 32; 78 | camera.position.y = 50; 79 | camera.position.z = 175; 80 | camera.lookAt(scene.position); 81 | window.addEventListener( 'resize', function () { 82 | camera.aspect = window.innerWidth / window.innerHeight; 83 | camera.updateProjectionMatrix(); 84 | 85 | renderer.setSize( window.innerWidth, window.innerHeight ); 86 | 87 | }, false ); 88 | 89 | //Controls Details 90 | var controls; 91 | controls = new THREE.OrbitControls(camera); 92 | 93 | //Web Shape Details 94 | var webGeometry = new THREE.RingGeometry(30, 15, 8, 8, 0, 6.3); 95 | var webMaterial = new THREE.WireframeGeometry(webGeometry,{ 96 | color: 0x156289, 97 | emissive: 0x072534, 98 | side: THREE.DoubleSide, 99 | flatShading: true, 100 | }); 101 | var webMesh = new THREE.LineSegments(webMaterial); 102 | webMesh.material.depthTest = true; 103 | webMesh.material.transparent = true; 104 | webMeshBack = webMesh.clone(); 105 | scene.add(webMesh); 106 | scene.add(webMeshBack); 107 | 108 | //Circle Details 109 | var circleGeometry = new THREE.SphereGeometry( 10, 20, 20 ); 110 | var circleMaterial = new THREE.MeshPhongMaterial( {color: 0x000000, flatShading: true} ); 111 | var sphere = new THREE.Mesh( circleGeometry, circleMaterial ); 112 | scene.add( sphere ) 113 | 114 | // Giant ShellMesh Details 115 | var shellGeometry = new THREE.SphereGeometry(100, 50, 50); 116 | var shellMaterial = new THREE.WireframeGeometry(shellGeometry,{ 117 | color: 0xffff00, 118 | emissive: 0x072534, 119 | side: THREE.DoubleSide, 120 | flatShading: false, 121 | }); 122 | var shellMesh = new THREE.LineSegments(shellMaterial); 123 | shellMesh.material.depthTest = true; 124 | shellMesh.material.transparent = true; 125 | scene.add(shellMesh); 126 | 127 | function animate(){ 128 | requestAnimationFrame(animate) //better than set interval because it pauses when user leaves the page 129 | analyser.getByteFrequencyData(dataArray) 130 | controls.autoRotate = true; 131 | controls.autoRotateSpeed = 1; 132 | controls.update(); 133 | 134 | sphere.rotation.z += 0.01; 135 | 136 | var k = 0; 137 | 138 | if(dataArray[k]){ 139 | TweenLite.to(directionalLight1, 1, {intensity: Math.random()* (dataArray[k] / 10 < 1 ? 1 : dataArray[k] / 10)}) 140 | TweenLite.to(directionalLight2, 1, {intensity: Math.random()* (dataArray[k] / 10 < 1 ? 1 : dataArray[k] / 10)}) 141 | TweenLite.to(directionalLight3, 1, {intensity: Math.random()* (dataArray[k] / 10 < 1 ? 1 : dataArray[k] / 10)}) 142 | TweenLite.to(directionalLight4, 1, {intensity: Math.random()* (dataArray[k] / 10 < 1 ? 1 : dataArray[k] / 10)}) 143 | }else{ 144 | null; 145 | } 146 | 147 | sphere.scale.x = (dataArray[k] / 30 < 1 ? 1.1 : dataArray[k] / 150); 148 | sphere.scale.y = (dataArray[k] / 30 < 1 ? 1.1 : dataArray[k] / 150); 149 | sphere.scale.z = (dataArray[k] / 30 < 1 ? 1.1 : dataArray[k] / 150); 150 | 151 | webMeshBack.position.z = -(dataArray[k] / 10 < 1 ? 1 : dataArray[k] / 10) 152 | webMesh.position.z = (dataArray[k] / 10 < 1 ? 1 : dataArray[k] / 10) 153 | for(var i = 0; i < dataArray.length; i++) { 154 | var scale = dataArray[k] / 30; 155 | k += (k < dataArray.length ? 1 : 0); 156 | } 157 | renderer.render(scene, camera) 158 | } 159 | animate() //gets called 60x per sec to render scene 160 | } -------------------------------------------------------------------------------- /js/utils/ParametricGeometries.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @author zz85 3 | * 4 | * Experimenting of primitive geometry creation using Surface Parametric equations 5 | * 6 | */ 7 | 8 | THREE.ParametricGeometries = { 9 | 10 | klein: function ( v, u, optionalTarget ) { 11 | 12 | var result = optionalTarget || new THREE.Vector3(); 13 | 14 | u *= Math.PI; 15 | v *= 2 * Math.PI; 16 | 17 | u = u * 2; 18 | var x, y, z; 19 | if ( u < Math.PI ) { 20 | 21 | x = 3 * Math.cos( u ) * ( 1 + Math.sin( u ) ) + ( 2 * ( 1 - Math.cos( u ) / 2 ) ) * Math.cos( u ) * Math.cos( v ); 22 | z = - 8 * Math.sin( u ) - 2 * ( 1 - Math.cos( u ) / 2 ) * Math.sin( u ) * Math.cos( v ); 23 | 24 | } else { 25 | 26 | x = 3 * Math.cos( u ) * ( 1 + Math.sin( u ) ) + ( 2 * ( 1 - Math.cos( u ) / 2 ) ) * Math.cos( v + Math.PI ); 27 | z = - 8 * Math.sin( u ); 28 | 29 | } 30 | 31 | y = - 2 * ( 1 - Math.cos( u ) / 2 ) * Math.sin( v ); 32 | 33 | return result.set( x, y, z ); 34 | 35 | }, 36 | 37 | plane: function ( width, height ) { 38 | 39 | return function( u, v, optionalTarget ) { 40 | 41 | var result = optionalTarget || new THREE.Vector3(); 42 | 43 | var x = u * width; 44 | var y = 0; 45 | var z = v * height; 46 | 47 | return result.set( x, y, z ); 48 | 49 | }; 50 | 51 | }, 52 | 53 | mobius: function( u, t, optionalTarget ) { 54 | 55 | var result = optionalTarget || new THREE.Vector3(); 56 | 57 | // flat mobius strip 58 | // http://www.wolframalpha.com/input/?i=M%C3%B6bius+strip+parametric+equations&lk=1&a=ClashPrefs_*Surface.MoebiusStrip.SurfaceProperty.ParametricEquations- 59 | u = u - 0.5; 60 | var v = 2 * Math.PI * t; 61 | 62 | var x, y, z; 63 | 64 | var a = 2; 65 | 66 | x = Math.cos( v ) * ( a + u * Math.cos( v / 2 ) ); 67 | y = Math.sin( v ) * ( a + u * Math.cos( v / 2 ) ); 68 | z = u * Math.sin( v / 2 ); 69 | 70 | return result.set( x, y, z ); 71 | 72 | }, 73 | 74 | mobius3d: function( u, t, optionalTarget ) { 75 | 76 | var result = optionalTarget || new THREE.Vector3(); 77 | 78 | // volumetric mobius strip 79 | 80 | u *= Math.PI; 81 | t *= 2 * Math.PI; 82 | 83 | u = u * 2; 84 | var phi = u / 2; 85 | var major = 2.25, a = 0.125, b = 0.65; 86 | 87 | var x, y, z; 88 | 89 | x = a * Math.cos( t ) * Math.cos( phi ) - b * Math.sin( t ) * Math.sin( phi ); 90 | z = a * Math.cos( t ) * Math.sin( phi ) + b * Math.sin( t ) * Math.cos( phi ); 91 | y = ( major + x ) * Math.sin( u ); 92 | x = ( major + x ) * Math.cos( u ); 93 | 94 | return result.set( x, y, z ); 95 | 96 | } 97 | 98 | }; 99 | 100 | 101 | /********************************************* 102 | * 103 | * Parametric Replacement for TubeGeometry 104 | * 105 | *********************************************/ 106 | 107 | THREE.ParametricGeometries.TubeGeometry = function( path, segments, radius, segmentsRadius, closed, debug ) { 108 | 109 | this.path = path; 110 | this.segments = segments || 64; 111 | this.radius = radius || 1; 112 | this.segmentsRadius = segmentsRadius || 8; 113 | this.closed = closed || false; 114 | if ( debug ) this.debug = new THREE.Object3D(); 115 | 116 | 117 | var scope = this, 118 | 119 | tangent, normal, binormal, 120 | 121 | numpoints = this.segments + 1, 122 | 123 | x, y, z, tx, ty, tz, u, v, 124 | 125 | cx, cy, pos, 126 | i, j, ip, jp, a, b, c, d, uva, uvb, uvc, uvd; 127 | 128 | var frames = path.computeFrenetFrames( segments, closed ), 129 | tangents = frames.tangents, 130 | normals = frames.normals, 131 | binormals = frames.binormals; 132 | 133 | // proxy internals 134 | this.tangents = tangents; 135 | this.normals = normals; 136 | this.binormals = binormals; 137 | 138 | 139 | 140 | var ParametricTube = function( u, v, optionalTarget ) { 141 | 142 | var result = optionalTarget || new THREE.Vector3(); 143 | 144 | v *= 2 * Math.PI; 145 | 146 | i = u * ( numpoints - 1 ); 147 | i = Math.floor( i ); 148 | 149 | pos = path.getPointAt( u ); 150 | 151 | tangent = tangents[ i ]; 152 | normal = normals[ i ]; 153 | binormal = binormals[ i ]; 154 | 155 | if ( scope.debug ) { 156 | 157 | scope.debug.add( new THREE.ArrowHelper( tangent, pos, radius, 0x0000ff ) ); 158 | scope.debug.add( new THREE.ArrowHelper( normal, pos, radius, 0xff0000 ) ); 159 | scope.debug.add( new THREE.ArrowHelper( binormal, pos, radius, 0x00ff00 ) ); 160 | 161 | } 162 | 163 | cx = - scope.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. 164 | cy = scope.radius * Math.sin( v ); 165 | 166 | pos.x += cx * normal.x + cy * binormal.x; 167 | pos.y += cx * normal.y + cy * binormal.y; 168 | pos.z += cx * normal.z + cy * binormal.z; 169 | 170 | return result.copy( pos ); 171 | 172 | }; 173 | 174 | THREE.ParametricGeometry.call( this, ParametricTube, segments, segmentsRadius ); 175 | 176 | }; 177 | 178 | THREE.ParametricGeometries.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); 179 | THREE.ParametricGeometries.TubeGeometry.prototype.constructor = THREE.ParametricGeometries.TubeGeometry; 180 | 181 | 182 | /********************************************* 183 | * 184 | * Parametric Replacement for TorusKnotGeometry 185 | * 186 | *********************************************/ 187 | THREE.ParametricGeometries.TorusKnotGeometry = function ( radius, tube, segmentsT, segmentsR, p, q ) { 188 | 189 | var scope = this; 190 | 191 | this.radius = radius || 200; 192 | this.tube = tube || 40; 193 | this.segmentsT = segmentsT || 64; 194 | this.segmentsR = segmentsR || 8; 195 | this.p = p || 2; 196 | this.q = q || 3; 197 | 198 | function TorusKnotCurve() { 199 | 200 | THREE.Curve.call( this ); 201 | 202 | } 203 | 204 | TorusKnotCurve.prototype = Object.create( THREE.Curve.prototype ); 205 | TorusKnotCurve.prototype.constructor = TorusKnotCurve; 206 | 207 | TorusKnotCurve.prototype.getPoint = function( t ){ 208 | 209 | t *= Math.PI * 2; 210 | 211 | var r = 0.5; 212 | 213 | var x = ( 1 + r * Math.cos( q * t ) ) * Math.cos( p * t ); 214 | var y = ( 1 + r * Math.cos( q * t ) ) * Math.sin( p * t ); 215 | var z = r * Math.sin( q * t ); 216 | 217 | return new THREE.Vector3( x, y, z ).multiplyScalar( radius ); 218 | 219 | }; 220 | 221 | var segments = segmentsT; 222 | var radiusSegments = segmentsR; 223 | var extrudePath = new TorusKnotCurve(); 224 | 225 | THREE.ParametricGeometries.TubeGeometry.call( this, extrudePath, segments, tube, radiusSegments, true, false ); 226 | 227 | }; 228 | 229 | THREE.ParametricGeometries.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); 230 | THREE.ParametricGeometries.TorusKnotGeometry.prototype.constructor = THREE.ParametricGeometries.TorusKnotGeometry; 231 | 232 | 233 | /********************************************* 234 | * 235 | * Parametric Replacement for SphereGeometry 236 | * 237 | *********************************************/ 238 | THREE.ParametricGeometries.SphereGeometry = function( size, u, v ) { 239 | 240 | function sphere( u, v, optionalTarget ) { 241 | 242 | var result = optionalTarget || new THREE.Vector3(); 243 | 244 | u *= Math.PI; 245 | v *= 2 * Math.PI; 246 | 247 | var x = size * Math.sin( u ) * Math.cos( v ); 248 | var y = size * Math.sin( u ) * Math.sin( v ); 249 | var z = size * Math.cos( u ); 250 | 251 | return result.set( x, y, z ); 252 | 253 | } 254 | 255 | THREE.ParametricGeometry.call( this, sphere, u, v, ! true ); 256 | 257 | }; 258 | 259 | THREE.ParametricGeometries.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); 260 | THREE.ParametricGeometries.SphereGeometry.prototype.constructor = THREE.ParametricGeometries.SphereGeometry; 261 | 262 | 263 | /********************************************* 264 | * 265 | * Parametric Replacement for PlaneGeometry 266 | * 267 | *********************************************/ 268 | 269 | THREE.ParametricGeometries.PlaneGeometry = function( width, depth, segmentsWidth, segmentsDepth ) { 270 | 271 | function plane( u, v, optionalTarget ) { 272 | 273 | var result = optionalTarget || new THREE.Vector3(); 274 | 275 | var x = u * width; 276 | var y = 0; 277 | var z = v * depth; 278 | 279 | return result.set( x, y, z ); 280 | 281 | } 282 | 283 | THREE.ParametricGeometry.call( this, plane, segmentsWidth, segmentsDepth ); 284 | 285 | }; 286 | 287 | THREE.ParametricGeometries.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); 288 | THREE.ParametricGeometries.PlaneGeometry.prototype.constructor = THREE.ParametricGeometries.PlaneGeometry; 289 | -------------------------------------------------------------------------------- /css/dat.gui.css: -------------------------------------------------------------------------------- 1 | .dg { 2 | /** Clear list styles */ 3 | /* Auto-place container */ 4 | /* Auto-placed GUI's */ 5 | /* Line items that don't contain folders. */ 6 | /** Folder names */ 7 | /** Hides closed items */ 8 | /** Controller row */ 9 | /** Name-half (left) */ 10 | /** Controller-half (right) */ 11 | /** Controller placement */ 12 | /** Shorter number boxes when slider is present. */ 13 | /** Ensure the entire boolean and function row shows a hand */ 14 | /** allow overflow for color selector */ } 15 | .dg ul { 16 | list-style: none; 17 | margin: 0; 18 | padding: 0; 19 | width: 100%; 20 | clear: both; } 21 | .dg.ac { 22 | position: fixed; 23 | top: 0; 24 | left: 0; 25 | right: 0; 26 | height: 0; 27 | z-index: 0; } 28 | .dg:not(.ac) .main { 29 | /** Exclude mains in ac so that we don't hide close button */ 30 | overflow: hidden; } 31 | .dg.main { 32 | -webkit-transition: opacity 0.1s linear; 33 | -o-transition: opacity 0.1s linear; 34 | -moz-transition: opacity 0.1s linear; 35 | transition: opacity 0.1s linear; } 36 | .dg.main.taller-than-window { 37 | overflow-y: auto; } 38 | .dg.main.taller-than-window .close-button { 39 | opacity: 1; 40 | /* TODO, these are style notes */ 41 | margin-top: -1px; 42 | border-top: 1px solid #2c2c2c; } 43 | .dg.main ul.closed .close-button { 44 | opacity: 1 !important; } 45 | .dg.main:hover .close-button, 46 | .dg.main .close-button.drag { 47 | opacity: 1; } 48 | .dg.main .close-button { 49 | /*opacity: 0;*/ 50 | -webkit-transition: opacity 0.1s linear; 51 | -o-transition: opacity 0.1s linear; 52 | -moz-transition: opacity 0.1s linear; 53 | transition: opacity 0.1s linear; 54 | border: 0; 55 | line-height: 19px; 56 | height: 20px; 57 | /* TODO, these are style notes */ 58 | cursor: pointer; 59 | text-align: center; 60 | background-color: #000; } 61 | .dg.main .close-button.close-top { 62 | position: relative; } 63 | .dg.main .close-button.close-bottom { 64 | position: absolute; } 65 | .dg.main .close-button:hover { 66 | background-color: #111; } 67 | .dg.a { 68 | float: right; 69 | margin-right: 15px; 70 | overflow-y: visible; } 71 | .dg.a.has-save > ul.close-top { 72 | margin-top: 0; } 73 | .dg.a.has-save > ul.close-bottom { 74 | margin-top: 27px; } 75 | .dg.a.has-save > ul.closed { 76 | margin-top: 0; } 77 | .dg.a .save-row { 78 | top: 0; 79 | z-index: 1002; } 80 | .dg.a .save-row.close-top { 81 | position: relative; } 82 | .dg.a .save-row.close-bottom { 83 | position: fixed; } 84 | .dg li { 85 | -webkit-transition: height 0.1s ease-out; 86 | -o-transition: height 0.1s ease-out; 87 | -moz-transition: height 0.1s ease-out; 88 | transition: height 0.1s ease-out; 89 | -webkit-transition: overflow 0.1s linear; 90 | -o-transition: overflow 0.1s linear; 91 | -moz-transition: overflow 0.1s linear; 92 | transition: overflow 0.1s linear; } 93 | .dg li:not(.folder) { 94 | cursor: auto; 95 | height: 27px; 96 | line-height: 27px; 97 | padding: 0 4px 0 5px; } 98 | .dg li.folder { 99 | padding: 0; 100 | border-left: 4px solid transparent; } 101 | .dg li.title { 102 | cursor: pointer; 103 | margin-left: -4px; } 104 | .dg .closed li:not(.title), 105 | .dg .closed ul li, 106 | .dg .closed ul li > * { 107 | height: 0; 108 | overflow: hidden; 109 | border: 0; } 110 | .dg .cr { 111 | clear: both; 112 | padding-left: 3px; 113 | height: 27px; 114 | overflow: hidden; } 115 | .dg .property-name { 116 | cursor: default; 117 | float: left; 118 | clear: left; 119 | width: 40%; 120 | overflow: hidden; 121 | text-overflow: ellipsis; } 122 | .dg .c { 123 | float: left; 124 | width: 60%; 125 | position: relative; } 126 | .dg .c input[type=text] { 127 | border: 0; 128 | margin-top: 4px; 129 | padding: 3px; 130 | width: 100%; 131 | float: right; } 132 | .dg .has-slider input[type=text] { 133 | width: 30%; 134 | /*display: none;*/ 135 | margin-left: 0; } 136 | .dg .slider { 137 | float: left; 138 | width: 66%; 139 | margin-left: -5px; 140 | margin-right: 0; 141 | height: 19px; 142 | margin-top: 4px; } 143 | .dg .slider-fg { 144 | height: 100%; } 145 | .dg .c input[type=checkbox] { 146 | margin-top: 7px; } 147 | .dg .c select { 148 | margin-top: 5px; } 149 | .dg .cr.function, 150 | .dg .cr.function .property-name, 151 | .dg .cr.function *, 152 | .dg .cr.boolean, 153 | .dg .cr.boolean * { 154 | cursor: pointer; } 155 | .dg .cr.color { 156 | overflow: visible; } 157 | .dg .selector { 158 | display: none; 159 | position: absolute; 160 | margin-left: -9px; 161 | margin-top: 23px; 162 | z-index: 10; } 163 | .dg .c:hover .selector, 164 | .dg .selector.drag { 165 | display: block; } 166 | .dg li.save-row { 167 | padding: 0; } 168 | .dg li.save-row .button { 169 | display: inline-block; 170 | padding: 0px 6px; } 171 | .dg.dialogue { 172 | background-color: #222; 173 | width: 460px; 174 | padding: 15px; 175 | font-size: 13px; 176 | line-height: 15px; } 177 | 178 | /* TODO Separate style and structure */ 179 | #dg-new-constructor { 180 | padding: 10px; 181 | color: #222; 182 | font-family: Monaco, monospace; 183 | font-size: 10px; 184 | border: 0; 185 | resize: none; 186 | box-shadow: inset 1px 1px 1px #888; 187 | word-wrap: break-word; 188 | margin: 12px 0; 189 | display: block; 190 | width: 440px; 191 | overflow-y: scroll; 192 | height: 100px; 193 | position: relative; } 194 | 195 | #dg-local-explain { 196 | display: none; 197 | font-size: 11px; 198 | line-height: 17px; 199 | border-radius: 3px; 200 | background-color: #333; 201 | padding: 8px; 202 | margin-top: 10px; } 203 | #dg-local-explain code { 204 | font-size: 10px; } 205 | 206 | #dat-gui-save-locally { 207 | display: none; } 208 | 209 | /** Main type */ 210 | .dg { 211 | color: #eee; 212 | font: 11px 'Lucida Grande', sans-serif; 213 | text-shadow: 0 -1px 0 #111; 214 | /** Auto place */ 215 | /* Controller row,
  • */ 216 | /** Controllers */ } 217 | .dg.main { 218 | /** Scrollbar */ } 219 | .dg.main::-webkit-scrollbar { 220 | width: 5px; 221 | background: #1a1a1a; } 222 | .dg.main::-webkit-scrollbar-corner { 223 | height: 0; 224 | display: none; } 225 | .dg.main::-webkit-scrollbar-thumb { 226 | border-radius: 5px; 227 | background: #676767; } 228 | .dg li:not(.folder) { 229 | background: #1a1a1a; 230 | border-bottom: 1px solid #2c2c2c; } 231 | .dg li.save-row { 232 | line-height: 25px; 233 | background: #dad5cb; 234 | border: 0; } 235 | .dg li.save-row select { 236 | margin-left: 5px; 237 | width: 108px; } 238 | .dg li.save-row .button { 239 | margin-left: 5px; 240 | margin-top: 1px; 241 | border-radius: 2px; 242 | font-size: 9px; 243 | line-height: 7px; 244 | padding: 4px 4px 5px 4px; 245 | background: #c5bdad; 246 | color: #fff; 247 | text-shadow: 0 1px 0 #b0a58f; 248 | box-shadow: 0 -1px 0 #b0a58f; 249 | cursor: pointer; } 250 | .dg li.save-row .button.gears { 251 | background: #c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat; 252 | height: 7px; 253 | width: 8px; } 254 | .dg li.save-row .button:hover { 255 | background-color: #bab19e; 256 | box-shadow: 0 -1px 0 #b0a58f; } 257 | .dg li.folder { 258 | border-bottom: 0; } 259 | .dg li.title { 260 | padding-left: 16px; 261 | background: #000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat; 262 | cursor: pointer; 263 | border-bottom: 1px solid rgba(255, 255, 255, 0.2); } 264 | .dg .closed li.title { 265 | background-image: url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==); } 266 | .dg .cr.boolean { 267 | border-left: 3px solid #806787; } 268 | .dg .cr.color { 269 | border-left: 3px solid; } 270 | .dg .cr.function { 271 | border-left: 3px solid #e61d5f; } 272 | .dg .cr.number { 273 | border-left: 3px solid #2FA1D6; } 274 | .dg .cr.number input[type=text] { 275 | color: #2FA1D6; } 276 | .dg .cr.string { 277 | border-left: 3px solid #1ed36f; } 278 | .dg .cr.string input[type=text] { 279 | color: #1ed36f; } 280 | .dg .cr.function:hover, .dg .cr.boolean:hover { 281 | background: #111; } 282 | .dg .c input[type=text] { 283 | background: #303030; 284 | outline: none; } 285 | .dg .c input[type=text]:hover { 286 | background: #3c3c3c; } 287 | .dg .c input[type=text]:focus { 288 | background: #494949; 289 | color: #fff; } 290 | .dg .c .slider { 291 | background: #303030; 292 | cursor: ew-resize; } 293 | .dg .c .slider-fg { 294 | background: #2FA1D6; 295 | max-width: 100%; } 296 | .dg .c .slider:hover { 297 | background: #3c3c3c; } 298 | .dg .c .slider:hover .slider-fg { 299 | background: #44abda; } 300 | -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); 2 | var analyser = audioCtx.createAnalyser(); 3 | var previousSearches = [] 4 | var source; 5 | var gui = new dat.GUI({ 6 | height: 5 * 32 - 1, 7 | }) 8 | var defaultSong = "https://firebasestorage.googleapis.com/v0/b/kantelabs-threejs.appspot.com/o/03%20-%20Smooth%20Operator.mp3?alt=media&token=27e95f4c-b4fb-4160-9bdc-02833cf65a84"; 9 | 10 | window.onload = function () { 11 | var fileUpload = document.querySelector('#audioFile'); //Grabs the file input and stores it in an variable 12 | var prevSongs = document.querySelector('#prevSongs'); 13 | var storageRef = firebase.storage().ref(); 14 | var dbRoot = firebase.database().ref(); 15 | var songsRef = dbRoot.child('songs'); 16 | var audioDiv = document.querySelector('.audio-container'); 17 | var audioPlayer = new Audio(defaultSong) 18 | audioPlayer.crossOrigin = "anonymous"; 19 | addAudioPlayer(audioPlayer); 20 | 21 | unlockAudioContext(audioCtx); 22 | 23 | document.querySelector('audio').addEventListener("play", () => { 24 | audioCtx.resume(); 25 | }) 26 | 27 | //Searches for and loads previous songs uploaded to firebase 28 | songsRef.on('child_added', snapshot => { 29 | previousSearches.push([snapshot.key, snapshot.val()]) 30 | return previousSearches 31 | }) 32 | 33 | setTimeout(loadPrevSongs, 1000) 34 | 35 | function loadPrevSongs() { 36 | previousSearches.map((song, i) => { 37 | let currSongLi = document.createElement(`li`) 38 | let currSongP = document.createElement(`p`) 39 | let songTitle = document.createTextNode(song[0]) 40 | currSongP.appendChild(songTitle) 41 | currSongP.dataset.name = (song[1]) 42 | currSongLi.appendChild(currSongP) 43 | prevSongs.appendChild(currSongLi) 44 | currSongLi.addEventListener("click", firebaseSong) 45 | }) 46 | } 47 | 48 | function firebaseSong(e) { 49 | console.log(e.target.dataset.name) 50 | let firebaseURL = e.target.dataset.name; 51 | let audioPlayer = document.querySelector('audio'); 52 | audioPlayer.src = firebaseURL; 53 | } 54 | 55 | fileUpload.onchange = (event) => { 56 | audioFile = event.target.files; 57 | var songName = audioFile[0].name; 58 | 59 | //Uploads Song to firebase 60 | var songRef = storageRef.child(songName) 61 | songRef.put(audioFile[0]).then(function (snapshot) { 62 | let dlUrl = snapshot.downloadURL; 63 | databaseRef = firebase.database().ref().child('songs').child(songName.split('.').slice(0, 1).join(' ')) 64 | databaseRef.set(dlUrl) 65 | console.log("uploaded song"); 66 | }) 67 | .then(res => (console.log(res))) 68 | .catch(err => console.log(err)) 69 | 70 | //Creates a temporary url for the file that was uploaded so that it could be played the audio element 71 | var audioPlayer = new Audio(URL.createObjectURL(audioFile[0])) 72 | audioPlayer.crossOrigin = "anonymous"; 73 | addAudioPlayer(audioPlayer); 74 | } 75 | 76 | function addAudioPlayer(audioPlayer) { 77 | //Prevents local memory of audio files so you can create a new instance on upload 78 | audioDiv.firstChild !== null ? (audioDiv.firstElementChild.remove(), (audioDiv.appendChild(audioPlayer))) : audioDiv.appendChild(audioPlayer); 79 | audioPlayer.controls = true; 80 | // audioPlayer.load(); 81 | 82 | analyzeAudio(audioPlayer); 83 | } 84 | } 85 | 86 | function analyzeAudio(audioPlayer) { 87 | // AnalyserNode is necessary to provide real-time frequency and time-domain analysis information. It is an AudioNode that passes the audio stream unchanged from the input to the output, but allows you to take the generated data, process it, and create audio visualizations. 88 | source = audioCtx.createMediaElementSource(audioPlayer) // Uploaded audio becomes the source for the media stream 89 | source.connect(analyser) 90 | analyser.connect(audioCtx.destination) 91 | 92 | analyser.fftSize = 256; // 256 for analyser.getByteFrequencyData(dataArray) and 2048 for analyser.getByteTimeDomainData(dataArray) 93 | var bufferLength = analyser.frequencyBinCount; 94 | var dataArray = new Uint8Array(bufferLength) 95 | console.log(bufferLength) 96 | 97 | //Scene Details 98 | var scene = new THREE.Scene(); //new scene instance 99 | scene.background = new THREE.Color(0x000000); 100 | scene.fog = new THREE.FogExp2(0xcccccc, 0.002); 101 | 102 | var renderer = new THREE.WebGLRenderer(); 103 | renderer.setSize(window.innerWidth, window.innerHeight); 104 | if (document.querySelector('canvas')) { 105 | cancelAnimationFrame(animate); 106 | scene.remove.apply(scene, scene.children); 107 | document.querySelector('canvas').remove(); 108 | document.body.appendChild(renderer.domElement); 109 | 110 | } else { 111 | document.body.appendChild(renderer.domElement) 112 | } 113 | 114 | //Lighting Details 115 | var light = new THREE.AmbientLight(0x505050); 116 | scene.add(light); 117 | var directionalLight = new THREE.DirectionalLight(0xffffff, 0.7); 118 | directionalLight.position.set(0, 1, 1); 119 | scene.add(directionalLight); 120 | 121 | directionalLight = new THREE.DirectionalLight(0xffffff, 0.7); 122 | directionalLight.position.set(1, 1, 0); 123 | scene.add(directionalLight); 124 | 125 | 126 | directionalLight = new THREE.DirectionalLight(0xffffff, 0.7); 127 | directionalLight.position.set(0, -1, -1); 128 | scene.add(directionalLight); 129 | 130 | directionalLight = new THREE.DirectionalLight(0xffffff, 0.7); 131 | directionalLight.position.set(-1, -1, 0); 132 | scene.add(directionalLight); 133 | 134 | //Camera Details 135 | var camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 1, 1000); 136 | camera.position.x = 32; 137 | camera.position.y = 50; 138 | camera.position.z = 50; 139 | camera.lookAt(scene.position); 140 | 141 | window.addEventListener('resize', function () { 142 | camera.aspect = window.innerWidth / window.innerHeight; 143 | camera.updateProjectionMatrix(); 144 | 145 | renderer.setSize(window.innerWidth, window.innerHeight); 146 | 147 | }, false); 148 | 149 | //Controls Details 150 | var controls; 151 | controls = new THREE.OrbitControls(camera, document.querySelector('canvas')); 152 | controls.autoRotate = false; 153 | 154 | gui.destroy() 155 | 156 | gui = new dat.GUI({ 157 | height: 5 * 32 - 1, 158 | }) 159 | 160 | var f1 = gui.addFolder('Camera') 161 | f1.add(controls, 'autoRotate', false, true) 162 | f1.add(controls, 'autoRotateSpeed', 0, 10).step(0.5) 163 | f1.add(camera.position, 'x', -500, 500).step(5) 164 | f1.add(camera.position, 'y', -500, 500).step(5) 165 | f1.add(camera.position, 'z', -500, 500).step(5) 166 | f1.open() 167 | 168 | 169 | //Cubes Details 170 | var cubes = new Array(); 171 | var cubeGeometry = new THREE.CubeGeometry(1.5, 1.5, 1.5) 172 | var cubeMaterial = new THREE.MeshPhongMaterial({ 173 | color: (Math.random() * 0xffffff), 174 | flatShading: false, 175 | specular: 0xffffff, 176 | shininess: 14, 177 | reflectivity: 2, 178 | fog: false 179 | }); 180 | 181 | var i = 0; 182 | for (var x = 0; x <= 256; x += 2) { 183 | var j = 0; 184 | cubes[i] = new Array(); 185 | for (var y = 0; y <= 62; y += 2) { 186 | cubes[i][j] = new THREE.Mesh(cubeGeometry, cubeMaterial); 187 | cubes[i][j].position.x = (y - 30); 188 | cubes[i][j].position.y = (0); 189 | cubes[i][j].position.z = (x); 190 | scene.add(cubes[i][j]) 191 | j++; 192 | } 193 | i++; 194 | } 195 | 196 | //BackgroundShapes Details 197 | var asteroidMesh = new Array() 198 | var asteroidGeometry = new THREE.TetrahedronGeometry((Math.random() + 0.5), 2); 199 | var asteroidMaterial = new THREE.MeshPhongMaterial({ 200 | color: (Math.random() * 0xffffff), 201 | flatShading: true 202 | }); 203 | 204 | var i = 0; 205 | for (var x = 0; x < 1; x++) { 206 | var j = 0; 207 | asteroidMesh[i] = new Array(); 208 | for (var y = 0; y < 1000; y++) { 209 | asteroidMesh[i][j] = new THREE.Mesh(asteroidGeometry, asteroidMaterial); 210 | asteroidMesh[i][j].position.x = (Math.random() - 0.5) * 300; 211 | asteroidMesh[i][j].position.y = (Math.random() - 0.5) * 300; 212 | asteroidMesh[i][j].position.z = (Math.random() - 0.5) * 300; 213 | asteroidMesh[i][j].scale.z = (Math.random() * 2, Math.random() * 2, Math.random() * 2); 214 | asteroidMesh[i][j].rotation.set(Math.random() * 4, Math.random() * 4, Math.random() * 4) 215 | scene.add(asteroidMesh[x][j]) 216 | j++; 217 | } 218 | i++; 219 | } 220 | 221 | function animate() { 222 | requestAnimationFrame(animate) //better than set interval because it pauses when user leaves the page 223 | analyser.getByteFrequencyData(dataArray) 224 | controls.update(); 225 | 226 | var k = 0; 227 | for (var i = 0; i < cubes.length; i++) { 228 | for (var j = 0; j < cubes[i].length; j++) { 229 | var scale = dataArray[k] / 10; 230 | cubes[i][j].scale.y = (scale < 1 ? 1 : scale); 231 | k += (k < dataArray.length ? 1 : 0); 232 | } 233 | } 234 | 235 | var k = 0; 236 | for (var i = 0; i < asteroidMesh.length; i++) { 237 | for (var j = 0; j < asteroidMesh[i].length; j++) { 238 | asteroidMesh[i][j].rotation.z += 0.02; 239 | } 240 | } 241 | renderer.render(scene, camera) 242 | } 243 | animate() //gets called 60x per sec to render scene 244 | } 245 | 246 | function unlockAudioContext(audioCtx) { 247 | if (audioCtx.state !== 'suspended') return; 248 | const b = document.body; 249 | const events = ['touchstart', 'touchend', 'mousedown', 'keydown']; 250 | events.forEach(e => b.addEventListener(e, unlock, false)); 251 | function unlock() { audioCtx.resume() } 252 | function clean() { events.forEach(e => b.removeEventListener(e, unlock)); } 253 | } 254 | -------------------------------------------------------------------------------- /js/utils/TweenLite.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * VERSION: 1.18.0 3 | * DATE: 2015-09-03 4 | * UPDATES AND DOCS AT: http://greensock.com 5 | * 6 | * @license Copyright (c) 2008-2015, GreenSock. All rights reserved. 7 | * This work is subject to the terms at http://greensock.com/standard-license or for 8 | * Club GreenSock members, the software agreement that was issued with your membership. 9 | * 10 | * @author: Jack Doyle, jack@greensock.com 11 | */ 12 | (function(t,e){"use strict";var i=t.GreenSockGlobals=t.GreenSockGlobals||t;if(!i.TweenLite){var s,r,n,a,o,l=function(t){var e,s=t.split("."),r=i;for(e=0;s.length>e;e++)r[s[e]]=r=r[s[e]]||{};return r},h=l("com.greensock"),_=1e-10,u=function(t){var e,i=[],s=t.length;for(e=0;e!==s;i.push(t[e++]));return i},f=function(){},c=function(){var t=Object.prototype.toString,e=t.call([]);return function(i){return null!=i&&(i instanceof Array||"object"==typeof i&&!!i.push&&t.call(i)===e)}}(),m={},p=function(s,r,n,a){this.sc=m[s]?m[s].sc:[],m[s]=this,this.gsClass=null,this.func=n;var o=[];this.check=function(h){for(var _,u,f,c,d,v=r.length,g=v;--v>-1;)(_=m[r[v]]||new p(r[v],[])).gsClass?(o[v]=_.gsClass,g--):h&&_.sc.push(this);if(0===g&&n)for(u=("com.greensock."+s).split("."),f=u.pop(),c=l(u.join("."))[f]=this.gsClass=n.apply(n,o),a&&(i[f]=c,d="undefined"!=typeof module&&module.exports,!d&&"function"==typeof define&&define.amd?define((t.GreenSockAMDPath?t.GreenSockAMDPath+"/":"")+s.split(".").pop(),[],function(){return c}):s===e&&d&&(module.exports=c)),v=0;this.sc.length>v;v++)this.sc[v].check()},this.check(!0)},d=t._gsDefine=function(t,e,i,s){return new p(t,e,i,s)},v=h._class=function(t,e,i){return e=e||function(){},d(t,[],function(){return e},i),e};d.globals=i;var g=[0,0,1,1],T=[],y=v("easing.Ease",function(t,e,i,s){this._func=t,this._type=i||0,this._power=s||0,this._params=e?g.concat(e):g},!0),w=y.map={},P=y.register=function(t,e,i,s){for(var r,n,a,o,l=e.split(","),_=l.length,u=(i||"easeIn,easeOut,easeInOut").split(",");--_>-1;)for(n=l[_],r=s?v("easing."+n,null,!0):h.easing[n]||{},a=u.length;--a>-1;)o=u[a],w[n+"."+o]=w[o+n]=r[o]=t.getRatio?t:t[o]||new t};for(n=y.prototype,n._calcEnd=!1,n.getRatio=function(t){if(this._func)return this._params[0]=t,this._func.apply(null,this._params);var e=this._type,i=this._power,s=1===e?1-t:2===e?t:.5>t?2*t:2*(1-t);return 1===i?s*=s:2===i?s*=s*s:3===i?s*=s*s*s:4===i&&(s*=s*s*s*s),1===e?1-s:2===e?s:.5>t?s/2:1-s/2},s=["Linear","Quad","Cubic","Quart","Quint,Strong"],r=s.length;--r>-1;)n=s[r]+",Power"+r,P(new y(null,null,1,r),n,"easeOut",!0),P(new y(null,null,2,r),n,"easeIn"+(0===r?",easeNone":"")),P(new y(null,null,3,r),n,"easeInOut");w.linear=h.easing.Linear.easeIn,w.swing=h.easing.Quad.easeInOut;var b=v("events.EventDispatcher",function(t){this._listeners={},this._eventTarget=t||this});n=b.prototype,n.addEventListener=function(t,e,i,s,r){r=r||0;var n,l,h=this._listeners[t],_=0;for(null==h&&(this._listeners[t]=h=[]),l=h.length;--l>-1;)n=h[l],n.c===e&&n.s===i?h.splice(l,1):0===_&&r>n.pr&&(_=l+1);h.splice(_,0,{c:e,s:i,up:s,pr:r}),this!==a||o||a.wake()},n.removeEventListener=function(t,e){var i,s=this._listeners[t];if(s)for(i=s.length;--i>-1;)if(s[i].c===e)return s.splice(i,1),void 0},n.dispatchEvent=function(t){var e,i,s,r=this._listeners[t];if(r)for(e=r.length,i=this._eventTarget;--e>-1;)s=r[e],s&&(s.up?s.c.call(s.s||i,{type:t,target:i}):s.c.call(s.s||i))};var k=t.requestAnimationFrame,A=t.cancelAnimationFrame,S=Date.now||function(){return(new Date).getTime()},x=S();for(s=["ms","moz","webkit","o"],r=s.length;--r>-1&&!k;)k=t[s[r]+"RequestAnimationFrame"],A=t[s[r]+"CancelAnimationFrame"]||t[s[r]+"CancelRequestAnimationFrame"];v("Ticker",function(t,e){var i,s,r,n,l,h=this,u=S(),c=e!==!1&&k,m=500,p=33,d="tick",v=function(t){var e,a,o=S()-x;o>m&&(u+=o-p),x+=o,h.time=(x-u)/1e3,e=h.time-l,(!i||e>0||t===!0)&&(h.frame++,l+=e+(e>=n?.004:n-e),a=!0),t!==!0&&(r=s(v)),a&&h.dispatchEvent(d)};b.call(h),h.time=h.frame=0,h.tick=function(){v(!0)},h.lagSmoothing=function(t,e){m=t||1/_,p=Math.min(e,m,0)},h.sleep=function(){null!=r&&(c&&A?A(r):clearTimeout(r),s=f,r=null,h===a&&(o=!1))},h.wake=function(){null!==r?h.sleep():h.frame>10&&(x=S()-m+5),s=0===i?f:c&&k?k:function(t){return setTimeout(t,0|1e3*(l-h.time)+1)},h===a&&(o=!0),v(2)},h.fps=function(t){return arguments.length?(i=t,n=1/(i||60),l=this.time+n,h.wake(),void 0):i},h.useRAF=function(t){return arguments.length?(h.sleep(),c=t,h.fps(i),void 0):c},h.fps(t),setTimeout(function(){c&&5>h.frame&&h.useRAF(!1)},1500)}),n=h.Ticker.prototype=new h.events.EventDispatcher,n.constructor=h.Ticker;var R=v("core.Animation",function(t,e){if(this.vars=e=e||{},this._duration=this._totalDuration=t||0,this._delay=Number(e.delay)||0,this._timeScale=1,this._active=e.immediateRender===!0,this.data=e.data,this._reversed=e.reversed===!0,H){o||a.wake();var i=this.vars.useFrames?K:H;i.add(this,i._time),this.vars.paused&&this.paused(!0)}});a=R.ticker=new h.Ticker,n=R.prototype,n._dirty=n._gc=n._initted=n._paused=!1,n._totalTime=n._time=0,n._rawPrevTime=-1,n._next=n._last=n._onUpdate=n._timeline=n.timeline=null,n._paused=!1;var C=function(){o&&S()-x>2e3&&a.wake(),setTimeout(C,2e3)};C(),n.play=function(t,e){return null!=t&&this.seek(t,e),this.reversed(!1).paused(!1)},n.pause=function(t,e){return null!=t&&this.seek(t,e),this.paused(!0)},n.resume=function(t,e){return null!=t&&this.seek(t,e),this.paused(!1)},n.seek=function(t,e){return this.totalTime(Number(t),e!==!1)},n.restart=function(t,e){return this.reversed(!1).paused(!1).totalTime(t?-this._delay:0,e!==!1,!0)},n.reverse=function(t,e){return null!=t&&this.seek(t||this.totalDuration(),e),this.reversed(!0).paused(!1)},n.render=function(){},n.invalidate=function(){return this._time=this._totalTime=0,this._initted=this._gc=!1,this._rawPrevTime=-1,(this._gc||!this.timeline)&&this._enabled(!0),this},n.isActive=function(){var t,e=this._timeline,i=this._startTime;return!e||!this._gc&&!this._paused&&e.isActive()&&(t=e.rawTime())>=i&&i+this.totalDuration()/this._timeScale>t},n._enabled=function(t,e){return o||a.wake(),this._gc=!t,this._active=this.isActive(),e!==!0&&(t&&!this.timeline?this._timeline.add(this,this._startTime-this._delay):!t&&this.timeline&&this._timeline._remove(this,!0)),!1},n._kill=function(){return this._enabled(!1,!1)},n.kill=function(t,e){return this._kill(t,e),this},n._uncache=function(t){for(var e=t?this:this.timeline;e;)e._dirty=!0,e=e.timeline;return this},n._swapSelfInParams=function(t){for(var e=t.length,i=t.concat();--e>-1;)"{self}"===t[e]&&(i[e]=this);return i},n._callback=function(t){var e=this.vars;e[t].apply(e[t+"Scope"]||e.callbackScope||this,e[t+"Params"]||T)},n.eventCallback=function(t,e,i,s){if("on"===(t||"").substr(0,2)){var r=this.vars;if(1===arguments.length)return r[t];null==e?delete r[t]:(r[t]=e,r[t+"Params"]=c(i)&&-1!==i.join("").indexOf("{self}")?this._swapSelfInParams(i):i,r[t+"Scope"]=s),"onUpdate"===t&&(this._onUpdate=e)}return this},n.delay=function(t){return arguments.length?(this._timeline.smoothChildTiming&&this.startTime(this._startTime+t-this._delay),this._delay=t,this):this._delay},n.duration=function(t){return arguments.length?(this._duration=this._totalDuration=t,this._uncache(!0),this._timeline.smoothChildTiming&&this._time>0&&this._timethis._duration?this._duration:t,e)):this._time},n.totalTime=function(t,e,i){if(o||a.wake(),!arguments.length)return this._totalTime;if(this._timeline){if(0>t&&!i&&(t+=this.totalDuration()),this._timeline.smoothChildTiming){this._dirty&&this.totalDuration();var s=this._totalDuration,r=this._timeline;if(t>s&&!i&&(t=s),this._startTime=(this._paused?this._pauseTime:r._time)-(this._reversed?s-t:t)/this._timeScale,r._dirty||this._uncache(!1),r._timeline)for(;r._timeline;)r._timeline._time!==(r._startTime+r._totalTime)/r._timeScale&&r.totalTime(r._totalTime,!0),r=r._timeline}this._gc&&this._enabled(!0,!1),(this._totalTime!==t||0===this._duration)&&(z.length&&V(),this.render(t,e,!1),z.length&&V())}return this},n.progress=n.totalProgress=function(t,e){var i=this.duration();return arguments.length?this.totalTime(i*t,e):i?this._time/i:this.ratio},n.startTime=function(t){return arguments.length?(t!==this._startTime&&(this._startTime=t,this.timeline&&this.timeline._sortChildren&&this.timeline.add(this,t-this._delay)),this):this._startTime},n.endTime=function(t){return this._startTime+(0!=t?this.totalDuration():this.duration())/this._timeScale},n.timeScale=function(t){if(!arguments.length)return this._timeScale;if(t=t||_,this._timeline&&this._timeline.smoothChildTiming){var e=this._pauseTime,i=e||0===e?e:this._timeline.totalTime();this._startTime=i-(i-this._startTime)*this._timeScale/t}return this._timeScale=t,this._uncache(!1)},n.reversed=function(t){return arguments.length?(t!=this._reversed&&(this._reversed=t,this.totalTime(this._timeline&&!this._timeline.smoothChildTiming?this.totalDuration()-this._totalTime:this._totalTime,!0)),this):this._reversed},n.paused=function(t){if(!arguments.length)return this._paused;var e,i,s=this._timeline;return t!=this._paused&&s&&(o||t||a.wake(),e=s.rawTime(),i=e-this._pauseTime,!t&&s.smoothChildTiming&&(this._startTime+=i,this._uncache(!1)),this._pauseTime=t?e:null,this._paused=t,this._active=this.isActive(),!t&&0!==i&&this._initted&&this.duration()&&(e=s.smoothChildTiming?this._totalTime:(e-this._startTime)/this._timeScale,this.render(e,e===this._totalTime,!0))),this._gc&&!t&&this._enabled(!0,!1),this};var D=v("core.SimpleTimeline",function(t){R.call(this,0,t),this.autoRemoveChildren=this.smoothChildTiming=!0});n=D.prototype=new R,n.constructor=D,n.kill()._gc=!1,n._first=n._last=n._recent=null,n._sortChildren=!1,n.add=n.insert=function(t,e){var i,s;if(t._startTime=Number(e||0)+t._delay,t._paused&&this!==t._timeline&&(t._pauseTime=t._startTime+(this.rawTime()-t._startTime)/t._timeScale),t.timeline&&t.timeline._remove(t,!0),t.timeline=t._timeline=this,t._gc&&t._enabled(!0,!0),i=this._last,this._sortChildren)for(s=t._startTime;i&&i._startTime>s;)i=i._prev;return i?(t._next=i._next,i._next=t):(t._next=this._first,this._first=t),t._next?t._next._prev=t:this._last=t,t._prev=i,this._recent=t,this._timeline&&this._uncache(!0),this},n._remove=function(t,e){return t.timeline===this&&(e||t._enabled(!1,!0),t._prev?t._prev._next=t._next:this._first===t&&(this._first=t._next),t._next?t._next._prev=t._prev:this._last===t&&(this._last=t._prev),t._next=t._prev=t.timeline=null,t===this._recent&&(this._recent=this._last),this._timeline&&this._uncache(!0)),this},n.render=function(t,e,i){var s,r=this._first;for(this._totalTime=this._time=this._rawPrevTime=t;r;)s=r._next,(r._active||t>=r._startTime&&!r._paused)&&(r._reversed?r.render((r._dirty?r.totalDuration():r._totalDuration)-(t-r._startTime)*r._timeScale,e,i):r.render((t-r._startTime)*r._timeScale,e,i)),r=s},n.rawTime=function(){return o||a.wake(),this._totalTime};var I=v("TweenLite",function(e,i,s){if(R.call(this,i,s),this.render=I.prototype.render,null==e)throw"Cannot tween a null target.";this.target=e="string"!=typeof e?e:I.selector(e)||e;var r,n,a,o=e.jquery||e.length&&e!==t&&e[0]&&(e[0]===t||e[0].nodeType&&e[0].style&&!e.nodeType),l=this.vars.overwrite;if(this._overwrite=l=null==l?$[I.defaultOverwrite]:"number"==typeof l?l>>0:$[l],(o||e instanceof Array||e.push&&c(e))&&"number"!=typeof e[0])for(this._targets=a=u(e),this._propLookup=[],this._siblings=[],r=0;a.length>r;r++)n=a[r],n?"string"!=typeof n?n.length&&n!==t&&n[0]&&(n[0]===t||n[0].nodeType&&n[0].style&&!n.nodeType)?(a.splice(r--,1),this._targets=a=a.concat(u(n))):(this._siblings[r]=W(n,this,!1),1===l&&this._siblings[r].length>1&&Y(n,this,null,1,this._siblings[r])):(n=a[r--]=I.selector(n),"string"==typeof n&&a.splice(r+1,1)):a.splice(r--,1);else this._propLookup={},this._siblings=W(e,this,!1),1===l&&this._siblings.length>1&&Y(e,this,null,1,this._siblings);(this.vars.immediateRender||0===i&&0===this._delay&&this.vars.immediateRender!==!1)&&(this._time=-_,this.render(-this._delay))},!0),E=function(e){return e&&e.length&&e!==t&&e[0]&&(e[0]===t||e[0].nodeType&&e[0].style&&!e.nodeType)},O=function(t,e){var i,s={};for(i in t)M[i]||i in e&&"transform"!==i&&"x"!==i&&"y"!==i&&"width"!==i&&"height"!==i&&"className"!==i&&"border"!==i||!(!Q[i]||Q[i]&&Q[i]._autoCSS)||(s[i]=t[i],delete t[i]);t.css=s};n=I.prototype=new R,n.constructor=I,n.kill()._gc=!1,n.ratio=0,n._firstPT=n._targets=n._overwrittenProps=n._startAt=null,n._notifyPluginsOfEnabled=n._lazy=!1,I.version="1.18.0",I.defaultEase=n._ease=new y(null,null,1,1),I.defaultOverwrite="auto",I.ticker=a,I.autoSleep=120,I.lagSmoothing=function(t,e){a.lagSmoothing(t,e)},I.selector=t.$||t.jQuery||function(e){var i=t.$||t.jQuery;return i?(I.selector=i,i(e)):"undefined"==typeof document?e:document.querySelectorAll?document.querySelectorAll(e):document.getElementById("#"===e.charAt(0)?e.substr(1):e)};var z=[],F={},L=/(?:(-|-=|\+=)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/gi,N=function(t){for(var e,i=this._firstPT,s=1e-6;i;)e=i.blob?t?this.join(""):this.start:i.c*t+i.s,i.r?e=Math.round(e):s>e&&e>-s&&(e=0),i.f?i.fp?i.t[i.p](i.fp,e):i.t[i.p](e):i.t[i.p]=e,i=i._next},U=function(t,e,i,s){var r,n,a,o,l,h,_,u=[t,e],f=0,c="",m=0;for(u.start=t,i&&(i(u),t=u[0],e=u[1]),u.length=0,r=t.match(L)||[],n=e.match(L)||[],s&&(s._next=null,s.blob=1,u._firstPT=s),l=n.length,o=0;l>o;o++)_=n[o],h=e.substr(f,e.indexOf(_,f)-f),c+=h||!o?h:",",f+=h.length,m?m=(m+1)%5:"rgba("===h.substr(-5)&&(m=1),_===r[o]||o>=r.length?c+=_:(c&&(u.push(c),c=""),a=parseFloat(r[o]),u.push(a),u._firstPT={_next:u._firstPT,t:u,p:u.length-1,s:a,c:("="===_.charAt(1)?parseInt(_.charAt(0)+"1",10)*parseFloat(_.substr(2)):parseFloat(_)-a)||0,f:0,r:m&&4>m}),f+=_.length;return c+=e.substr(f),c&&u.push(c),u.setRatio=N,u},j=function(t,e,i,s,r,n,a,o){var l,h,_="get"===i?t[e]:i,u=typeof t[e],f="string"==typeof s&&"="===s.charAt(1),c={t:t,p:e,s:_,f:"function"===u,pg:0,n:r||e,r:n,pr:0,c:f?parseInt(s.charAt(0)+"1",10)*parseFloat(s.substr(2)):parseFloat(s)-_||0};return"number"!==u&&("function"===u&&"get"===i&&(h=e.indexOf("set")||"function"!=typeof t["get"+e.substr(3)]?e:"get"+e.substr(3),c.s=_=a?t[h](a):t[h]()),"string"==typeof _&&(a||isNaN(_))?(c.fp=a,l=U(_,s,o||I.defaultStringFilter,c),c={t:l,p:"setRatio",s:0,c:1,f:2,pg:0,n:r||e,pr:0}):f||(c.c=parseFloat(s)-parseFloat(_)||0)),c.c?((c._next=this._firstPT)&&(c._next._prev=c),this._firstPT=c,c):void 0},G=I._internals={isArray:c,isSelector:E,lazyTweens:z,blobDif:U},Q=I._plugins={},q=G.tweenLookup={},B=0,M=G.reservedProps={ease:1,delay:1,overwrite:1,onComplete:1,onCompleteParams:1,onCompleteScope:1,useFrames:1,runBackwards:1,startAt:1,onUpdate:1,onUpdateParams:1,onUpdateScope:1,onStart:1,onStartParams:1,onStartScope:1,onReverseComplete:1,onReverseCompleteParams:1,onReverseCompleteScope:1,onRepeat:1,onRepeatParams:1,onRepeatScope:1,easeParams:1,yoyo:1,immediateRender:1,repeat:1,repeatDelay:1,data:1,paused:1,reversed:1,autoCSS:1,lazy:1,onOverwrite:1,callbackScope:1,stringFilter:1},$={none:0,all:1,auto:2,concurrent:3,allOnStart:4,preexisting:5,"true":1,"false":0},K=R._rootFramesTimeline=new D,H=R._rootTimeline=new D,J=30,V=G.lazyRender=function(){var t,e=z.length;for(F={};--e>-1;)t=z[e],t&&t._lazy!==!1&&(t.render(t._lazy[0],t._lazy[1],!0),t._lazy=!1);z.length=0};H._startTime=a.time,K._startTime=a.frame,H._active=K._active=!0,setTimeout(V,1),R._updateRoot=I.render=function(){var t,e,i;if(z.length&&V(),H.render((a.time-H._startTime)*H._timeScale,!1,!1),K.render((a.frame-K._startTime)*K._timeScale,!1,!1),z.length&&V(),a.frame>=J){J=a.frame+(parseInt(I.autoSleep,10)||120);for(i in q){for(e=q[i].tweens,t=e.length;--t>-1;)e[t]._gc&&e.splice(t,1);0===e.length&&delete q[i]}if(i=H._first,(!i||i._paused)&&I.autoSleep&&!K._first&&1===a._listeners.tick.length){for(;i&&i._paused;)i=i._next;i||a.sleep()}}},a.addEventListener("tick",R._updateRoot);var W=function(t,e,i){var s,r,n=t._gsTweenID;if(q[n||(t._gsTweenID=n="t"+B++)]||(q[n]={target:t,tweens:[]}),e&&(s=q[n].tweens,s[r=s.length]=e,i))for(;--r>-1;)s[r]===e&&s.splice(r,1);return q[n].tweens},X=function(t,e,i,s){var r,n,a=t.vars.onOverwrite;return a&&(r=a(t,e,i,s)),a=I.onOverwrite,a&&(n=a(t,e,i,s)),r!==!1&&n!==!1},Y=function(t,e,i,s,r){var n,a,o,l;if(1===s||s>=4){for(l=r.length,n=0;l>n;n++)if((o=r[n])!==e)o._gc||o._kill(null,t,e)&&(a=!0);else if(5===s)break;return a}var h,u=e._startTime+_,f=[],c=0,m=0===e._duration;for(n=r.length;--n>-1;)(o=r[n])===e||o._gc||o._paused||(o._timeline!==e._timeline?(h=h||Z(e,0,m),0===Z(o,h,m)&&(f[c++]=o)):u>=o._startTime&&o._startTime+o.totalDuration()/o._timeScale>u&&((m||!o._initted)&&2e-10>=u-o._startTime||(f[c++]=o)));for(n=c;--n>-1;)if(o=f[n],2===s&&o._kill(i,t,e)&&(a=!0),2!==s||!o._firstPT&&o._initted){if(2!==s&&!X(o,e))continue;o._enabled(!1,!1)&&(a=!0)}return a},Z=function(t,e,i){for(var s=t._timeline,r=s._timeScale,n=t._startTime;s._timeline;){if(n+=s._startTime,r*=s._timeScale,s._paused)return-100;s=s._timeline}return n/=r,n>e?n-e:i&&n===e||!t._initted&&2*_>n-e?_:(n+=t.totalDuration()/t._timeScale/r)>e+_?0:n-e-_};n._init=function(){var t,e,i,s,r,n=this.vars,a=this._overwrittenProps,o=this._duration,l=!!n.immediateRender,h=n.ease;if(n.startAt){this._startAt&&(this._startAt.render(-1,!0),this._startAt.kill()),r={};for(s in n.startAt)r[s]=n.startAt[s];if(r.overwrite=!1,r.immediateRender=!0,r.lazy=l&&n.lazy!==!1,r.startAt=r.delay=null,this._startAt=I.to(this.target,0,r),l)if(this._time>0)this._startAt=null;else if(0!==o)return}else if(n.runBackwards&&0!==o)if(this._startAt)this._startAt.render(-1,!0),this._startAt.kill(),this._startAt=null;else{0!==this._time&&(l=!1),i={};for(s in n)M[s]&&"autoCSS"!==s||(i[s]=n[s]);if(i.overwrite=0,i.data="isFromStart",i.lazy=l&&n.lazy!==!1,i.immediateRender=l,this._startAt=I.to(this.target,0,i),l){if(0===this._time)return}else this._startAt._init(),this._startAt._enabled(!1),this.vars.immediateRender&&(this._startAt=null)}if(this._ease=h=h?h instanceof y?h:"function"==typeof h?new y(h,n.easeParams):w[h]||I.defaultEase:I.defaultEase,n.easeParams instanceof Array&&h.config&&(this._ease=h.config.apply(h,n.easeParams)),this._easeType=this._ease._type,this._easePower=this._ease._power,this._firstPT=null,this._targets)for(t=this._targets.length;--t>-1;)this._initProps(this._targets[t],this._propLookup[t]={},this._siblings[t],a?a[t]:null)&&(e=!0);else e=this._initProps(this.target,this._propLookup,this._siblings,a);if(e&&I._onPluginEvent("_onInitAllProps",this),a&&(this._firstPT||"function"!=typeof this.target&&this._enabled(!1,!1)),n.runBackwards)for(i=this._firstPT;i;)i.s+=i.c,i.c=-i.c,i=i._next;this._onUpdate=n.onUpdate,this._initted=!0},n._initProps=function(e,i,s,r){var n,a,o,l,h,_;if(null==e)return!1;F[e._gsTweenID]&&V(),this.vars.css||e.style&&e!==t&&e.nodeType&&Q.css&&this.vars.autoCSS!==!1&&O(this.vars,e);for(n in this.vars)if(_=this.vars[n],M[n])_&&(_ instanceof Array||_.push&&c(_))&&-1!==_.join("").indexOf("{self}")&&(this.vars[n]=_=this._swapSelfInParams(_,this));else if(Q[n]&&(l=new Q[n])._onInitTween(e,this.vars[n],this)){for(this._firstPT=h={_next:this._firstPT,t:l,p:"setRatio",s:0,c:1,f:1,n:n,pg:1,pr:l._priority},a=l._overwriteProps.length;--a>-1;)i[l._overwriteProps[a]]=this._firstPT;(l._priority||l._onInitAllProps)&&(o=!0),(l._onDisable||l._onEnable)&&(this._notifyPluginsOfEnabled=!0),h._next&&(h._next._prev=h)}else i[n]=j.call(this,e,n,"get",_,n,0,null,this.vars.stringFilter);return r&&this._kill(r,e)?this._initProps(e,i,s,r):this._overwrite>1&&this._firstPT&&s.length>1&&Y(e,this,i,this._overwrite,s)?(this._kill(i,e),this._initProps(e,i,s,r)):(this._firstPT&&(this.vars.lazy!==!1&&this._duration||this.vars.lazy&&!this._duration)&&(F[e._gsTweenID]=!0),o)},n.render=function(t,e,i){var s,r,n,a,o=this._time,l=this._duration,h=this._rawPrevTime;if(t>=l)this._totalTime=this._time=l,this.ratio=this._ease._calcEnd?this._ease.getRatio(1):1,this._reversed||(s=!0,r="onComplete",i=i||this._timeline.autoRemoveChildren),0===l&&(this._initted||!this.vars.lazy||i)&&(this._startTime===this._timeline._duration&&(t=0),(0===t||0>h||h===_&&"isPause"!==this.data)&&h!==t&&(i=!0,h>_&&(r="onReverseComplete")),this._rawPrevTime=a=!e||t||h===t?t:_);else if(1e-7>t)this._totalTime=this._time=0,this.ratio=this._ease._calcEnd?this._ease.getRatio(0):0,(0!==o||0===l&&h>0)&&(r="onReverseComplete",s=this._reversed),0>t&&(this._active=!1,0===l&&(this._initted||!this.vars.lazy||i)&&(h>=0&&(h!==_||"isPause"!==this.data)&&(i=!0),this._rawPrevTime=a=!e||t||h===t?t:_)),this._initted||(i=!0);else if(this._totalTime=this._time=t,this._easeType){var u=t/l,f=this._easeType,c=this._easePower;(1===f||3===f&&u>=.5)&&(u=1-u),3===f&&(u*=2),1===c?u*=u:2===c?u*=u*u:3===c?u*=u*u*u:4===c&&(u*=u*u*u*u),this.ratio=1===f?1-u:2===f?u:.5>t/l?u/2:1-u/2}else this.ratio=this._ease.getRatio(t/l);if(this._time!==o||i){if(!this._initted){if(this._init(),!this._initted||this._gc)return;if(!i&&this._firstPT&&(this.vars.lazy!==!1&&this._duration||this.vars.lazy&&!this._duration))return this._time=this._totalTime=o,this._rawPrevTime=h,z.push(this),this._lazy=[t,e],void 0;this._time&&!s?this.ratio=this._ease.getRatio(this._time/l):s&&this._ease._calcEnd&&(this.ratio=this._ease.getRatio(0===this._time?0:1))}for(this._lazy!==!1&&(this._lazy=!1),this._active||!this._paused&&this._time!==o&&t>=0&&(this._active=!0),0===o&&(this._startAt&&(t>=0?this._startAt.render(t,e,i):r||(r="_dummyGS")),this.vars.onStart&&(0!==this._time||0===l)&&(e||this._callback("onStart"))),n=this._firstPT;n;)n.f?n.t[n.p](n.c*this.ratio+n.s):n.t[n.p]=n.c*this.ratio+n.s,n=n._next;this._onUpdate&&(0>t&&this._startAt&&t!==-1e-4&&this._startAt.render(t,e,i),e||(this._time!==o||s)&&this._callback("onUpdate")),r&&(!this._gc||i)&&(0>t&&this._startAt&&!this._onUpdate&&t!==-1e-4&&this._startAt.render(t,e,i),s&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!e&&this.vars[r]&&this._callback(r),0===l&&this._rawPrevTime===_&&a!==_&&(this._rawPrevTime=0))}},n._kill=function(t,e,i){if("all"===t&&(t=null),null==t&&(null==e||e===this.target))return this._lazy=!1,this._enabled(!1,!1);e="string"!=typeof e?e||this._targets||this.target:I.selector(e)||e;var s,r,n,a,o,l,h,_,u,f=i&&this._time&&i._startTime===this._startTime&&this._timeline===i._timeline;if((c(e)||E(e))&&"number"!=typeof e[0])for(s=e.length;--s>-1;)this._kill(t,e[s],i)&&(l=!0);else{if(this._targets){for(s=this._targets.length;--s>-1;)if(e===this._targets[s]){o=this._propLookup[s]||{},this._overwrittenProps=this._overwrittenProps||[],r=this._overwrittenProps[s]=t?this._overwrittenProps[s]||{}:"all";break}}else{if(e!==this.target)return!1;o=this._propLookup,r=this._overwrittenProps=t?this._overwrittenProps||{}:"all"}if(o){if(h=t||o,_=t!==r&&"all"!==r&&t!==o&&("object"!=typeof t||!t._tempKill),i&&(I.onOverwrite||this.vars.onOverwrite)){for(n in h)o[n]&&(u||(u=[]),u.push(n));if((u||!t)&&!X(this,i,e,u))return!1}for(n in h)(a=o[n])&&(f&&(a.f?a.t[a.p](a.s):a.t[a.p]=a.s,l=!0),a.pg&&a.t._kill(h)&&(l=!0),a.pg&&0!==a.t._overwriteProps.length||(a._prev?a._prev._next=a._next:a===this._firstPT&&(this._firstPT=a._next),a._next&&(a._next._prev=a._prev),a._next=a._prev=null),delete o[n]),_&&(r[n]=1);!this._firstPT&&this._initted&&this._enabled(!1,!1)}}return l},n.invalidate=function(){return this._notifyPluginsOfEnabled&&I._onPluginEvent("_onDisable",this),this._firstPT=this._overwrittenProps=this._startAt=this._onUpdate=null,this._notifyPluginsOfEnabled=this._active=this._lazy=!1,this._propLookup=this._targets?{}:[],R.prototype.invalidate.call(this),this.vars.immediateRender&&(this._time=-_,this.render(-this._delay)),this},n._enabled=function(t,e){if(o||a.wake(),t&&this._gc){var i,s=this._targets;if(s)for(i=s.length;--i>-1;)this._siblings[i]=W(s[i],this,!0);else this._siblings=W(this.target,this,!0)}return R.prototype._enabled.call(this,t,e),this._notifyPluginsOfEnabled&&this._firstPT?I._onPluginEvent(t?"_onEnable":"_onDisable",this):!1},I.to=function(t,e,i){return new I(t,e,i)},I.from=function(t,e,i){return i.runBackwards=!0,i.immediateRender=0!=i.immediateRender,new I(t,e,i)},I.fromTo=function(t,e,i,s){return s.startAt=i,s.immediateRender=0!=s.immediateRender&&0!=i.immediateRender,new I(t,e,s)},I.delayedCall=function(t,e,i,s,r){return new I(e,0,{delay:t,onComplete:e,onCompleteParams:i,callbackScope:s,onReverseComplete:e,onReverseCompleteParams:i,immediateRender:!1,lazy:!1,useFrames:r,overwrite:0})},I.set=function(t,e){return new I(t,0,e)},I.getTweensOf=function(t,e){if(null==t)return[];t="string"!=typeof t?t:I.selector(t)||t;var i,s,r,n;if((c(t)||E(t))&&"number"!=typeof t[0]){for(i=t.length,s=[];--i>-1;)s=s.concat(I.getTweensOf(t[i],e));for(i=s.length;--i>-1;)for(n=s[i],r=i;--r>-1;)n===s[r]&&s.splice(i,1)}else for(s=W(t).concat(),i=s.length;--i>-1;)(s[i]._gc||e&&!s[i].isActive())&&s.splice(i,1);return s},I.killTweensOf=I.killDelayedCallsTo=function(t,e,i){"object"==typeof e&&(i=e,e=!1);for(var s=I.getTweensOf(t,e),r=s.length;--r>-1;)s[r]._kill(i,t)};var te=v("plugins.TweenPlugin",function(t,e){this._overwriteProps=(t||"").split(","),this._propName=this._overwriteProps[0],this._priority=e||0,this._super=te.prototype},!0);if(n=te.prototype,te.version="1.18.0",te.API=2,n._firstPT=null,n._addTween=j,n.setRatio=N,n._kill=function(t){var e,i=this._overwriteProps,s=this._firstPT;if(null!=t[this._propName])this._overwriteProps=[];else for(e=i.length;--e>-1;)null!=t[i[e]]&&i.splice(e,1);for(;s;)null!=t[s.n]&&(s._next&&(s._next._prev=s._prev),s._prev?(s._prev._next=s._next,s._prev=null):this._firstPT===s&&(this._firstPT=s._next)),s=s._next;return!1},n._roundProps=function(t,e){for(var i=this._firstPT;i;)(t[this._propName]||null!=i.n&&t[i.n.split(this._propName+"_").join("")])&&(i.r=e),i=i._next},I._onPluginEvent=function(t,e){var i,s,r,n,a,o=e._firstPT;if("_onInitAllProps"===t){for(;o;){for(a=o._next,s=r;s&&s.pr>o.pr;)s=s._next;(o._prev=s?s._prev:n)?o._prev._next=o:r=o,(o._next=s)?s._prev=o:n=o,o=a}o=e._firstPT=r}for(;o;)o.pg&&"function"==typeof o.t[t]&&o.t[t]()&&(i=!0),o=o._next;return i},te.activate=function(t){for(var e=t.length;--e>-1;)t[e].API===te.API&&(Q[(new t[e])._propName]=t[e]);return!0},d.plugin=function(t){if(!(t&&t.propName&&t.init&&t.API))throw"illegal plugin definition.";var e,i=t.propName,s=t.priority||0,r=t.overwriteProps,n={init:"_onInitTween",set:"setRatio",kill:"_kill",round:"_roundProps",initAll:"_onInitAllProps"},a=v("plugins."+i.charAt(0).toUpperCase()+i.substr(1)+"Plugin",function(){te.call(this,i,s),this._overwriteProps=r||[]},t.global===!0),o=a.prototype=new te(i);o.constructor=a,a.API=t.API;for(e in n)"function"==typeof t[e]&&(o[n[e]]=t[e]);return a.version=t.version,te.activate([a]),a},s=t._gsQueue){for(r=0;s.length>r;r++)s[r]();for(n in m)m[n].func||t.console.log("GSAP encountered missing dependency: com.greensock."+n)}o=!1}})("undefined"!=typeof module&&module.exports&&"undefined"!=typeof global?global:this||window,"TweenLite"); -------------------------------------------------------------------------------- /js/utils/OrbitControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author qiao / https://github.com/qiao 3 | * @author mrdoob / http://mrdoob.com 4 | * @author alteredq / http://alteredqualia.com/ 5 | * @author WestLangley / http://github.com/WestLangley 6 | * @author erich666 / http://erichaines.com 7 | */ 8 | 9 | // This set of controls performs orbiting, dollying (zooming), and panning. 10 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). 11 | // 12 | // Orbit - left mouse / touch: one finger move 13 | // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish 14 | // Pan - right mouse, or arrow keys / touch: three finger swipe 15 | 16 | THREE.OrbitControls = function ( object, domElement ) { 17 | 18 | this.object = object; 19 | 20 | this.domElement = ( domElement !== undefined ) ? domElement : document; 21 | 22 | // Set to false to disable this control 23 | this.enabled = true; 24 | 25 | // "target" sets the location of focus, where the object orbits around 26 | this.target = new THREE.Vector3(); 27 | 28 | // How far you can dolly in and out ( PerspectiveCamera only ) 29 | this.minDistance = 0; 30 | this.maxDistance = Infinity; 31 | 32 | // How far you can zoom in and out ( OrthographicCamera only ) 33 | this.minZoom = 0; 34 | this.maxZoom = Infinity; 35 | 36 | // How far you can orbit vertically, upper and lower limits. 37 | // Range is 0 to Math.PI radians. 38 | this.minPolarAngle = 0; // radians 39 | this.maxPolarAngle = Math.PI; // radians 40 | 41 | // How far you can orbit horizontally, upper and lower limits. 42 | // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. 43 | this.minAzimuthAngle = - Infinity; // radians 44 | this.maxAzimuthAngle = Infinity; // radians 45 | 46 | // Set to true to enable damping (inertia) 47 | // If damping is enabled, you must call controls.update() in your animation loop 48 | this.enableDamping = false; 49 | this.dampingFactor = 0.25; 50 | 51 | // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. 52 | // Set to false to disable zooming 53 | this.enableZoom = true; 54 | this.zoomSpeed = 1.0; 55 | 56 | // Set to false to disable rotating 57 | this.enableRotate = true; 58 | this.rotateSpeed = 1.0; 59 | 60 | // Set to false to disable panning 61 | this.enablePan = true; 62 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push 63 | 64 | // Set to true to automatically rotate around the target 65 | // If auto-rotate is enabled, you must call controls.update() in your animation loop 66 | this.autoRotate = false; 67 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 68 | 69 | // Set to false to disable use of the keys 70 | this.enableKeys = true; 71 | 72 | // The four arrow keys 73 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; 74 | 75 | // Mouse buttons 76 | this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; 77 | 78 | // for reset 79 | this.target0 = this.target.clone(); 80 | this.position0 = this.object.position.clone(); 81 | this.zoom0 = this.object.zoom; 82 | 83 | // 84 | // public methods 85 | // 86 | 87 | this.getPolarAngle = function () { 88 | 89 | return spherical.phi; 90 | 91 | }; 92 | 93 | this.getAzimuthalAngle = function () { 94 | 95 | return spherical.theta; 96 | 97 | }; 98 | 99 | this.saveState = function () { 100 | 101 | scope.target0.copy( scope.target ); 102 | scope.position0.copy( scope.object.position ); 103 | scope.zoom0 = scope.object.zoom; 104 | 105 | }; 106 | 107 | this.reset = function () { 108 | 109 | scope.target.copy( scope.target0 ); 110 | scope.object.position.copy( scope.position0 ); 111 | scope.object.zoom = scope.zoom0; 112 | 113 | scope.object.updateProjectionMatrix(); 114 | scope.dispatchEvent( changeEvent ); 115 | 116 | scope.update(); 117 | 118 | state = STATE.NONE; 119 | 120 | }; 121 | 122 | // this method is exposed, but perhaps it would be better if we can make it private... 123 | this.update = function () { 124 | 125 | var offset = new THREE.Vector3(); 126 | 127 | // so camera.up is the orbit axis 128 | var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); 129 | var quatInverse = quat.clone().inverse(); 130 | 131 | var lastPosition = new THREE.Vector3(); 132 | var lastQuaternion = new THREE.Quaternion(); 133 | 134 | return function update() { 135 | 136 | var position = scope.object.position; 137 | 138 | offset.copy( position ).sub( scope.target ); 139 | 140 | // rotate offset to "y-axis-is-up" space 141 | offset.applyQuaternion( quat ); 142 | 143 | // angle from z-axis around y-axis 144 | spherical.setFromVector3( offset ); 145 | 146 | if ( scope.autoRotate && state === STATE.NONE ) { 147 | 148 | rotateLeft( getAutoRotationAngle() ); 149 | 150 | } 151 | 152 | spherical.theta += sphericalDelta.theta; 153 | spherical.phi += sphericalDelta.phi; 154 | 155 | // restrict theta to be between desired limits 156 | spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) ); 157 | 158 | // restrict phi to be between desired limits 159 | spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) ); 160 | 161 | spherical.makeSafe(); 162 | 163 | 164 | spherical.radius *= scale; 165 | 166 | // restrict radius to be between desired limits 167 | spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); 168 | 169 | // move target to panned location 170 | scope.target.add( panOffset ); 171 | 172 | offset.setFromSpherical( spherical ); 173 | 174 | // rotate offset back to "camera-up-vector-is-up" space 175 | offset.applyQuaternion( quatInverse ); 176 | 177 | position.copy( scope.target ).add( offset ); 178 | 179 | scope.object.lookAt( scope.target ); 180 | 181 | if ( scope.enableDamping === true ) { 182 | 183 | sphericalDelta.theta *= ( 1 - scope.dampingFactor ); 184 | sphericalDelta.phi *= ( 1 - scope.dampingFactor ); 185 | 186 | } else { 187 | 188 | sphericalDelta.set( 0, 0, 0 ); 189 | 190 | } 191 | 192 | scale = 1; 193 | panOffset.set( 0, 0, 0 ); 194 | 195 | // update condition is: 196 | // min(camera displacement, camera rotation in radians)^2 > EPS 197 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8 198 | 199 | if ( zoomChanged || 200 | lastPosition.distanceToSquared( scope.object.position ) > EPS || 201 | 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { 202 | 203 | scope.dispatchEvent( changeEvent ); 204 | 205 | lastPosition.copy( scope.object.position ); 206 | lastQuaternion.copy( scope.object.quaternion ); 207 | zoomChanged = false; 208 | 209 | return true; 210 | 211 | } 212 | 213 | return false; 214 | 215 | }; 216 | 217 | }(); 218 | 219 | this.dispose = function () { 220 | 221 | scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false ); 222 | scope.domElement.removeEventListener( 'mousedown', onMouseDown, false ); 223 | scope.domElement.removeEventListener( 'wheel', onMouseWheel, false ); 224 | 225 | scope.domElement.removeEventListener( 'touchstart', onTouchStart, false ); 226 | scope.domElement.removeEventListener( 'touchend', onTouchEnd, false ); 227 | scope.domElement.removeEventListener( 'touchmove', onTouchMove, false ); 228 | 229 | document.removeEventListener( 'mousemove', onMouseMove, false ); 230 | document.removeEventListener( 'mouseup', onMouseUp, false ); 231 | 232 | window.removeEventListener( 'keydown', onKeyDown, false ); 233 | 234 | //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? 235 | 236 | }; 237 | 238 | // 239 | // internals 240 | // 241 | 242 | var scope = this; 243 | 244 | var changeEvent = { type: 'change' }; 245 | var startEvent = { type: 'start' }; 246 | var endEvent = { type: 'end' }; 247 | 248 | var STATE = { NONE: - 1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY: 4, TOUCH_PAN: 5 }; 249 | 250 | var state = STATE.NONE; 251 | 252 | var EPS = 0.000001; 253 | 254 | // current position in spherical coordinates 255 | var spherical = new THREE.Spherical(); 256 | var sphericalDelta = new THREE.Spherical(); 257 | 258 | var scale = 1; 259 | var panOffset = new THREE.Vector3(); 260 | var zoomChanged = false; 261 | 262 | var rotateStart = new THREE.Vector2(); 263 | var rotateEnd = new THREE.Vector2(); 264 | var rotateDelta = new THREE.Vector2(); 265 | 266 | var panStart = new THREE.Vector2(); 267 | var panEnd = new THREE.Vector2(); 268 | var panDelta = new THREE.Vector2(); 269 | 270 | var dollyStart = new THREE.Vector2(); 271 | var dollyEnd = new THREE.Vector2(); 272 | var dollyDelta = new THREE.Vector2(); 273 | 274 | function getAutoRotationAngle() { 275 | 276 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; 277 | 278 | } 279 | 280 | function getZoomScale() { 281 | 282 | return Math.pow( 0.95, scope.zoomSpeed ); 283 | 284 | } 285 | 286 | function rotateLeft( angle ) { 287 | 288 | sphericalDelta.theta -= angle; 289 | 290 | } 291 | 292 | function rotateUp( angle ) { 293 | 294 | sphericalDelta.phi -= angle; 295 | 296 | } 297 | 298 | var panLeft = function () { 299 | 300 | var v = new THREE.Vector3(); 301 | 302 | return function panLeft( distance, objectMatrix ) { 303 | 304 | v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix 305 | v.multiplyScalar( - distance ); 306 | 307 | panOffset.add( v ); 308 | 309 | }; 310 | 311 | }(); 312 | 313 | var panUp = function () { 314 | 315 | var v = new THREE.Vector3(); 316 | 317 | return function panUp( distance, objectMatrix ) { 318 | 319 | v.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix 320 | v.multiplyScalar( distance ); 321 | 322 | panOffset.add( v ); 323 | 324 | }; 325 | 326 | }(); 327 | 328 | // deltaX and deltaY are in pixels; right and down are positive 329 | var pan = function () { 330 | 331 | var offset = new THREE.Vector3(); 332 | 333 | return function pan( deltaX, deltaY ) { 334 | 335 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 336 | 337 | if ( scope.object instanceof THREE.PerspectiveCamera ) { 338 | 339 | // perspective 340 | var position = scope.object.position; 341 | offset.copy( position ).sub( scope.target ); 342 | var targetDistance = offset.length(); 343 | 344 | // half of the fov is center to top of screen 345 | targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); 346 | 347 | // we actually don't use screenWidth, since perspective camera is fixed to screen height 348 | panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix ); 349 | panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix ); 350 | 351 | } else if ( scope.object instanceof THREE.OrthographicCamera ) { 352 | 353 | // orthographic 354 | panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix ); 355 | panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix ); 356 | 357 | } else { 358 | 359 | // camera neither orthographic nor perspective 360 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); 361 | scope.enablePan = false; 362 | 363 | } 364 | 365 | }; 366 | 367 | }(); 368 | 369 | function dollyIn( dollyScale ) { 370 | 371 | if ( scope.object instanceof THREE.PerspectiveCamera ) { 372 | 373 | scale /= dollyScale; 374 | 375 | } else if ( scope.object instanceof THREE.OrthographicCamera ) { 376 | 377 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); 378 | scope.object.updateProjectionMatrix(); 379 | zoomChanged = true; 380 | 381 | } else { 382 | 383 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); 384 | scope.enableZoom = false; 385 | 386 | } 387 | 388 | } 389 | 390 | function dollyOut( dollyScale ) { 391 | 392 | if ( scope.object instanceof THREE.PerspectiveCamera ) { 393 | 394 | scale *= dollyScale; 395 | 396 | } else if ( scope.object instanceof THREE.OrthographicCamera ) { 397 | 398 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); 399 | scope.object.updateProjectionMatrix(); 400 | zoomChanged = true; 401 | 402 | } else { 403 | 404 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); 405 | scope.enableZoom = false; 406 | 407 | } 408 | 409 | } 410 | 411 | // 412 | // event callbacks - update the object state 413 | // 414 | 415 | function handleMouseDownRotate( event ) { 416 | 417 | //console.log( 'handleMouseDownRotate' ); 418 | 419 | rotateStart.set( event.clientX, event.clientY ); 420 | 421 | } 422 | 423 | function handleMouseDownDolly( event ) { 424 | 425 | //console.log( 'handleMouseDownDolly' ); 426 | 427 | dollyStart.set( event.clientX, event.clientY ); 428 | 429 | } 430 | 431 | function handleMouseDownPan( event ) { 432 | 433 | //console.log( 'handleMouseDownPan' ); 434 | 435 | panStart.set( event.clientX, event.clientY ); 436 | 437 | } 438 | 439 | function handleMouseMoveRotate( event ) { 440 | 441 | //console.log( 'handleMouseMoveRotate' ); 442 | 443 | rotateEnd.set( event.clientX, event.clientY ); 444 | rotateDelta.subVectors( rotateEnd, rotateStart ); 445 | 446 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 447 | 448 | // rotating across whole screen goes 360 degrees around 449 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); 450 | 451 | // rotating up and down along whole screen attempts to go 360, but limited to 180 452 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); 453 | 454 | rotateStart.copy( rotateEnd ); 455 | 456 | scope.update(); 457 | 458 | } 459 | 460 | function handleMouseMoveDolly( event ) { 461 | 462 | //console.log( 'handleMouseMoveDolly' ); 463 | 464 | dollyEnd.set( event.clientX, event.clientY ); 465 | 466 | dollyDelta.subVectors( dollyEnd, dollyStart ); 467 | 468 | if ( dollyDelta.y > 0 ) { 469 | 470 | dollyIn( getZoomScale() ); 471 | 472 | } else if ( dollyDelta.y < 0 ) { 473 | 474 | dollyOut( getZoomScale() ); 475 | 476 | } 477 | 478 | dollyStart.copy( dollyEnd ); 479 | 480 | scope.update(); 481 | 482 | } 483 | 484 | function handleMouseMovePan( event ) { 485 | 486 | //console.log( 'handleMouseMovePan' ); 487 | 488 | panEnd.set( event.clientX, event.clientY ); 489 | 490 | panDelta.subVectors( panEnd, panStart ); 491 | 492 | pan( panDelta.x, panDelta.y ); 493 | 494 | panStart.copy( panEnd ); 495 | 496 | scope.update(); 497 | 498 | } 499 | 500 | function handleMouseUp( event ) { 501 | 502 | // console.log( 'handleMouseUp' ); 503 | 504 | } 505 | 506 | function handleMouseWheel( event ) { 507 | 508 | // console.log( 'handleMouseWheel' ); 509 | 510 | if ( event.deltaY < 0 ) { 511 | 512 | dollyOut( getZoomScale() ); 513 | 514 | } else if ( event.deltaY > 0 ) { 515 | 516 | dollyIn( getZoomScale() ); 517 | 518 | } 519 | 520 | scope.update(); 521 | 522 | } 523 | 524 | function handleKeyDown( event ) { 525 | 526 | //console.log( 'handleKeyDown' ); 527 | 528 | switch ( event.keyCode ) { 529 | 530 | case scope.keys.UP: 531 | pan( 0, scope.keyPanSpeed ); 532 | scope.update(); 533 | break; 534 | 535 | case scope.keys.BOTTOM: 536 | pan( 0, - scope.keyPanSpeed ); 537 | scope.update(); 538 | break; 539 | 540 | case scope.keys.LEFT: 541 | pan( scope.keyPanSpeed, 0 ); 542 | scope.update(); 543 | break; 544 | 545 | case scope.keys.RIGHT: 546 | pan( - scope.keyPanSpeed, 0 ); 547 | scope.update(); 548 | break; 549 | 550 | } 551 | 552 | } 553 | 554 | function handleTouchStartRotate( event ) { 555 | 556 | //console.log( 'handleTouchStartRotate' ); 557 | 558 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 559 | 560 | } 561 | 562 | function handleTouchStartDolly( event ) { 563 | 564 | //console.log( 'handleTouchStartDolly' ); 565 | 566 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 567 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 568 | 569 | var distance = Math.sqrt( dx * dx + dy * dy ); 570 | 571 | dollyStart.set( 0, distance ); 572 | 573 | } 574 | 575 | function handleTouchStartPan( event ) { 576 | 577 | //console.log( 'handleTouchStartPan' ); 578 | 579 | panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 580 | 581 | } 582 | 583 | function handleTouchMoveRotate( event ) { 584 | 585 | //console.log( 'handleTouchMoveRotate' ); 586 | 587 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 588 | rotateDelta.subVectors( rotateEnd, rotateStart ); 589 | 590 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 591 | 592 | // rotating across whole screen goes 360 degrees around 593 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); 594 | 595 | // rotating up and down along whole screen attempts to go 360, but limited to 180 596 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); 597 | 598 | rotateStart.copy( rotateEnd ); 599 | 600 | scope.update(); 601 | 602 | } 603 | 604 | function handleTouchMoveDolly( event ) { 605 | 606 | //console.log( 'handleTouchMoveDolly' ); 607 | 608 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 609 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 610 | 611 | var distance = Math.sqrt( dx * dx + dy * dy ); 612 | 613 | dollyEnd.set( 0, distance ); 614 | 615 | dollyDelta.subVectors( dollyEnd, dollyStart ); 616 | 617 | if ( dollyDelta.y > 0 ) { 618 | 619 | dollyOut( getZoomScale() ); 620 | 621 | } else if ( dollyDelta.y < 0 ) { 622 | 623 | dollyIn( getZoomScale() ); 624 | 625 | } 626 | 627 | dollyStart.copy( dollyEnd ); 628 | 629 | scope.update(); 630 | 631 | } 632 | 633 | function handleTouchMovePan( event ) { 634 | 635 | //console.log( 'handleTouchMovePan' ); 636 | 637 | panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 638 | 639 | panDelta.subVectors( panEnd, panStart ); 640 | 641 | pan( panDelta.x, panDelta.y ); 642 | 643 | panStart.copy( panEnd ); 644 | 645 | scope.update(); 646 | 647 | } 648 | 649 | function handleTouchEnd( event ) { 650 | 651 | //console.log( 'handleTouchEnd' ); 652 | 653 | } 654 | 655 | // 656 | // event handlers - FSM: listen for events and reset state 657 | // 658 | 659 | function onMouseDown( event ) { 660 | 661 | if ( scope.enabled === false ) return; 662 | 663 | event.preventDefault(); 664 | 665 | switch ( event.button ) { 666 | 667 | case scope.mouseButtons.ORBIT: 668 | 669 | if ( scope.enableRotate === false ) return; 670 | 671 | handleMouseDownRotate( event ); 672 | 673 | state = STATE.ROTATE; 674 | 675 | break; 676 | 677 | case scope.mouseButtons.ZOOM: 678 | 679 | if ( scope.enableZoom === false ) return; 680 | 681 | handleMouseDownDolly( event ); 682 | 683 | state = STATE.DOLLY; 684 | 685 | break; 686 | 687 | case scope.mouseButtons.PAN: 688 | 689 | if ( scope.enablePan === false ) return; 690 | 691 | handleMouseDownPan( event ); 692 | 693 | state = STATE.PAN; 694 | 695 | break; 696 | 697 | } 698 | 699 | if ( state !== STATE.NONE ) { 700 | 701 | document.addEventListener( 'mousemove', onMouseMove, false ); 702 | document.addEventListener( 'mouseup', onMouseUp, false ); 703 | 704 | scope.dispatchEvent( startEvent ); 705 | 706 | } 707 | 708 | } 709 | 710 | function onMouseMove( event ) { 711 | 712 | if ( scope.enabled === false ) return; 713 | 714 | event.preventDefault(); 715 | 716 | switch ( state ) { 717 | 718 | case STATE.ROTATE: 719 | 720 | if ( scope.enableRotate === false ) return; 721 | 722 | handleMouseMoveRotate( event ); 723 | 724 | break; 725 | 726 | case STATE.DOLLY: 727 | 728 | if ( scope.enableZoom === false ) return; 729 | 730 | handleMouseMoveDolly( event ); 731 | 732 | break; 733 | 734 | case STATE.PAN: 735 | 736 | if ( scope.enablePan === false ) return; 737 | 738 | handleMouseMovePan( event ); 739 | 740 | break; 741 | 742 | } 743 | 744 | } 745 | 746 | function onMouseUp( event ) { 747 | 748 | if ( scope.enabled === false ) return; 749 | 750 | handleMouseUp( event ); 751 | 752 | document.removeEventListener( 'mousemove', onMouseMove, false ); 753 | document.removeEventListener( 'mouseup', onMouseUp, false ); 754 | 755 | scope.dispatchEvent( endEvent ); 756 | 757 | state = STATE.NONE; 758 | 759 | } 760 | 761 | function onMouseWheel( event ) { 762 | 763 | if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return; 764 | 765 | event.preventDefault(); 766 | event.stopPropagation(); 767 | 768 | handleMouseWheel( event ); 769 | 770 | scope.dispatchEvent( startEvent ); // not sure why these are here... 771 | scope.dispatchEvent( endEvent ); 772 | 773 | } 774 | 775 | function onKeyDown( event ) { 776 | 777 | if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; 778 | 779 | handleKeyDown( event ); 780 | 781 | } 782 | 783 | function onTouchStart( event ) { 784 | 785 | if ( scope.enabled === false ) return; 786 | 787 | switch ( event.touches.length ) { 788 | 789 | case 1: // one-fingered touch: rotate 790 | 791 | if ( scope.enableRotate === false ) return; 792 | 793 | handleTouchStartRotate( event ); 794 | 795 | state = STATE.TOUCH_ROTATE; 796 | 797 | break; 798 | 799 | case 2: // two-fingered touch: dolly 800 | 801 | if ( scope.enableZoom === false ) return; 802 | 803 | handleTouchStartDolly( event ); 804 | 805 | state = STATE.TOUCH_DOLLY; 806 | 807 | break; 808 | 809 | case 3: // three-fingered touch: pan 810 | 811 | if ( scope.enablePan === false ) return; 812 | 813 | handleTouchStartPan( event ); 814 | 815 | state = STATE.TOUCH_PAN; 816 | 817 | break; 818 | 819 | default: 820 | 821 | state = STATE.NONE; 822 | 823 | } 824 | 825 | if ( state !== STATE.NONE ) { 826 | 827 | scope.dispatchEvent( startEvent ); 828 | 829 | } 830 | 831 | } 832 | 833 | function onTouchMove( event ) { 834 | 835 | if ( scope.enabled === false ) return; 836 | 837 | event.preventDefault(); 838 | event.stopPropagation(); 839 | 840 | switch ( event.touches.length ) { 841 | 842 | case 1: // one-fingered touch: rotate 843 | 844 | if ( scope.enableRotate === false ) return; 845 | if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?... 846 | 847 | handleTouchMoveRotate( event ); 848 | 849 | break; 850 | 851 | case 2: // two-fingered touch: dolly 852 | 853 | if ( scope.enableZoom === false ) return; 854 | if ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?... 855 | 856 | handleTouchMoveDolly( event ); 857 | 858 | break; 859 | 860 | case 3: // three-fingered touch: pan 861 | 862 | if ( scope.enablePan === false ) return; 863 | if ( state !== STATE.TOUCH_PAN ) return; // is this needed?... 864 | 865 | handleTouchMovePan( event ); 866 | 867 | break; 868 | 869 | default: 870 | 871 | state = STATE.NONE; 872 | 873 | } 874 | 875 | } 876 | 877 | function onTouchEnd( event ) { 878 | 879 | if ( scope.enabled === false ) return; 880 | 881 | handleTouchEnd( event ); 882 | 883 | scope.dispatchEvent( endEvent ); 884 | 885 | state = STATE.NONE; 886 | 887 | } 888 | 889 | function onContextMenu( event ) { 890 | 891 | if ( scope.enabled === false ) return; 892 | 893 | event.preventDefault(); 894 | 895 | } 896 | 897 | // 898 | 899 | scope.domElement.addEventListener( 'contextmenu', onContextMenu, false ); 900 | 901 | scope.domElement.addEventListener( 'mousedown', onMouseDown, false ); 902 | scope.domElement.addEventListener( 'wheel', onMouseWheel, false ); 903 | 904 | scope.domElement.addEventListener( 'touchstart', onTouchStart, false ); 905 | scope.domElement.addEventListener( 'touchend', onTouchEnd, false ); 906 | scope.domElement.addEventListener( 'touchmove', onTouchMove, false ); 907 | 908 | window.addEventListener( 'keydown', onKeyDown, false ); 909 | 910 | // force an update at start 911 | 912 | this.update(); 913 | 914 | }; 915 | 916 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); 917 | THREE.OrbitControls.prototype.constructor = THREE.OrbitControls; 918 | 919 | Object.defineProperties( THREE.OrbitControls.prototype, { 920 | 921 | center: { 922 | 923 | get: function () { 924 | 925 | console.warn( 'THREE.OrbitControls: .center has been renamed to .target' ); 926 | return this.target; 927 | 928 | } 929 | 930 | }, 931 | 932 | // backward compatibility 933 | 934 | noZoom: { 935 | 936 | get: function () { 937 | 938 | console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); 939 | return ! this.enableZoom; 940 | 941 | }, 942 | 943 | set: function ( value ) { 944 | 945 | console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); 946 | this.enableZoom = ! value; 947 | 948 | } 949 | 950 | }, 951 | 952 | noRotate: { 953 | 954 | get: function () { 955 | 956 | console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); 957 | return ! this.enableRotate; 958 | 959 | }, 960 | 961 | set: function ( value ) { 962 | 963 | console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); 964 | this.enableRotate = ! value; 965 | 966 | } 967 | 968 | }, 969 | 970 | noPan: { 971 | 972 | get: function () { 973 | 974 | console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); 975 | return ! this.enablePan; 976 | 977 | }, 978 | 979 | set: function ( value ) { 980 | 981 | console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); 982 | this.enablePan = ! value; 983 | 984 | } 985 | 986 | }, 987 | 988 | noKeys: { 989 | 990 | get: function () { 991 | 992 | console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); 993 | return ! this.enableKeys; 994 | 995 | }, 996 | 997 | set: function ( value ) { 998 | 999 | console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); 1000 | this.enableKeys = ! value; 1001 | 1002 | } 1003 | 1004 | }, 1005 | 1006 | staticMoving: { 1007 | 1008 | get: function () { 1009 | 1010 | console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); 1011 | return ! this.enableDamping; 1012 | 1013 | }, 1014 | 1015 | set: function ( value ) { 1016 | 1017 | console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); 1018 | this.enableDamping = ! value; 1019 | 1020 | } 1021 | 1022 | }, 1023 | 1024 | dynamicDampingFactor: { 1025 | 1026 | get: function () { 1027 | 1028 | console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); 1029 | return this.dampingFactor; 1030 | 1031 | }, 1032 | 1033 | set: function ( value ) { 1034 | 1035 | console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); 1036 | this.dampingFactor = value; 1037 | 1038 | } 1039 | 1040 | } 1041 | 1042 | } ); 1043 | -------------------------------------------------------------------------------- /js/utils/dat.gui.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.dat=t():e.dat=t()}(this,function(){return function(e){function t(o){if(n[o])return n[o].exports;var i=n[o]={exports:{},id:o,loaded:!1};return e[o].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(1),r=o(i);t.default=r.default,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(2),r=o(i),a=n(6),l=o(a),s=n(3),u=o(s),d=n(7),c=o(d),f=n(8),_=o(f),p=n(10),h=o(p),m=n(11),b=o(m),g=n(12),v=o(g),y=n(13),w=o(y),x=n(14),E=o(x),C=n(15),A=o(C),S=n(16),k=o(S),O=n(9),T=o(O),R=n(17),L=o(R);t.default={color:{Color:r.default,math:l.default,interpret:u.default},controllers:{Controller:c.default,BooleanController:_.default,OptionController:h.default,StringController:b.default,NumberController:v.default,NumberControllerBox:w.default,NumberControllerSlider:E.default,FunctionController:A.default,ColorController:k.default},dom:{dom:T.default},gui:{GUI:L.default},GUI:L.default},e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t,n){Object.defineProperty(e,t,{get:function(){return"RGB"===this.__state.space?this.__state[t]:(h.recalculateRGB(this,t,n),this.__state[t])},set:function(e){"RGB"!==this.__state.space&&(h.recalculateRGB(this,t,n),this.__state.space="RGB"),this.__state[t]=e}})}function a(e,t){Object.defineProperty(e,t,{get:function(){return"HSV"===this.__state.space?this.__state[t]:(h.recalculateHSV(this),this.__state[t])},set:function(e){"HSV"!==this.__state.space&&(h.recalculateHSV(this),this.__state.space="HSV"),this.__state[t]=e}})}t.__esModule=!0;var l=n(3),s=o(l),u=n(6),d=o(u),c=n(4),f=o(c),_=n(5),p=o(_),h=function(){function e(){if(i(this,e),this.__state=s.default.apply(this,arguments),this.__state===!1)throw new Error("Failed to interpret color arguments");this.__state.a=this.__state.a||1}return e.prototype.toString=function(){return(0,f.default)(this)},e.prototype.toHexString=function(){return(0,f.default)(this,!0)},e.prototype.toOriginal=function(){return this.__state.conversion.write(this)},e}();h.recalculateRGB=function(e,t,n){if("HEX"===e.__state.space)e.__state[t]=d.default.component_from_hex(e.__state.hex,n);else{if("HSV"!==e.__state.space)throw new Error("Corrupted color state");p.default.extend(e.__state,d.default.hsv_to_rgb(e.__state.h,e.__state.s,e.__state.v))}},h.recalculateHSV=function(e){var t=d.default.rgb_to_hsv(e.r,e.g,e.b);p.default.extend(e.__state,{s:t.s,v:t.v}),p.default.isNaN(t.h)?p.default.isUndefined(e.__state.h)&&(e.__state.h=0):e.__state.h=t.h},h.COMPONENTS=["r","g","b","h","s","v","hex","a"],r(h.prototype,"r",2),r(h.prototype,"g",1),r(h.prototype,"b",0),a(h.prototype,"h"),a(h.prototype,"s"),a(h.prototype,"v"),Object.defineProperty(h.prototype,"a",{get:function(){return this.__state.a},set:function(e){this.__state.a=e}}),Object.defineProperty(h.prototype,"hex",{get:function(){return"HEX"!==!this.__state.space&&(this.__state.hex=d.default.rgb_to_hex(this.r,this.g,this.b)),this.__state.hex},set:function(e){this.__state.space="HEX",this.__state.hex=e}}),t.default=h,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(4),r=o(i),a=n(5),l=o(a),s=[{litmus:l.default.isString,conversions:{THREE_CHAR_HEX:{read:function(e){var t=e.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return null!==t&&{space:"HEX",hex:parseInt("0x"+t[1].toString()+t[1].toString()+t[2].toString()+t[2].toString()+t[3].toString()+t[3].toString(),0)}},write:r.default},SIX_CHAR_HEX:{read:function(e){var t=e.match(/^#([A-F0-9]{6})$/i);return null!==t&&{space:"HEX",hex:parseInt("0x"+t[1].toString(),0)}},write:r.default},CSS_RGB:{read:function(e){var t=e.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);return null!==t&&{space:"RGB",r:parseFloat(t[1]),g:parseFloat(t[2]),b:parseFloat(t[3])}},write:r.default},CSS_RGBA:{read:function(e){var t=e.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);return null!==t&&{space:"RGB",r:parseFloat(t[1]),g:parseFloat(t[2]),b:parseFloat(t[3]),a:parseFloat(t[4])}},write:r.default}}},{litmus:l.default.isNumber,conversions:{HEX:{read:function(e){return{space:"HEX",hex:e,conversionName:"HEX"}},write:function(e){return e.hex}}}},{litmus:l.default.isArray,conversions:{RGB_ARRAY:{read:function(e){return 3===e.length&&{space:"RGB",r:e[0],g:e[1],b:e[2]}},write:function(e){return[e.r,e.g,e.b]}},RGBA_ARRAY:{read:function(e){return 4===e.length&&{space:"RGB",r:e[0],g:e[1],b:e[2],a:e[3]}},write:function(e){return[e.r,e.g,e.b,e.a]}}}},{litmus:l.default.isObject,conversions:{RGBA_OBJ:{read:function(e){return!!(l.default.isNumber(e.r)&&l.default.isNumber(e.g)&&l.default.isNumber(e.b)&&l.default.isNumber(e.a))&&{space:"RGB",r:e.r,g:e.g,b:e.b,a:e.a}},write:function(e){return{r:e.r,g:e.g,b:e.b,a:e.a}}},RGB_OBJ:{read:function(e){return!!(l.default.isNumber(e.r)&&l.default.isNumber(e.g)&&l.default.isNumber(e.b))&&{space:"RGB",r:e.r,g:e.g,b:e.b}},write:function(e){return{r:e.r,g:e.g,b:e.b}}},HSVA_OBJ:{read:function(e){return!!(l.default.isNumber(e.h)&&l.default.isNumber(e.s)&&l.default.isNumber(e.v)&&l.default.isNumber(e.a))&&{space:"HSV",h:e.h,s:e.s,v:e.v,a:e.a}},write:function(e){return{h:e.h,s:e.s,v:e.v,a:e.a}}},HSV_OBJ:{read:function(e){return!!(l.default.isNumber(e.h)&&l.default.isNumber(e.s)&&l.default.isNumber(e.v))&&{space:"HSV",h:e.h,s:e.s,v:e.v}},write:function(e){return{h:e.h,s:e.s,v:e.v}}}}}],u=void 0,d=void 0,c=function(){d=!1;var e=arguments.length>1?l.default.toArray(arguments):arguments[0];return l.default.each(s,function(t){if(t.litmus(e))return l.default.each(t.conversions,function(t,n){if(u=t.read(e),d===!1&&u!==!1)return d=u,u.conversionName=n,u.conversion=t,l.default.BREAK}),l.default.BREAK}),d};t.default=c,e.exports=t.default},function(e,t){"use strict";t.__esModule=!0,t.default=function(e,t){var n=e.__state.conversionName.toString(),o=Math.round(e.r),i=Math.round(e.g),r=Math.round(e.b),a=e.a,l=Math.round(e.h),s=e.s.toFixed(1),u=e.v.toFixed(1);if(t||"THREE_CHAR_HEX"===n||"SIX_CHAR_HEX"===n){for(var d=e.hex.toString(16);d.length<6;)d="0"+d;return"#"+d}return"CSS_RGB"===n?"rgb("+o+","+i+","+r+")":"CSS_RGBA"===n?"rgba("+o+","+i+","+r+","+a+")":"HEX"===n?"0x"+e.hex.toString(16):"RGB_ARRAY"===n?"["+o+","+i+","+r+"]":"RGBA_ARRAY"===n?"["+o+","+i+","+r+","+a+"]":"RGB_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+"}":"RGBA_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+",a:"+a+"}":"HSV_OBJ"===n?"{h:"+l+",s:"+s+",v:"+u+"}":"HSVA_OBJ"===n?"{h:"+l+",s:"+s+",v:"+u+",a:"+a+"}":"unknown format"},e.exports=t.default},function(e,t){"use strict";t.__esModule=!0;var n=Array.prototype.forEach,o=Array.prototype.slice,i={BREAK:{},extend:function(e){return this.each(o.call(arguments,1),function(t){var n=this.isObject(t)?Object.keys(t):[];n.forEach(function(n){this.isUndefined(t[n])||(e[n]=t[n])}.bind(this))},this),e},defaults:function(e){return this.each(o.call(arguments,1),function(t){var n=this.isObject(t)?Object.keys(t):[];n.forEach(function(n){this.isUndefined(e[n])&&(e[n]=t[n])}.bind(this))},this),e},compose:function(){var e=o.call(arguments);return function(){for(var t=o.call(arguments),n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},each:function(e,t,o){if(e)if(n&&e.forEach&&e.forEach===n)e.forEach(t,o);else if(e.length===e.length+0){var i=void 0,r=void 0;for(i=0,r=e.length;i>8*t&255},hex_with_component:function(e,t,o){return o<<(n=8*t)|e&~(255<-1?t.length-t.indexOf(".")-1:0}t.__esModule=!0;var s=n(7),u=o(s),d=n(5),c=o(d),f=function(e){function t(n,o,a){i(this,t);var s=r(this,e.call(this,n,o)),u=a||{};return s.__min=u.min,s.__max=u.max,s.__step=u.step,c.default.isUndefined(s.__step)?0===s.initialValue?s.__impliedStep=1:s.__impliedStep=Math.pow(10,Math.floor(Math.log(Math.abs(s.initialValue))/Math.LN10))/10:s.__impliedStep=s.__step,s.__precision=l(s.__impliedStep),s}return a(t,e),t.prototype.setValue=function(t){var n=t;return void 0!==this.__min&&nthis.__max&&(n=this.__max),void 0!==this.__step&&n%this.__step!==0&&(n=Math.round(n/this.__step)*this.__step),e.prototype.setValue.call(this,n)},t.prototype.min=function(e){return this.__min=e,this},t.prototype.max=function(e){return this.__max=e,this},t.prototype.step=function(e){return this.__step=e,this.__impliedStep=e,this.__precision=l(e),this},t}(u.default);t.default=f,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t){var n=Math.pow(10,t);return Math.round(e*n)/n}t.__esModule=!0;var s=n(12),u=o(s),d=n(9),c=o(d),f=n(5),_=o(f),p=function(e){function t(n,o,a){function l(){var e=parseFloat(m.__input.value);_.default.isNaN(e)||m.setValue(e)}function s(){m.__onFinishChange&&m.__onFinishChange.call(m,m.getValue())}function u(){s()}function d(e){var t=b-e.clientY;m.setValue(m.getValue()+t*m.__impliedStep),b=e.clientY}function f(){c.default.unbind(window,"mousemove",d),c.default.unbind(window,"mouseup",f),s()}function p(e){c.default.bind(window,"mousemove",d),c.default.bind(window,"mouseup",f),b=e.clientY}i(this,t);var h=r(this,e.call(this,n,o,a));h.__truncationSuspended=!1;var m=h,b=void 0;return h.__input=document.createElement("input"),h.__input.setAttribute("type","text"),c.default.bind(h.__input,"change",l),c.default.bind(h.__input,"blur",u),c.default.bind(h.__input,"mousedown",p),c.default.bind(h.__input,"keydown",function(e){13===e.keyCode&&(m.__truncationSuspended=!0,this.blur(),m.__truncationSuspended=!1,s())}),h.updateDisplay(),h.domElement.appendChild(h.__input),h}return a(t,e),t.prototype.updateDisplay=function(){return this.__input.value=this.__truncationSuspended?this.getValue():l(this.getValue(),this.__precision),e.prototype.updateDisplay.call(this)},t}(u.default);t.default=p,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t,n,o,i){return o+(i-o)*((e-t)/(n-t))}t.__esModule=!0;var s=n(12),u=o(s),d=n(9),c=o(d),f=function(e){function t(n,o,a,s,u){function d(e){document.activeElement.blur(),c.default.bind(window,"mousemove",f),c.default.bind(window,"mouseup",_),f(e)}function f(e){e.preventDefault();var t=h.__background.getBoundingClientRect();return h.setValue(l(e.clientX,t.left,t.right,h.__min,h.__max)),!1}function _(){c.default.unbind(window,"mousemove",f),c.default.unbind(window,"mouseup",_),h.__onFinishChange&&h.__onFinishChange.call(h,h.getValue())}i(this,t);var p=r(this,e.call(this,n,o,{min:a,max:s,step:u})),h=p;return p.__background=document.createElement("div"),p.__foreground=document.createElement("div"),c.default.bind(p.__background,"mousedown",d),c.default.addClass(p.__background,"slider"),c.default.addClass(p.__foreground,"slider-fg"),p.updateDisplay(),p.__background.appendChild(p.__foreground),p.domElement.appendChild(p.__background),p}return a(t,e),t.prototype.updateDisplay=function(){var t=(this.getValue()-this.__min)/(this.__max-this.__min);return this.__foreground.style.width=100*t+"%",e.prototype.updateDisplay.call(this)},t}(u.default);t.default=f,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0;var l=n(7),s=o(l),u=n(9),d=o(u),c=function(e){function t(n,o,a){i(this,t);var l=r(this,e.call(this,n,o)),s=l;return l.__button=document.createElement("div"),l.__button.innerHTML=void 0===a?"Fire":a,d.default.bind(l.__button,"click",function(e){return e.preventDefault(),s.fire(),!1}),d.default.addClass(l.__button,"button"),l.domElement.appendChild(l.__button),l}return a(t,e),t.prototype.fire=function(){this.__onChange&&this.__onChange.call(this),this.getValue().call(this.object),this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())},t}(s.default);t.default=c,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t,n,o){e.style.background="",g.default.each(y,function(i){e.style.cssText+="background: "+i+"linear-gradient("+t+", "+n+" 0%, "+o+" 100%); "})}function s(e){e.style.background="",e.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);",e.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}t.__esModule=!0;var u=n(7),d=o(u),c=n(9),f=o(c),_=n(2),p=o(_),h=n(3),m=o(h),b=n(5),g=o(b),v=function(e){function t(n,o){function a(e){h(e),f.default.bind(window,"mousemove",h),f.default.bind(window,"mouseup",u)}function u(){f.default.unbind(window,"mousemove",h),f.default.unbind(window,"mouseup",u),_()}function d(){var e=(0,m.default)(this.value);e!==!1?(y.__color.__state=e,y.setValue(y.__color.toOriginal())):this.value=y.__color.toString()}function c(){f.default.unbind(window,"mousemove",b),f.default.unbind(window,"mouseup",c),_()}function _(){y.__onFinishChange&&y.__onFinishChange.call(y,y.__color.toOriginal())}function h(e){e.preventDefault();var t=y.__saturation_field.getBoundingClientRect(),n=(e.clientX-t.left)/(t.right-t.left),o=1-(e.clientY-t.top)/(t.bottom-t.top);return o>1?o=1:o<0&&(o=0),n>1?n=1:n<0&&(n=0),y.__color.v=o,y.__color.s=n,y.setValue(y.__color.toOriginal()),!1}function b(e){e.preventDefault();var t=y.__hue_field.getBoundingClientRect(),n=1-(e.clientY-t.top)/(t.bottom-t.top);return n>1?n=1:n<0&&(n=0),y.__color.h=360*n,y.setValue(y.__color.toOriginal()),!1}i(this,t);var v=r(this,e.call(this,n,o));v.__color=new p.default(v.getValue()),v.__temp=new p.default(0);var y=v;v.domElement=document.createElement("div"),f.default.makeSelectable(v.domElement,!1),v.__selector=document.createElement("div"),v.__selector.className="selector",v.__saturation_field=document.createElement("div"),v.__saturation_field.className="saturation-field",v.__field_knob=document.createElement("div"),v.__field_knob.className="field-knob",v.__field_knob_border="2px solid ",v.__hue_knob=document.createElement("div"),v.__hue_knob.className="hue-knob",v.__hue_field=document.createElement("div"),v.__hue_field.className="hue-field",v.__input=document.createElement("input"),v.__input.type="text",v.__input_textShadow="0 1px 1px ",f.default.bind(v.__input,"keydown",function(e){13===e.keyCode&&d.call(this)}),f.default.bind(v.__input,"blur",d),f.default.bind(v.__selector,"mousedown",function(){f.default.addClass(this,"drag").bind(window,"mouseup",function(){f.default.removeClass(y.__selector,"drag")})});var w=document.createElement("div");return g.default.extend(v.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}),g.default.extend(v.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:v.__field_knob_border+(v.__color.v<.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1}),g.default.extend(v.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1}),g.default.extend(v.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"}),g.default.extend(w.style,{width:"100%",height:"100%",background:"none"}),l(w,"top","rgba(0,0,0,0)","#000"),g.default.extend(v.__hue_field.style,{width:"15px",height:"100px",border:"1px solid #555",cursor:"ns-resize",position:"absolute",top:"3px",right:"3px"}),s(v.__hue_field),g.default.extend(v.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:v.__input_textShadow+"rgba(0,0,0,0.7)"}),f.default.bind(v.__saturation_field,"mousedown",a),f.default.bind(v.__field_knob,"mousedown",a),f.default.bind(v.__hue_field,"mousedown",function(e){b(e),f.default.bind(window,"mousemove",b),f.default.bind(window,"mouseup",c)}),v.__saturation_field.appendChild(w),v.__selector.appendChild(v.__field_knob),v.__selector.appendChild(v.__saturation_field),v.__selector.appendChild(v.__hue_field),v.__hue_field.appendChild(v.__hue_knob),v.domElement.appendChild(v.__input),v.domElement.appendChild(v.__selector),v.updateDisplay(),v}return a(t,e),t.prototype.updateDisplay=function(){var e=(0,m.default)(this.getValue());if(e!==!1){var t=!1;g.default.each(p.default.COMPONENTS,function(n){if(!g.default.isUndefined(e[n])&&!g.default.isUndefined(this.__color.__state[n])&&e[n]!==this.__color.__state[n])return t=!0,{}},this),t&&g.default.extend(this.__color.__state,e)}g.default.extend(this.__temp.__state,this.__color.__state),this.__temp.a=1;var n=this.__color.v<.5||this.__color.s>.5?255:0,o=255-n;g.default.extend(this.__field_knob.style,{marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toHexString(),border:this.__field_knob_border+"rgb("+n+","+n+","+n+")"}),this.__hue_knob.style.marginTop=100*(1-this.__color.h/360)+"px",this.__temp.s=1,this.__temp.v=1,l(this.__saturation_field,"left","#fff",this.__temp.toHexString()),this.__input.value=this.__color.toString(),g.default.extend(this.__input.style,{backgroundColor:this.__color.toHexString(),color:"rgb("+n+","+n+","+n+")",textShadow:this.__input_textShadow+"rgba("+o+","+o+","+o+",.7)"})},t}(d.default),y=["-moz-","-o-","-webkit-","-ms-",""];t.default=v,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var o=document.createElement("li");return t&&o.appendChild(t),n?e.__ul.insertBefore(o,n):e.__ul.appendChild(o),e.onResize(),o}function r(e,t){var n=e.__preset_select[e.__preset_select.selectedIndex];t?n.innerHTML=n.value+"*":n.innerHTML=n.value}function a(e,t,n){if(n.__li=t,n.__gui=e,U.default.extend(n,{options:function(t){if(arguments.length>1){var o=n.__li.nextElementSibling;return n.remove(),s(e,n.object,n.property,{before:o,factoryArgs:[U.default.toArray(arguments)]})}if(U.default.isArray(t)||U.default.isObject(t)){var i=n.__li.nextElementSibling;return n.remove(),s(e,n.object,n.property,{before:i,factoryArgs:[t]})}},name:function(e){return n.__li.firstElementChild.firstElementChild.innerHTML=e,n},listen:function(){return n.__gui.listen(n),n},remove:function(){return n.__gui.remove(n),n}}),n instanceof N.default){var o=new B.default(n.object,n.property,{ 2 | min:n.__min,max:n.__max,step:n.__step});U.default.each(["updateDisplay","onChange","onFinishChange","step"],function(e){var t=n[e],i=o[e];n[e]=o[e]=function(){var e=Array.prototype.slice.call(arguments);return i.apply(o,e),t.apply(n,e)}}),z.default.addClass(t,"has-slider"),n.domElement.insertBefore(o.domElement,n.domElement.firstElementChild)}else if(n instanceof B.default){var i=function(t){if(U.default.isNumber(n.__min)&&U.default.isNumber(n.__max)){var o=n.__li.firstElementChild.firstElementChild.innerHTML,i=n.__gui.__listening.indexOf(n)>-1;n.remove();var r=s(e,n.object,n.property,{before:n.__li.nextElementSibling,factoryArgs:[n.__min,n.__max,n.__step]});return r.name(o),i&&r.listen(),r}return t};n.min=U.default.compose(i,n.min),n.max=U.default.compose(i,n.max)}else n instanceof O.default?(z.default.bind(t,"click",function(){z.default.fakeEvent(n.__checkbox,"click")}),z.default.bind(n.__checkbox,"click",function(e){e.stopPropagation()})):n instanceof R.default?(z.default.bind(t,"click",function(){z.default.fakeEvent(n.__button,"click")}),z.default.bind(t,"mouseover",function(){z.default.addClass(n.__button,"hover")}),z.default.bind(t,"mouseout",function(){z.default.removeClass(n.__button,"hover")})):n instanceof j.default&&(z.default.addClass(t,"color"),n.updateDisplay=U.default.compose(function(e){return t.style.borderLeftColor=n.__color.toString(),e},n.updateDisplay),n.updateDisplay());n.setValue=U.default.compose(function(t){return e.getRoot().__preset_select&&n.isModified()&&r(e.getRoot(),!0),t},n.setValue)}function l(e,t){var n=e.getRoot(),o=n.__rememberedObjects.indexOf(t.object);if(o!==-1){var i=n.__rememberedObjectIndecesToControllers[o];if(void 0===i&&(i={},n.__rememberedObjectIndecesToControllers[o]=i),i[t.property]=t,n.load&&n.load.remembered){var r=n.load.remembered,a=void 0;if(r[e.preset])a=r[e.preset];else{if(!r[Q])return;a=r[Q]}if(a[o]&&void 0!==a[o][t.property]){var l=a[o][t.property];t.initialValue=l,t.setValue(l)}}}}function s(e,t,n,o){if(void 0===t[n])throw new Error('Object "'+t+'" has no property "'+n+'"');var r=void 0;if(o.color)r=new j.default(t,n);else{var s=[t,n].concat(o.factoryArgs);r=C.default.apply(e,s)}o.before instanceof S.default&&(o.before=o.before.__li),l(e,r),z.default.addClass(r.domElement,"c");var u=document.createElement("span");z.default.addClass(u,"property-name"),u.innerHTML=r.property;var d=document.createElement("div");d.appendChild(u),d.appendChild(r.domElement);var c=i(e,d,o.before);return z.default.addClass(c,oe.CLASS_CONTROLLER_ROW),r instanceof j.default?z.default.addClass(c,"color"):z.default.addClass(c,g(r.getValue())),a(e,c,r),e.__controllers.push(r),r}function u(e,t){return document.location.href+"."+t}function d(e,t,n){var o=document.createElement("option");o.innerHTML=t,o.value=t,e.__preset_select.appendChild(o),n&&(e.__preset_select.selectedIndex=e.__preset_select.length-1)}function c(e,t){t.style.display=e.useLocalStorage?"block":"none"}function f(e){var t=e.__save_row=document.createElement("li");z.default.addClass(e.domElement,"has-save"),e.__ul.insertBefore(t,e.__ul.firstChild),z.default.addClass(t,"save-row");var n=document.createElement("span");n.innerHTML=" ",z.default.addClass(n,"button gears");var o=document.createElement("span");o.innerHTML="Save",z.default.addClass(o,"button"),z.default.addClass(o,"save");var i=document.createElement("span");i.innerHTML="New",z.default.addClass(i,"button"),z.default.addClass(i,"save-as");var r=document.createElement("span");r.innerHTML="Revert",z.default.addClass(r,"button"),z.default.addClass(r,"revert");var a=e.__preset_select=document.createElement("select");if(e.load&&e.load.remembered?U.default.each(e.load.remembered,function(t,n){d(e,n,n===e.preset)}):d(e,Q,!1),z.default.bind(a,"change",function(){for(var t=0;t0&&(e.preset=this.preset,e.remembered||(e.remembered={}),e.remembered[this.preset]=h(this)),e.folders={},U.default.each(this.__folders,function(t,n){e.folders[n]=t.getSaveObject()}),e},save:function(){this.load.remembered||(this.load.remembered={}),this.load.remembered[this.preset]=h(this),r(this,!1),this.saveToLocalStorageIfPossible()},saveAs:function(e){this.load.remembered||(this.load.remembered={},this.load.remembered[Q]=h(this,!0)),this.load.remembered[e]=h(this),this.preset=e,d(this,e,!0),this.saveToLocalStorageIfPossible()},revert:function(e){U.default.each(this.__controllers,function(t){this.getRoot().load.remembered?l(e||this.getRoot(),t):t.setValue(t.initialValue),t.__onFinishChange&&t.__onFinishChange.call(t,t.getValue())},this),U.default.each(this.__folders,function(e){e.revert(e)}),e||r(this.getRoot(),!1)},listen:function(e){var t=0===this.__listening.length;this.__listening.push(e),t&&b(this.__listening)},updateDisplay:function(){U.default.each(this.__controllers,function(e){e.updateDisplay()}),U.default.each(this.__folders,function(e){e.updateDisplay()})}}),t.default=oe,e.exports=t.default},function(e,t){"use strict";e.exports={load:function(e,t){var n=t||document,o=n.createElement("link");o.type="text/css",o.rel="stylesheet",o.href=e,n.getElementsByTagName("head")[0].appendChild(o)},inject:function(e,t){var n=t||document,o=document.createElement("style");o.type="text/css",o.innerHTML=e;var i=n.getElementsByTagName("head")[0];try{i.appendChild(o)}catch(e){}}}},function(e,t){e.exports="
    Here's the new load parameter for your GUI's constructor:
    Automatically save values to localStorage on exit.
    The values saved to localStorage will override those passed to dat.GUI's constructor. This makes it easier to work incrementally, but localStorage is fragile, and your friends may not see the same values you do.
    "},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(10),r=o(i),a=n(13),l=o(a),s=n(14),u=o(s),d=n(11),c=o(d),f=n(15),_=o(f),p=n(8),h=o(p),m=n(5),b=o(m),g=function(e,t){var n=e[t];return b.default.isArray(arguments[2])||b.default.isObject(arguments[2])?new r.default(e,t,arguments[2]):b.default.isNumber(n)?b.default.isNumber(arguments[2])&&b.default.isNumber(arguments[3])?b.default.isNumber(arguments[4])?new u.default(e,t,arguments[2],arguments[3],arguments[4]):new u.default(e,t,arguments[2],arguments[3]):b.default.isNumber(arguments[4])?new l.default(e,t,{min:arguments[2],max:arguments[3],step:arguments[4]}):new l.default(e,t,{min:arguments[2],max:arguments[3]}):b.default.isString(n)?new c.default(e,t):b.default.isFunction(n)?new _.default(e,t,""):b.default.isBoolean(n)?new h.default(e,t):null};t.default=g,e.exports=t.default},function(e,t){"use strict";function n(e){setTimeout(e,1e3/60)}t.__esModule=!0,t.default=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||n,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var r=n(9),a=o(r),l=n(5),s=o(l),u=function(){function e(){i(this,e),this.backgroundElement=document.createElement("div"),s.default.extend(this.backgroundElement.style,{backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear",transition:"opacity 0.2s linear"}),a.default.makeFullscreen(this.backgroundElement),this.backgroundElement.style.position="fixed",this.domElement=document.createElement("div"),s.default.extend(this.domElement.style,{position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear",transition:"transform 0.2s ease-out, opacity 0.2s linear"}),document.body.appendChild(this.backgroundElement),document.body.appendChild(this.domElement);var t=this;a.default.bind(this.backgroundElement,"click",function(){t.hide()})}return e.prototype.show=function(){var e=this;this.backgroundElement.style.display="block",this.domElement.style.display="block",this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)",this.layout(),s.default.defer(function(){e.backgroundElement.style.opacity=1,e.domElement.style.opacity=1,e.domElement.style.webkitTransform="scale(1)"})},e.prototype.hide=function e(){var t=this,e=function e(){t.domElement.style.display="none",t.backgroundElement.style.display="none",a.default.unbind(t.domElement,"webkitTransitionEnd",e),a.default.unbind(t.domElement,"transitionend",e),a.default.unbind(t.domElement,"oTransitionEnd",e)};a.default.bind(this.domElement,"webkitTransitionEnd",e),a.default.bind(this.domElement,"transitionend",e),a.default.bind(this.domElement,"oTransitionEnd",e),this.backgroundElement.style.opacity=0,this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)"},e.prototype.layout=function(){this.domElement.style.left=window.innerWidth/2-a.default.getWidth(this.domElement)/2+"px",this.domElement.style.top=window.innerHeight/2-a.default.getHeight(this.domElement)/2+"px"},e}();t.default=u,e.exports=t.default},function(e,t,n){t=e.exports=n(24)(),t.push([e.id,".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1!important}.dg.main .close-button.drag,.dg.main:hover .close-button{opacity:1}.dg.main .close-button{transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{transition:height .1s ease-out;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid transparent}.dg li.title{margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%;position:relative}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:7px}.dg .c select{margin-top:5px}.dg .cr.boolean,.dg .cr.boolean *,.dg .cr.function,.dg .cr.function *,.dg .cr.function .property-name{cursor:pointer}.dg .cr.color{overflow:visible}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco,monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px Lucida Grande,sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid hsla(0,0%,100%,.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2fa1d6}.dg .cr.number input[type=text]{color:#2fa1d6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.boolean:hover,.dg .cr.function:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2fa1d6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}",""])},function(e,t){e.exports=function(){var e=[];return e.toString=function(){for(var e=[],t=0;t