diff --git a/basic_course/BOX/.gitkeep b/basic_course/BOX/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/basic_course/BOX/box.html b/basic_course/BOX/box.html
new file mode 100644
index 0000000000000000000000000000000000000000..605feabc4ae2c7f3276746708b6a7b749857bef4
--- /dev/null
+++ b/basic_course/BOX/box.html
@@ -0,0 +1,17 @@
+<html>
+
+<head>
+<title>WebGLHelloAPI</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+
+<script type="text/javascript" src="box.js">
+</script>
+
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="600" height="600"></canvas>
+</body>
+
+</html>
diff --git a/basic_course/BOX/box.js b/basic_course/BOX/box.js
new file mode 100644
index 0000000000000000000000000000000000000000..c929b2d6f6a018be9be5185dc5d46fe8291cc93f
--- /dev/null
+++ b/basic_course/BOX/box.js
@@ -0,0 +1,199 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    /* gl.getError returns the last error that occurred using WebGL for debugging */ 
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+var vertexData = [
+        -0.5, -0.5, 0.5, 1.0, 0.0, 1.0, 1.0,  // First Triangle
+        -0.5,  0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 
+         0.5,  0.5, 0.5,  1.0, 0.0, 0.0, 1.0, 
+
+         0.5,  0.5, -0.5, 1.0, 1.0, 1.0, 1.0, 
+         0.5, -0.5, -0.5, 1.0, 0.0, 1.0, 1.0,  // Second Triangle
+         -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0, 
+
+		 // You need to make here!
+
+];
+var elementData = [ 0,1,2,3,4,5]; 
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+	gl.elementBuffer = gl.createBuffer(); 
+	gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.elementBuffer);
+	gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(elementData),gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color; \
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 transformationMatrix; \
+			uniform mediump mat4 virwMatrix; \
+			uniform mediump mat4 projMatrix; \
+			varying highp vec4 color;\
+			void main(void)  \
+			{ \
+				gl_Position = transformationMatrix * myVertex; \
+				color = myColor; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+var rotY = 0.0; 
+
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+
+    gl.clear(gl.COLOR_BUFFER_BIT);
+
+    var matrixLocation = gl.getUniformLocation(gl.programObject, "transformationMatrix");
+    var transformationMatrix = [
+        Math.cos(rotY),	0.0, -Math.sin(rotY),	0.0,
+        0.0,			1.0,  0.0,				0.0, 
+        Math.sin(rotY), 0.0, Math.cos(rotY),	0.5, // For pseudo perspective View
+        0.0,			0.0, 0.0,				1.0
+    ];
+	rotY += 0.01;
+
+
+    gl.uniformMatrix4fv(matrixLocation, gl.FALSE, transformationMatrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
+	// gl.vertexAttrib4f(1, Math.random(), 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	// gl.lineWidth(6.0);  // It is not working at Chrome!
+    // gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT,0);
+    // gl.drawArrays(gl.POINTS, 0, 6);
+    // gl.drawArrays(gl.LINES, 0, 6);
+	gl.drawArrays(gl.TRIANGLES, 0, 6); 
+	console.log("Enum for Primitive Assumbly", gl.TRIANGLES, gl.TRIANGLE, gl.POINTS);  
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/Hello/.gitkeep b/basic_course/Hello/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/basic_course/Hello/hello.js b/basic_course/Hello/hello.js
new file mode 100644
index 0000000000000000000000000000000000000000..c7ddfb95e41408d45e518d2810949f5af5cf0800
--- /dev/null
+++ b/basic_course/Hello/hello.js
@@ -0,0 +1,174 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    /* gl.getError returns the last error that occurred using WebGL for debugging */ 
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl", {antialias: true, depth: false}) || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+		gl.disable(gl.SAMPLE_COVERAGE); 
+		console.log(gl.isEnabled(gl.SAMPLE_COVERAGE)); 
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+function initialiseBuffer() {
+
+    var vertexData = [
+        -0.4, -0.4, 0.0, // Bottom left
+         0.4, -0.4, 0.0, // Bottom right
+         0.0, 0.4, 0.0  // Top middle
+    ];
+
+    // Generate a buffer object
+    gl.vertexBuffer = gl.createBuffer();
+    // Bind buffer as a vertex buffer so we can fill it with data
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    /* Set the buffer's size, data and usage */
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			void main(void) \
+			{ \
+				gl_FragColor = vec4(1.0, 1.0, 0.66, 1.0); \
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			uniform mediump mat4 transformationMatrix; \
+			void main(void)  \
+			{ \
+				gl_Position = transformationMatrix * myVertex; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+
+    return testGLError("initialiseShaders");
+}
+
+function renderScene() {
+
+    gl.clearColor(0.6, 0.8, 1.0, 1.0);
+
+    gl.clear(gl.COLOR_BUFFER_BIT);
+
+    var matrixLocation = gl.getUniformLocation(gl.programObject, "transformationMatrix");
+    var transformationMatrix = [
+        1.0, 0.0, 0.0, 0.0,
+        0.0, 1.0, 0.0, 0.0,
+        0.0, 0.0, 1.0, 0.0,
+        0.0, 0.0, 0.0, 1.0
+    ];
+
+    gl.uniformMatrix4fv(matrixLocation, gl.FALSE, transformationMatrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+    // Enable the user-defined vertex array
+    gl.enableVertexAttribArray(0);
+    // Set the vertex data to this attribute index, with the number of floats in each position
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 0, 0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+    gl.drawArrays(gl.TRIANGLES, 0, 3);
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+	
+
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/Hello/hello.png b/basic_course/Hello/hello.png
new file mode 100644
index 0000000000000000000000000000000000000000..ef7e045751bcb0cd4dd90555bbc3304b101d898f
Binary files /dev/null and b/basic_course/Hello/hello.png differ
diff --git a/basic_course/Hello/index.html b/basic_course/Hello/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..1ac38e16ff83abddd37c3371f6f8a698dce7bbe9
--- /dev/null
+++ b/basic_course/Hello/index.html
@@ -0,0 +1,17 @@
+<html>
+
+<head>
+<title>WebGLHelloAPI</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+
+<script type="text/javascript" src="hello.js">
+</script>
+
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+</body>
+
+</html>
diff --git a/basic_course/VBO/.gitkeep b/basic_course/VBO/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/basic_course/VBO/hello.js b/basic_course/VBO/hello.js
new file mode 100644
index 0000000000000000000000000000000000000000..f8d47ed5943bdf49bbb9115e9f08b40d7a1a538f
--- /dev/null
+++ b/basic_course/VBO/hello.js
@@ -0,0 +1,190 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    /* gl.getError returns the last error that occurred using WebGL for debugging */ 
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+var vertexData = [
+        -0.4, -0.4, 0.0, 1.0, 0.0, 1.0, 1.0,// Bottom left
+         0.4, -0.4, 0.0, 1.0, 1.0, 1.0, 1.0,// Bottom right
+         0.0, 0.4, 0.0,  1.0, 0.0, 0.0, 1.0,// Top middle
+         0.6, 0.6, 0.0,  1.0, 1.0, 1.0, 1.0,// Bottom left
+         0.8, 0.6, 0.0,  1.0, 0.0, 1.0, 1.0,// Bottom right
+         0.7, 0.8, 0.0,   0.0, 0.0, 1.0, 1.0 // Top middle
+];
+var elementData = [ 0,1,2,3,4,5]; 
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+	gl.elementBuffer = gl.createBuffer(); 
+	gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.elementBuffer);
+	gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(elementData),gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color;\
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 transformationMatrix; \
+			varying  highp vec4 color;\
+			void main(void)  \
+			{ \
+				gl_Position = transformationMatrix * myVertex; \
+				gl_PointSize = 8.0; \
+				color = myColor; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+
+    gl.clear(gl.COLOR_BUFFER_BIT);
+
+    var matrixLocation = gl.getUniformLocation(gl.programObject, "transformationMatrix");
+    var transformationMatrix = [
+        1.0, 0.0, 0.0, 0.0,
+        0.0, 1.0, 0.0, 0.0,
+        0.0, 0.0, 1.0, 0.0,
+        0.0, 0.0, 0.0, 1.0
+    ];
+
+    gl.uniformMatrix4fv(matrixLocation, gl.FALSE, transformationMatrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
+	// gl.vertexAttrib4f(1, Math.random(), 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	// gl.lineWidth(6.0);  // It is not working at Chrome!
+    // gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT,0);
+    // gl.drawArrays(gl.POINTS, 0, 6);
+    // gl.drawArrays(gl.LINES, 0, 6);
+	gl.drawArrays(gl.TRIANGLES, 0, 6); 
+	console.log("Enum for Primitive Assumbly", gl.TRIANGLES, gl.TRIANGLE, gl.POINTS);  
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/VBO/hello_multiple_array.js b/basic_course/VBO/hello_multiple_array.js
new file mode 100644
index 0000000000000000000000000000000000000000..6af9eb99a708e914bc6d168d72303d708f823402
--- /dev/null
+++ b/basic_course/VBO/hello_multiple_array.js
@@ -0,0 +1,198 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    /* gl.getError returns the last error that occurred using WebGL for debugging */ 
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+var vertexData = [
+        -0.4, -0.4, 0.0, // Bottom left
+         0.4, -0.4, 0.0, // Bottom right
+         0.0, 0.4, 0.0,  // Top middle
+         0.6, 0.6, 0.0, // Bottom left
+         0.8, 0.6, 0.0, // Bottom right
+         0.7, 0.8, 0.0  // Top middle
+];
+var elementData = [ 0,1,2,3,4,5]; 
+var colorData = [
+	1.0, 0.0, 1.0, 1.0, 
+	1.0, 1.0, 1.0, 1.0, 
+	1.0, 0.0, 0.0, 1.0, 
+	1.0, 1.0, 1.0, 1.0, 
+	1.0, 0.0, 1.0, 1.0, 
+	0.0, 0.0, 1.0, 1.0 ];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+    gl.colorBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.colorBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colorData), gl.STATIC_DRAW);
+
+	gl.elementBuffer = gl.createBuffer(); 
+	gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.elementBuffer);
+	gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(elementData),gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color;\
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 transformationMatrix; \
+			varying  highp vec4 color;\
+			void main(void)  \
+			{ \
+				gl_Position = transformationMatrix * myVertex; \
+				color = myColor; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+     gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+
+    gl.clear(gl.COLOR_BUFFER_BIT);
+
+    var matrixLocation = gl.getUniformLocation(gl.programObject, "transformationMatrix");
+    var transformationMatrix = [
+        1.0, 0.0, 0.0, 0.0,
+        0.0, 1.0, 0.0, 0.0,
+        0.0, 0.0, 1.0, 0.0,
+        0.0, 0.0, 0.0, 1.0
+    ];
+
+    gl.uniformMatrix4fv(matrixLocation, gl.FALSE, transformationMatrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+    // Enable the user-defined vertex array
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    // Set the vertex data to this attribute index, with the number of floats in each position
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 0, 0);
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.colorBuffer);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 0, 0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+    // gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT,0);
+    gl.drawArrays(gl.TRIANGLES, 0, 6);
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/VBO/index.html b/basic_course/VBO/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..1ac38e16ff83abddd37c3371f6f8a698dce7bbe9
--- /dev/null
+++ b/basic_course/VBO/index.html
@@ -0,0 +1,17 @@
+<html>
+
+<head>
+<title>WebGLHelloAPI</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+
+<script type="text/javascript" src="hello.js">
+</script>
+
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+</body>
+
+</html>
diff --git a/basic_course/frag_op/.gitkeep b/basic_course/frag_op/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/basic_course/frag_op/gl-matrix.js b/basic_course/frag_op/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..4553f9ea44878e9b79894c1de08af95ea9814317
--- /dev/null
+++ b/basic_course/frag_op/gl-matrix.js
@@ -0,0 +1,7611 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.3.0
+
+Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, (function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Float32ArrayConstructor | ArrayConstructor} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {ReadonlyMat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return "mat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {ReadonlyMat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {ReadonlyMat2} L the lower triangular matrix
+   * @param {ReadonlyMat2} D the diagonal matrix
+   * @param {ReadonlyMat2} U the upper triangular matrix
+   * @param {ReadonlyMat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, b,
+   *  c, d,
+   *  tx, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, b, 0,
+   *  c, d, 0,
+   *  tx, ty, 1]
+   * </pre>
+   * The last column is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {ReadonlyMat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return "mat2d(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {ReadonlyMat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to translate
+   * @param {ReadonlyVec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 matrix from the given quaternion
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyMat4} a Mat4 to derive the normal matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {ReadonlyMat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return "mat3(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {ReadonlyMat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {ReadonlyVec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Rotates a mat4 by the given angle around the given axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {ReadonlyQuat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @param {ReadonlyVec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {ReadonlyMat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {ReadonlyMat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
+    r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
+    r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {ReadonlyVec3} a The first operand
+   * @param {ReadonlyVec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        bx = b[0],
+        by = b[1],
+        bz = b[2],
+        mag1 = Math.sqrt(ax * ax + ay * ay + az * az),
+        mag2 = Math.sqrt(bx * bx + by * by + bz * bz),
+        mag = mag1 * mag2,
+        cosine = mag && dot(a, b) / mag;
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {ReadonlyVec4} result the receiving vector
+   * @param {ReadonlyVec4} U the first vector
+   * @param {ReadonlyVec4} V the second vector
+   * @param {ReadonlyVec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return "vec4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyVec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {ReadonlyQuat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Gets the angular distance between two unit quaternions
+   *
+   * @param  {ReadonlyQuat} a     Origin unit quaternion
+   * @param  {ReadonlyQuat} b     Destination unit quaternion
+   * @return {Number}     Angle, in radians, between the two quaternions
+   */
+
+  function getAngle(a, b) {
+    var dotproduct = dot$2(a, b);
+    return Math.acos(2 * dotproduct * dotproduct - 1);
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Calculate the exponential of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function exp(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var et = Math.exp(w);
+    var s = r > 0 ? et * Math.sin(r) / r : 0;
+    out[0] = x * s;
+    out[1] = y * s;
+    out[2] = z * s;
+    out[3] = et * Math.cos(r);
+    return out;
+  }
+  /**
+   * Calculate the natural logarithm of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function ln(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var t = r > 0 ? Math.atan2(r, w) / r : 0;
+    out[0] = x * t;
+    out[1] = y * t;
+    out[2] = z * t;
+    out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w);
+    return out;
+  }
+  /**
+   * Calculate the scalar power of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @param {Number} b amount to scale the quaternion by
+   * @returns {quat} out
+   */
+
+  function pow(out, a, b) {
+    ln(out, a);
+    scale$6(out, out, b);
+    exp(out, out);
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random unit quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyMat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {ReadonlyQuat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return "quat(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {ReadonlyQuat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat} a The first quaternion.
+   * @param {ReadonlyQuat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat} a The first vector.
+   * @param {ReadonlyQuat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {ReadonlyVec3} a the initial vector
+   * @param {ReadonlyVec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {ReadonlyQuat} c the third operand
+   * @param {ReadonlyQuat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {ReadonlyVec3} view  the vector representing the viewing direction
+   * @param {ReadonlyVec3} right the vector representing the local "right" direction
+   * @param {ReadonlyVec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    getAngle: getAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    exp: exp,
+    ln: ln,
+    pow: pow,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q a normalized quaternion
+   * @param {ReadonlyVec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyVec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {ReadonlyMat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {ReadonlyQuat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return "quat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ")";
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat2} a the first dual quaternion.
+   * @param {ReadonlyQuat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat2} a the first dual quat.
+   * @param {ReadonlyQuat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {ReadonlyVec2} a The vec2 point to rotate
+   * @param {ReadonlyVec2} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, rad) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(rad),
+        cosC = Math.cos(rad); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {ReadonlyVec2} a The first operand
+   * @param {ReadonlyVec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1],
+        // mag is the product of the magnitudes of a and b
+    mag = Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2),
+        // mag &&.. short circuits if mag == 0
+    cosine = mag && (x1 * x2 + y1 * y2) / mag; // Math.min(Math.max(cosine, -1), 1) clamps the cosine between -1 and 1
+
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return "vec2(" + a[0] + ", " + a[1] + ")";
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/basic_course/frag_op/hello.js b/basic_course/frag_op/hello.js
new file mode 100644
index 0000000000000000000000000000000000000000..c8558cd8dab662c2ef3bbec7f78ee9f7b5052a43
--- /dev/null
+++ b/basic_course/frag_op/hello.js
@@ -0,0 +1,255 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl", {stencil: true}) || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+var vertexData = [
+		// Backface (RED/WHITE) -> z = -0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 0.5,
+         0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 0.5,
+         0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 0.5,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 0.5,
+        -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 0.5,
+         0.5,  0.5, -0.5,  1.0, 1.0, 1.0, 0.5, 
+		// Front (BLUE/WHITE) -> z = 0.5
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 0.5,
+         0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 0.5,
+         0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 0.5,
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 0.5,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 0.5, 
+        -0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 0.5,
+		// LEFT (GREEN/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 0.5,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 0.0, 0.5,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 0.0, 0.5,
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 0.5,
+        -0.5, -0.5,  0.5,  0.0, 1.0, 0.0, 0.5,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 0.5, 
+		// RIGHT (YELLOE/WHITE) -> z = 0.5
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 0.5,
+         0.5,  0.5, -0.5,  1.0, 1.0, 0.0, 0.5,
+         0.5,  0.5,  0.5,  1.0, 1.0, 0.0, 0.5,
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 0.5,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 0.5, 
+         0.5, -0.5,  0.5,  1.0, 1.0, 0.0, 0.5,
+		// BOTTON (MAGENTA/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 0.5,
+         0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 0.5,
+         0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 0.5,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 0.5,
+         0.5, -0.5,  0.5,  1.0, 1.0, 1.0, 0.5, 
+        -0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 0.5,
+		// TOP (CYAN/WHITE) -> z = 0.5
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 0.5,
+         0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 0.5,
+         0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 0.5,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 0.5,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 0.5,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 0.5 
+];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color;\
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 mMat; \
+			uniform mediump mat4 vMat; \
+			uniform mediump mat4 pMat; \
+			varying  highp vec4 color;\
+			void main(void)  \
+			{ \
+				gl_Position = pMat * vMat * mMat * myVertex; \
+				gl_PointSize = 8.0; \
+				color = myColor; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    // console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+flag_animation = 0; 
+function toggleAnimation()
+{
+	flag_animation ^= 1; 
+}
+
+rotY = 0.0;
+
+function renderScene() {
+
+	gl.disable(gl.SCISSOR_TEST);
+	//gl.enable(gl.SCISSOR_TEST);
+	// gl.scissor(350, 250, 100, 100); 
+
+	//gl.enable(gl.SCISSOR_TEST);
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+	gl.clearDepth(1.0);										// Added for depth Test 
+	gl.clearStencil(0); 
+
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);	// Added for depth Test 
+	gl.disable(gl.DEPTH_TEST);								// Added for depth Test 
+	gl.depthFunc(gl.LESS); 
+	// gl.disable(gl.POLYGON_OFFSET_FILL); 
+	// gl.enable(gl.CULL_FACE);								// Added for depth Test 
+	// gl.enable(gl.STENCIL_TEST); 
+	gl.enable(gl.BLEND); 
+	gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 
+
+
+    var mMatLocation = gl.getUniformLocation(gl.programObject, "mMat");
+    var vMatLocation = gl.getUniformLocation(gl.programObject, "vMat");
+    var pMatLocation = gl.getUniformLocation(gl.programObject, "pMat");
+    var mMat = []; 
+	mat4.translate(mMat, mMat, [0.0, 0.0, 0.0]); 
+	if ( flag_animation ){
+		rotY += 0.01;
+	}
+	var vMat = [];
+	mat4.lookAt(vMat, [0.0, 0.0, 3.0], [0.0,0.0,0.0], [0.0, 1.0, 0.0]);
+	var pMat = [];
+	mat4.identity(pMat); 
+	// mat4.ortho(pMat, -2*800.0/600.0, 2*800.0/600.0, -2, 2, 1, 7.0)
+	mat4.perspective(pMat, 3.64/2.0, 800.0/600.0, 0.5, 9);
+	// console.log("pMAT:", pMat);
+
+    gl.uniformMatrix4fv(vMatLocation, gl.FALSE, vMat );
+    gl.uniformMatrix4fv(pMatLocation, gl.FALSE, pMat );
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+	//vertexData[0] += 0.01; 
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    //gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
+	//gl.vertexAttrib4f(1, 1.0, 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+	// gl.stencilFunc(gl.ALWAYS, 1, 0xff); 
+	// gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE); 
+
+	mat4.identity(mMat); 
+	mat4.rotateY(mMat, mMat, rotY); 
+	gl.uniformMatrix4fv(mMatLocation, gl.FALSE, mMat );
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+
+	// gl.enable(gl.POLYGON_OFFSET_FILL); 
+	// gl.polygonOffset(-0.1, -0.1); 
+	// gl.stencilFunc(gl.EQUAL, 1, 0xff); 
+	// gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); 
+
+	mat4.identity(mMat); 
+	mat4.rotateY(mMat, mMat, rotY*2.0); 
+	mat4.translate(mMat, mMat, [0.8, 0.8, 0.8, 0.0]); 
+	gl.uniformMatrix4fv(mMatLocation, gl.FALSE, mMat );
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+
+    if (!testGLError("gl.drawArrays")) { return false; }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) { return; }
+    if (!initialiseBuffer()) { return; }
+    if (!initialiseShaders()) { return; }
+	// renderScene();
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000, 60); };
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/frag_op/hello_start.js b/basic_course/frag_op/hello_start.js
new file mode 100644
index 0000000000000000000000000000000000000000..7c9abe1a670221f19dd07490d0162a0ad580c06a
--- /dev/null
+++ b/basic_course/frag_op/hello_start.js
@@ -0,0 +1,238 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+var vertexData = [
+		// Backface (RED/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 1.0, 1.0, 
+		// Front (BLUE/WHITE) -> z = 0.5
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// LEFT (GREEN/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0, 
+		// RIGHT (YELLOE/WHITE) -> z = 0.5
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// BOTTON (MAGENTA/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// TOP (CYAN/WHITE) -> z = 0.5
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0 
+];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color;\
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 mMat; \
+			uniform mediump mat4 vMat; \
+			uniform mediump mat4 pMat; \
+			varying  highp vec4 color;\
+			void main(void)  \
+			{ \
+				gl_Position = pMat * vMat * mMat * myVertex; \
+				gl_PointSize = 8.0; \
+				color = myColor; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    // console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+flag_animation = 0; 
+function toggleAnimation()
+{
+	flag_animation ^= 1; 
+}
+
+rotY = 0.0;
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+	gl.clearDepth(1.0);										// Added for depth Test 
+
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);	// Added for depth Test 
+	gl.enable(gl.DEPTH_TEST);								// Added for depth Test 
+
+    var mMatLocation = gl.getUniformLocation(gl.programObject, "mMat");
+    var vMatLocation = gl.getUniformLocation(gl.programObject, "vMat");
+    var pMatLocation = gl.getUniformLocation(gl.programObject, "pMat");
+    var mMat = []; 
+	mat4.translate(mMat, mMat, [0.0, 0.0, 0.0]); 
+	if ( flag_animation ){
+		rotY += 0.01;
+	}
+	var vMat = [];
+	mat4.lookAt(vMat, [0.0, 0.0, 3.0], [0.0,0.0,0.0], [0.0, 1.0, 0.0]);
+	console.log(vMat); 
+	var pMat = [];
+	mat4.identity(pMat); 
+	// mat4.ortho(pMat, -2*800.0/600.0, 2*800.0/600.0, -2, 2, 1, 7.0)
+	mat4.perspective(pMat, 3.64/2.0, 800.0/600.0, 0.5, 9);
+	// console.log("pMAT:", pMat);
+
+    gl.uniformMatrix4fv(vMatLocation, gl.FALSE, vMat );
+    gl.uniformMatrix4fv(pMatLocation, gl.FALSE, pMat );
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+	//vertexData[0] += 0.01; 
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    //gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
+	//gl.vertexAttrib4f(1, 1.0, 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	var i; 
+	mat4.identity(mMat); 
+	mat4.rotateY(mMat, mMat, rotY); 
+	gl.uniformMatrix4fv(mMatLocation, gl.FALSE, mMat );
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+
+	mat4.identity(mMat); 
+	mat4.rotateY(mMat, mMat, 4.0*rotY); 
+	mat4.translate(mMat, mMat, [0.6, 0.6, 0.6, 0.0]); 
+	gl.uniformMatrix4fv(mMatLocation, gl.FALSE, mMat );
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) { return; }
+    if (!initialiseBuffer()) { return; }
+    if (!initialiseShaders()) { return; }
+	// renderScene();
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000, 60); };
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/frag_op/index.html b/basic_course/frag_op/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..ea3ea9b98e0edd7858516fef6bef03c4f4add9e3
--- /dev/null
+++ b/basic_course/frag_op/index.html
@@ -0,0 +1,22 @@
+<html>
+
+<head>
+<title>WebGL Tutorial 07 - Transform Coding</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js"> </script>
+<script> 
+window['mat4'] = glMatrix.mat4;
+window['vec4'] = glMatrix.vec4;
+window['vec3'] = glMatrix.vec4;
+</script>
+<script type="text/javascript" src="hello.js"> </script>
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+	<br>
+<button onclick="toggleAnimation()">Toggle Animation</button>
+</body>
+
+</html>
diff --git a/basic_course/gl-matrix/gl-matrix-min.js b/basic_course/gl-matrix/gl-matrix-min.js
new file mode 100644
index 0000000000000000000000000000000000000000..9a1253bd7925aca19478e7b4ccc01e4891a1e33d
--- /dev/null
+++ b/basic_course/gl-matrix/gl-matrix-min.js
@@ -0,0 +1,28 @@
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.3.0
+
+Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t=t||self).glMatrix={})}(this,(function(t){"use strict";var n="undefined"!=typeof Float32Array?Float32Array:Array,a=Math.random;var r=Math.PI/180;Math.hypot||(Math.hypot=function(){for(var t=0,n=arguments.length;n--;)t+=arguments[n]*arguments[n];return Math.sqrt(t)});var e=Object.freeze({__proto__:null,EPSILON:1e-6,get ARRAY_TYPE(){return n},RANDOM:a,setMatrixArrayType:function(t){n=t},toRadian:function(t){return t*r},equals:function(t,n){return Math.abs(t-n)<=1e-6*Math.max(1,Math.abs(t),Math.abs(n))}});function u(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=a[0],h=a[1],c=a[2],s=a[3];return t[0]=r*i+u*h,t[1]=e*i+o*h,t[2]=r*c+u*s,t[3]=e*c+o*s,t}function o(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}var i=u,h=o,c=Object.freeze({__proto__:null,create:function(){var t=new n(4);return n!=Float32Array&&(t[1]=0,t[2]=0),t[0]=1,t[3]=1,t},clone:function(t){var a=new n(4);return a[0]=t[0],a[1]=t[1],a[2]=t[2],a[3]=t[3],a},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t},fromValues:function(t,a,r,e){var u=new n(4);return u[0]=t,u[1]=a,u[2]=r,u[3]=e,u},set:function(t,n,a,r,e){return t[0]=n,t[1]=a,t[2]=r,t[3]=e,t},transpose:function(t,n){if(t===n){var a=n[1];t[1]=n[2],t[2]=a}else t[0]=n[0],t[1]=n[2],t[2]=n[1],t[3]=n[3];return t},invert:function(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=a*u-e*r;return o?(o=1/o,t[0]=u*o,t[1]=-r*o,t[2]=-e*o,t[3]=a*o,t):null},adjoint:function(t,n){var a=n[0];return t[0]=n[3],t[1]=-n[1],t[2]=-n[2],t[3]=a,t},determinant:function(t){return t[0]*t[3]-t[2]*t[1]},multiply:u,rotate:function(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=Math.sin(a),h=Math.cos(a);return t[0]=r*h+u*i,t[1]=e*h+o*i,t[2]=r*-i+u*h,t[3]=e*-i+o*h,t},scale:function(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=a[0],h=a[1];return t[0]=r*i,t[1]=e*i,t[2]=u*h,t[3]=o*h,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t},str:function(t){return"mat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3])},LDU:function(t,n,a,r){return t[2]=r[2]/r[0],a[0]=r[0],a[1]=r[1],a[3]=r[3]-t[2]*a[1],[t,n,a]},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t},subtract:o,exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]},equals:function(t,n){var a=t[0],r=t[1],e=t[2],u=t[3],o=n[0],i=n[1],h=n[2],c=n[3];return Math.abs(a-o)<=1e-6*Math.max(1,Math.abs(a),Math.abs(o))&&Math.abs(r-i)<=1e-6*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(e-h)<=1e-6*Math.max(1,Math.abs(e),Math.abs(h))&&Math.abs(u-c)<=1e-6*Math.max(1,Math.abs(u),Math.abs(c))},multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t},mul:i,sub:h});function s(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=n[4],h=n[5],c=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return t[0]=r*c+u*s,t[1]=e*c+o*s,t[2]=r*M+u*f,t[3]=e*M+o*f,t[4]=r*l+u*v+i,t[5]=e*l+o*v+h,t}function M(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t}var f=s,l=M,v=Object.freeze({__proto__:null,create:function(){var t=new n(6);return n!=Float32Array&&(t[1]=0,t[2]=0,t[4]=0,t[5]=0),t[0]=1,t[3]=1,t},clone:function(t){var a=new n(6);return a[0]=t[0],a[1]=t[1],a[2]=t[2],a[3]=t[3],a[4]=t[4],a[5]=t[5],a},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t},fromValues:function(t,a,r,e,u,o){var i=new n(6);return i[0]=t,i[1]=a,i[2]=r,i[3]=e,i[4]=u,i[5]=o,i},set:function(t,n,a,r,e,u,o){return t[0]=n,t[1]=a,t[2]=r,t[3]=e,t[4]=u,t[5]=o,t},invert:function(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=n[4],i=n[5],h=a*u-r*e;return h?(h=1/h,t[0]=u*h,t[1]=-r*h,t[2]=-e*h,t[3]=a*h,t[4]=(e*i-u*o)*h,t[5]=(r*o-a*i)*h,t):null},determinant:function(t){return t[0]*t[3]-t[1]*t[2]},multiply:s,rotate:function(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=n[4],h=n[5],c=Math.sin(a),s=Math.cos(a);return t[0]=r*s+u*c,t[1]=e*s+o*c,t[2]=r*-c+u*s,t[3]=e*-c+o*s,t[4]=i,t[5]=h,t},scale:function(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=n[4],h=n[5],c=a[0],s=a[1];return t[0]=r*c,t[1]=e*c,t[2]=u*s,t[3]=o*s,t[4]=i,t[5]=h,t},translate:function(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=n[4],h=n[5],c=a[0],s=a[1];return t[0]=r,t[1]=e,t[2]=u,t[3]=o,t[4]=r*c+u*s+i,t[5]=e*c+o*s+h,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t[4]=0,t[5]=0,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t[4]=0,t[5]=0,t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=n[0],t[5]=n[1],t},str:function(t){return"mat2d("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],1)},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t},subtract:M,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]},equals:function(t,n){var a=t[0],r=t[1],e=t[2],u=t[3],o=t[4],i=t[5],h=n[0],c=n[1],s=n[2],M=n[3],f=n[4],l=n[5];return Math.abs(a-h)<=1e-6*Math.max(1,Math.abs(a),Math.abs(h))&&Math.abs(r-c)<=1e-6*Math.max(1,Math.abs(r),Math.abs(c))&&Math.abs(e-s)<=1e-6*Math.max(1,Math.abs(e),Math.abs(s))&&Math.abs(u-M)<=1e-6*Math.max(1,Math.abs(u),Math.abs(M))&&Math.abs(o-f)<=1e-6*Math.max(1,Math.abs(o),Math.abs(f))&&Math.abs(i-l)<=1e-6*Math.max(1,Math.abs(i),Math.abs(l))},mul:f,sub:l});function b(){var t=new n(9);return n!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function m(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],p=a[6],x=a[7],y=a[8];return t[0]=f*r+l*o+v*c,t[1]=f*e+l*i+v*s,t[2]=f*u+l*h+v*M,t[3]=b*r+m*o+d*c,t[4]=b*e+m*i+d*s,t[5]=b*u+m*h+d*M,t[6]=p*r+x*o+y*c,t[7]=p*e+x*i+y*s,t[8]=p*u+x*h+y*M,t}function d(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t}var p=m,x=d,y=Object.freeze({__proto__:null,create:b,fromMat4:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[4],t[4]=n[5],t[5]=n[6],t[6]=n[8],t[7]=n[9],t[8]=n[10],t},clone:function(t){var a=new n(9);return a[0]=t[0],a[1]=t[1],a[2]=t[2],a[3]=t[3],a[4]=t[4],a[5]=t[5],a[6]=t[6],a[7]=t[7],a[8]=t[8],a},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromValues:function(t,a,r,e,u,o,i,h,c){var s=new n(9);return s[0]=t,s[1]=a,s[2]=r,s[3]=e,s[4]=u,s[5]=o,s[6]=i,s[7]=h,s[8]=c,s},set:function(t,n,a,r,e,u,o,i,h,c){return t[0]=n,t[1]=a,t[2]=r,t[3]=e,t[4]=u,t[5]=o,t[6]=i,t[7]=h,t[8]=c,t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},transpose:function(t,n){if(t===n){var a=n[1],r=n[2],e=n[5];t[1]=n[3],t[2]=n[6],t[3]=a,t[5]=n[7],t[6]=r,t[7]=e}else t[0]=n[0],t[1]=n[3],t[2]=n[6],t[3]=n[1],t[4]=n[4],t[5]=n[7],t[6]=n[2],t[7]=n[5],t[8]=n[8];return t},invert:function(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8],M=s*o-i*c,f=-s*u+i*h,l=c*u-o*h,v=a*M+r*f+e*l;return v?(v=1/v,t[0]=M*v,t[1]=(-s*r+e*c)*v,t[2]=(i*r-e*o)*v,t[3]=f*v,t[4]=(s*a-e*h)*v,t[5]=(-i*a+e*u)*v,t[6]=l*v,t[7]=(-c*a+r*h)*v,t[8]=(o*a-r*u)*v,t):null},adjoint:function(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8];return t[0]=o*s-i*c,t[1]=e*c-r*s,t[2]=r*i-e*o,t[3]=i*h-u*s,t[4]=a*s-e*h,t[5]=e*u-a*i,t[6]=u*c-o*h,t[7]=r*h-a*c,t[8]=a*o-r*u,t},determinant:function(t){var n=t[0],a=t[1],r=t[2],e=t[3],u=t[4],o=t[5],i=t[6],h=t[7],c=t[8];return n*(c*u-o*h)+a*(-c*e+o*i)+r*(h*e-u*i)},multiply:m,translate:function(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=a[0],l=a[1];return t[0]=r,t[1]=e,t[2]=u,t[3]=o,t[4]=i,t[5]=h,t[6]=f*r+l*o+c,t[7]=f*e+l*i+s,t[8]=f*u+l*h+M,t},rotate:function(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=Math.sin(a),l=Math.cos(a);return t[0]=l*r+f*o,t[1]=l*e+f*i,t[2]=l*u+f*h,t[3]=l*o-f*r,t[4]=l*i-f*e,t[5]=l*h-f*u,t[6]=c,t[7]=s,t[8]=M,t},scale:function(t,n,a){var r=a[0],e=a[1];return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=e*n[3],t[4]=e*n[4],t[5]=e*n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=n[0],t[7]=n[1],t[8]=1,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=-a,t[4]=r,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=n[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromMat2d:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=0,t[3]=n[2],t[4]=n[3],t[5]=0,t[6]=n[4],t[7]=n[5],t[8]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=a+a,i=r+r,h=e+e,c=a*o,s=r*o,M=r*i,f=e*o,l=e*i,v=e*h,b=u*o,m=u*i,d=u*h;return t[0]=1-M-v,t[3]=s-d,t[6]=f+m,t[1]=s+d,t[4]=1-c-v,t[7]=l-b,t[2]=f-m,t[5]=l+b,t[8]=1-c-M,t},normalFromMat4:function(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],p=a*i-r*o,x=a*h-e*o,y=a*c-u*o,q=r*h-e*i,g=r*c-u*i,_=e*c-u*h,A=s*b-M*v,w=s*m-f*v,R=s*d-l*v,z=M*m-f*b,j=M*d-l*b,P=f*d-l*m,S=p*P-x*j+y*z+q*R-g*w+_*A;return S?(S=1/S,t[0]=(i*P-h*j+c*z)*S,t[1]=(h*R-o*P-c*w)*S,t[2]=(o*j-i*R+c*A)*S,t[3]=(e*j-r*P-u*z)*S,t[4]=(a*P-e*R+u*w)*S,t[5]=(r*R-a*j-u*A)*S,t[6]=(b*_-m*g+d*q)*S,t[7]=(m*y-v*_-d*x)*S,t[8]=(v*g-b*y+d*p)*S,t):null},projection:function(t,n,a){return t[0]=2/n,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/a,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t},str:function(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t},subtract:d,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]},equals:function(t,n){var a=t[0],r=t[1],e=t[2],u=t[3],o=t[4],i=t[5],h=t[6],c=t[7],s=t[8],M=n[0],f=n[1],l=n[2],v=n[3],b=n[4],m=n[5],d=n[6],p=n[7],x=n[8];return Math.abs(a-M)<=1e-6*Math.max(1,Math.abs(a),Math.abs(M))&&Math.abs(r-f)<=1e-6*Math.max(1,Math.abs(r),Math.abs(f))&&Math.abs(e-l)<=1e-6*Math.max(1,Math.abs(e),Math.abs(l))&&Math.abs(u-v)<=1e-6*Math.max(1,Math.abs(u),Math.abs(v))&&Math.abs(o-b)<=1e-6*Math.max(1,Math.abs(o),Math.abs(b))&&Math.abs(i-m)<=1e-6*Math.max(1,Math.abs(i),Math.abs(m))&&Math.abs(h-d)<=1e-6*Math.max(1,Math.abs(h),Math.abs(d))&&Math.abs(c-p)<=1e-6*Math.max(1,Math.abs(c),Math.abs(p))&&Math.abs(s-x)<=1e-6*Math.max(1,Math.abs(s),Math.abs(x))},mul:p,sub:x});function q(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function g(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],b=n[12],m=n[13],d=n[14],p=n[15],x=a[0],y=a[1],q=a[2],g=a[3];return t[0]=x*r+y*i+q*M+g*b,t[1]=x*e+y*h+q*f+g*m,t[2]=x*u+y*c+q*l+g*d,t[3]=x*o+y*s+q*v+g*p,x=a[4],y=a[5],q=a[6],g=a[7],t[4]=x*r+y*i+q*M+g*b,t[5]=x*e+y*h+q*f+g*m,t[6]=x*u+y*c+q*l+g*d,t[7]=x*o+y*s+q*v+g*p,x=a[8],y=a[9],q=a[10],g=a[11],t[8]=x*r+y*i+q*M+g*b,t[9]=x*e+y*h+q*f+g*m,t[10]=x*u+y*c+q*l+g*d,t[11]=x*o+y*s+q*v+g*p,x=a[12],y=a[13],q=a[14],g=a[15],t[12]=x*r+y*i+q*M+g*b,t[13]=x*e+y*h+q*f+g*m,t[14]=x*u+y*c+q*l+g*d,t[15]=x*o+y*s+q*v+g*p,t}function _(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=r+r,h=e+e,c=u+u,s=r*i,M=r*h,f=r*c,l=e*h,v=e*c,b=u*c,m=o*i,d=o*h,p=o*c;return t[0]=1-(l+b),t[1]=M+p,t[2]=f-d,t[3]=0,t[4]=M-p,t[5]=1-(s+b),t[6]=v+m,t[7]=0,t[8]=f+d,t[9]=v-m,t[10]=1-(s+l),t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t}function A(t,n){return t[0]=n[12],t[1]=n[13],t[2]=n[14],t}function w(t,n){var a=n[0],r=n[1],e=n[2],u=n[4],o=n[5],i=n[6],h=n[8],c=n[9],s=n[10];return t[0]=Math.hypot(a,r,e),t[1]=Math.hypot(u,o,i),t[2]=Math.hypot(h,c,s),t}function R(t,a){var r=new n(3);w(r,a);var e=1/r[0],u=1/r[1],o=1/r[2],i=a[0]*e,h=a[1]*u,c=a[2]*o,s=a[4]*e,M=a[5]*u,f=a[6]*o,l=a[8]*e,v=a[9]*u,b=a[10]*o,m=i+M+b,d=0;return m>0?(d=2*Math.sqrt(m+1),t[3]=.25*d,t[0]=(f-v)/d,t[1]=(l-c)/d,t[2]=(h-s)/d):i>M&&i>b?(d=2*Math.sqrt(1+i-M-b),t[3]=(f-v)/d,t[0]=.25*d,t[1]=(h+s)/d,t[2]=(l+c)/d):M>b?(d=2*Math.sqrt(1+M-i-b),t[3]=(l-c)/d,t[0]=(h+s)/d,t[1]=.25*d,t[2]=(f+v)/d):(d=2*Math.sqrt(1+b-i-M),t[3]=(h-s)/d,t[0]=(l+c)/d,t[1]=(f+v)/d,t[2]=.25*d),t}function z(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t[9]=n[9]-a[9],t[10]=n[10]-a[10],t[11]=n[11]-a[11],t[12]=n[12]-a[12],t[13]=n[13]-a[13],t[14]=n[14]-a[14],t[15]=n[15]-a[15],t}var j=g,P=z,S=Object.freeze({__proto__:null,create:function(){var t=new n(16);return n!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0),t[0]=1,t[5]=1,t[10]=1,t[15]=1,t},clone:function(t){var a=new n(16);return a[0]=t[0],a[1]=t[1],a[2]=t[2],a[3]=t[3],a[4]=t[4],a[5]=t[5],a[6]=t[6],a[7]=t[7],a[8]=t[8],a[9]=t[9],a[10]=t[10],a[11]=t[11],a[12]=t[12],a[13]=t[13],a[14]=t[14],a[15]=t[15],a},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},fromValues:function(t,a,r,e,u,o,i,h,c,s,M,f,l,v,b,m){var d=new n(16);return d[0]=t,d[1]=a,d[2]=r,d[3]=e,d[4]=u,d[5]=o,d[6]=i,d[7]=h,d[8]=c,d[9]=s,d[10]=M,d[11]=f,d[12]=l,d[13]=v,d[14]=b,d[15]=m,d},set:function(t,n,a,r,e,u,o,i,h,c,s,M,f,l,v,b,m){return t[0]=n,t[1]=a,t[2]=r,t[3]=e,t[4]=u,t[5]=o,t[6]=i,t[7]=h,t[8]=c,t[9]=s,t[10]=M,t[11]=f,t[12]=l,t[13]=v,t[14]=b,t[15]=m,t},identity:q,transpose:function(t,n){if(t===n){var a=n[1],r=n[2],e=n[3],u=n[6],o=n[7],i=n[11];t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=a,t[6]=n[9],t[7]=n[13],t[8]=r,t[9]=u,t[11]=n[14],t[12]=e,t[13]=o,t[14]=i}else t[0]=n[0],t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=n[1],t[5]=n[5],t[6]=n[9],t[7]=n[13],t[8]=n[2],t[9]=n[6],t[10]=n[10],t[11]=n[14],t[12]=n[3],t[13]=n[7],t[14]=n[11],t[15]=n[15];return t},invert:function(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],p=a*i-r*o,x=a*h-e*o,y=a*c-u*o,q=r*h-e*i,g=r*c-u*i,_=e*c-u*h,A=s*b-M*v,w=s*m-f*v,R=s*d-l*v,z=M*m-f*b,j=M*d-l*b,P=f*d-l*m,S=p*P-x*j+y*z+q*R-g*w+_*A;return S?(S=1/S,t[0]=(i*P-h*j+c*z)*S,t[1]=(e*j-r*P-u*z)*S,t[2]=(b*_-m*g+d*q)*S,t[3]=(f*g-M*_-l*q)*S,t[4]=(h*R-o*P-c*w)*S,t[5]=(a*P-e*R+u*w)*S,t[6]=(m*y-v*_-d*x)*S,t[7]=(s*_-f*y+l*x)*S,t[8]=(o*j-i*R+c*A)*S,t[9]=(r*R-a*j-u*A)*S,t[10]=(v*g-b*y+d*p)*S,t[11]=(M*y-s*g-l*p)*S,t[12]=(i*w-o*z-h*A)*S,t[13]=(a*z-r*w+e*A)*S,t[14]=(b*x-v*q-m*p)*S,t[15]=(s*q-M*x+f*p)*S,t):null},adjoint:function(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15];return t[0]=i*(f*d-l*m)-M*(h*d-c*m)+b*(h*l-c*f),t[1]=-(r*(f*d-l*m)-M*(e*d-u*m)+b*(e*l-u*f)),t[2]=r*(h*d-c*m)-i*(e*d-u*m)+b*(e*c-u*h),t[3]=-(r*(h*l-c*f)-i*(e*l-u*f)+M*(e*c-u*h)),t[4]=-(o*(f*d-l*m)-s*(h*d-c*m)+v*(h*l-c*f)),t[5]=a*(f*d-l*m)-s*(e*d-u*m)+v*(e*l-u*f),t[6]=-(a*(h*d-c*m)-o*(e*d-u*m)+v*(e*c-u*h)),t[7]=a*(h*l-c*f)-o*(e*l-u*f)+s*(e*c-u*h),t[8]=o*(M*d-l*b)-s*(i*d-c*b)+v*(i*l-c*M),t[9]=-(a*(M*d-l*b)-s*(r*d-u*b)+v*(r*l-u*M)),t[10]=a*(i*d-c*b)-o*(r*d-u*b)+v*(r*c-u*i),t[11]=-(a*(i*l-c*M)-o*(r*l-u*M)+s*(r*c-u*i)),t[12]=-(o*(M*m-f*b)-s*(i*m-h*b)+v*(i*f-h*M)),t[13]=a*(M*m-f*b)-s*(r*m-e*b)+v*(r*f-e*M),t[14]=-(a*(i*m-h*b)-o*(r*m-e*b)+v*(r*h-e*i)),t[15]=a*(i*f-h*M)-o*(r*f-e*M)+s*(r*h-e*i),t},determinant:function(t){var n=t[0],a=t[1],r=t[2],e=t[3],u=t[4],o=t[5],i=t[6],h=t[7],c=t[8],s=t[9],M=t[10],f=t[11],l=t[12],v=t[13],b=t[14],m=t[15];return(n*o-a*u)*(M*m-f*b)-(n*i-r*u)*(s*m-f*v)+(n*h-e*u)*(s*b-M*v)+(a*i-r*o)*(c*m-f*l)-(a*h-e*o)*(c*b-M*l)+(r*h-e*i)*(c*v-s*l)},multiply:g,translate:function(t,n,a){var r,e,u,o,i,h,c,s,M,f,l,v,b=a[0],m=a[1],d=a[2];return n===t?(t[12]=n[0]*b+n[4]*m+n[8]*d+n[12],t[13]=n[1]*b+n[5]*m+n[9]*d+n[13],t[14]=n[2]*b+n[6]*m+n[10]*d+n[14],t[15]=n[3]*b+n[7]*m+n[11]*d+n[15]):(r=n[0],e=n[1],u=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],t[0]=r,t[1]=e,t[2]=u,t[3]=o,t[4]=i,t[5]=h,t[6]=c,t[7]=s,t[8]=M,t[9]=f,t[10]=l,t[11]=v,t[12]=r*b+i*m+M*d+n[12],t[13]=e*b+h*m+f*d+n[13],t[14]=u*b+c*m+l*d+n[14],t[15]=o*b+s*m+v*d+n[15]),t},scale:function(t,n,a){var r=a[0],e=a[1],u=a[2];return t[0]=n[0]*r,t[1]=n[1]*r,t[2]=n[2]*r,t[3]=n[3]*r,t[4]=n[4]*e,t[5]=n[5]*e,t[6]=n[6]*e,t[7]=n[7]*e,t[8]=n[8]*u,t[9]=n[9]*u,t[10]=n[10]*u,t[11]=n[11]*u,t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},rotate:function(t,n,a,r){var e,u,o,i,h,c,s,M,f,l,v,b,m,d,p,x,y,q,g,_,A,w,R,z,j=r[0],P=r[1],S=r[2],E=Math.hypot(j,P,S);return E<1e-6?null:(j*=E=1/E,P*=E,S*=E,e=Math.sin(a),o=1-(u=Math.cos(a)),i=n[0],h=n[1],c=n[2],s=n[3],M=n[4],f=n[5],l=n[6],v=n[7],b=n[8],m=n[9],d=n[10],p=n[11],x=j*j*o+u,y=P*j*o+S*e,q=S*j*o-P*e,g=j*P*o-S*e,_=P*P*o+u,A=S*P*o+j*e,w=j*S*o+P*e,R=P*S*o-j*e,z=S*S*o+u,t[0]=i*x+M*y+b*q,t[1]=h*x+f*y+m*q,t[2]=c*x+l*y+d*q,t[3]=s*x+v*y+p*q,t[4]=i*g+M*_+b*A,t[5]=h*g+f*_+m*A,t[6]=c*g+l*_+d*A,t[7]=s*g+v*_+p*A,t[8]=i*w+M*R+b*z,t[9]=h*w+f*R+m*z,t[10]=c*w+l*R+d*z,t[11]=s*w+v*R+p*z,n!==t&&(t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t)},rotateX:function(t,n,a){var r=Math.sin(a),e=Math.cos(a),u=n[4],o=n[5],i=n[6],h=n[7],c=n[8],s=n[9],M=n[10],f=n[11];return n!==t&&(t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[4]=u*e+c*r,t[5]=o*e+s*r,t[6]=i*e+M*r,t[7]=h*e+f*r,t[8]=c*e-u*r,t[9]=s*e-o*r,t[10]=M*e-i*r,t[11]=f*e-h*r,t},rotateY:function(t,n,a){var r=Math.sin(a),e=Math.cos(a),u=n[0],o=n[1],i=n[2],h=n[3],c=n[8],s=n[9],M=n[10],f=n[11];return n!==t&&(t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[0]=u*e-c*r,t[1]=o*e-s*r,t[2]=i*e-M*r,t[3]=h*e-f*r,t[8]=u*r+c*e,t[9]=o*r+s*e,t[10]=i*r+M*e,t[11]=h*r+f*e,t},rotateZ:function(t,n,a){var r=Math.sin(a),e=Math.cos(a),u=n[0],o=n[1],i=n[2],h=n[3],c=n[4],s=n[5],M=n[6],f=n[7];return n!==t&&(t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[0]=u*e+c*r,t[1]=o*e+s*r,t[2]=i*e+M*r,t[3]=h*e+f*r,t[4]=c*e-u*r,t[5]=s*e-o*r,t[6]=M*e-i*r,t[7]=f*e-h*r,t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=n[0],t[13]=n[1],t[14]=n[2],t[15]=1,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=n[1],t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=n[2],t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromRotation:function(t,n,a){var r,e,u,o=a[0],i=a[1],h=a[2],c=Math.hypot(o,i,h);return c<1e-6?null:(o*=c=1/c,i*=c,h*=c,r=Math.sin(n),u=1-(e=Math.cos(n)),t[0]=o*o*u+e,t[1]=i*o*u+h*r,t[2]=h*o*u-i*r,t[3]=0,t[4]=o*i*u-h*r,t[5]=i*i*u+e,t[6]=h*i*u+o*r,t[7]=0,t[8]=o*h*u+i*r,t[9]=i*h*u-o*r,t[10]=h*h*u+e,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t)},fromXRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=r,t[6]=a,t[7]=0,t[8]=0,t[9]=-a,t[10]=r,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromYRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=0,t[2]=-a,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=a,t[9]=0,t[10]=r,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromZRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=0,t[4]=-a,t[5]=r,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromRotationTranslation:_,fromQuat2:function(t,a){var r=new n(3),e=-a[0],u=-a[1],o=-a[2],i=a[3],h=a[4],c=a[5],s=a[6],M=a[7],f=e*e+u*u+o*o+i*i;return f>0?(r[0]=2*(h*i+M*e+c*o-s*u)/f,r[1]=2*(c*i+M*u+s*e-h*o)/f,r[2]=2*(s*i+M*o+h*u-c*e)/f):(r[0]=2*(h*i+M*e+c*o-s*u),r[1]=2*(c*i+M*u+s*e-h*o),r[2]=2*(s*i+M*o+h*u-c*e)),_(t,a,r),t},getTranslation:A,getScaling:w,getRotation:R,fromRotationTranslationScale:function(t,n,a,r){var e=n[0],u=n[1],o=n[2],i=n[3],h=e+e,c=u+u,s=o+o,M=e*h,f=e*c,l=e*s,v=u*c,b=u*s,m=o*s,d=i*h,p=i*c,x=i*s,y=r[0],q=r[1],g=r[2];return t[0]=(1-(v+m))*y,t[1]=(f+x)*y,t[2]=(l-p)*y,t[3]=0,t[4]=(f-x)*q,t[5]=(1-(M+m))*q,t[6]=(b+d)*q,t[7]=0,t[8]=(l+p)*g,t[9]=(b-d)*g,t[10]=(1-(M+v))*g,t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t},fromRotationTranslationScaleOrigin:function(t,n,a,r,e){var u=n[0],o=n[1],i=n[2],h=n[3],c=u+u,s=o+o,M=i+i,f=u*c,l=u*s,v=u*M,b=o*s,m=o*M,d=i*M,p=h*c,x=h*s,y=h*M,q=r[0],g=r[1],_=r[2],A=e[0],w=e[1],R=e[2],z=(1-(b+d))*q,j=(l+y)*q,P=(v-x)*q,S=(l-y)*g,E=(1-(f+d))*g,O=(m+p)*g,T=(v+x)*_,D=(m-p)*_,F=(1-(f+b))*_;return t[0]=z,t[1]=j,t[2]=P,t[3]=0,t[4]=S,t[5]=E,t[6]=O,t[7]=0,t[8]=T,t[9]=D,t[10]=F,t[11]=0,t[12]=a[0]+A-(z*A+S*w+T*R),t[13]=a[1]+w-(j*A+E*w+D*R),t[14]=a[2]+R-(P*A+O*w+F*R),t[15]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=a+a,i=r+r,h=e+e,c=a*o,s=r*o,M=r*i,f=e*o,l=e*i,v=e*h,b=u*o,m=u*i,d=u*h;return t[0]=1-M-v,t[1]=s+d,t[2]=f-m,t[3]=0,t[4]=s-d,t[5]=1-c-v,t[6]=l+b,t[7]=0,t[8]=f+m,t[9]=l-b,t[10]=1-c-M,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},frustum:function(t,n,a,r,e,u,o){var i=1/(a-n),h=1/(e-r),c=1/(u-o);return t[0]=2*u*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*u*h,t[6]=0,t[7]=0,t[8]=(a+n)*i,t[9]=(e+r)*h,t[10]=(o+u)*c,t[11]=-1,t[12]=0,t[13]=0,t[14]=o*u*2*c,t[15]=0,t},perspective:function(t,n,a,r,e){var u,o=1/Math.tan(n/2);return t[0]=o/a,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=o,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=-1,t[12]=0,t[13]=0,t[15]=0,null!=e&&e!==1/0?(u=1/(r-e),t[10]=(e+r)*u,t[14]=2*e*r*u):(t[10]=-1,t[14]=-2*r),t},perspectiveFromFieldOfView:function(t,n,a,r){var e=Math.tan(n.upDegrees*Math.PI/180),u=Math.tan(n.downDegrees*Math.PI/180),o=Math.tan(n.leftDegrees*Math.PI/180),i=Math.tan(n.rightDegrees*Math.PI/180),h=2/(o+i),c=2/(e+u);return t[0]=h,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=c,t[6]=0,t[7]=0,t[8]=-(o-i)*h*.5,t[9]=(e-u)*c*.5,t[10]=r/(a-r),t[11]=-1,t[12]=0,t[13]=0,t[14]=r*a/(a-r),t[15]=0,t},ortho:function(t,n,a,r,e,u,o){var i=1/(n-a),h=1/(r-e),c=1/(u-o);return t[0]=-2*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*h,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*c,t[11]=0,t[12]=(n+a)*i,t[13]=(e+r)*h,t[14]=(o+u)*c,t[15]=1,t},lookAt:function(t,n,a,r){var e,u,o,i,h,c,s,M,f,l,v=n[0],b=n[1],m=n[2],d=r[0],p=r[1],x=r[2],y=a[0],g=a[1],_=a[2];return Math.abs(v-y)<1e-6&&Math.abs(b-g)<1e-6&&Math.abs(m-_)<1e-6?q(t):(s=v-y,M=b-g,f=m-_,e=p*(f*=l=1/Math.hypot(s,M,f))-x*(M*=l),u=x*(s*=l)-d*f,o=d*M-p*s,(l=Math.hypot(e,u,o))?(e*=l=1/l,u*=l,o*=l):(e=0,u=0,o=0),i=M*o-f*u,h=f*e-s*o,c=s*u-M*e,(l=Math.hypot(i,h,c))?(i*=l=1/l,h*=l,c*=l):(i=0,h=0,c=0),t[0]=e,t[1]=i,t[2]=s,t[3]=0,t[4]=u,t[5]=h,t[6]=M,t[7]=0,t[8]=o,t[9]=c,t[10]=f,t[11]=0,t[12]=-(e*v+u*b+o*m),t[13]=-(i*v+h*b+c*m),t[14]=-(s*v+M*b+f*m),t[15]=1,t)},targetTo:function(t,n,a,r){var e=n[0],u=n[1],o=n[2],i=r[0],h=r[1],c=r[2],s=e-a[0],M=u-a[1],f=o-a[2],l=s*s+M*M+f*f;l>0&&(s*=l=1/Math.sqrt(l),M*=l,f*=l);var v=h*f-c*M,b=c*s-i*f,m=i*M-h*s;return(l=v*v+b*b+m*m)>0&&(v*=l=1/Math.sqrt(l),b*=l,m*=l),t[0]=v,t[1]=b,t[2]=m,t[3]=0,t[4]=M*m-f*b,t[5]=f*v-s*m,t[6]=s*b-M*v,t[7]=0,t[8]=s,t[9]=M,t[10]=f,t[11]=0,t[12]=e,t[13]=u,t[14]=o,t[15]=1,t},str:function(t){return"mat4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+", "+t[9]+", "+t[10]+", "+t[11]+", "+t[12]+", "+t[13]+", "+t[14]+", "+t[15]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t[9]=n[9]+a[9],t[10]=n[10]+a[10],t[11]=n[11]+a[11],t[12]=n[12]+a[12],t[13]=n[13]+a[13],t[14]=n[14]+a[14],t[15]=n[15]+a[15],t},subtract:z,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=n[11]*a,t[12]=n[12]*a,t[13]=n[13]*a,t[14]=n[14]*a,t[15]=n[15]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t[9]=n[9]+a[9]*r,t[10]=n[10]+a[10]*r,t[11]=n[11]+a[11]*r,t[12]=n[12]+a[12]*r,t[13]=n[13]+a[13]*r,t[14]=n[14]+a[14]*r,t[15]=n[15]+a[15]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]&&t[9]===n[9]&&t[10]===n[10]&&t[11]===n[11]&&t[12]===n[12]&&t[13]===n[13]&&t[14]===n[14]&&t[15]===n[15]},equals:function(t,n){var a=t[0],r=t[1],e=t[2],u=t[3],o=t[4],i=t[5],h=t[6],c=t[7],s=t[8],M=t[9],f=t[10],l=t[11],v=t[12],b=t[13],m=t[14],d=t[15],p=n[0],x=n[1],y=n[2],q=n[3],g=n[4],_=n[5],A=n[6],w=n[7],R=n[8],z=n[9],j=n[10],P=n[11],S=n[12],E=n[13],O=n[14],T=n[15];return Math.abs(a-p)<=1e-6*Math.max(1,Math.abs(a),Math.abs(p))&&Math.abs(r-x)<=1e-6*Math.max(1,Math.abs(r),Math.abs(x))&&Math.abs(e-y)<=1e-6*Math.max(1,Math.abs(e),Math.abs(y))&&Math.abs(u-q)<=1e-6*Math.max(1,Math.abs(u),Math.abs(q))&&Math.abs(o-g)<=1e-6*Math.max(1,Math.abs(o),Math.abs(g))&&Math.abs(i-_)<=1e-6*Math.max(1,Math.abs(i),Math.abs(_))&&Math.abs(h-A)<=1e-6*Math.max(1,Math.abs(h),Math.abs(A))&&Math.abs(c-w)<=1e-6*Math.max(1,Math.abs(c),Math.abs(w))&&Math.abs(s-R)<=1e-6*Math.max(1,Math.abs(s),Math.abs(R))&&Math.abs(M-z)<=1e-6*Math.max(1,Math.abs(M),Math.abs(z))&&Math.abs(f-j)<=1e-6*Math.max(1,Math.abs(f),Math.abs(j))&&Math.abs(l-P)<=1e-6*Math.max(1,Math.abs(l),Math.abs(P))&&Math.abs(v-S)<=1e-6*Math.max(1,Math.abs(v),Math.abs(S))&&Math.abs(b-E)<=1e-6*Math.max(1,Math.abs(b),Math.abs(E))&&Math.abs(m-O)<=1e-6*Math.max(1,Math.abs(m),Math.abs(O))&&Math.abs(d-T)<=1e-6*Math.max(1,Math.abs(d),Math.abs(T))},mul:j,sub:P});function E(){var t=new n(3);return n!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function O(t){var n=t[0],a=t[1],r=t[2];return Math.hypot(n,a,r)}function T(t,a,r){var e=new n(3);return e[0]=t,e[1]=a,e[2]=r,e}function D(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t}function F(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t}function I(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t}function L(t,n){var a=n[0]-t[0],r=n[1]-t[1],e=n[2]-t[2];return Math.hypot(a,r,e)}function V(t,n){var a=n[0]-t[0],r=n[1]-t[1],e=n[2]-t[2];return a*a+r*r+e*e}function Q(t){var n=t[0],a=t[1],r=t[2];return n*n+a*a+r*r}function Y(t,n){var a=n[0],r=n[1],e=n[2],u=a*a+r*r+e*e;return u>0&&(u=1/Math.sqrt(u)),t[0]=n[0]*u,t[1]=n[1]*u,t[2]=n[2]*u,t}function X(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Z(t,n,a){var r=n[0],e=n[1],u=n[2],o=a[0],i=a[1],h=a[2];return t[0]=e*h-u*i,t[1]=u*o-r*h,t[2]=r*i-e*o,t}var B,N=D,k=F,U=I,W=L,C=V,G=O,H=Q,J=(B=E(),function(t,n,a,r,e,u){var o,i;for(n||(n=3),a||(a=0),i=r?Math.min(r*n+a,t.length):t.length,o=a;o<i;o+=n)B[0]=t[o],B[1]=t[o+1],B[2]=t[o+2],e(B,B,u),t[o]=B[0],t[o+1]=B[1],t[o+2]=B[2];return t}),K=Object.freeze({__proto__:null,create:E,clone:function(t){var a=new n(3);return a[0]=t[0],a[1]=t[1],a[2]=t[2],a},length:O,fromValues:T,copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t},set:function(t,n,a,r){return t[0]=n,t[1]=a,t[2]=r,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t},subtract:D,multiply:F,divide:I,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t[2]=Math.ceil(n[2]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t[2]=Math.floor(n[2]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t[2]=Math.min(n[2],a[2]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t[2]=Math.max(n[2],a[2]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t[2]=Math.round(n[2]),t},scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t},scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t},distance:L,squaredDistance:V,squaredLength:Q,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t[2]=1/n[2],t},normalize:Y,dot:X,cross:Z,lerp:function(t,n,a,r){var e=n[0],u=n[1],o=n[2];return t[0]=e+r*(a[0]-e),t[1]=u+r*(a[1]-u),t[2]=o+r*(a[2]-o),t},hermite:function(t,n,a,r,e,u){var o=u*u,i=o*(2*u-3)+1,h=o*(u-2)+u,c=o*(u-1),s=o*(3-2*u);return t[0]=n[0]*i+a[0]*h+r[0]*c+e[0]*s,t[1]=n[1]*i+a[1]*h+r[1]*c+e[1]*s,t[2]=n[2]*i+a[2]*h+r[2]*c+e[2]*s,t},bezier:function(t,n,a,r,e,u){var o=1-u,i=o*o,h=u*u,c=i*o,s=3*u*i,M=3*h*o,f=h*u;return t[0]=n[0]*c+a[0]*s+r[0]*M+e[0]*f,t[1]=n[1]*c+a[1]*s+r[1]*M+e[1]*f,t[2]=n[2]*c+a[2]*s+r[2]*M+e[2]*f,t},random:function(t,n){n=n||1;var r=2*a()*Math.PI,e=2*a()-1,u=Math.sqrt(1-e*e)*n;return t[0]=Math.cos(r)*u,t[1]=Math.sin(r)*u,t[2]=e*n,t},transformMat4:function(t,n,a){var r=n[0],e=n[1],u=n[2],o=a[3]*r+a[7]*e+a[11]*u+a[15];return o=o||1,t[0]=(a[0]*r+a[4]*e+a[8]*u+a[12])/o,t[1]=(a[1]*r+a[5]*e+a[9]*u+a[13])/o,t[2]=(a[2]*r+a[6]*e+a[10]*u+a[14])/o,t},transformMat3:function(t,n,a){var r=n[0],e=n[1],u=n[2];return t[0]=r*a[0]+e*a[3]+u*a[6],t[1]=r*a[1]+e*a[4]+u*a[7],t[2]=r*a[2]+e*a[5]+u*a[8],t},transformQuat:function(t,n,a){var r=a[0],e=a[1],u=a[2],o=a[3],i=n[0],h=n[1],c=n[2],s=e*c-u*h,M=u*i-r*c,f=r*h-e*i,l=e*f-u*M,v=u*s-r*f,b=r*M-e*s,m=2*o;return s*=m,M*=m,f*=m,l*=2,v*=2,b*=2,t[0]=i+s+l,t[1]=h+M+v,t[2]=c+f+b,t},rotateX:function(t,n,a,r){var e=[],u=[];return e[0]=n[0]-a[0],e[1]=n[1]-a[1],e[2]=n[2]-a[2],u[0]=e[0],u[1]=e[1]*Math.cos(r)-e[2]*Math.sin(r),u[2]=e[1]*Math.sin(r)+e[2]*Math.cos(r),t[0]=u[0]+a[0],t[1]=u[1]+a[1],t[2]=u[2]+a[2],t},rotateY:function(t,n,a,r){var e=[],u=[];return e[0]=n[0]-a[0],e[1]=n[1]-a[1],e[2]=n[2]-a[2],u[0]=e[2]*Math.sin(r)+e[0]*Math.cos(r),u[1]=e[1],u[2]=e[2]*Math.cos(r)-e[0]*Math.sin(r),t[0]=u[0]+a[0],t[1]=u[1]+a[1],t[2]=u[2]+a[2],t},rotateZ:function(t,n,a,r){var e=[],u=[];return e[0]=n[0]-a[0],e[1]=n[1]-a[1],e[2]=n[2]-a[2],u[0]=e[0]*Math.cos(r)-e[1]*Math.sin(r),u[1]=e[0]*Math.sin(r)+e[1]*Math.cos(r),u[2]=e[2],t[0]=u[0]+a[0],t[1]=u[1]+a[1],t[2]=u[2]+a[2],t},angle:function(t,n){var a=t[0],r=t[1],e=t[2],u=n[0],o=n[1],i=n[2],h=Math.sqrt(a*a+r*r+e*e)*Math.sqrt(u*u+o*o+i*i),c=h&&X(t,n)/h;return Math.acos(Math.min(Math.max(c,-1),1))},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t},str:function(t){return"vec3("+t[0]+", "+t[1]+", "+t[2]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]},equals:function(t,n){var a=t[0],r=t[1],e=t[2],u=n[0],o=n[1],i=n[2];return Math.abs(a-u)<=1e-6*Math.max(1,Math.abs(a),Math.abs(u))&&Math.abs(r-o)<=1e-6*Math.max(1,Math.abs(r),Math.abs(o))&&Math.abs(e-i)<=1e-6*Math.max(1,Math.abs(e),Math.abs(i))},sub:N,mul:k,div:U,dist:W,sqrDist:C,len:G,sqrLen:H,forEach:J});function $(){var t=new n(4);return n!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[3]=0),t}function tt(t){var a=new n(4);return a[0]=t[0],a[1]=t[1],a[2]=t[2],a[3]=t[3],a}function nt(t,a,r,e){var u=new n(4);return u[0]=t,u[1]=a,u[2]=r,u[3]=e,u}function at(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t}function rt(t,n,a,r,e){return t[0]=n,t[1]=a,t[2]=r,t[3]=e,t}function et(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t}function ut(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}function ot(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t[3]=n[3]*a[3],t}function it(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t[3]=n[3]/a[3],t}function ht(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t}function ct(t,n){var a=n[0]-t[0],r=n[1]-t[1],e=n[2]-t[2],u=n[3]-t[3];return Math.hypot(a,r,e,u)}function st(t,n){var a=n[0]-t[0],r=n[1]-t[1],e=n[2]-t[2],u=n[3]-t[3];return a*a+r*r+e*e+u*u}function Mt(t){var n=t[0],a=t[1],r=t[2],e=t[3];return Math.hypot(n,a,r,e)}function ft(t){var n=t[0],a=t[1],r=t[2],e=t[3];return n*n+a*a+r*r+e*e}function lt(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=a*a+r*r+e*e+u*u;return o>0&&(o=1/Math.sqrt(o)),t[0]=a*o,t[1]=r*o,t[2]=e*o,t[3]=u*o,t}function vt(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]+t[3]*n[3]}function bt(t,n,a,r){var e=n[0],u=n[1],o=n[2],i=n[3];return t[0]=e+r*(a[0]-e),t[1]=u+r*(a[1]-u),t[2]=o+r*(a[2]-o),t[3]=i+r*(a[3]-i),t}function mt(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]}function dt(t,n){var a=t[0],r=t[1],e=t[2],u=t[3],o=n[0],i=n[1],h=n[2],c=n[3];return Math.abs(a-o)<=1e-6*Math.max(1,Math.abs(a),Math.abs(o))&&Math.abs(r-i)<=1e-6*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(e-h)<=1e-6*Math.max(1,Math.abs(e),Math.abs(h))&&Math.abs(u-c)<=1e-6*Math.max(1,Math.abs(u),Math.abs(c))}var pt=ut,xt=ot,yt=it,qt=ct,gt=st,_t=Mt,At=ft,wt=function(){var t=$();return function(n,a,r,e,u,o){var i,h;for(a||(a=4),r||(r=0),h=e?Math.min(e*a+r,n.length):n.length,i=r;i<h;i+=a)t[0]=n[i],t[1]=n[i+1],t[2]=n[i+2],t[3]=n[i+3],u(t,t,o),n[i]=t[0],n[i+1]=t[1],n[i+2]=t[2],n[i+3]=t[3];return n}}(),Rt=Object.freeze({__proto__:null,create:$,clone:tt,fromValues:nt,copy:at,set:rt,add:et,subtract:ut,multiply:ot,divide:it,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t[2]=Math.ceil(n[2]),t[3]=Math.ceil(n[3]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t[2]=Math.floor(n[2]),t[3]=Math.floor(n[3]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t[2]=Math.min(n[2],a[2]),t[3]=Math.min(n[3],a[3]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t[2]=Math.max(n[2],a[2]),t[3]=Math.max(n[3],a[3]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t[2]=Math.round(n[2]),t[3]=Math.round(n[3]),t},scale:ht,scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t},distance:ct,squaredDistance:st,length:Mt,squaredLength:ft,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=-n[3],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t[2]=1/n[2],t[3]=1/n[3],t},normalize:lt,dot:vt,cross:function(t,n,a,r){var e=a[0]*r[1]-a[1]*r[0],u=a[0]*r[2]-a[2]*r[0],o=a[0]*r[3]-a[3]*r[0],i=a[1]*r[2]-a[2]*r[1],h=a[1]*r[3]-a[3]*r[1],c=a[2]*r[3]-a[3]*r[2],s=n[0],M=n[1],f=n[2],l=n[3];return t[0]=M*c-f*h+l*i,t[1]=-s*c+f*o-l*u,t[2]=s*h-M*o+l*e,t[3]=-s*i+M*u-f*e,t},lerp:bt,random:function(t,n){var r,e,u,o,i,h;n=n||1;do{i=(r=2*a()-1)*r+(e=2*a()-1)*e}while(i>=1);do{h=(u=2*a()-1)*u+(o=2*a()-1)*o}while(h>=1);var c=Math.sqrt((1-i)/h);return t[0]=n*r,t[1]=n*e,t[2]=n*u*c,t[3]=n*o*c,t},transformMat4:function(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3];return t[0]=a[0]*r+a[4]*e+a[8]*u+a[12]*o,t[1]=a[1]*r+a[5]*e+a[9]*u+a[13]*o,t[2]=a[2]*r+a[6]*e+a[10]*u+a[14]*o,t[3]=a[3]*r+a[7]*e+a[11]*u+a[15]*o,t},transformQuat:function(t,n,a){var r=n[0],e=n[1],u=n[2],o=a[0],i=a[1],h=a[2],c=a[3],s=c*r+i*u-h*e,M=c*e+h*r-o*u,f=c*u+o*e-i*r,l=-o*r-i*e-h*u;return t[0]=s*c+l*-o+M*-h-f*-i,t[1]=M*c+l*-i+f*-o-s*-h,t[2]=f*c+l*-h+s*-i-M*-o,t[3]=n[3],t},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=0,t},str:function(t){return"vec4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},exactEquals:mt,equals:dt,sub:pt,mul:xt,div:yt,dist:qt,sqrDist:gt,len:_t,sqrLen:At,forEach:wt});function zt(){var t=new n(4);return n!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t[3]=1,t}function jt(t,n,a){a*=.5;var r=Math.sin(a);return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=Math.cos(a),t}function Pt(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=a[0],h=a[1],c=a[2],s=a[3];return t[0]=r*s+o*i+e*c-u*h,t[1]=e*s+o*h+u*i-r*c,t[2]=u*s+o*c+r*h-e*i,t[3]=o*s-r*i-e*h-u*c,t}function St(t,n,a){a*=.5;var r=n[0],e=n[1],u=n[2],o=n[3],i=Math.sin(a),h=Math.cos(a);return t[0]=r*h+o*i,t[1]=e*h+u*i,t[2]=u*h-e*i,t[3]=o*h-r*i,t}function Et(t,n,a){a*=.5;var r=n[0],e=n[1],u=n[2],o=n[3],i=Math.sin(a),h=Math.cos(a);return t[0]=r*h-u*i,t[1]=e*h+o*i,t[2]=u*h+r*i,t[3]=o*h-e*i,t}function Ot(t,n,a){a*=.5;var r=n[0],e=n[1],u=n[2],o=n[3],i=Math.sin(a),h=Math.cos(a);return t[0]=r*h+e*i,t[1]=e*h-r*i,t[2]=u*h+o*i,t[3]=o*h-u*i,t}function Tt(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=Math.sqrt(a*a+r*r+e*e),i=Math.exp(u),h=o>0?i*Math.sin(o)/o:0;return t[0]=a*h,t[1]=r*h,t[2]=e*h,t[3]=i*Math.cos(o),t}function Dt(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=Math.sqrt(a*a+r*r+e*e),i=o>0?Math.atan2(o,u)/o:0;return t[0]=a*i,t[1]=r*i,t[2]=e*i,t[3]=.5*Math.log(a*a+r*r+e*e+u*u),t}function Ft(t,n,a,r){var e,u,o,i,h,c=n[0],s=n[1],M=n[2],f=n[3],l=a[0],v=a[1],b=a[2],m=a[3];return(u=c*l+s*v+M*b+f*m)<0&&(u=-u,l=-l,v=-v,b=-b,m=-m),1-u>1e-6?(e=Math.acos(u),o=Math.sin(e),i=Math.sin((1-r)*e)/o,h=Math.sin(r*e)/o):(i=1-r,h=r),t[0]=i*c+h*l,t[1]=i*s+h*v,t[2]=i*M+h*b,t[3]=i*f+h*m,t}function It(t,n){var a,r=n[0]+n[4]+n[8];if(r>0)a=Math.sqrt(r+1),t[3]=.5*a,a=.5/a,t[0]=(n[5]-n[7])*a,t[1]=(n[6]-n[2])*a,t[2]=(n[1]-n[3])*a;else{var e=0;n[4]>n[0]&&(e=1),n[8]>n[3*e+e]&&(e=2);var u=(e+1)%3,o=(e+2)%3;a=Math.sqrt(n[3*e+e]-n[3*u+u]-n[3*o+o]+1),t[e]=.5*a,a=.5/a,t[3]=(n[3*u+o]-n[3*o+u])*a,t[u]=(n[3*u+e]+n[3*e+u])*a,t[o]=(n[3*o+e]+n[3*e+o])*a}return t}var Lt,Vt,Qt,Yt,Xt,Zt,Bt=tt,Nt=nt,kt=at,Ut=rt,Wt=et,Ct=Pt,Gt=ht,Ht=vt,Jt=bt,Kt=Mt,$t=Kt,tn=ft,nn=tn,an=lt,rn=mt,en=dt,un=(Lt=E(),Vt=T(1,0,0),Qt=T(0,1,0),function(t,n,a){var r=X(n,a);return r<-.999999?(Z(Lt,Vt,n),G(Lt)<1e-6&&Z(Lt,Qt,n),Y(Lt,Lt),jt(t,Lt,Math.PI),t):r>.999999?(t[0]=0,t[1]=0,t[2]=0,t[3]=1,t):(Z(Lt,n,a),t[0]=Lt[0],t[1]=Lt[1],t[2]=Lt[2],t[3]=1+r,an(t,t))}),on=(Yt=zt(),Xt=zt(),function(t,n,a,r,e,u){return Ft(Yt,n,e,u),Ft(Xt,a,r,u),Ft(t,Yt,Xt,2*u*(1-u)),t}),hn=(Zt=b(),function(t,n,a,r){return Zt[0]=a[0],Zt[3]=a[1],Zt[6]=a[2],Zt[1]=r[0],Zt[4]=r[1],Zt[7]=r[2],Zt[2]=-n[0],Zt[5]=-n[1],Zt[8]=-n[2],an(t,It(t,Zt))}),cn=Object.freeze({__proto__:null,create:zt,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t},setAxisAngle:jt,getAxisAngle:function(t,n){var a=2*Math.acos(n[3]),r=Math.sin(a/2);return r>1e-6?(t[0]=n[0]/r,t[1]=n[1]/r,t[2]=n[2]/r):(t[0]=1,t[1]=0,t[2]=0),a},getAngle:function(t,n){var a=Ht(t,n);return Math.acos(2*a*a-1)},multiply:Pt,rotateX:St,rotateY:Et,rotateZ:Ot,calculateW:function(t,n){var a=n[0],r=n[1],e=n[2];return t[0]=a,t[1]=r,t[2]=e,t[3]=Math.sqrt(Math.abs(1-a*a-r*r-e*e)),t},exp:Tt,ln:Dt,pow:function(t,n,a){return Dt(t,n),Gt(t,t,a),Tt(t,t),t},slerp:Ft,random:function(t){var n=a(),r=a(),e=a(),u=Math.sqrt(1-n),o=Math.sqrt(n);return t[0]=u*Math.sin(2*Math.PI*r),t[1]=u*Math.cos(2*Math.PI*r),t[2]=o*Math.sin(2*Math.PI*e),t[3]=o*Math.cos(2*Math.PI*e),t},invert:function(t,n){var a=n[0],r=n[1],e=n[2],u=n[3],o=a*a+r*r+e*e+u*u,i=o?1/o:0;return t[0]=-a*i,t[1]=-r*i,t[2]=-e*i,t[3]=u*i,t},conjugate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t},fromMat3:It,fromEuler:function(t,n,a,r){var e=.5*Math.PI/180;n*=e,a*=e,r*=e;var u=Math.sin(n),o=Math.cos(n),i=Math.sin(a),h=Math.cos(a),c=Math.sin(r),s=Math.cos(r);return t[0]=u*h*s-o*i*c,t[1]=o*i*s+u*h*c,t[2]=o*h*c-u*i*s,t[3]=o*h*s+u*i*c,t},str:function(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},clone:Bt,fromValues:Nt,copy:kt,set:Ut,add:Wt,mul:Ct,scale:Gt,dot:Ht,lerp:Jt,length:Kt,len:$t,squaredLength:tn,sqrLen:nn,normalize:an,exactEquals:rn,equals:en,rotationTo:un,sqlerp:on,setAxes:hn});function sn(t,n,a){var r=.5*a[0],e=.5*a[1],u=.5*a[2],o=n[0],i=n[1],h=n[2],c=n[3];return t[0]=o,t[1]=i,t[2]=h,t[3]=c,t[4]=r*c+e*h-u*i,t[5]=e*c+u*o-r*h,t[6]=u*c+r*i-e*o,t[7]=-r*o-e*i-u*h,t}function Mn(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t}var fn=kt;var ln=kt;function vn(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=a[4],h=a[5],c=a[6],s=a[7],M=n[4],f=n[5],l=n[6],v=n[7],b=a[0],m=a[1],d=a[2],p=a[3];return t[0]=r*p+o*b+e*d-u*m,t[1]=e*p+o*m+u*b-r*d,t[2]=u*p+o*d+r*m-e*b,t[3]=o*p-r*b-e*m-u*d,t[4]=r*s+o*i+e*c-u*h+M*p+v*b+f*d-l*m,t[5]=e*s+o*h+u*i-r*c+f*p+v*m+l*b-M*d,t[6]=u*s+o*c+r*h-e*i+l*p+v*d+M*m-f*b,t[7]=o*s-r*i-e*h-u*c+v*p-M*b-f*m-l*d,t}var bn=vn;var mn=Ht;var dn=Kt,pn=dn,xn=tn,yn=xn;var qn=Object.freeze({__proto__:null,create:function(){var t=new n(8);return n!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[4]=0,t[5]=0,t[6]=0,t[7]=0),t[3]=1,t},clone:function(t){var a=new n(8);return a[0]=t[0],a[1]=t[1],a[2]=t[2],a[3]=t[3],a[4]=t[4],a[5]=t[5],a[6]=t[6],a[7]=t[7],a},fromValues:function(t,a,r,e,u,o,i,h){var c=new n(8);return c[0]=t,c[1]=a,c[2]=r,c[3]=e,c[4]=u,c[5]=o,c[6]=i,c[7]=h,c},fromRotationTranslationValues:function(t,a,r,e,u,o,i){var h=new n(8);h[0]=t,h[1]=a,h[2]=r,h[3]=e;var c=.5*u,s=.5*o,M=.5*i;return h[4]=c*e+s*r-M*a,h[5]=s*e+M*t-c*r,h[6]=M*e+c*a-s*t,h[7]=-c*t-s*a-M*r,h},fromRotationTranslation:sn,fromTranslation:function(t,n){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=.5*n[0],t[5]=.5*n[1],t[6]=.5*n[2],t[7]=0,t},fromRotation:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},fromMat4:function(t,a){var r=zt();R(r,a);var e=new n(3);return A(e,a),sn(t,r,e),t},copy:Mn,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},set:function(t,n,a,r,e,u,o,i,h){return t[0]=n,t[1]=a,t[2]=r,t[3]=e,t[4]=u,t[5]=o,t[6]=i,t[7]=h,t},getReal:fn,getDual:function(t,n){return t[0]=n[4],t[1]=n[5],t[2]=n[6],t[3]=n[7],t},setReal:ln,setDual:function(t,n){return t[4]=n[0],t[5]=n[1],t[6]=n[2],t[7]=n[3],t},getTranslation:function(t,n){var a=n[4],r=n[5],e=n[6],u=n[7],o=-n[0],i=-n[1],h=-n[2],c=n[3];return t[0]=2*(a*c+u*o+r*h-e*i),t[1]=2*(r*c+u*i+e*o-a*h),t[2]=2*(e*c+u*h+a*i-r*o),t},translate:function(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=.5*a[0],h=.5*a[1],c=.5*a[2],s=n[4],M=n[5],f=n[6],l=n[7];return t[0]=r,t[1]=e,t[2]=u,t[3]=o,t[4]=o*i+e*c-u*h+s,t[5]=o*h+u*i-r*c+M,t[6]=o*c+r*h-e*i+f,t[7]=-r*i-e*h-u*c+l,t},rotateX:function(t,n,a){var r=-n[0],e=-n[1],u=-n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=i*o+s*r+h*u-c*e,f=h*o+s*e+c*r-i*u,l=c*o+s*u+i*e-h*r,v=s*o-i*r-h*e-c*u;return St(t,n,a),r=t[0],e=t[1],u=t[2],o=t[3],t[4]=M*o+v*r+f*u-l*e,t[5]=f*o+v*e+l*r-M*u,t[6]=l*o+v*u+M*e-f*r,t[7]=v*o-M*r-f*e-l*u,t},rotateY:function(t,n,a){var r=-n[0],e=-n[1],u=-n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=i*o+s*r+h*u-c*e,f=h*o+s*e+c*r-i*u,l=c*o+s*u+i*e-h*r,v=s*o-i*r-h*e-c*u;return Et(t,n,a),r=t[0],e=t[1],u=t[2],o=t[3],t[4]=M*o+v*r+f*u-l*e,t[5]=f*o+v*e+l*r-M*u,t[6]=l*o+v*u+M*e-f*r,t[7]=v*o-M*r-f*e-l*u,t},rotateZ:function(t,n,a){var r=-n[0],e=-n[1],u=-n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=i*o+s*r+h*u-c*e,f=h*o+s*e+c*r-i*u,l=c*o+s*u+i*e-h*r,v=s*o-i*r-h*e-c*u;return Ot(t,n,a),r=t[0],e=t[1],u=t[2],o=t[3],t[4]=M*o+v*r+f*u-l*e,t[5]=f*o+v*e+l*r-M*u,t[6]=l*o+v*u+M*e-f*r,t[7]=v*o-M*r-f*e-l*u,t},rotateByQuatAppend:function(t,n,a){var r=a[0],e=a[1],u=a[2],o=a[3],i=n[0],h=n[1],c=n[2],s=n[3];return t[0]=i*o+s*r+h*u-c*e,t[1]=h*o+s*e+c*r-i*u,t[2]=c*o+s*u+i*e-h*r,t[3]=s*o-i*r-h*e-c*u,i=n[4],h=n[5],c=n[6],s=n[7],t[4]=i*o+s*r+h*u-c*e,t[5]=h*o+s*e+c*r-i*u,t[6]=c*o+s*u+i*e-h*r,t[7]=s*o-i*r-h*e-c*u,t},rotateByQuatPrepend:function(t,n,a){var r=n[0],e=n[1],u=n[2],o=n[3],i=a[0],h=a[1],c=a[2],s=a[3];return t[0]=r*s+o*i+e*c-u*h,t[1]=e*s+o*h+u*i-r*c,t[2]=u*s+o*c+r*h-e*i,t[3]=o*s-r*i-e*h-u*c,i=a[4],h=a[5],c=a[6],s=a[7],t[4]=r*s+o*i+e*c-u*h,t[5]=e*s+o*h+u*i-r*c,t[6]=u*s+o*c+r*h-e*i,t[7]=o*s-r*i-e*h-u*c,t},rotateAroundAxis:function(t,n,a,r){if(Math.abs(r)<1e-6)return Mn(t,n);var e=Math.hypot(a[0],a[1],a[2]);r*=.5;var u=Math.sin(r),o=u*a[0]/e,i=u*a[1]/e,h=u*a[2]/e,c=Math.cos(r),s=n[0],M=n[1],f=n[2],l=n[3];t[0]=s*c+l*o+M*h-f*i,t[1]=M*c+l*i+f*o-s*h,t[2]=f*c+l*h+s*i-M*o,t[3]=l*c-s*o-M*i-f*h;var v=n[4],b=n[5],m=n[6],d=n[7];return t[4]=v*c+d*o+b*h-m*i,t[5]=b*c+d*i+m*o-v*h,t[6]=m*c+d*h+v*i-b*o,t[7]=d*c-v*o-b*i-m*h,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t},multiply:vn,mul:bn,scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t},dot:mn,lerp:function(t,n,a,r){var e=1-r;return mn(n,a)<0&&(r=-r),t[0]=n[0]*e+a[0]*r,t[1]=n[1]*e+a[1]*r,t[2]=n[2]*e+a[2]*r,t[3]=n[3]*e+a[3]*r,t[4]=n[4]*e+a[4]*r,t[5]=n[5]*e+a[5]*r,t[6]=n[6]*e+a[6]*r,t[7]=n[7]*e+a[7]*r,t},invert:function(t,n){var a=xn(n);return t[0]=-n[0]/a,t[1]=-n[1]/a,t[2]=-n[2]/a,t[3]=n[3]/a,t[4]=-n[4]/a,t[5]=-n[5]/a,t[6]=-n[6]/a,t[7]=n[7]/a,t},conjugate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t[4]=-n[4],t[5]=-n[5],t[6]=-n[6],t[7]=n[7],t},length:dn,len:pn,squaredLength:xn,sqrLen:yn,normalize:function(t,n){var a=xn(n);if(a>0){a=Math.sqrt(a);var r=n[0]/a,e=n[1]/a,u=n[2]/a,o=n[3]/a,i=n[4],h=n[5],c=n[6],s=n[7],M=r*i+e*h+u*c+o*s;t[0]=r,t[1]=e,t[2]=u,t[3]=o,t[4]=(i-r*M)/a,t[5]=(h-e*M)/a,t[6]=(c-u*M)/a,t[7]=(s-o*M)/a}return t},str:function(t){return"quat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]},equals:function(t,n){var a=t[0],r=t[1],e=t[2],u=t[3],o=t[4],i=t[5],h=t[6],c=t[7],s=n[0],M=n[1],f=n[2],l=n[3],v=n[4],b=n[5],m=n[6],d=n[7];return Math.abs(a-s)<=1e-6*Math.max(1,Math.abs(a),Math.abs(s))&&Math.abs(r-M)<=1e-6*Math.max(1,Math.abs(r),Math.abs(M))&&Math.abs(e-f)<=1e-6*Math.max(1,Math.abs(e),Math.abs(f))&&Math.abs(u-l)<=1e-6*Math.max(1,Math.abs(u),Math.abs(l))&&Math.abs(o-v)<=1e-6*Math.max(1,Math.abs(o),Math.abs(v))&&Math.abs(i-b)<=1e-6*Math.max(1,Math.abs(i),Math.abs(b))&&Math.abs(h-m)<=1e-6*Math.max(1,Math.abs(h),Math.abs(m))&&Math.abs(c-d)<=1e-6*Math.max(1,Math.abs(c),Math.abs(d))}});function gn(){var t=new n(2);return n!=Float32Array&&(t[0]=0,t[1]=0),t}function _n(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t}function An(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t}function wn(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t}function Rn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return Math.hypot(a,r)}function zn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return a*a+r*r}function jn(t){var n=t[0],a=t[1];return Math.hypot(n,a)}function Pn(t){var n=t[0],a=t[1];return n*n+a*a}var Sn=jn,En=_n,On=An,Tn=wn,Dn=Rn,Fn=zn,In=Pn,Ln=function(){var t=gn();return function(n,a,r,e,u,o){var i,h;for(a||(a=2),r||(r=0),h=e?Math.min(e*a+r,n.length):n.length,i=r;i<h;i+=a)t[0]=n[i],t[1]=n[i+1],u(t,t,o),n[i]=t[0],n[i+1]=t[1];return n}}(),Vn=Object.freeze({__proto__:null,create:gn,clone:function(t){var a=new n(2);return a[0]=t[0],a[1]=t[1],a},fromValues:function(t,a){var r=new n(2);return r[0]=t,r[1]=a,r},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t},set:function(t,n,a){return t[0]=n,t[1]=a,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t},subtract:_n,multiply:An,divide:wn,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t},scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t},scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t},distance:Rn,squaredDistance:zn,length:jn,squaredLength:Pn,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t},normalize:function(t,n){var a=n[0],r=n[1],e=a*a+r*r;return e>0&&(e=1/Math.sqrt(e)),t[0]=n[0]*e,t[1]=n[1]*e,t},dot:function(t,n){return t[0]*n[0]+t[1]*n[1]},cross:function(t,n,a){var r=n[0]*a[1]-n[1]*a[0];return t[0]=t[1]=0,t[2]=r,t},lerp:function(t,n,a,r){var e=n[0],u=n[1];return t[0]=e+r*(a[0]-e),t[1]=u+r*(a[1]-u),t},random:function(t,n){n=n||1;var r=2*a()*Math.PI;return t[0]=Math.cos(r)*n,t[1]=Math.sin(r)*n,t},transformMat2:function(t,n,a){var r=n[0],e=n[1];return t[0]=a[0]*r+a[2]*e,t[1]=a[1]*r+a[3]*e,t},transformMat2d:function(t,n,a){var r=n[0],e=n[1];return t[0]=a[0]*r+a[2]*e+a[4],t[1]=a[1]*r+a[3]*e+a[5],t},transformMat3:function(t,n,a){var r=n[0],e=n[1];return t[0]=a[0]*r+a[3]*e+a[6],t[1]=a[1]*r+a[4]*e+a[7],t},transformMat4:function(t,n,a){var r=n[0],e=n[1];return t[0]=a[0]*r+a[4]*e+a[12],t[1]=a[1]*r+a[5]*e+a[13],t},rotate:function(t,n,a,r){var e=n[0]-a[0],u=n[1]-a[1],o=Math.sin(r),i=Math.cos(r);return t[0]=e*i-u*o+a[0],t[1]=e*o+u*i+a[1],t},angle:function(t,n){var a=t[0],r=t[1],e=n[0],u=n[1],o=Math.sqrt(a*a+r*r)*Math.sqrt(e*e+u*u),i=o&&(a*e+r*u)/o;return Math.acos(Math.min(Math.max(i,-1),1))},zero:function(t){return t[0]=0,t[1]=0,t},str:function(t){return"vec2("+t[0]+", "+t[1]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]},equals:function(t,n){var a=t[0],r=t[1],e=n[0],u=n[1];return Math.abs(a-e)<=1e-6*Math.max(1,Math.abs(a),Math.abs(e))&&Math.abs(r-u)<=1e-6*Math.max(1,Math.abs(r),Math.abs(u))},len:Sn,sub:En,mul:On,div:Tn,dist:Dn,sqrDist:Fn,sqrLen:In,forEach:Ln});t.glMatrix=e,t.mat2=c,t.mat2d=v,t.mat3=y,t.mat4=S,t.quat=cn,t.quat2=qn,t.vec2=Vn,t.vec3=K,t.vec4=Rt,Object.defineProperty(t,"__esModule",{value:!0})}));
diff --git a/basic_course/gl-matrix/gl-matrix.js b/basic_course/gl-matrix/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..4553f9ea44878e9b79894c1de08af95ea9814317
--- /dev/null
+++ b/basic_course/gl-matrix/gl-matrix.js
@@ -0,0 +1,7611 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.3.0
+
+Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, (function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Float32ArrayConstructor | ArrayConstructor} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {ReadonlyMat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return "mat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {ReadonlyMat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {ReadonlyMat2} L the lower triangular matrix
+   * @param {ReadonlyMat2} D the diagonal matrix
+   * @param {ReadonlyMat2} U the upper triangular matrix
+   * @param {ReadonlyMat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, b,
+   *  c, d,
+   *  tx, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, b, 0,
+   *  c, d, 0,
+   *  tx, ty, 1]
+   * </pre>
+   * The last column is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {ReadonlyMat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return "mat2d(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {ReadonlyMat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to translate
+   * @param {ReadonlyVec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 matrix from the given quaternion
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyMat4} a Mat4 to derive the normal matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {ReadonlyMat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return "mat3(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {ReadonlyMat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {ReadonlyVec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Rotates a mat4 by the given angle around the given axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {ReadonlyQuat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @param {ReadonlyVec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {ReadonlyMat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {ReadonlyMat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
+    r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
+    r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {ReadonlyVec3} a The first operand
+   * @param {ReadonlyVec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        bx = b[0],
+        by = b[1],
+        bz = b[2],
+        mag1 = Math.sqrt(ax * ax + ay * ay + az * az),
+        mag2 = Math.sqrt(bx * bx + by * by + bz * bz),
+        mag = mag1 * mag2,
+        cosine = mag && dot(a, b) / mag;
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {ReadonlyVec4} result the receiving vector
+   * @param {ReadonlyVec4} U the first vector
+   * @param {ReadonlyVec4} V the second vector
+   * @param {ReadonlyVec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return "vec4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyVec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {ReadonlyQuat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Gets the angular distance between two unit quaternions
+   *
+   * @param  {ReadonlyQuat} a     Origin unit quaternion
+   * @param  {ReadonlyQuat} b     Destination unit quaternion
+   * @return {Number}     Angle, in radians, between the two quaternions
+   */
+
+  function getAngle(a, b) {
+    var dotproduct = dot$2(a, b);
+    return Math.acos(2 * dotproduct * dotproduct - 1);
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Calculate the exponential of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function exp(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var et = Math.exp(w);
+    var s = r > 0 ? et * Math.sin(r) / r : 0;
+    out[0] = x * s;
+    out[1] = y * s;
+    out[2] = z * s;
+    out[3] = et * Math.cos(r);
+    return out;
+  }
+  /**
+   * Calculate the natural logarithm of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function ln(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var t = r > 0 ? Math.atan2(r, w) / r : 0;
+    out[0] = x * t;
+    out[1] = y * t;
+    out[2] = z * t;
+    out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w);
+    return out;
+  }
+  /**
+   * Calculate the scalar power of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @param {Number} b amount to scale the quaternion by
+   * @returns {quat} out
+   */
+
+  function pow(out, a, b) {
+    ln(out, a);
+    scale$6(out, out, b);
+    exp(out, out);
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random unit quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyMat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {ReadonlyQuat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return "quat(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {ReadonlyQuat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat} a The first quaternion.
+   * @param {ReadonlyQuat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat} a The first vector.
+   * @param {ReadonlyQuat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {ReadonlyVec3} a the initial vector
+   * @param {ReadonlyVec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {ReadonlyQuat} c the third operand
+   * @param {ReadonlyQuat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {ReadonlyVec3} view  the vector representing the viewing direction
+   * @param {ReadonlyVec3} right the vector representing the local "right" direction
+   * @param {ReadonlyVec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    getAngle: getAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    exp: exp,
+    ln: ln,
+    pow: pow,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q a normalized quaternion
+   * @param {ReadonlyVec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyVec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {ReadonlyMat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {ReadonlyQuat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return "quat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ")";
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat2} a the first dual quaternion.
+   * @param {ReadonlyQuat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat2} a the first dual quat.
+   * @param {ReadonlyQuat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {ReadonlyVec2} a The vec2 point to rotate
+   * @param {ReadonlyVec2} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, rad) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(rad),
+        cosC = Math.cos(rad); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {ReadonlyVec2} a The first operand
+   * @param {ReadonlyVec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1],
+        // mag is the product of the magnitudes of a and b
+    mag = Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2),
+        // mag &&.. short circuits if mag == 0
+    cosine = mag && (x1 * x2 + y1 * y2) / mag; // Math.min(Math.max(cosine, -1), 1) clamps the cosine between -1 and 1
+
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return "vec2(" + a[0] + ", " + a[1] + ")";
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/basic_course/gl-matrix/glm-js.min.js b/basic_course/gl-matrix/glm-js.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..8142db782689f48f32027e35fbe99af546721a34
--- /dev/null
+++ b/basic_course/gl-matrix/glm-js.min.js
@@ -0,0 +1,273 @@
+/*! glm-js built 2017-04-02 11:34:38-04:00 | (c) humbletim | http://humbletim.github.io/glm-js */
+(function declare_glmjs_glmatrix(globals, $GLM_log, $GLM_console_log) { var GLM, GLMAT, GLMAT_VERSION, GLMJS_PREFIX, $GLM_console_factory, glm; ArrayBuffer.exists;
+/*
+
+ --------------------------------------------------------------------------
+ glm-js | (c) humbletim | http://humbletim.github.io/glm-js
+ --------------------------------------------------------------------------
+
+ The MIT License (MIT)
+
+ Copyright (c) 2015-2016 humbletim
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ --------------------------------------------------------------------------
+ gl-matrix | (c) Brandon Jones, Colin MacKenzie IV | http://glmatrix.net/
+ --------------------------------------------------------------------------
+
+ Copyright (c) 2013 Brandon Jones, Colin MacKenzie IV
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+
+  2. Altered source versions must be plainly marked as such, and must not
+     be misrepresented as being the original software.
+
+  3. This notice may not be removed or altered from any source distribution.
+*/
+GLMAT={};GLMAT_VERSION="2.2.2";
+(function(a){a.VERSION=GLMAT_VERSION;if(!b)var b=1E-6;if(!c)var c="undefined"!==typeof Float32Array?Float32Array:Array;if(!e)var e=Math.random;var d={setMatrixArrayType:function(y){c=y}};"undefined"!==typeof a&&(a.glMatrix=d);var h=Math.PI/180;d.toRadian=function(y){return y*h};d={create:function(){var y=new c(2);y[0]=0;y[1]=0;return y},clone:function(y){var a=new c(2);a[0]=y[0];a[1]=y[1];return a},fromValues:function(y,a){var v=new c(2);v[0]=y;v[1]=a;return v},copy:function(y,a){y[0]=a[0];y[1]=a[1];
+return y},set:function(y,a,v){y[0]=a;y[1]=v;return y},add:function(y,a,v){y[0]=a[0]+v[0];y[1]=a[1]+v[1];return y},subtract:function(y,a,v){y[0]=a[0]-v[0];y[1]=a[1]-v[1];return y}};d.sub=d.subtract;d.multiply=function(y,a,v){y[0]=a[0]*v[0];y[1]=a[1]*v[1];return y};d.mul=d.multiply;d.divide=function(y,a,v){y[0]=a[0]/v[0];y[1]=a[1]/v[1];return y};d.div=d.divide;d.min=function(y,a,v){y[0]=Math.min(a[0],v[0]);y[1]=Math.min(a[1],v[1]);return y};d.max=function(y,a,v){y[0]=Math.max(a[0],v[0]);y[1]=Math.max(a[1],
+v[1]);return y};d.scale=function(y,a,v){y[0]=a[0]*v;y[1]=a[1]*v;return y};d.scaleAndAdd=function(y,a,v,b){y[0]=a[0]+v[0]*b;y[1]=a[1]+v[1]*b;return y};d.distance=function(a,f){var v=f[0]-a[0],b=f[1]-a[1];return Math.sqrt(v*v+b*b)};d.dist=d.distance;d.squaredDistance=function(a,f){var v=f[0]-a[0],b=f[1]-a[1];return v*v+b*b};d.sqrDist=d.squaredDistance;d.length=function(a){var f=a[0];a=a[1];return Math.sqrt(f*f+a*a)};d.len=d.length;d.squaredLength=function(a){var f=a[0];a=a[1];return f*f+a*a};d.sqrLen=
+d.squaredLength;d.negate=function(a,f){a[0]=-f[0];a[1]=-f[1];return a};d.inverse=function(a,f){a[0]=1/f[0];a[1]=1/f[1];return a};d.normalize=function(a,f){var v=f[0],b=f[1],v=v*v+b*b;0<v&&(v=1/Math.sqrt(v),a[0]=f[0]*v,a[1]=f[1]*v);return a};d.dot=function(a,f){return a[0]*f[0]+a[1]*f[1]};d.cross=function(a,f,v){f=f[0]*v[1]-f[1]*v[0];a[0]=a[1]=0;a[2]=f;return a};d.lerp=function(a,f,v,b){var c=f[0];f=f[1];a[0]=c+b*(v[0]-c);a[1]=f+b*(v[1]-f);return a};d.random=function(a,f){f=f||1;var v=2*e()*Math.PI;
+a[0]=Math.cos(v)*f;a[1]=Math.sin(v)*f;return a};d.transformMat2=function(a,f,v){var b=f[0];f=f[1];a[0]=v[0]*b+v[2]*f;a[1]=v[1]*b+v[3]*f;return a};d.transformMat2d=function(a,f,v){var b=f[0];f=f[1];a[0]=v[0]*b+v[2]*f+v[4];a[1]=v[1]*b+v[3]*f+v[5];return a};d.transformMat3=function(a,f,b){var c=f[0];f=f[1];a[0]=b[0]*c+b[3]*f+b[6];a[1]=b[1]*c+b[4]*f+b[7];return a};d.transformMat4=function(a,f,b){var c=f[0];f=f[1];a[0]=b[0]*c+b[4]*f+b[12];a[1]=b[1]*c+b[5]*f+b[13];return a};var j=d.create();d.forEach=function(a,
+f,b,c,d,e){f||(f=2);b||(b=0);for(c=c?Math.min(c*f+b,a.length):a.length;b<c;b+=f)j[0]=a[b],j[1]=a[b+1],d(j,j,e),a[b]=j[0],a[b+1]=j[1];return a};d.str=function(a){return"vec2("+a[0]+", "+a[1]+")"};"undefined"!==typeof a&&(a.vec2=d);var g={create:function(){var a=new c(3);a[0]=0;a[1]=0;a[2]=0;return a},clone:function(a){var f=new c(3);f[0]=a[0];f[1]=a[1];f[2]=a[2];return f},fromValues:function(a,f,b){var P=new c(3);P[0]=a;P[1]=f;P[2]=b;return P},copy:function(a,f){a[0]=f[0];a[1]=f[1];a[2]=f[2];return a},
+set:function(a,f,b,c){a[0]=f;a[1]=b;a[2]=c;return a},add:function(a,f,b){a[0]=f[0]+b[0];a[1]=f[1]+b[1];a[2]=f[2]+b[2];return a},subtract:function(a,f,b){a[0]=f[0]-b[0];a[1]=f[1]-b[1];a[2]=f[2]-b[2];return a}};g.sub=g.subtract;g.multiply=function(a,f,b){a[0]=f[0]*b[0];a[1]=f[1]*b[1];a[2]=f[2]*b[2];return a};g.mul=g.multiply;g.divide=function(a,f,b){a[0]=f[0]/b[0];a[1]=f[1]/b[1];a[2]=f[2]/b[2];return a};g.div=g.divide;g.min=function(a,f,b){a[0]=Math.min(f[0],b[0]);a[1]=Math.min(f[1],b[1]);a[2]=Math.min(f[2],
+b[2]);return a};g.max=function(a,f,b){a[0]=Math.max(f[0],b[0]);a[1]=Math.max(f[1],b[1]);a[2]=Math.max(f[2],b[2]);return a};g.scale=function(a,f,b){a[0]=f[0]*b;a[1]=f[1]*b;a[2]=f[2]*b;return a};g.scaleAndAdd=function(a,f,b,c){a[0]=f[0]+b[0]*c;a[1]=f[1]+b[1]*c;a[2]=f[2]+b[2]*c;return a};g.distance=function(a,f){var b=f[0]-a[0],c=f[1]-a[1],d=f[2]-a[2];return Math.sqrt(b*b+c*c+d*d)};g.dist=g.distance;g.squaredDistance=function(a,f){var b=f[0]-a[0],c=f[1]-a[1],d=f[2]-a[2];return b*b+c*c+d*d};g.sqrDist=
+g.squaredDistance;g.length=function(a){var f=a[0],b=a[1];a=a[2];return Math.sqrt(f*f+b*b+a*a)};g.len=g.length;g.squaredLength=function(a){var f=a[0],b=a[1];a=a[2];return f*f+b*b+a*a};g.sqrLen=g.squaredLength;g.negate=function(a,f){a[0]=-f[0];a[1]=-f[1];a[2]=-f[2];return a};g.inverse=function(a,f){a[0]=1/f[0];a[1]=1/f[1];a[2]=1/f[2];return a};g.normalize=function(a,f){var b=f[0],c=f[1],d=f[2],b=b*b+c*c+d*d;0<b&&(b=1/Math.sqrt(b),a[0]=f[0]*b,a[1]=f[1]*b,a[2]=f[2]*b);return a};g.dot=function(a,f){return a[0]*
+f[0]+a[1]*f[1]+a[2]*f[2]};g.cross=function(a,f,b){var c=f[0],d=f[1];f=f[2];var e=b[0],l=b[1];b=b[2];a[0]=d*b-f*l;a[1]=f*e-c*b;a[2]=c*l-d*e;return a};g.lerp=function(a,f,b,c){var d=f[0],e=f[1];f=f[2];a[0]=d+c*(b[0]-d);a[1]=e+c*(b[1]-e);a[2]=f+c*(b[2]-f);return a};g.random=function(a,f){f=f||1;var b=2*e()*Math.PI,c=2*e()-1,d=Math.sqrt(1-c*c)*f;a[0]=Math.cos(b)*d;a[1]=Math.sin(b)*d;a[2]=c*f;return a};g.transformMat4=function(a,f,b){var c=f[0],d=f[1];f=f[2];var e=b[3]*c+b[7]*d+b[11]*f+b[15],e=e||1;a[0]=
+(b[0]*c+b[4]*d+b[8]*f+b[12])/e;a[1]=(b[1]*c+b[5]*d+b[9]*f+b[13])/e;a[2]=(b[2]*c+b[6]*d+b[10]*f+b[14])/e;return a};g.transformMat3=function(a,f,b){var c=f[0],d=f[1];f=f[2];a[0]=c*b[0]+d*b[3]+f*b[6];a[1]=c*b[1]+d*b[4]+f*b[7];a[2]=c*b[2]+d*b[5]+f*b[8];return a};g.transformQuat=function(a,f,b){var c=f[0],d=f[1],e=f[2];f=b[0];var l=b[1],x=b[2];b=b[3];var u=b*c+l*e-x*d,J=b*d+x*c-f*e,g=b*e+f*d-l*c,c=-f*c-l*d-x*e;a[0]=u*b+c*-f+J*-x-g*-l;a[1]=J*b+c*-l+g*-f-u*-x;a[2]=g*b+c*-x+u*-l-J*-f;return a};g.rotateX=
+function(a,f,b,c){var d=[],e=[];d[0]=f[0]-b[0];d[1]=f[1]-b[1];d[2]=f[2]-b[2];e[0]=d[0];e[1]=d[1]*Math.cos(c)-d[2]*Math.sin(c);e[2]=d[1]*Math.sin(c)+d[2]*Math.cos(c);a[0]=e[0]+b[0];a[1]=e[1]+b[1];a[2]=e[2]+b[2];return a};g.rotateY=function(a,f,b,c){var d=[],e=[];d[0]=f[0]-b[0];d[1]=f[1]-b[1];d[2]=f[2]-b[2];e[0]=d[2]*Math.sin(c)+d[0]*Math.cos(c);e[1]=d[1];e[2]=d[2]*Math.cos(c)-d[0]*Math.sin(c);a[0]=e[0]+b[0];a[1]=e[1]+b[1];a[2]=e[2]+b[2];return a};g.rotateZ=function(a,f,b,c){var d=[],e=[];d[0]=f[0]-
+b[0];d[1]=f[1]-b[1];d[2]=f[2]-b[2];e[0]=d[0]*Math.cos(c)-d[1]*Math.sin(c);e[1]=d[0]*Math.sin(c)+d[1]*Math.cos(c);e[2]=d[2];a[0]=e[0]+b[0];a[1]=e[1]+b[1];a[2]=e[2]+b[2];return a};var k=g.create();g.forEach=function(a,f,b,c,d,e){f||(f=3);b||(b=0);for(c=c?Math.min(c*f+b,a.length):a.length;b<c;b+=f)k[0]=a[b],k[1]=a[b+1],k[2]=a[b+2],d(k,k,e),a[b]=k[0],a[b+1]=k[1],a[b+2]=k[2];return a};g.str=function(a){return"vec3("+a[0]+", "+a[1]+", "+a[2]+")"};"undefined"!==typeof a&&(a.vec3=g);var i={create:function(){var a=
+new c(4);a[0]=0;a[1]=0;a[2]=0;a[3]=0;return a},clone:function(a){var f=new c(4);f[0]=a[0];f[1]=a[1];f[2]=a[2];f[3]=a[3];return f},fromValues:function(a,f,b,d){var e=new c(4);e[0]=a;e[1]=f;e[2]=b;e[3]=d;return e},copy:function(a,f){a[0]=f[0];a[1]=f[1];a[2]=f[2];a[3]=f[3];return a},set:function(a,f,b,c,d){a[0]=f;a[1]=b;a[2]=c;a[3]=d;return a},add:function(a,f,b){a[0]=f[0]+b[0];a[1]=f[1]+b[1];a[2]=f[2]+b[2];a[3]=f[3]+b[3];return a},subtract:function(a,f,b){a[0]=f[0]-b[0];a[1]=f[1]-b[1];a[2]=f[2]-b[2];
+a[3]=f[3]-b[3];return a}};i.sub=i.subtract;i.multiply=function(a,f,b){a[0]=f[0]*b[0];a[1]=f[1]*b[1];a[2]=f[2]*b[2];a[3]=f[3]*b[3];return a};i.mul=i.multiply;i.divide=function(a,f,b){a[0]=f[0]/b[0];a[1]=f[1]/b[1];a[2]=f[2]/b[2];a[3]=f[3]/b[3];return a};i.div=i.divide;i.min=function(a,f,b){a[0]=Math.min(f[0],b[0]);a[1]=Math.min(f[1],b[1]);a[2]=Math.min(f[2],b[2]);a[3]=Math.min(f[3],b[3]);return a};i.max=function(a,f,b){a[0]=Math.max(f[0],b[0]);a[1]=Math.max(f[1],b[1]);a[2]=Math.max(f[2],b[2]);a[3]=
+Math.max(f[3],b[3]);return a};i.scale=function(a,f,b){a[0]=f[0]*b;a[1]=f[1]*b;a[2]=f[2]*b;a[3]=f[3]*b;return a};i.scaleAndAdd=function(a,f,b,c){a[0]=f[0]+b[0]*c;a[1]=f[1]+b[1]*c;a[2]=f[2]+b[2]*c;a[3]=f[3]+b[3]*c;return a};i.distance=function(a,f){var b=f[0]-a[0],c=f[1]-a[1],d=f[2]-a[2],e=f[3]-a[3];return Math.sqrt(b*b+c*c+d*d+e*e)};i.dist=i.distance;i.squaredDistance=function(a,f){var b=f[0]-a[0],c=f[1]-a[1],d=f[2]-a[2],e=f[3]-a[3];return b*b+c*c+d*d+e*e};i.sqrDist=i.squaredDistance;i.length=function(a){var f=
+a[0],b=a[1],c=a[2];a=a[3];return Math.sqrt(f*f+b*b+c*c+a*a)};i.len=i.length;i.squaredLength=function(a){var f=a[0],b=a[1],c=a[2];a=a[3];return f*f+b*b+c*c+a*a};i.sqrLen=i.squaredLength;i.negate=function(a,f){a[0]=-f[0];a[1]=-f[1];a[2]=-f[2];a[3]=-f[3];return a};i.inverse=function(a,f){a[0]=1/f[0];a[1]=1/f[1];a[2]=1/f[2];a[3]=1/f[3];return a};i.normalize=function(a,f){var b=f[0],c=f[1],d=f[2],e=f[3],b=b*b+c*c+d*d+e*e;0<b&&(b=1/Math.sqrt(b),a[0]=f[0]*b,a[1]=f[1]*b,a[2]=f[2]*b,a[3]=f[3]*b);return a};
+i.dot=function(a,f){return a[0]*f[0]+a[1]*f[1]+a[2]*f[2]+a[3]*f[3]};i.lerp=function(a,f,b,c){var d=f[0],e=f[1],l=f[2];f=f[3];a[0]=d+c*(b[0]-d);a[1]=e+c*(b[1]-e);a[2]=l+c*(b[2]-l);a[3]=f+c*(b[3]-f);return a};i.random=function(a,f){f=f||1;a[0]=e();a[1]=e();a[2]=e();a[3]=e();i.normalize(a,a);i.scale(a,a,f);return a};i.transformMat4=function(a,f,b){var c=f[0],d=f[1],e=f[2];f=f[3];a[0]=b[0]*c+b[4]*d+b[8]*e+b[12]*f;a[1]=b[1]*c+b[5]*d+b[9]*e+b[13]*f;a[2]=b[2]*c+b[6]*d+b[10]*e+b[14]*f;a[3]=b[3]*c+b[7]*d+
+b[11]*e+b[15]*f;return a};i.transformQuat=function(a,b,c){var d=b[0],e=b[1],n=b[2];b=c[0];var l=c[1],x=c[2];c=c[3];var u=c*d+l*n-x*e,J=c*e+x*d-b*n,g=c*n+b*e-l*d,d=-b*d-l*e-x*n;a[0]=u*c+d*-b+J*-x-g*-l;a[1]=J*c+d*-l+g*-b-u*-x;a[2]=g*c+d*-x+u*-l-J*-b;return a};var w=i.create();i.forEach=function(a,b,c,d,e,n){b||(b=4);c||(c=0);for(d=d?Math.min(d*b+c,a.length):a.length;c<d;c+=b)w[0]=a[c],w[1]=a[c+1],w[2]=a[c+2],w[3]=a[c+3],e(w,w,n),a[c]=w[0],a[c+1]=w[1],a[c+2]=w[2],a[c+3]=w[3];return a};i.str=function(a){return"vec4("+
+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+")"};"undefined"!==typeof a&&(a.vec4=i);d={create:function(){var a=new c(4);a[0]=1;a[1]=0;a[2]=0;a[3]=1;return a},clone:function(a){var b=new c(4);b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];return b},copy:function(a,b){a[0]=b[0];a[1]=b[1];a[2]=b[2];a[3]=b[3];return a},identity:function(a){a[0]=1;a[1]=0;a[2]=0;a[3]=1;return a},transpose:function(a,b){if(a===b){var c=b[1];a[1]=b[2];a[2]=c}else a[0]=b[0],a[1]=b[2],a[2]=b[1],a[3]=b[3];return a},invert:function(a,b){var c=
+b[0],d=b[1],e=b[2],n=b[3],l=c*n-e*d;if(!l)return null;l=1/l;a[0]=n*l;a[1]=-d*l;a[2]=-e*l;a[3]=c*l;return a},adjoint:function(a,b){var c=b[0];a[0]=b[3];a[1]=-b[1];a[2]=-b[2];a[3]=c;return a},determinant:function(a){return a[0]*a[3]-a[2]*a[1]},multiply:function(a,b,c){var d=b[0],e=b[1],n=b[2];b=b[3];var l=c[0],x=c[1],u=c[2];c=c[3];a[0]=d*l+n*x;a[1]=e*l+b*x;a[2]=d*u+n*c;a[3]=e*u+b*c;return a}};d.mul=d.multiply;d.rotate=function(a,b,c){var d=b[0],e=b[1],n=b[2];b=b[3];var l=Math.sin(c);c=Math.cos(c);a[0]=
+d*c+n*l;a[1]=e*c+b*l;a[2]=d*-l+n*c;a[3]=e*-l+b*c;return a};d.scale=function(a,b,c){var d=b[1],e=b[2],n=b[3],l=c[0];c=c[1];a[0]=b[0]*l;a[1]=d*l;a[2]=e*c;a[3]=n*c;return a};d.str=function(a){return"mat2("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+")"};d.frob=function(a){return Math.sqrt(Math.pow(a[0],2)+Math.pow(a[1],2)+Math.pow(a[2],2)+Math.pow(a[3],2))};d.LDU=function(a,b,c,d){a[2]=d[2]/d[0];c[0]=d[0];c[1]=d[1];c[3]=d[3]-a[2]*c[1];return[a,b,c]};"undefined"!==typeof a&&(a.mat2=d);d={create:function(){var a=
+new c(6);a[0]=1;a[1]=0;a[2]=0;a[3]=1;a[4]=0;a[5]=0;return a},clone:function(a){var b=new c(6);b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];return b},copy:function(a,b){a[0]=b[0];a[1]=b[1];a[2]=b[2];a[3]=b[3];a[4]=b[4];a[5]=b[5];return a},identity:function(a){a[0]=1;a[1]=0;a[2]=0;a[3]=1;a[4]=0;a[5]=0;return a},invert:function(a,b){var c=b[0],d=b[1],e=b[2],n=b[3],l=b[4],x=b[5],u=c*n-d*e;if(!u)return null;u=1/u;a[0]=n*u;a[1]=-d*u;a[2]=-e*u;a[3]=c*u;a[4]=(e*x-n*l)*u;a[5]=(d*l-c*x)*u;return a},
+determinant:function(a){return a[0]*a[3]-a[1]*a[2]},multiply:function(a,b,c){var d=b[0],e=b[1],n=b[2],l=b[3],x=b[4];b=b[5];var u=c[0],g=c[1],h=c[2],K=c[3],j=c[4];c=c[5];a[0]=d*u+n*g;a[1]=e*u+l*g;a[2]=d*h+n*K;a[3]=e*h+l*K;a[4]=d*j+n*c+x;a[5]=e*j+l*c+b;return a}};d.mul=d.multiply;d.rotate=function(a,b,c){var d=b[0],e=b[1],n=b[2],l=b[3],x=b[4];b=b[5];var u=Math.sin(c);c=Math.cos(c);a[0]=d*c+n*u;a[1]=e*c+l*u;a[2]=d*-u+n*c;a[3]=e*-u+l*c;a[4]=x;a[5]=b;return a};d.scale=function(a,b,c){var d=b[1],e=b[2],
+n=b[3],l=b[4],x=b[5],u=c[0];c=c[1];a[0]=b[0]*u;a[1]=d*u;a[2]=e*c;a[3]=n*c;a[4]=l;a[5]=x;return a};d.translate=function(a,b,c){var d=b[0],e=b[1],n=b[2],l=b[3],x=b[4];b=b[5];var u=c[0];c=c[1];a[0]=d;a[1]=e;a[2]=n;a[3]=l;a[4]=d*u+n*c+x;a[5]=e*u+l*c+b;return a};d.str=function(a){return"mat2d("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+")"};d.frob=function(a){return Math.sqrt(Math.pow(a[0],2)+Math.pow(a[1],2)+Math.pow(a[2],2)+Math.pow(a[3],2)+Math.pow(a[4],2)+Math.pow(a[5],2)+1)};"undefined"!==
+typeof a&&(a.mat2d=d);d={create:function(){var a=new c(9);a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=1;a[5]=0;a[6]=0;a[7]=0;a[8]=1;return a},fromMat4:function(a,b){a[0]=b[0];a[1]=b[1];a[2]=b[2];a[3]=b[4];a[4]=b[5];a[5]=b[6];a[6]=b[8];a[7]=b[9];a[8]=b[10];return a},clone:function(a){var b=new c(9);b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];return b},copy:function(a,b){a[0]=b[0];a[1]=b[1];a[2]=b[2];a[3]=b[3];a[4]=b[4];a[5]=b[5];a[6]=b[6];a[7]=b[7];a[8]=b[8];return a},
+identity:function(a){a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=1;a[5]=0;a[6]=0;a[7]=0;a[8]=1;return a},transpose:function(a,b){if(a===b){var c=b[1],d=b[2],e=b[5];a[1]=b[3];a[2]=b[6];a[3]=c;a[5]=b[7];a[6]=d;a[7]=e}else a[0]=b[0],a[1]=b[3],a[2]=b[6],a[3]=b[1],a[4]=b[4],a[5]=b[7],a[6]=b[2],a[7]=b[5],a[8]=b[8];return a},invert:function(a,b){var c=b[0],d=b[1],e=b[2],n=b[3],l=b[4],x=b[5],u=b[6],g=b[7],h=b[8],K=h*l-x*g,j=-h*n+x*u,m=g*n-l*u,i=c*K+d*j+e*m;if(!i)return null;i=1/i;a[0]=K*i;a[1]=(-h*d+e*g)*i;a[2]=(x*
+d-e*l)*i;a[3]=j*i;a[4]=(h*c-e*u)*i;a[5]=(-x*c+e*n)*i;a[6]=m*i;a[7]=(-g*c+d*u)*i;a[8]=(l*c-d*n)*i;return a},adjoint:function(a,b){var c=b[0],d=b[1],e=b[2],n=b[3],l=b[4],x=b[5],u=b[6],g=b[7],h=b[8];a[0]=l*h-x*g;a[1]=e*g-d*h;a[2]=d*x-e*l;a[3]=x*u-n*h;a[4]=c*h-e*u;a[5]=e*n-c*x;a[6]=n*g-l*u;a[7]=d*u-c*g;a[8]=c*l-d*n;return a},determinant:function(a){var b=a[3],c=a[4],d=a[5],e=a[6],n=a[7],l=a[8];return a[0]*(l*c-d*n)+a[1]*(-l*b+d*e)+a[2]*(n*b-c*e)},multiply:function(a,b,c){var d=b[0],e=b[1],n=b[2],l=b[3],
+x=b[4],u=b[5],g=b[6],h=b[7];b=b[8];var j=c[0],m=c[1],i=c[2],k=c[3],q=c[4],t=c[5],s=c[6],r=c[7];c=c[8];a[0]=j*d+m*l+i*g;a[1]=j*e+m*x+i*h;a[2]=j*n+m*u+i*b;a[3]=k*d+q*l+t*g;a[4]=k*e+q*x+t*h;a[5]=k*n+q*u+t*b;a[6]=s*d+r*l+c*g;a[7]=s*e+r*x+c*h;a[8]=s*n+r*u+c*b;return a}};d.mul=d.multiply;d.translate=function(a,b,c){var d=b[0],e=b[1],n=b[2],l=b[3],x=b[4],u=b[5],g=b[6],h=b[7];b=b[8];var j=c[0];c=c[1];a[0]=d;a[1]=e;a[2]=n;a[3]=l;a[4]=x;a[5]=u;a[6]=j*d+c*l+g;a[7]=j*e+c*x+h;a[8]=j*n+c*u+b;return a};d.rotate=
+function(a,b,c){var d=b[0],e=b[1],n=b[2],l=b[3],x=b[4],u=b[5],g=b[6],h=b[7];b=b[8];var j=Math.sin(c);c=Math.cos(c);a[0]=c*d+j*l;a[1]=c*e+j*x;a[2]=c*n+j*u;a[3]=c*l-j*d;a[4]=c*x-j*e;a[5]=c*u-j*n;a[6]=g;a[7]=h;a[8]=b;return a};d.scale=function(a,b,c){var d=c[0];c=c[1];a[0]=d*b[0];a[1]=d*b[1];a[2]=d*b[2];a[3]=c*b[3];a[4]=c*b[4];a[5]=c*b[5];a[6]=b[6];a[7]=b[7];a[8]=b[8];return a};d.fromMat2d=function(a,b){a[0]=b[0];a[1]=b[1];a[2]=0;a[3]=b[2];a[4]=b[3];a[5]=0;a[6]=b[4];a[7]=b[5];a[8]=1;return a};d.fromQuat=
+function(a,b){var c=b[0],d=b[1],e=b[2],n=b[3],l=c+c,x=d+d,u=e+e,c=c*l,g=d*l,d=d*x,h=e*l,j=e*x,e=e*u,l=n*l,x=n*x,n=n*u;a[0]=1-d-e;a[3]=g-n;a[6]=h+x;a[1]=g+n;a[4]=1-c-e;a[7]=j-l;a[2]=h-x;a[5]=j+l;a[8]=1-c-d;return a};d.normalFromMat4=function(a,b){var c=b[0],d=b[1],e=b[2],n=b[3],l=b[4],x=b[5],u=b[6],g=b[7],h=b[8],j=b[9],m=b[10],i=b[11],k=b[12],q=b[13],t=b[14],s=b[15],r=c*x-d*l,z=c*u-e*l,w=c*g-n*l,A=d*u-e*x,E=d*g-n*x,F=e*g-n*u,G=h*q-j*k,H=h*t-m*k,h=h*s-i*k,I=j*t-m*q,j=j*s-i*q,m=m*s-i*t,i=r*m-z*j+w*I+
+A*h-E*H+F*G;if(!i)return null;i=1/i;a[0]=(x*m-u*j+g*I)*i;a[1]=(u*h-l*m-g*H)*i;a[2]=(l*j-x*h+g*G)*i;a[3]=(e*j-d*m-n*I)*i;a[4]=(c*m-e*h+n*H)*i;a[5]=(d*h-c*j-n*G)*i;a[6]=(q*F-t*E+s*A)*i;a[7]=(t*w-k*F-s*z)*i;a[8]=(k*E-q*w+s*r)*i;return a};d.str=function(a){return"mat3("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", "+a[8]+")"};d.frob=function(a){return Math.sqrt(Math.pow(a[0],2)+Math.pow(a[1],2)+Math.pow(a[2],2)+Math.pow(a[3],2)+Math.pow(a[4],2)+Math.pow(a[5],2)+Math.pow(a[6],
+2)+Math.pow(a[7],2)+Math.pow(a[8],2))};"undefined"!==typeof a&&(a.mat3=d);var r={create:function(){var a=new c(16);a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=1;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=1;a[11]=0;a[12]=0;a[13]=0;a[14]=0;a[15]=1;return a},clone:function(a){var b=new c(16);b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];b[13]=a[13];b[14]=a[14];b[15]=a[15];return b},copy:function(a,b){a[0]=b[0];a[1]=b[1];a[2]=
+b[2];a[3]=b[3];a[4]=b[4];a[5]=b[5];a[6]=b[6];a[7]=b[7];a[8]=b[8];a[9]=b[9];a[10]=b[10];a[11]=b[11];a[12]=b[12];a[13]=b[13];a[14]=b[14];a[15]=b[15];return a},identity:function(a){a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=1;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=1;a[11]=0;a[12]=0;a[13]=0;a[14]=0;a[15]=1;return a},transpose:function(a,b){if(a===b){var c=b[1],d=b[2],e=b[3],n=b[6],l=b[7],g=b[11];a[1]=b[4];a[2]=b[8];a[3]=b[12];a[4]=c;a[6]=b[9];a[7]=b[13];a[8]=d;a[9]=n;a[11]=b[14];a[12]=e;a[13]=l;a[14]=g}else a[0]=
+b[0],a[1]=b[4],a[2]=b[8],a[3]=b[12],a[4]=b[1],a[5]=b[5],a[6]=b[9],a[7]=b[13],a[8]=b[2],a[9]=b[6],a[10]=b[10],a[11]=b[14],a[12]=b[3],a[13]=b[7],a[14]=b[11],a[15]=b[15];return a},invert:function(a,b){var c=b[0],d=b[1],e=b[2],n=b[3],l=b[4],g=b[5],u=b[6],h=b[7],j=b[8],m=b[9],i=b[10],k=b[11],q=b[12],t=b[13],s=b[14],r=b[15],z=c*g-d*l,w=c*u-e*l,B=c*h-n*l,A=d*u-e*g,E=d*h-n*g,F=e*h-n*u,G=j*t-m*q,H=j*s-i*q,I=j*r-k*q,L=m*s-i*t,M=m*r-k*t,O=i*r-k*s,D=z*O-w*M+B*L+A*I-E*H+F*G;if(!D)return null;D=1/D;a[0]=(g*O-u*
+M+h*L)*D;a[1]=(e*M-d*O-n*L)*D;a[2]=(t*F-s*E+r*A)*D;a[3]=(i*E-m*F-k*A)*D;a[4]=(u*I-l*O-h*H)*D;a[5]=(c*O-e*I+n*H)*D;a[6]=(s*B-q*F-r*w)*D;a[7]=(j*F-i*B+k*w)*D;a[8]=(l*M-g*I+h*G)*D;a[9]=(d*I-c*M-n*G)*D;a[10]=(q*E-t*B+r*z)*D;a[11]=(m*B-j*E-k*z)*D;a[12]=(g*H-l*L-u*G)*D;a[13]=(c*L-d*H+e*G)*D;a[14]=(t*w-q*A-s*z)*D;a[15]=(j*A-m*w+i*z)*D;return a},adjoint:function(a,b){var c=b[0],d=b[1],e=b[2],n=b[3],l=b[4],g=b[5],h=b[6],j=b[7],m=b[8],i=b[9],k=b[10],q=b[11],t=b[12],s=b[13],r=b[14],z=b[15];a[0]=g*(k*z-q*r)-
+i*(h*z-j*r)+s*(h*q-j*k);a[1]=-(d*(k*z-q*r)-i*(e*z-n*r)+s*(e*q-n*k));a[2]=d*(h*z-j*r)-g*(e*z-n*r)+s*(e*j-n*h);a[3]=-(d*(h*q-j*k)-g*(e*q-n*k)+i*(e*j-n*h));a[4]=-(l*(k*z-q*r)-m*(h*z-j*r)+t*(h*q-j*k));a[5]=c*(k*z-q*r)-m*(e*z-n*r)+t*(e*q-n*k);a[6]=-(c*(h*z-j*r)-l*(e*z-n*r)+t*(e*j-n*h));a[7]=c*(h*q-j*k)-l*(e*q-n*k)+m*(e*j-n*h);a[8]=l*(i*z-q*s)-m*(g*z-j*s)+t*(g*q-j*i);a[9]=-(c*(i*z-q*s)-m*(d*z-n*s)+t*(d*q-n*i));a[10]=c*(g*z-j*s)-l*(d*z-n*s)+t*(d*j-n*g);a[11]=-(c*(g*q-j*i)-l*(d*q-n*i)+m*(d*j-n*g));a[12]=
+-(l*(i*r-k*s)-m*(g*r-h*s)+t*(g*k-h*i));a[13]=c*(i*r-k*s)-m*(d*r-e*s)+t*(d*k-e*i);a[14]=-(c*(g*r-h*s)-l*(d*r-e*s)+t*(d*h-e*g));a[15]=c*(g*k-h*i)-l*(d*k-e*i)+m*(d*h-e*g);return a},determinant:function(a){var b=a[0],c=a[1],d=a[2],e=a[3],n=a[4],l=a[5],g=a[6],h=a[7],j=a[8],i=a[9],m=a[10],k=a[11],q=a[12],s=a[13],t=a[14];a=a[15];return(b*l-c*n)*(m*a-k*t)-(b*g-d*n)*(i*a-k*s)+(b*h-e*n)*(i*t-m*s)+(c*g-d*l)*(j*a-k*q)-(c*h-e*l)*(j*t-m*q)+(d*h-e*g)*(j*s-i*q)},multiply:function(a,b,c){var d=b[0],e=b[1],n=b[2],
+l=b[3],g=b[4],h=b[5],j=b[6],i=b[7],m=b[8],k=b[9],q=b[10],s=b[11],t=b[12],r=b[13],z=b[14];b=b[15];var w=c[0],C=c[1],B=c[2],A=c[3];a[0]=w*d+C*g+B*m+A*t;a[1]=w*e+C*h+B*k+A*r;a[2]=w*n+C*j+B*q+A*z;a[3]=w*l+C*i+B*s+A*b;w=c[4];C=c[5];B=c[6];A=c[7];a[4]=w*d+C*g+B*m+A*t;a[5]=w*e+C*h+B*k+A*r;a[6]=w*n+C*j+B*q+A*z;a[7]=w*l+C*i+B*s+A*b;w=c[8];C=c[9];B=c[10];A=c[11];a[8]=w*d+C*g+B*m+A*t;a[9]=w*e+C*h+B*k+A*r;a[10]=w*n+C*j+B*q+A*z;a[11]=w*l+C*i+B*s+A*b;w=c[12];C=c[13];B=c[14];A=c[15];a[12]=w*d+C*g+B*m+A*t;a[13]=
+w*e+C*h+B*k+A*r;a[14]=w*n+C*j+B*q+A*z;a[15]=w*l+C*i+B*s+A*b;return a}};r.mul=r.multiply;r.translate=function(a,b,c){var d=c[0],e=c[1];c=c[2];var n,l,g,h,j,i,m,k,q,s,t,r;b===a?(a[12]=b[0]*d+b[4]*e+b[8]*c+b[12],a[13]=b[1]*d+b[5]*e+b[9]*c+b[13],a[14]=b[2]*d+b[6]*e+b[10]*c+b[14],a[15]=b[3]*d+b[7]*e+b[11]*c+b[15]):(n=b[0],l=b[1],g=b[2],h=b[3],j=b[4],i=b[5],m=b[6],k=b[7],q=b[8],s=b[9],t=b[10],r=b[11],a[0]=n,a[1]=l,a[2]=g,a[3]=h,a[4]=j,a[5]=i,a[6]=m,a[7]=k,a[8]=q,a[9]=s,a[10]=t,a[11]=r,a[12]=n*d+j*e+q*c+
+b[12],a[13]=l*d+i*e+s*c+b[13],a[14]=g*d+m*e+t*c+b[14],a[15]=h*d+k*e+r*c+b[15]);return a};r.scale=function(a,b,c){var d=c[0],e=c[1];c=c[2];a[0]=b[0]*d;a[1]=b[1]*d;a[2]=b[2]*d;a[3]=b[3]*d;a[4]=b[4]*e;a[5]=b[5]*e;a[6]=b[6]*e;a[7]=b[7]*e;a[8]=b[8]*c;a[9]=b[9]*c;a[10]=b[10]*c;a[11]=b[11]*c;a[12]=b[12];a[13]=b[13];a[14]=b[14];a[15]=b[15];return a};r.rotate=function(a,c,d,e){var g=e[0],n=e[1];e=e[2];var l=Math.sqrt(g*g+n*n+e*e),h,j,i,m,k,q,s,t,r,z,w,Q,C,B,A,E,F,G,H,I;if(Math.abs(l)<b)return null;l=1/l;g*=
+l;n*=l;e*=l;h=Math.sin(d);j=Math.cos(d);i=1-j;d=c[0];l=c[1];m=c[2];k=c[3];q=c[4];s=c[5];t=c[6];r=c[7];z=c[8];w=c[9];Q=c[10];C=c[11];B=g*g*i+j;A=n*g*i+e*h;E=e*g*i-n*h;F=g*n*i-e*h;G=n*n*i+j;H=e*n*i+g*h;I=g*e*i+n*h;g=n*e*i-g*h;n=e*e*i+j;a[0]=d*B+q*A+z*E;a[1]=l*B+s*A+w*E;a[2]=m*B+t*A+Q*E;a[3]=k*B+r*A+C*E;a[4]=d*F+q*G+z*H;a[5]=l*F+s*G+w*H;a[6]=m*F+t*G+Q*H;a[7]=k*F+r*G+C*H;a[8]=d*I+q*g+z*n;a[9]=l*I+s*g+w*n;a[10]=m*I+t*g+Q*n;a[11]=k*I+r*g+C*n;c!==a&&(a[12]=c[12],a[13]=c[13],a[14]=c[14],a[15]=c[15]);return a};
+r.rotateX=function(a,b,c){var d=Math.sin(c);c=Math.cos(c);var e=b[4],g=b[5],l=b[6],h=b[7],j=b[8],i=b[9],m=b[10],k=b[11];b!==a&&(a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3],a[12]=b[12],a[13]=b[13],a[14]=b[14],a[15]=b[15]);a[4]=e*c+j*d;a[5]=g*c+i*d;a[6]=l*c+m*d;a[7]=h*c+k*d;a[8]=j*c-e*d;a[9]=i*c-g*d;a[10]=m*c-l*d;a[11]=k*c-h*d;return a};r.rotateY=function(a,b,c){var d=Math.sin(c);c=Math.cos(c);var e=b[0],g=b[1],l=b[2],h=b[3],j=b[8],i=b[9],m=b[10],k=b[11];b!==a&&(a[4]=b[4],a[5]=b[5],a[6]=b[6],a[7]=b[7],
+a[12]=b[12],a[13]=b[13],a[14]=b[14],a[15]=b[15]);a[0]=e*c-j*d;a[1]=g*c-i*d;a[2]=l*c-m*d;a[3]=h*c-k*d;a[8]=e*d+j*c;a[9]=g*d+i*c;a[10]=l*d+m*c;a[11]=h*d+k*c;return a};r.rotateZ=function(a,b,c){var d=Math.sin(c);c=Math.cos(c);var e=b[0],g=b[1],l=b[2],h=b[3],j=b[4],i=b[5],m=b[6],k=b[7];b!==a&&(a[8]=b[8],a[9]=b[9],a[10]=b[10],a[11]=b[11],a[12]=b[12],a[13]=b[13],a[14]=b[14],a[15]=b[15]);a[0]=e*c+j*d;a[1]=g*c+i*d;a[2]=l*c+m*d;a[3]=h*c+k*d;a[4]=j*c-e*d;a[5]=i*c-g*d;a[6]=m*c-l*d;a[7]=k*c-h*d;return a};r.fromRotationTranslation=
+function(a,b,c){var d=b[0],e=b[1],g=b[2],h=b[3],j=d+d,i=e+e,m=g+g;b=d*j;var k=d*i,d=d*m,q=e*i,e=e*m,g=g*m,j=h*j,i=h*i,h=h*m;a[0]=1-(q+g);a[1]=k+h;a[2]=d-i;a[3]=0;a[4]=k-h;a[5]=1-(b+g);a[6]=e+j;a[7]=0;a[8]=d+i;a[9]=e-j;a[10]=1-(b+q);a[11]=0;a[12]=c[0];a[13]=c[1];a[14]=c[2];a[15]=1;return a};r.fromQuat=function(a,b){var c=b[0],d=b[1],e=b[2],g=b[3],h=c+c,j=d+d,i=e+e,c=c*h,m=d*h,d=d*j,k=e*h,q=e*j,e=e*i,h=g*h,j=g*j,g=g*i;a[0]=1-d-e;a[1]=m+g;a[2]=k-j;a[3]=0;a[4]=m-g;a[5]=1-c-e;a[6]=q+h;a[7]=0;a[8]=k+j;
+a[9]=q-h;a[10]=1-c-d;a[11]=0;a[12]=0;a[13]=0;a[14]=0;a[15]=1;return a};r.frustum=function(a,b,c,d,e,g,h){var j=1/(c-b),i=1/(e-d),m=1/(g-h);a[0]=2*g*j;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=2*g*i;a[6]=0;a[7]=0;a[8]=(c+b)*j;a[9]=(e+d)*i;a[10]=(h+g)*m;a[11]=-1;a[12]=0;a[13]=0;a[14]=2*(h*g)*m;a[15]=0;return a};r.perspective=function(a,b,c,d,e){b=1/Math.tan(b/2);var g=1/(d-e);a[0]=b/c;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=b;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=(e+d)*g;a[11]=-1;a[12]=0;a[13]=0;a[14]=2*e*d*g;a[15]=0;
+return a};r.ortho=function(a,b,c,d,e,g,h){var j=1/(b-c),i=1/(d-e),m=1/(g-h);a[0]=-2*j;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=-2*i;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=2*m;a[11]=0;a[12]=(b+c)*j;a[13]=(e+d)*i;a[14]=(h+g)*m;a[15]=1;return a};r.lookAt=function(a,c,d,e){var g,h,j,i,m,k,q,s,t=c[0],z=c[1];c=c[2];j=e[0];i=e[1];h=e[2];q=d[0];e=d[1];g=d[2];if(Math.abs(t-q)<b&&Math.abs(z-e)<b&&Math.abs(c-g)<b)return r.identity(a);d=t-q;e=z-e;q=c-g;s=1/Math.sqrt(d*d+e*e+q*q);d*=s;e*=s;q*=s;g=i*q-h*e;h=h*d-j*q;j=j*e-i*
+d;(s=Math.sqrt(g*g+h*h+j*j))?(s=1/s,g*=s,h*=s,j*=s):j=h=g=0;i=e*j-q*h;m=q*g-d*j;k=d*h-e*g;(s=Math.sqrt(i*i+m*m+k*k))?(s=1/s,i*=s,m*=s,k*=s):k=m=i=0;a[0]=g;a[1]=i;a[2]=d;a[3]=0;a[4]=h;a[5]=m;a[6]=e;a[7]=0;a[8]=j;a[9]=k;a[10]=q;a[11]=0;a[12]=-(g*t+h*z+j*c);a[13]=-(i*t+m*z+k*c);a[14]=-(d*t+e*z+q*c);a[15]=1;return a};r.str=function(a){return"mat4("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", "+a[8]+", "+a[9]+", "+a[10]+", "+a[11]+", "+a[12]+", "+a[13]+", "+a[14]+", "+
+a[15]+")"};r.frob=function(a){return Math.sqrt(Math.pow(a[0],2)+Math.pow(a[1],2)+Math.pow(a[2],2)+Math.pow(a[3],2)+Math.pow(a[4],2)+Math.pow(a[5],2)+Math.pow(a[6],2)+Math.pow(a[7],2)+Math.pow(a[8],2)+Math.pow(a[9],2)+Math.pow(a[10],2)+Math.pow(a[11],2)+Math.pow(a[12],2)+Math.pow(a[13],2)+Math.pow(a[14],2)+Math.pow(a[15],2))};"undefined"!==typeof a&&(a.mat4=r);var m={create:function(){var a=new c(4);a[0]=0;a[1]=0;a[2]=0;a[3]=1;return a}},q=g.create(),s=g.fromValues(1,0,0),t=g.fromValues(0,1,0);m.rotationTo=
+function(a,b,c){var d=g.dot(b,c);if(-0.999999>d)return g.cross(q,s,b),1E-6>g.length(q)&&g.cross(q,t,b),g.normalize(q,q),m.setAxisAngle(a,q,Math.PI),a;if(0.999999<d)return a[0]=0,a[1]=0,a[2]=0,a[3]=1,a;g.cross(q,b,c);a[0]=q[0];a[1]=q[1];a[2]=q[2];a[3]=1+d;return m.normalize(a,a)};var z=d.create();m.setAxes=function(a,b,c,d){z[0]=c[0];z[3]=c[1];z[6]=c[2];z[1]=d[0];z[4]=d[1];z[7]=d[2];z[2]=-b[0];z[5]=-b[1];z[8]=-b[2];return m.normalize(a,m.fromMat3(a,z))};m.clone=i.clone;m.fromValues=i.fromValues;m.copy=
+i.copy;m.set=i.set;m.identity=function(a){a[0]=0;a[1]=0;a[2]=0;a[3]=1;return a};m.setAxisAngle=function(a,b,c){c*=0.5;var d=Math.sin(c);a[0]=d*b[0];a[1]=d*b[1];a[2]=d*b[2];a[3]=Math.cos(c);return a};m.add=i.add;m.multiply=function(a,b,c){var d=b[0],e=b[1],g=b[2];b=b[3];var h=c[0],j=c[1],i=c[2];c=c[3];a[0]=d*c+b*h+e*i-g*j;a[1]=e*c+b*j+g*h-d*i;a[2]=g*c+b*i+d*j-e*h;a[3]=b*c-d*h-e*j-g*i;return a};m.mul=m.multiply;m.scale=i.scale;m.rotateX=function(a,b,c){c*=0.5;var d=b[0],e=b[1],g=b[2];b=b[3];var h=Math.sin(c);
+c=Math.cos(c);a[0]=d*c+b*h;a[1]=e*c+g*h;a[2]=g*c-e*h;a[3]=b*c-d*h;return a};m.rotateY=function(a,b,c){c*=0.5;var d=b[0],e=b[1],g=b[2];b=b[3];var h=Math.sin(c);c=Math.cos(c);a[0]=d*c-g*h;a[1]=e*c+b*h;a[2]=g*c+d*h;a[3]=b*c-e*h;return a};m.rotateZ=function(a,b,c){c*=0.5;var d=b[0],e=b[1],g=b[2];b=b[3];var h=Math.sin(c);c=Math.cos(c);a[0]=d*c+e*h;a[1]=e*c-d*h;a[2]=g*c+b*h;a[3]=b*c-g*h;return a};m.calculateW=function(a,b){var c=b[0],d=b[1],e=b[2];a[0]=c;a[1]=d;a[2]=e;a[3]=Math.sqrt(Math.abs(1-c*c-d*d-
+e*e));return a};m.dot=i.dot;m.lerp=i.lerp;m.slerp=function(a,b,c,d){var e=b[0],g=b[1],h=b[2];b=b[3];var j=c[0],i=c[1],m=c[2];c=c[3];var k,q,s;q=e*j+g*i+h*m+b*c;0>q&&(q=-q,j=-j,i=-i,m=-m,c=-c);1E-6<1-q?(k=Math.acos(q),s=Math.sin(k),q=Math.sin((1-d)*k)/s,d=Math.sin(d*k)/s):q=1-d;a[0]=q*e+d*j;a[1]=q*g+d*i;a[2]=q*h+d*m;a[3]=q*b+d*c;return a};m.invert=function(a,b){var c=b[0],d=b[1],e=b[2],g=b[3],h=c*c+d*d+e*e+g*g,h=h?1/h:0;a[0]=-c*h;a[1]=-d*h;a[2]=-e*h;a[3]=g*h;return a};m.conjugate=function(a,b){a[0]=
+-b[0];a[1]=-b[1];a[2]=-b[2];a[3]=b[3];return a};m.length=i.length;m.len=m.length;m.squaredLength=i.squaredLength;m.sqrLen=m.squaredLength;m.normalize=i.normalize;m.fromMat3=function(a,b){var c=b[0]+b[4]+b[8];if(0<c)c=Math.sqrt(c+1),a[3]=0.5*c,c=0.5/c,a[0]=(b[5]-b[7])*c,a[1]=(b[6]-b[2])*c,a[2]=(b[1]-b[3])*c;else{var d=0;b[4]>b[0]&&(d=1);b[8]>b[3*d+d]&&(d=2);var e=(d+1)%3,g=(d+2)%3,c=Math.sqrt(b[3*d+d]-b[3*e+e]-b[3*g+g]+1);a[d]=0.5*c;c=0.5/c;a[3]=(b[3*e+g]-b[3*g+e])*c;a[e]=(b[3*e+d]+b[3*d+e])*c;a[g]=
+(b[3*g+d]+b[3*d+g])*c}return a};m.str=function(a){return"quat("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+")"};"undefined"!==typeof a&&(a.quat=m)})(GLMAT);try{module.exports=GLMAT}catch(e$$10){}try{glm.exists&&alert("glm.common.js loaded over exist glm instance: "+glm)}catch(e$$11){}glm=null;GLMJS_PREFIX="glm-js: ";
+GLM={$DEBUG:"undefined"!==typeof $GLM_DEBUG&&$GLM_DEBUG,version:"0.0.6c",GLM_VERSION:96,$outer:{polyfills:GLM_polyfills(),functions:{},intern:function(a,b){if(a)if(void 0===b&&"object"===typeof a)for(var c in a)GLM.$outer.intern(c,a[c]);else return GLM.$DEBUG&&GLM.$outer.console.debug("intern "+a,b&&(b.name||typeof b)),GLM.$outer[a]=b},$import:function(a){GLM.$outer.$import=function(){throw Error("glm.$outer.$import already called...");};GLM.$outer.intern(a.statics);GLM.$template.extend(GLM,GLM.$template["declare<T,V,number>"](a["declare<T,V,number>"]),
+GLM.$template["declare<T,V,...>"](a["declare<T,V,...>"]),GLM.$template["declare<T,...>"](a["declare<T,...>"]),GLM.$template["declare<T>"](a["declare<T>"]));GLM.$init(a)},console:$GLM_reset_logging(),quat_array_from_xyz:function(a){var b=glm.quat(),c=glm.mat3(1);b["*="](glm.angleAxis(a.x,c[0]));b["*="](glm.angleAxis(a.y,c[1]));b["*="](glm.angleAxis(a.z,c[2]));return b.elements},Array:Array,ArrayBuffer:ArrayBuffer,Float32Array:Float32Array,Float64Array:Float64Array,Uint8Array:Uint8Array,Uint16Array:Uint16Array,
+Uint32Array:Uint32Array,Int8Array:Int8Array,Int16Array:Int16Array,Int32Array:Int32Array,DataView:"undefined"!==typeof DataView&&DataView,$rebindTypedArrays:function(a){var b=Object.keys(GLM.$outer).filter(RegExp.prototype.test.bind(/.Array$|^ArrayBuffer$|^DataView$/)).map(function(b){var e=a.call(this,b,GLM.$outer[b]);e!==GLM.$outer[b]&&(GLM.$outer.console.warn("$rebindTypedArrays("+b+")... replacing"),GLM.$outer[b]=e);return e});GLM.$subarray=GLM.patch_subarray();return b}},$extern:$GLM_extern,$log:$GLM_log,
+GLMJSError:$GLM_GLMJSError("GLMJSError"),_radians:function(a){return a*this.PI/180}.bind(Math),_degrees:function(a){return 180*a/this.PI}.bind(Math),normalize:$GLM_extern("normalize"),inverse:$GLM_extern("inverse"),distance:$GLM_extern("distance"),length:$GLM_extern("length"),length2:$GLM_extern("length2"),transpose:$GLM_extern("transpose"),slerp:$GLM_extern("slerp"),mix:$GLM_extern("mix"),clamp:$GLM_extern("clamp"),angleAxis:$GLM_extern("angleAxis"),rotate:$GLM_extern("rotate"),scale:$GLM_extern("scale"),
+translate:$GLM_extern("translate"),lookAt:$GLM_extern("lookAt"),cross:$GLM_extern("cross"),dot:$GLM_extern("dot"),perspective:function(a,b,c,e){return GLM.$outer.mat4_perspective(a,b,c,e)},ortho:function(a,b,c,e,d,h){return GLM.$outer.mat4_ortho(a,b,c,e,d,h)},_eulerAngles:function(a){return GLM.$outer.vec3_eulerAngles(a)},angle:function(a){return 2*Math.acos(a.w)},axis:function(a){var b=1-a.w*a.w;if(0>=b)return glm.vec3(0,0,1);b=1/Math.sqrt(b);return glm.vec3(a.x*b,a.y*b,a.z*b)},$from_ptr:function(a,
+b,c){if(this!==GLM)throw new GLM.GLMJSError("... use glm.make_<type>() (not new glm.make<type>())");b=new GLM.$outer.Float32Array(b.buffer||b,c||0,a.componentLength);b=new GLM.$outer.Float32Array(b);return new a(b)},make_vec2:function(a,b){return GLM.$from_ptr.call(this,GLM.vec2,a,2===arguments.length?b:a.byteOffset)},make_vec3:function(a,b){return GLM.$from_ptr.call(this,GLM.vec3,a,2===arguments.length?b:a.byteOffset)},make_vec4:function(a,b){return GLM.$from_ptr.call(this,GLM.vec4,a,2===arguments.length?
+b:a.byteOffset)},make_quat:function(a,b){return GLM.$from_ptr.call(this,GLM.quat,a,2===arguments.length?b:a.byteOffset)},make_mat3:function(a,b){return GLM.$from_ptr.call(this,GLM.mat3,a,2===arguments.length?b:a.byteOffset)},make_mat4:function(a,b){return GLM.$from_ptr.call(this,GLM.mat4,a,2===arguments.length?b:a.byteOffset)},diagonal4x4:function(a){if("vec4"!==GLM.$typeof(a))throw new GLM.GLMJSError("unsupported argtype to GLM.diagonal4x4: "+["type:"+GLM.$typeof(a)]);a=a.elements;return new GLM.mat4([a[0],
+0,0,0,0,a[1],0,0,0,0,a[2],0,0,0,0,a[3]])},diagonal3x3:function(a){if("vec3"!==GLM.$typeof(a))throw new GLM.GLMJSError("unsupported argtype to GLM.diagonal3x3: "+["type:"+GLM.$typeof(a)]);a=a.elements;return new GLM.mat3([a[0],0,0,0,a[1],0,0,0,a[2]])},_toMat4:function(a){return new GLM.mat4(GLM.$outer.mat4_array_from_quat(a))},FAITHFUL:!0,to_string:function(a,b){try{var c=a.$type||typeof a;if(!GLM[c])throw new GLM.GLMJSError("unsupported argtype to GLM.to_string: "+["type:"+c,a]);return GLM.FAITHFUL?
+GLM.$to_string(a,b).replace(/[\t\n]/g,""):GLM.$to_string(a,b)}catch(e){return GLM.$DEBUG&&GLM.$outer.console.error("to_string error: ",c,a+"",e),e+""}},$sizeof:function(a){return a.BYTES_PER_ELEMENT},$types:[],$isGLMConstructor:function(a){return!!(a&&a.prototype instanceof GLM.$GLMBaseType)},$getGLMType:function(a){return a instanceof GLM.$GLMBaseType&&a.constructor||"string"===typeof a&&GLM[a]},$isGLMObject:function(a){return!!(a instanceof GLM.$GLMBaseType&&a.$type)},$typeof:function(a){return a instanceof
+GLM.$GLMBaseType?a.$type:"undefined"},$to_array:function(a){return[].slice.call(a.elements)},$to_json:function(a,b,c){this instanceof GLM.$GLMBaseType&&(c=b,b=a,a=this);return JSON.stringify(GLM.$to_object(a),b,c)},$inspect:function(a){this instanceof GLM.$GLMBaseType&&(a=this);return GLM.$to_json(a,null,2)},_clamp:function(a,b,c){return a<b?b:a>c?c:a},_abs:function(a){return Math.abs(a)},_equal:function(a,b){return a===b},_epsilonEqual:function(a,b,c){return Math.abs(a-b)<c},_fract:function(a){return a-
+Math.floor(a)},_frexp:function(){function a(b,c){var e=GLM.$outer.DataView||a._DataView;if(0==b)return c&&Array.isArray(c)?c[0]=c[1]=0:[0,0];e=new e(new GLM.$outer.ArrayBuffer(8));e.setFloat64(0,b);var d=e.getUint32(0)>>>20&2047;0===d&&(e.setFloat64(0,b*Math.pow(2,64)),d=(e.getUint32(0)>>>20&2047)-64);e=d-1022;d=GLM.ldexp(b,-e);return c&&Array.isArray(c)?(c[0]=e,c[1]=d):[d,e]}a._DataView=function(a){this.buffer=a;this.setFloat64=function(a,b){if(0!==a)throw Error("...this is a very limited DataView emulator");
+(new Uint8Array(this.buffer)).set([].reverse.call(new Uint8Array((new Float64Array([b])).buffer)),a)};this.getUint32=function(a){if(0!==a)throw Error("...this is a very limited DataView emulator");return(new Uint32Array((new Uint8Array([].slice.call(new Uint8Array(this.buffer)).reverse())).buffer))[1]}};return a}(),_ldexp:function(a,b){return 1023<b?a*Math.pow(2,1023)*Math.pow(2,b-1023):-1074>b?a*Math.pow(2,-1074)*Math.pow(2,b+1074):a*Math.pow(2,b)},_max:Math.max,_min:Math.min,sqrt:Math.sqrt,__sign:function(a){return 0<
+a?1:0>a?-1:+a},$constants:{epsilon:1E-6,euler:0.5772156649015329,e:Math.E,ln_ten:Math.LN10,ln_two:Math.LN2,pi:Math.PI,half_pi:Math.PI/2,quarter_pi:Math.PI/4,one_over_pi:1/Math.PI,two_over_pi:2/Math.PI,root_pi:Math.sqrt(Math.PI),root_two:Math.sqrt(2),root_three:Math.sqrt(3),two_over_root_pi:2/Math.sqrt(Math.PI),one_over_root_two:Math.SQRT1_2,root_two:Math.SQRT2},FIXEDPRECISION:6,$toFixedString:function(a,b,c,e){void 0===e&&(e=GLM.FIXEDPRECISION);if(!c||!c.map)throw Error("unsupported argtype to $toFixedString(..,..,props="+
+typeof c+")");try{var d="";c.map(function(c){c=b[d=c];if(!c.toFixed)throw Error("!toFixed in w"+[c,a,JSON.stringify(b)]);return c.toFixed(0)})}catch(h){throw GLM.$DEBUG&&GLM.$outer.console.error("$toFixedString error",a,typeof b,Object.prototype.toString.call(b),d),GLM.$DEBUG&&glm.$log("$toFixedString error",a,typeof b,Object.prototype.toString.call(b),d),new GLM.GLMJSError(h);}c=c.map(function(a){return b[a].toFixed(e)});return a+"("+c.join(", ")+")"}};GLM._sign=Math.sign||GLM.__sign;
+for(var p in GLM.$constants)(function(a,b){GLM[b]=function(){return a};GLM[b].valueOf=GLM[b]})(GLM.$constants[p],p);
+GLM.$GLMBaseType=function(){function a(a,c){var e=a.$||{};this.$type=c;this.$type_name=e.name||"<"+c+">";e.components&&(this.$components=e.components[0]);this.$len=this.components=a.componentLength;this.constructor=a;this.byteLength=a.BYTES_PER_ELEMENT;GLM.$types.push(c)}a.prototype={clone:function(){return new this.constructor(new this.elements.constructor(this.elements))},toString:function(){return GLM.$to_string(this)},inspect:function(){return GLM.$inspect(this)},toJSON:function(){return GLM.$to_object(this)}};
+Object.defineProperty(a.prototype,"address",{get:function(){var a=this.elements.byteOffset.toString(16);return"0x00000000".substr(0,10-a.length)+a}});return a}();
+(function(){function a(a,b,c){return a.subarray(b,c||a.length)}function b(a,b,c){var e=a.constructor;c=c||a.length;return new e(a.buffer,a.byteOffset+b*e.BYTES_PER_ELEMENT,c-b)}function c(){var a=new GLM.$outer.Float32Array([0,0]);a.subarray(1).subarray(0)[0]=1;var b=c.result=[a[1],(new GLM.$outer.Float32Array(16)).subarray(12,16).length];return!(a[1]!==b[0]||4!==b[1])}function e(a){var b=new GLM.$outer.Float32Array([0,0]);a(a(b,1),0)[0]=1;a=e.result=[b[1],a(new GLM.$outer.Float32Array(16),12,16).length];
+return!(b[1]!==a[0]||4!==a[1])}Object.defineProperty(GLM,"patch_subarray",{configurable:!0,value:function(){var d=!c()?b:a;d.workaround_broken_spidermonkey_subarray=b;d.native_subarray=a;if(!e(d))throw Error("failed to resolve working TypedArray.subarray implementation... "+e.result);return d}})})();GLM.$subarray=GLM.patch_subarray();
+var GLM_template=GLM.$template={_genArgError:function(a,b,c,e){~e.indexOf(void 0)&&(e=e.slice(0,e.indexOf(void 0)));var d=RegExp.prototype.test.bind(/^[^$_]/);return new GLM.GLMJSError("unsupported argtype to "+b+" "+a.$sig+": [typ="+c+"] :: got arg types: "+e.map(GLM.$template.jstypes.get)+" // supported types: "+Object.keys(a).filter(d).join("||"))},jstypes:{get:function(a){return null===a?"null":void 0===a?"undefined":a.$type||GLM.$template.jstypes[typeof a]||GLM.$template.jstypes[a+""]||function(a){if("object"===
+typeof a){if(a instanceof GLM.$outer.Float32Array)return"Float32Array";if(a instanceof GLM.$outer.ArrayBuffer)return"ArrayBuffer";if(Array.isArray(a))return"array"}return"<unknown "+[typeof a,a]+">"}(a)},"0":"float","boolean":"bool",number:"float",string:"string","[object Float32Array]":"Float32Array","[object ArrayBuffer]":"ArrayBuffer","function":"function"},_add_overrides:function(a,b){for(var c in b)b[c]&&GLM[c].override(a,b[c])},_add_inline_override:function(a,b,c){this[b]=eval(GLM.$template._traceable("glm_"+
+a+"_"+b,c))();return this},_inline_helpers:function(a,b){Object.defineProperty(a,"GLM",{value:GLM});return{$type:"built-in",$type_name:b,$template:a,F:a,dbg:b,override:this._add_inline_override.bind(a,b),link:function(c){var e=a[c];e||(e=a[[c,"undefined"]]);if(!e)throw new GLM.GLMJSError("error linking direct function for "+b+"<"+c+"> or "+b+"<"+[c,void 0]+">");return/\bthis[\[.]/.test(e+"")?e.bind(a):e}}},"template<T>":function(a,b){a.$sig="template<T>";var c=GLM.$template.jstypes,e=GLM.$template._genArgError,
+d=GLM.$GLMBaseType;return this.slingshot(this._inline_helpers(a,b),eval(this._traceable("Tglm_"+b,function(b){this instanceof d&&(b=this);var j=[b&&b.$type||c[typeof b]||c.get(b)||"null"];if(!a[j])throw e(a,arguments.callee.dbg,j,[b]);return a[j](b)}))())},"template<T,...>":function(a,b){a.$sig="template<T,...>";var c=GLM.$template.jstypes,e=GLM.$template._genArgError,d=GLM.$GLMBaseType;return this.slingshot(this._inline_helpers(a,b),eval(this._traceable("Tdotglm_"+b,function(b){for(var j=Array(arguments.length),
+g=0;g<j.length;g++)j[g]=arguments[g];this instanceof d&&j.unshift(b=this);g=[b&&b.$type||c[typeof b]||c.get(b)||"null"];if(!a[g])throw e(a,arguments.callee.dbg,g,j);return a[g].apply(a,j)}))())},"template<T,V,number>":function(a,b){a.$sig="template<T,V,number>";var c=GLM.$template.jstypes,e=GLM.$template._genArgError,d=GLM.GLMJSError,h=GLM.$GLMBaseType;return this.slingshot(this._inline_helpers(a,b),eval(this._traceable("TVnglm_"+b,function(){for(var b=Array(arguments.length),g=0;g<b.length;g++)b[g]=
+arguments[g];this instanceof h&&b.unshift(this);var g=b[0],k=b[1],b=b[2],i=[g&&g.$type||c[typeof g]||c[g+""]||"<unknown "+g+">",k&&k.$type||c[typeof k]||c[k+""]||"<unknown "+k+">"];if(!a[i])throw e(a,arguments.callee.dbg,i,[g,k,b]);if("number"!==typeof b)throw new d(arguments.callee.dbg+a.$sig+": unsupported n type: "+[typeof b,b]);return a[i](g,k,b)}))())},"template<T,V,...>":function(a,b){a.$sig="template<T,V,...>";var c=GLM.$template.jstypes,e=GLM.$GLMBaseType,d=GLM.$template._genArgError,h=GLM.$outer.Array;
+return this.slingshot(this._inline_helpers(a,b),eval(this._traceable("TVglm_"+b,function(){for(var b=new h(arguments.length),g=0;g<b.length;g++)b[g]=arguments[g];this instanceof e&&b.unshift(this);var g=b[0],k=b[1],g=[g&&g.$type||c[typeof g],k&&k.$type||c[typeof k]||c[k+""]||h.isArray(k)&&"array"+k.length+""||""+k+""];if(!a[g])throw d(a,arguments.callee.dbg,g,b);return a[g].apply(a,b)}))())},override:function(a,b,c,e,d){function h(a,c){GLM.$outer.console.debug("glm.$template.override: "+b+" ... "+
+Object.keys(a.$template).filter(function(a){return!~a.indexOf("$")}).map(function(a){return!~c.indexOf(a)?"*"+a+"*":a}).join(" | "))}GLM.$DEBUG&&GLM.$outer.console.debug("glm.$template.override: ",a,b,c.$op?'$op: ["'+c.$op+'"]':"");if(!e)throw Error("unspecified target group "+e+' (expected override(<TV>, "p", {TSP}, ret={GROUP}))');var j=e[b];if(j&&j.$op!==c.$op)throw Error('glm.$template.override: mismatch merging existing override: .$op "'+[j.$op,"!=",c.$op].join(" ")+'"  p='+[b,j.$op,c.$op,"||"+
+Object.keys(j.$template).join("||")]);var g=GLM.$template[a](GLM.$template.deNify(c,b),b);if(j&&j.F.$sig!==g.F.$sig)throw Error('glm.$template.override: mismatch merging existing override: .$sig "'+[j&&j.F.$sig,"!=",g.F.$sig].join(" ")+'"  p='+[b,j&&j.F.$sig,g.F.$sig,"||"+Object.keys(j&&j.$template||{}).join("||")]);g.$op=c.$op;if(j){for(var k in g.$template)"$op"===k||"$sig"===k||(a=k in j.$template,!a||!0===d?(GLM.$DEBUG&&GLM.$outer.console.debug("glm.$template.override: "+b+" ... "+k+" merged"),
+j.$template[k]=g.$template[k]):a&&GLM.$DEBUG&&GLM.$outer.console.debug("glm.$template.override: "+b+" ... "+k+" skipped"));if(GLM.$DEBUG){var i=[];Object.keys(j.$template).forEach(function(a){a in g.$template||(GLM.$DEBUG&&GLM.$outer.console.debug("glm.$template.override: "+b+" ... "+a+" carried-forward"),i.push(a))});h(e[b],i)}}else e[b]=g,GLM.$DEBUG&&h(e[b],[]);return e},_override:function(a,b,c){for(var e in b){if("mat4_scale"!==e&&"object"!==typeof b[e])throw new GLM.GLMJSError("expect object property overrides"+
+[e,b[e],Object.keys(c)]);"object"===typeof b[e]?this.override(a,e,b[e],c,!0):ret_scale=5}return c},slingshot:function(){return this.extend.apply(this,[].reverse.call(arguments))},extend:function(a,b){[].slice.call(arguments,1).forEach(function(b){if(b)for(var e in b)b.hasOwnProperty(e)&&(a[e]=b[e])});return a},"declare<T,V,...>":function(a){return!a?{}:this._override("template<T,V,...>",a,GLM.$outer.functions)},"declare<T>":function(a){return!a?{}:this._override("template<T>",a,GLM.$outer.functions)},
+"declare<T,...>":function(a){return!a?{}:this._override("template<T,...>",a,GLM.$outer.functions)},"declare<T,V,number>":function(a){return!a?{}:this._override("template<T,V,number>",a,GLM.$outer.functions)},_tojsname:function(a){return(a||"_").replace(/[^$a-zA-Z0-9_]/g,"_")},_traceable:function(a,b){var c=b;if("function"!==typeof c)throw new GLM.GLMJSError("_traceable expects tidy function as second arg "+c);if(!a)throw new GLM.GLMJSError("_traceable expects hint or what's the point"+[c,a]);a=this._tojsname(a||
+"_traceable");c=c.toString().replace(/^(\s*var\s*(\w+)\s*=\s*)__VA_ARGS__;/mg,function(a,b,c){return b+"new Array(arguments.length);for(var I=0;I<varname.length;I++)varname[I]=arguments[I];".replace(/I/g,"__VA_ARGS__I").replace(/varname/g,c)}).replace(/\barguments[.]callee\b/g,a);if(/^function _traceable/.test(c))throw new GLM.GLMJSError("already wrapped in a _traceable: "+[c,a]);c='function _traceable(){ "use strict"; SRC; return HINT; }'.replace("HINT",a.replace(/[$]/g,"$$$$")).replace("SRC",c.replace(/[$]/g,
+"$$$$").replace(/^function\s*\(/,"function "+a+"("));c="1,"+c;if(GLM.$DEBUG)try{eval(c)}catch(e){throw console.error("_traceable error",a,c,b,e),e;}return c},deNify:function(a,b){var c={vec:[2,3,4],mat:[3,4]},e=this._tojsname.bind(this),d;for(d in a){var h=!1;d.replace(/([vV]ec|[mM]at)(?:\w*)<N>/,function(j,g){h=!0;var k=a[d];delete a[d];c[g.toLowerCase()].forEach(function(c){var g=d.replace(/<N[*]N>/g,c*c).replace(/<N>/g,c);if(!(g in a)){var h=e("glm_"+b+"_"+g);a[g]=eval("'use strict'; 1,"+(k+"").replace(/^function\s*\(/,
+"function "+h+"(").replace(/N[*]N/g,c*c).replace(/N/g,c))}})}.bind(this));/^[$]/.test(d)?GLM.$DEBUG&&GLM.$outer.console.debug("@ NOT naming "+d):!h&&("function"===typeof a[d]&&!a[d].name)&&(GLM.$DEBUG&&GLM.$outer.console.debug("naming "+e(b+"_"+d)),a[d]=eval(this._traceable("glm_"+b+"_"+d,a[d]))())}return a},$_module_stamp:+new Date,_iso:"/[*][^/*]*[*]/",_get_argnames:function(a){return(a+"").replace(/\s+/g,"").replace(RegExp(this._iso,"g"),"").split("){",1)[0].replace(/^[^(]*[(]/,"").replace(/=[^,]+/g,
+"").split(",").filter(Boolean)},_fix_$_names:function(a,b){Object.keys(b).filter(function(a){return"function"===typeof b[a]&&!b[a].name}).map(function(c){var e=a+"_"+c;GLM.$DEBUG&&GLM.$outer.console.debug("naming $."+c+" == "+e,this._traceable(e,b[c]));b[c]=eval(this._traceable("glm_"+e,b[c]))()}.bind(this));return b},_typedArrayMaker:function(a,b){return function(c){if(c.length===a)return new b(c);var e=new b(a);e.set(c);return e}},GLMType:function(a,b){var c=this._fix_$_names(a,b),e=c.identity.length,
+d,h=Object,j=GLM.$template._get_argnames.bind(GLM.$template),g=GLM.GLMJSError,k={},i;for(i in c)"function"===typeof c[i]&&function(a){k[i]=function(b){return a.apply(c,b)}}(c[i]);d=function(b){var d=k[typeof b[0]+b.length];if(!d){var e="glm."+a;b=e+"("+b.map(function(a){return typeof a})+")";d=h.keys(c).filter(function(a){return"function"===typeof c[a]&&/^\w+\d+$/.test(a)}).map(function(a){return e+"("+j(c[a])+")"});throw new g("no constructor found for: "+b+"\nsupported signatures:\n\t"+d.join("\n\t"));
+}return d};var w,r=GLM;GLM.$template._get_argnames.bind(GLM.$template);w=function(b,c){2<r.$DEBUG&&r.$outer.console.info("adopting elements...",typeof b);if(b.length!=e){if(!1===c)return c;r.$outer.console.error(a+" elements size mismatch: "+["wanted:"+e,"handed:"+b.length]);var d=r.$subarray(b,0,e);throw new r.GLMJSError(a+" elements size mismatch: "+["wanted:"+e,"handed:"+b.length,"theoreticaly-correctable?:"+(d.length===e)]);}return b};var m=this._typedArrayMaker(e,GLM.$outer.Float32Array),q,s=
+GLM.$outer;q=function(a){return a instanceof s.Float32Array};var t=function(a,b,c,g,h,i,j,k){return eval(k("glm_"+h+"$class",function(c){for(var f=new a(arguments.length),g=0;g<f.length;g++)f[g]=arguments[g];var h=d(f),g=t;if(this instanceof g)f=q(c)?w(c):m(h(f)),b.defineProperty(this,"elements",{enumerable:!1,configurable:!0,value:f});else return f=q(c)&&c.length===e?m(c):h(f),new g(f)}))()}(Array,Object,GLM,c,a,GLM.$template._get_argnames.bind(GLM.$template),GLM.GLMJSError,GLM.$template._traceable.bind(GLM.$template));
+c.components=c.components?c.components.map(function(a){return"string"===typeof a?a.split(""):a}):[];t.$=c;t.componentLength=e;t.BYTES_PER_ELEMENT=e*GLM.$outer.Float32Array.BYTES_PER_ELEMENT;t.prototype=new GLM.$GLMBaseType(t,a);t.toJSON=function(){var b={glm$type:a,glm$class:t.prototype.$type_name,glm$eg:(new t).object},c;for(c in t)/function |^[$]/.test(c+t[c])||(b[c]=t[c]);return b};return t}};
+GLM.$template["declare<T,V,...>"]({cross:{"vec2,vec2":function(a,b){return this.GLM.vec3(0,0,a.x*b.y-a.y*b.x)}},distance:{"vec<N>,vec<N>":function(a,b){return this.GLM.length(b.sub(a))}}});
+GLM.$template["declare<T,V,number>"]({mix:{"float,float":function(a,b,c){return b*c+a*(1-c)},"vec<N>,vec<N>":function(a,b,c){var e=1-c,d=new this.GLM.vecN(new a.elements.constructor(N)),h=d.elements;a=a.elements;b=b.elements;for(var j=0;j<N;j++)h[j]=b[j]*c+a[j]*e;return d}},clamp:{"float,float":function(a,b,c){return GLM._clamp(a,b,c)},"vec<N>,float":function(a,b,c){return new GLM.vecN(GLM.$to_array(a).map(function(a){return GLM._clamp(a,b,c)}))}},epsilonEqual:{"float,float":GLM._epsilonEqual,"vec<N>,vec<N>":function(a,
+b,c){for(var e=this["float,float"],d=glm.bvecN(),h=0;h<N;h++)d[h]=e(a[h],b[h],c);return d},"ivec<N>,ivec<N>":function(a,b,c){return this["vecN,vecN"](a,b,c)},"uvec<N>,uvec<N>":function(a,b,c){return this["vecN,vecN"](a,b,c)},"quat,quat":function(a,b,c){for(var e=this["float,float"],d=glm.bvec4(),h=0;4>h;h++)d[h]=e(a[h],b[h],c);return d},"mat<N>,mat<N>":function(){throw new GLM.GLMJSError("error: 'epsilonEqual' only accept floating-point and integer scalar or vector inputs");}}});
+GLM.$template.extend(GLM,GLM.$template["declare<T>"]({degrees:{"float":function(a){return this.GLM._degrees(a)},"vec<N>":function(a){return new this.GLM.vecN(this.GLM.$to_array(a).map(this.GLM._degrees))}},radians:{"float":function(a){return this.GLM._radians(a)},"vec<N>":function(a){return new this.GLM.vecN(this.GLM.$to_array(a).map(this.GLM._radians))}},sign:{"null":function(){return 0},undefined:function(){return NaN},string:function(){return NaN},"float":function(a){return GLM._sign(a)},"vec<N>":function(a){return new GLM.vecN(GLM.$to_array(a).map(GLM._sign))},
+"ivec<N>":function(a){return new GLM.ivecN(GLM.$to_array(a).map(GLM._sign))}},abs:{"float":function(a){return GLM._abs(a)},"vec<N>":function(a){return new GLM.vecN(GLM.$to_array(a).map(GLM._abs))}},fract:{"float":function(a){return GLM._fract(a)},"vec<N>":function(a){return new GLM.vecN(GLM.$to_array(a).map(GLM._fract))}},all:{"vec<N>":function(a){return N===GLM.$to_array(a).filter(Boolean).length},"bvec<N>":function(a){return N===GLM.$to_array(a).filter(Boolean).length},"ivec<N>":function(a){return N===
+GLM.$to_array(a).filter(Boolean).length},"uvec<N>":function(a){return N===GLM.$to_array(a).filter(Boolean).length},quat:function(a){return 4===GLM.$to_array(a).filter(Boolean).length}},$to_object:{vec2:function(a){return{x:a.x,y:a.y}},vec3:function(a){return{x:a.x,y:a.y,z:a.z}},vec4:function(a){return{x:a.x,y:a.y,z:a.z,w:a.w}},uvec2:function(a){return{x:a.x,y:a.y}},uvec3:function(a){return{x:a.x,y:a.y,z:a.z}},uvec4:function(a){return{x:a.x,y:a.y,z:a.z,w:a.w}},ivec2:function(a){return{x:a.x,y:a.y}},
+ivec3:function(a){return{x:a.x,y:a.y,z:a.z}},ivec4:function(a){return{x:a.x,y:a.y,z:a.z,w:a.w}},bvec2:function(a){return{x:!!a.x,y:!!a.y}},bvec3:function(a){return{x:!!a.x,y:!!a.y,z:!!a.z}},bvec4:function(a){return{x:!!a.x,y:!!a.y,z:!!a.z,w:!!a.w}},quat:function(a){return{w:a.w,x:a.x,y:a.y,z:a.z}},mat3:function(a){return{"0":this.vec3(a[0]),1:this.vec3(a[1]),2:this.vec3(a[2])}},mat4:function(a){return{"0":this.vec4(a[0]),1:this.vec4(a[1]),2:this.vec4(a[2]),3:this.vec4(a[3])}}},roll:{$atan2:Math.atan2,
+quat:function(a){return this.$atan2(2*(a.x*a.y+a.w*a.z),a.w*a.w+a.x*a.x-a.y*a.y-a.z*a.z)}},pitch:{$atan2:Math.atan2,quat:function(a){return this.$atan2(2*(a.y*a.z+a.w*a.x),a.w*a.w-a.x*a.x-a.y*a.y+a.z*a.z)}},yaw:{$asin:Math.asin,quat:function(a){return this.$asin(this.GLM.clamp(-2*(a.x*a.z-a.w*a.y),-1,1))}},eulerAngles:{quat:function(a){return this.GLM.vec3(this.GLM.pitch(a),this.GLM.yaw(a),this.GLM.roll(a))}}}),GLM.$template["declare<T,...>"]({$from_glsl:{string:function(a,b){var c;a.replace(/^([$\w]+)\(([-.0-9ef, ]+)\)$/,
+function(a,d,h){a=glm[d]||glm["$"+d];if(!a)throw new GLM.GLMJSError("glsl decoding issue: unknown type '"+d+"'");c=h.split(",").map(parseFloat);if(!b||b===a)c=a.apply(glm,c);else{if(!0===b||b===Array){for(;c.length<a.componentLength;)c.push(c[c.length-1]);return c}throw new GLM.GLMJSError("glsl decoding issue: second argument expected to be undefined|true|Array");}});return c}},$to_glsl:{"vec<N>":function(a,b){var c=GLM.$to_array(a);b&&("object"===typeof b&&"precision"in b)&&(c=c.map(function(a){return a.toFixed(b.precision)}));
+for(;c.length&&c[c.length-2]===c[c.length-1];)c.pop();return a.$type+"("+c+")"},"uvec<N>":function(a,b){return this.vecN(a,b)},"ivec<N>":function(a,b){return this.vecN(a,b)},"bvec<N>":function(a,b){return this.vecN(a,b)},quat:function(a,b){var c;b&&("object"===typeof b&&"precision"in b)&&(c=b.precision);return 0===a.x+a.y+a.z?"quat("+(void 0===c?a.w:a.w.toFixed(c))+")":this.vec4(a,b)},"mat<N>":function(a,b){var c;b&&("object"===typeof b&&"precision"in b)&&(c=b.precision);var e=GLM.$to_array(a);void 0!==
+c&&(e=e.map(function(a){return a.toFixed(c)}));return e.reduce(function(a,b){return a+1*b},0)===e[0]*N?"matN("+e[0]+")":"matN("+e+")"}},frexp:{"float":function(a,b){return 1===arguments.length?this["float,undefined"](a):this["float,array"](a,b)},"vec<N>":function(a,b){if(2>arguments.length)throw new GLM.GLMJSError("frexp(vecN, ivecN) expected ivecN as second parameter");return GLM.vecN(GLM.$to_array(a).map(function(a,e){var d=GLM._frexp(a);b[e]=d[1];return d[0]}))},"float,undefined":function(a){return GLM._frexp(a)},
+"float,array":function(a,b){return GLM._frexp(a,b)}},ldexp:{"float":GLM._ldexp,"vec<N>":function(a,b){return GLM.vecN(GLM.$to_array(a).map(function(a,e){return GLM._ldexp(a,b[e])}))}}}));
+GLM.$template["declare<T,V,...>"]({rotate:{"float,vec3":function(a,b){return this.GLM.$outer.mat4_angleAxis(a,b)},"mat4,float":function(a,b,c){return a.mul(this.GLM.$outer.mat4_angleAxis(b,c))}},scale:{$outer:GLM.$outer,"mat4,vec3":function(a,b){return a.mul(this.$outer.mat4_scale(b))},"vec3,undefined":function(a){return this.$outer.mat4_scale(a)}},translate:{"mat4,vec3":function(a,b){return a.mul(this.GLM.$outer.mat4_translation(b))},"vec3,undefined":function(a){return this.GLM.$outer.mat4_translation(a)}},
+angleAxis:{"float,vec3":function(a,b){return this.GLM.$outer.quat_angleAxis(a,b)}},min:{"float,float":function(a,b){return this.GLM._min(a,b)},"vec<N>,float":function(a,b){return new this.GLM.vecN(this.GLM.$to_array(a).map(function(a){return this.GLM._min(a,b)}.bind(this)))}},max:{"float,float":function(a,b){return this.GLM._max(a,b)},"vec<N>,float":function(a,b){return new this.GLM.vecN(this.GLM.$to_array(a).map(function(a){return this.GLM._max(a,b)}.bind(this)))}},equal:{"float,float":GLM._equal,
+"vec<N>,vec<N>":function(a,b){for(var c=this["float,float"],e=glm.bvecN(),d=0;d<N;d++)e[d]=c(a[d],b[d]);return e},"bvec<N>,bvec<N>":function(a,b){return this["vecN,vecN"](a,b)},"ivec<N>,ivec<N>":function(a,b){return this["vecN,vecN"](a,b)},"uvec<N>,uvec<N>":function(a,b){return this["vecN,vecN"](a,b)},"quat,quat":function(a,b){for(var c=this["float,float"],e=glm.bvec4(),d=0;4>d;d++)e[d]=c(a[d],b[d]);return e}},_slerp:{"quat,quat":function(a,b,c){var e=b,d=glm.dot(glm.vec4(a),glm.vec4(b));0>d&&(e=
+b.mul(-1),d=-d);if(d>1-glm.epsilon())return glm.quat(glm.mix(a.w,e.w,c),glm.mix(a.x,e.x,c),glm.mix(a.y,e.y,c),glm.mix(a.z,e.z,c));b=Math.acos(d);return(a.mul(Math.sin((1-c)*b))+e.mul(Math.sin(c*b)))/Math.sin(b)}},rotation:{"vec3,vec3":function(a,b){var c=this.$dot(a,b),e=new a.constructor(new a.elements.constructor(3));if(c>=1-this.$epsilon)return this.$quat();if(c<-1+this.$epsilon)return e=this.$cross(this.$m[2],a),this.$length2(e)<this.$epsilon&&(e=this.$cross(this.$m[0],a)),e=this.$normalize(e),
+this.$angleAxis(this.$pi,e);var e=this.$cross(a,b),c=this.$sqrt(2*(1+c)),d=1/c;return this.$quat(0.5*c,e.x*d,e.y*d,e.z*d)}},project:{"vec3,mat4":function(a,b,c,e){a=glm.vec4(a,1);a=b["*"](a);a=c["*"](a);a["/="](a.w);a=a["*"](0.5)["+"](0.5);a[0]=a[0]*e[2]+e[0];a[1]=a[1]*e[3]+e[1];return glm.vec3(a)}},unProject:{"vec3,mat4":function(a,b,c,e){b=glm.inverse(c["*"](b));a=glm.vec4(a,1);a.x=(a.x-e[0])/e[2];a.y=(a.y-e[1])/e[3];a=a["*"](2)["-"](glm.vec4(1));e=b["*"](a);e["/="](e.w);return glm.vec3(e)}},orientedAngle:{"vec3,vec3":function(a,
+b,c){var e=Math.acos(glm.clamp(glm.dot(a,b),0,1));return glm.mix(e,-e,0>glm.dot(c,glm.cross(a,b))?1:0)}}});
+GLM.$to_string=GLM.$template["declare<T,...>"]({$to_string:{"function":function(a){return"[function "+(a.name||"anonymous")+"]"},ArrayBuffer:function(a){return"[object ArrayBuffer "+JSON.stringify({byteLength:a.byteLength})+"]"},Float32Array:function(a){return"[object Float32Array "+JSON.stringify({length:a.length,byteOffset:a.byteOffset,byteLength:a.byteLength,BPE:a.BYTES_PER_ELEMENT})+"]"},"float":function(a,b){return GLM.$toFixedString("float",{value:a},["value"],b&&b.precision)},string:function(a){return a},
+bool:function(a){return"bool("+a+")"},"vec<N>":function(a,b){return GLM.$toFixedString(a.$type_name,a,a.$components,b&&b.precision)},"uvec<N>":function(a,b){return GLM.$toFixedString(a.$type_name,a,a.$components,b&&"object"===typeof b&&b.precision||0)},"ivec<N>":function(a,b){return GLM.$toFixedString(a.$type_name,a,a.$components,b&&"object"===typeof b&&b.precision||0)},"bvec<N>":function(a){return a.$type_name+"("+GLM.$to_array(a).map(Boolean).join(", ")+")"},"mat<N>":function(a,b){var c=[0,1,2,
+3].slice(0,N).map(function(b){return a[b]}).map(function(a){return GLM.$toFixedString("\t",a,a.$components,b&&b.precision)});return a.$type_name+"(\n"+c.join(", \n")+"\n)"},quat:function(a,b){a=GLM.degrees(GLM.eulerAngles(a));return GLM.$toFixedString("<quat>"+a.$type_name,a,["x","y","z"],b&&b.precision)}}}).$to_string;
+GLM.$template["declare<T,V,...>"]({copy:{$op:"=","vec<N>,vec<N>":function(a,b){a.elements.set(b.elements);return a},"vec<N>,array<N>":function(a,b){a.elements.set(b);return a},"vec<N>,uvec<N>":function(a,b){a.elements.set(b.elements);return a},"vec<N>,ivec<N>":function(a,b){a.elements.set(b.elements);return a},"vec<N>,bvec<N>":function(a,b){a.elements.set(b.elements);return a},"uvec<N>,uvec<N>":function(a,b){a.elements.set(b.elements);return a},"uvec<N>,array<N>":function(a,b){a.elements.set(b);return a},
+"uvec<N>,vec<N>":function(a,b){a.elements.set(b.elements);return a},"uvec<N>,ivec<N>":function(a,b){a.elements.set(b.elements);return a},"uvec<N>,bvec<N>":function(a,b){a.elements.set(b.elements);return a},"ivec<N>,ivec<N>":function(a,b){a.elements.set(b.elements);return a},"ivec<N>,array<N>":function(a,b){a.elements.set(b);return a},"ivec<N>,vec<N>":function(a,b){a.elements.set(b.elements);return a},"ivec<N>,uvec<N>":function(a,b){a.elements.set(b.elements);return a},"ivec<N>,bvec<N>":function(a,
+b){a.elements.set(b.elements);return a},"bvec<N>,ivec<N>":function(a,b){a.elements.set(b.elements);return a},"bvec<N>,array<N>":function(a,b){a.elements.set(b);return a},"bvec<N>,vec<N>":function(a,b){a.elements.set(b.elements);return a},"bvec<N>,uvec<N>":function(a,b){a.elements.set(b.elements);return a},"bvec<N>,bvec<N>":function(a,b){a.elements.set(b.elements);return a},"quat,quat":function(a,b){a.elements.set(b.elements);return a},"mat<N>,mat<N>":function(a,b){a.elements.set(b.elements);return a},
+"mat<N>,array<N>":function(a,b){b=b.reduce(function(a,b){if(!a.concat)throw new GLM.GLMJSError("matN,arrayN -- [[.length===4] x 4] expected");return a.concat(b)});if(b===N)throw new GLM.GLMJSError("matN,arrayN -- [[N],[N],[N],[N]] expected");return a["="](b)},"mat<N>,array<N*N>":function(a,b){a.elements.set(b);return a},"mat4,array9":function(a,b){a.elements.set((new GLM.mat4(b)).elements);return a}},sub:{$op:"-",_sub:function(a,b){return this.GLM.$to_array(a).map(function(a,e){return a-b[e]})},"vec<N>,vec<N>":function(a,
+b){return new this.GLM.vecN(this._sub(a,b))},"vec<N>,uvec<N>":function(a,b){return new this.GLM.vecN(this._sub(a,b))},"uvec<N>,uvec<N>":function(a,b){return new this.GLM.uvecN(this._sub(a,b))},"uvec<N>,ivec<N>":function(a,b){return new this.GLM.uvecN(this._sub(a,b))},"vec<N>,ivec<N>":function(a,b){return new this.GLM.vecN(this._sub(a,b))},"ivec<N>,uvec<N>":function(a,b){return new this.GLM.ivecN(this._sub(a,b))},"ivec<N>,ivec<N>":function(a,b){return new this.GLM.ivecN(this._sub(a,b))}},sub_eq:{$op:"-=",
+"vec<N>,vec<N>":function(a,b){for(var c=a.elements,e=b.elements,d=0;d<N;d++)c[d]-=e[d];return a},"vec<N>,uvec<N>":function(a,b){return this["vecN,vecN"](a,b)},"uvec<N>,uvec<N>":function(a,b){return this["vecN,vecN"](a,b)},"uvec<N>,ivec<N>":function(a,b){return this["vecN,vecN"](a,b)},"vec<N>,ivec<N>":function(a,b){return this["vecN,vecN"](a,b)},"ivec<N>,ivec<N>":function(a,b){return this["vecN,vecN"](a,b)},"ivec<N>,uvec<N>":function(a,b){return this["vecN,vecN"](a,b)}},add:{$op:"+",_add:function(a,
+b){return this.GLM.$to_array(a).map(function(a,e){return a+b[e]})},"vec<N>,float":function(a,b){return new this.GLM.vecN(this._add(a,[b,b,b,b]))},"vec<N>,vec<N>":function(a,b){return new this.GLM.vecN(this._add(a,b))},"vec<N>,uvec<N>":function(a,b){return new this.GLM.vecN(this._add(a,b))},"uvec<N>,uvec<N>":function(a,b){return new this.GLM.uvecN(this._add(a,b))},"uvec<N>,ivec<N>":function(a,b){return new this.GLM.uvecN(this._add(a,b))},"vec<N>,ivec<N>":function(a,b){return new this.GLM.vecN(this._add(a,
+b))},"ivec<N>,ivec<N>":function(a,b){return new this.GLM.ivecN(this._add(a,b))},"ivec<N>,uvec<N>":function(a,b){return new this.GLM.ivecN(this._add(a,b))}},add_eq:{$op:"+=","vec<N>,vec<N>":function(a,b){for(var c=a.elements,e=b.elements,d=0;d<N;d++)c[d]+=e[d];return a},"vec<N>,uvec<N>":function(a,b){return this["vecN,vecN"](a,b)},"uvec<N>,uvec<N>":function(a,b){return this["vecN,vecN"](a,b)},"uvec<N>,ivec<N>":function(a,b){return this["vecN,vecN"](a,b)},"vec<N>,ivec<N>":function(a,b){return this["vecN,vecN"](a,
+b)},"ivec<N>,ivec<N>":function(a,b){return this["vecN,vecN"](a,b)},"ivec<N>,uvec<N>":function(a,b){return this["vecN,vecN"](a,b)}},div:{$op:"/","vec<N>,float":function(a,b){return new this.GLM.vecN(this.GLM.$to_array(a).map(function(a){return a/b}))}},div_eq:{$op:"/=","vec<N>,float":function(a,b){for(var c=0;c<N;c++)a.elements[c]/=b;return a}},mul:{$op:"*","vec<N>,vec<N>":function(a,b){return new this.GLM.vecN(this.GLM.$to_array(a).map(function(a,e){return a*b[e]}))}},eql_epsilon:function(a){return{$op:"~=",
+"vec<N>,vec<N>":a,"mat<N>,mat<N>":a,"quat,quat":a,"uvec<N>,uvec<N>":a,"ivec<N>,ivec<N>":a}}(function(a,b){return this.GLM.all(this.GLM.epsilonEqual(a,b,this.GLM.epsilon()))}),eql:function(a){return{$op:"==","mat<N>,mat<N>":function(a,c){return c.elements.length===glm.$to_array(a).filter(function(a,b){return a===c.elements[b]}).length},"vec<N>,vec<N>":a,"quat,quat":a,"uvec<N>,uvec<N>":a,"ivec<N>,ivec<N>":a,"bvec<N>,bvec<N>":a}}(function(a,b){return GLM.all(GLM.equal(a,b))})});
+GLM.string={$type_name:"string",$:{}};GLM.number={$type_name:"float",$:{}};GLM["boolean"]={$type:"bool",$type_name:"bool",$:{}};
+GLM.vec2=GLM.$template.GLMType("vec2",{name:"fvec2",identity:[0,0],components:["xy","01"],undefined0:function(){return this.identity},number1:function(a){return[a,a]},number2:function(a,b){return[a,b]},object1:function(a){if(null!==a)switch(a.length){case 4:case 3:case 2:return[a[0],a[1]];default:if("y"in a&&"x"in a){if(typeof a.x!==typeof a.y)throw new GLM.GLMJSError("unrecognized .x-ish object passed to GLM.vec2: "+a);return"string"===typeof a.x?[1*a.x,1*a.y]:[a.x,a.y]}}throw new GLM.GLMJSError("unrecognized object passed to GLM.vec2: "+
+a);}});
+GLM.uvec2=GLM.$template.GLMType("uvec2",{name:"uvec2",identity:[0,0],components:["xy","01"],_clamp:function(a){return~~a},undefined0:function(){return this.identity},number1:function(a){a=this._clamp(a);return[a,a]},number2:function(a,b){a=this._clamp(a);b=this._clamp(b);return[a,b]},object1:function(a){switch(a.length){case 4:case 3:case 2:return[a[0],a[1]].map(this._clamp);default:if("y"in a&&"x"in a){if(typeof a.x!==typeof a.y)throw new GLM.GLMJSError("unrecognized .x-ish object passed to GLM."+this.name+
+": "+a);return[a.x,a.y].map(this._clamp)}}throw new GLM.GLMJSError("unrecognized object passed to GLM."+this.name+": "+a);}});
+GLM.vec3=GLM.$template.GLMType("vec3",{name:"fvec3",identity:[0,0,0],components:["xyz","012","rgb"],undefined0:function(){return GLM.vec3.$.identity},number1:function(a){return[a,a,a]},number2:function(a,b){return[a,b,b]},number3:function(a,b,c){return[a,b,c]},Error:GLM.GLMJSError,object1:function(a){if(a)switch(a.length){case 4:case 3:return[a[0],a[1],a[2]];case 2:return[a[0],a[1],a[1]];default:if("z"in a&&"x"in a){if(typeof a.x!==typeof a.y)throw new this.Error("unrecognized .x-ish object passed to GLM.vec3: "+
+a);return"string"===typeof a.x?[1*a.x,1*a.y,1*a.z]:[a.x,a.y,a.z]}}throw new this.Error("unrecognized object passed to GLM.vec3: "+a);},object2:function(a,b){if(a instanceof GLM.vec2||a instanceof GLM.uvec2||a instanceof GLM.ivec2||a instanceof GLM.bvec2)return[a.x,a.y,b];throw new GLM.GLMJSError("unrecognized object passed to GLM.vec3(o,z): "+[a,b]);}});
+GLM.uvec3=GLM.$template.GLMType("uvec3",{name:"uvec3",identity:[0,0,0],components:["xyz","012"],_clamp:GLM.uvec2.$._clamp,undefined0:function(){return this.identity},number1:function(a){a=this._clamp(a);return[a,a,a]},number2:function(a,b){a=this._clamp(a);b=this._clamp(b);return[a,b,b]},number3:function(a,b,c){a=this._clamp(a);b=this._clamp(b);c=this._clamp(c);return[a,b,c]},object1:function(a){if(a)switch(a.length){case 4:case 3:return[a[0],a[1],a[2]].map(this._clamp);case 2:return[a[0],a[1],a[1]].map(this._clamp);
+default:if("z"in a&&"x"in a){if(typeof a.x!==typeof a.y)throw new GLM.GLMJSError("unrecognized .x-ish object passed to GLM."+this.name+": "+a);return[a.x,a.y,a.z].map(this._clamp)}}throw new GLM.GLMJSError("unrecognized object passed to GLM."+this.name+": "+a);},object2:function(a,b){if(a instanceof GLM.vec2)return[a.x,a.y,b].map(this._clamp);if(a instanceof GLM.uvec2||a instanceof GLM.ivec2||a instanceof GLM.bvec2)return[a.x,a.y,this._clamp(b)];throw new GLM.GLMJSError("unrecognized object passed to GLM."+
+this.name+"(o,z): "+[a,b]);}});
+GLM.vec4=GLM.$template.GLMType("vec4",{name:"fvec4",identity:[0,0,0,0],components:["xyzw","0123","rgba"],undefined0:function(){return this.identity},number1:function(a){return[a,a,a,a]},number2:function(a,b){return[a,b,b,b]},number3:function(a,b,c){return[a,b,c,c]},number4:function(a,b,c,e){return[a,b,c,e]},Error:GLM.GLMJSError,object1:function(a){if(a)switch(a.length){case 4:return[a[0],a[1],a[2],a[3]];case 3:return[a[0],a[1],a[2],a[2]];case 2:return[a[0],a[1],a[1],a[1]];default:if("w"in a&&"x"in
+a){if(typeof a.x!==typeof a.w)throw new this.Error("unrecognized .x-ish object passed to GLM.vec4: "+a);return"string"===typeof a.x?[1*a.x,1*a.y,1*a.z,1*a.w]:[a.x,a.y,a.z,a.w]}}throw new this.Error("unrecognized object passed to GLM.vec4: "+[a,a&&a.$type]);},$GLM:GLM,object2:function(a,b){if(a instanceof this.$GLM.vec3||a instanceof this.$GLM.uvec3||a instanceof this.$GLM.ivec3||a instanceof this.$GLM.bvec3)return[a.x,a.y,a.z,b];throw new this.$GLM.GLMJSError("unrecognized object passed to GLM.vec4(o,w): "+
+[a,b]);},object3:function(a,b,c){if(a instanceof this.$GLM.vec2||a instanceof this.$GLM.uvec2||a instanceof this.$GLM.ivec2||a instanceof this.$GLM.bvec2)return[a.x,a.y,b,c];throw new this.$GLM.GLMJSError("unrecognized object passed to GLM.vec4(o,z,w): "+[a,b,c]);}});
+GLM.uvec4=GLM.$template.GLMType("uvec4",{name:"uvec4",identity:[0,0,0,0],components:["xyzw","0123"],_clamp:GLM.uvec2.$._clamp,undefined0:function(){return this.identity},number1:function(a){a=this._clamp(a);return[a,a,a,a]},number2:function(a,b){a=this._clamp(a);b=this._clamp(b);return[a,b,b,b]},number3:function(a,b,c){a=this._clamp(a);b=this._clamp(b);c=this._clamp(c);return[a,b,c,c]},number4:function(a,b,c,e){return[a,b,c,e].map(this._clamp)},Error:GLM.GLMJSError,object1:function(a){if(a)switch(a.length){case 4:return[a[0],
+a[1],a[2],a[3]].map(this._clamp);case 3:return[a[0],a[1],a[2],a[2]].map(this._clamp);case 2:return[a[0],a[1],a[1],a[1]].map(this._clamp);default:if("w"in a&&"x"in a){if(typeof a.x!==typeof a.y)throw new this.Error("unrecognized .x-ish object passed to GLM."+this.name+": "+a);return[a.x,a.y,a.z,a.w].map(this._clamp)}}throw new GLM.GLMJSError("unrecognized object passed to GLM."+this.name+": "+[a,a&&a.$type]);},object2:function(a,b){if(a instanceof GLM.vec3)return[a.x,a.y,a.z,b].map(this._clamp);if(a instanceof
+GLM.uvec3||a instanceof GLM.ivec3||a instanceof GLM.bvec3)return[a.x,a.y,a.z,this._clamp(b)];throw new GLM.GLMJSError("unrecognized object passed to GLM."+this.name+"(o,w): "+[a,b]);},object3:function(a,b,c){if(a instanceof GLM.vec2)return[a.x,a.y,b,c].map(this._clamp);if(a instanceof GLM.uvec2||a instanceof GLM.ivec2||a instanceof GLM.bvec2)return[a.x,a.y,this._clamp(b),this._clamp(c)];throw new GLM.GLMJSError("unrecognized object passed to GLM."+this.name+"(o,z,w): "+[a,b,c]);}});
+GLM.ivec2=GLM.$template.GLMType("ivec2",GLM.$template.extend({},GLM.uvec2.$,{name:"ivec2"}));GLM.ivec3=GLM.$template.GLMType("ivec3",GLM.$template.extend({},GLM.uvec3.$,{name:"ivec3"}));GLM.ivec4=GLM.$template.GLMType("ivec4",GLM.$template.extend({},GLM.uvec4.$,{name:"ivec4"}));GLM.bvec2=GLM.$template.GLMType("bvec2",GLM.$template.extend({},GLM.uvec2.$,{name:"bvec2",boolean1:GLM.uvec2.$.number1,boolean2:GLM.uvec2.$.number2}));
+GLM.bvec3=GLM.$template.GLMType("bvec3",GLM.$template.extend({},GLM.uvec3.$,{name:"bvec3",boolean1:GLM.uvec3.$.number1,boolean2:GLM.uvec3.$.number2,boolean3:GLM.uvec3.$.number3}));GLM.bvec4=GLM.$template.GLMType("bvec4",GLM.$template.extend({},GLM.uvec4.$,{name:"bvec4",boolean1:GLM.uvec4.$.number1,boolean2:GLM.uvec4.$.number2,boolean3:GLM.uvec4.$.number3,boolean4:GLM.uvec4.$.number4}));GLM.bvec2.$._clamp=GLM.bvec3.$._clamp=GLM.bvec4.$._clamp=function(a){return!!a};
+GLM.mat3=GLM.$template.GLMType("mat3",{name:"mat3x3",identity:[1,0,0,0,1,0,0,0,1],undefined0:function(){return this.identity},number1:function(a){return 1===a?this.identity:[a,0,0,0,a,0,0,0,a]},number9:function(a,b,c,e,d,h,j,g,k){return arguments},Error:GLM.GLMJSError,$vec3:GLM.vec3,object1:function(a){if(a){var b=a.elements||a;if(16===b.length)return[b[0],b[1],b[2],b[4],b[5],b[6],b[8],b[9],b[10]];if(9===b.length)return b;if(0 in b&&1 in b&&2 in b&&!(3 in b)&&"object"===typeof b[2])return[b[0],b[1],
+b[2]].map(this.$vec3.$.object1).reduce(function(a,b){return a.concat(b)})}throw new this.Error("unrecognized object passed to GLM.mat3: "+a);},object3:function(a,b,c){return[a,b,c].map(glm.$to_array).reduce(function(a,b){return a.concat(b)})}});
+GLM.mat4=GLM.$template.GLMType("mat4",{name:"mat4x4",identity:[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],undefined0:function(){return this.identity},number16:function(a,b,c,e,d,h,j,g,k,i,w,r,m,q,s,t){return arguments},number1:function(a){return 1===a?this.identity:[a,0,0,0,0,a,0,0,0,0,a,0,0,0,0,a]},Error:GLM.GLMJSError,$vec4:GLM.vec4,object1:function(a){var b;if(a){b=a.elements||a;if(9===b.length)return[b[0],b[1],b[2],0,b[3],b[4],b[5],0,b[6],b[7],b[8],0,0,0,0,1];if(4===b.length&&b[0]&&4===b[0].length)return b[0].concat(b[1],
+b[2],b[3]);if(16===b.length)return b;if(0 in b&&1 in b&&2 in b&&3 in b&&!(4 in b)&&"object"===typeof b[3])return[b[0],b[1],b[2],b[3]].map(this.$vec4.$.object1).reduce(function(a,b){return a.concat(b)})}throw new this.Error("unrecognized object passed to GLM.mat4: "+[a,b&&b.length]);},object4:function(a,b,c,e){return[a,b,c,e].map(glm.$to_array).reduce(function(a,b){return a.concat(b)})}});
+GLM.quat=GLM.$template.GLMType("quat",{identity:[0,0,0,1],components:["xyzw","0123"],undefined0:function(){return this.identity},number1:function(a){if(1!==a)throw Error("only quat(1) syntax supported for quat(number1 args)...");return this.identity},number4:function(a,b,c,e){return[b,c,e,a]},$GLM:GLM,$M3:GLM.mat3(),$quat_array_from_zyx:function(a){var b=this.$M3;return this.$GLM.$outer.quat_angleAxis(a.z,b[2]).mul(this.$GLM.$outer.quat_angleAxis(a.y,b[1])).mul(this.$GLM.$outer.quat_angleAxis(a.x,
+b[0])).elements},object1:function(a){if(a){if(a instanceof this.$GLM.mat4)return this.$GLM.$outer.quat_array_from_mat4(a);if(4===a.length)return[a[0],a[1],a[2],a[3]];if(a instanceof this.$GLM.quat)return[a.x,a.y,a.z,a.w];if(a instanceof this.$GLM.vec3)return this.$quat_array_from_zyx(a);if("w"in a&&"x"in a)return"string"===typeof a.x?[1*a.x,1*a.y,1*a.z,1*a.w]:[a.x,a.y,a.z,a.w]}throw new this.$GLM.GLMJSError("unrecognized object passed to GLM.quat.object1: "+[a,a&&a.$type,typeof a,a&&a.constructor]);
+}});
+(function(){var a=function(a,b,c,e){var k={def:function(b,c){this[b]=c;Object.defineProperty(a.prototype,b,c)}};a.$properties=a.$properties||k;var i=a.$properties.def.bind(a.$properties),w=[0,1,2,3].map(function(a){return{enumerable:c,get:function(){return this.elements[a]},set:function(b){this.elements[a]=b}}});b.forEach(function(a,b){i(a,w[b])});if(isNaN(b[0])&&!/^_/.test(b[0])){var k=b.slice(),r=GLM.$subarray;do(function(a,b,c){"quat"===b&&(b="vec"+c);var d=GLM[b];i(a,{enumerable:!1,get:function(){return new d(r(this.elements,0*
+c,1*c))},set:function(a){return(new d(r(this.elements,0*c,1*c)))["="](a)}})})(k.join(""),a.prototype.$type.replace(/[1-9]$/,k.length),k.length);while(k[1]!=k.pop());if(e)return a.$properties;k=b.slice();if(b={xyz:{yz:1},xyzw:{yzw:1,yz:1,zw:2}}[k.join("")])for(var m in b)(function(a,b,c,d){i(a,{enumerable:!1,get:function(){return new GLM[b](GLM.$subarray(this.elements,0*c+d,1*c+d))},set:function(a){return(new GLM[b](GLM.$subarray(this.elements,0*c+d,1*c+d)))["="](a)}})})(m,a.prototype.$type.replace(/[1-9]$/,
+m.length),m.length,b[m])}return a.$properties};a(GLM.vec2,GLM.vec2.$.components[0],!0);a(GLM.vec2,GLM.vec2.$.components[1]);a(GLM.vec3,GLM.vec3.$.components[0],!0);a(GLM.vec3,GLM.vec3.$.components[1]);a(GLM.vec3,GLM.vec3.$.components[2]);a(GLM.vec4,GLM.vec4.$.components[0],!0);a(GLM.vec4,GLM.vec4.$.components[1]);a(GLM.vec4,GLM.vec4.$.components[2]);a(GLM.quat,GLM.quat.$.components[0],!0,"noswizzles");a(GLM.quat,GLM.quat.$.components[1]);GLM.quat.$properties.def("wxyz",{enumerable:!1,get:function(){return new GLM.vec4(this.w,
+this.x,this.y,this.z)},set:function(a){a=GLM.vec4(a);return this["="](GLM.quat(a.x,a.y,a.z,a.w))}});"uvec2 uvec3 uvec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4".split(" ").forEach(function(b){a(GLM[b],GLM[b].$.components[0],!0);a(GLM[b],GLM[b].$.components[1])});Object.defineProperty(GLM.quat.prototype,"_x",{get:function(){throw Error("erroneous quat._x access");}});var b={2:{yx:{enumerable:!1,get:function(){return new GLM.vec2(this.y,this.x)},set:function(a){a=GLM.vec2(a);this.y=a[0];this.x=a[1]}}},3:{xz:{enumerable:!1,
+get:function(){return new GLM.vec2(this.x,this.z)},set:function(a){a=GLM.vec2(a);this.x=a[0];this.z=a[1]}},zx:{enumerable:!1,get:function(){return new GLM.vec2(this.z,this.x)},set:function(a){a=GLM.vec2(a);this.z=a[0];this.x=a[1]}},xzy:{enumerable:!1,get:function(){return new GLM.vec3(this.x,this.z,this.y)},set:function(a){a=GLM.vec3(a);this.x=a[0];this.z=a[1];this.y=a[2]}}},4:{xw:{enumerable:!1,get:function(){return new GLM.vec2(this.x,this.w)},set:function(a){a=GLM.vec2(a);this.x=a[0];this.w=a[1]}},
+wz:{enumerable:!1,get:function(){return new GLM.vec2(this.w,this.z)},set:function(a){a=GLM.vec2(a);this.w=a[0];this.z=a[1]}},wxz:{enumerable:!1,get:function(){return new GLM.vec3(this.w,this.x,this.z)},set:function(a){a=GLM.vec3(a);this.w=a[0];this.x=a[1];this.z=a[2];return this}},xyw:{enumerable:!1,get:function(){return new GLM.vec3(this.x,this.y,this.w)},set:function(a){a=GLM.vec3(a);this.x=a[0];this.y=a[1];this.w=a[2];return this}},xzw:{enumerable:!1,get:function(){return new GLM.vec3(this.x,this.z,
+this.w)},set:function(a){a=GLM.vec3(a);this.x=a[0];this.z=a[1];this.w=a[2]}},wxyz:{enumerable:!1,get:function(){return new GLM.vec4(this.w,this.x,this.y,this.z)},set:function(a){a=GLM.vec4(a);this.w=a[0];this.x=a[1];this.y=a[2];this.z=a[3];return this}}}},c;for(c in b)for(var e in b[c])2>=c&&GLM.vec2.$properties.def(e,b[c][e]),3>=c&&GLM.vec3.$properties.def(e,b[c][e]),4>=c&&GLM.vec4.$properties.def(e,b[c][e]);GLM.$partition=function(a,b,c,e){if(void 0===c)throw new GLM.GLMJSError("nrows is undefined");
+var k=b.$.identity.length;c=c||k;for(var i=function(a){3<GLM.$DEBUG&&GLM.$outer.console.debug("CACHEDBG: "+a)},w=0;w<c;w++)(function(c){var j=e&&e+c,q=c*k;Object.defineProperty(a,c,{configurable:!0,enumerable:!0,set:function(e){if(e instanceof b)this.elements.set(e.elements,q);else if(e&&e.length===k)this.elements.set(e,q);else throw new GLM.GLMJSError("unsupported argtype to "+(a&&a.$type)+"["+c+"] setter: "+[typeof e,e]);},get:function(){if(e){if(this[j])return c||i("cache hit "+j),this[j];c||i("cache miss "+
+j)}var a,d=new b(a=GLM.$subarray(this.elements,q,q+k));if(d.elements!==a)throw new GLM.GLMJSError("v.elements !== t "+[GLM.$subarray,d.elements.constructor===a.constructor,d.elements.buffer===a.buffer]);e&&Object.defineProperty(this,j,{configurable:!0,enumerable:!1,value:d});return d}})})(w)};GLM.$partition(GLM.mat4.prototype,GLM.vec4,4,"_cache_");GLM.$partition(GLM.mat3.prototype,GLM.vec3,3,"_cache_")})();
+GLM.$dumpTypes=function(a){GLM.$types.forEach(function(b){GLM[b].componentLength&&a("GLM."+b,JSON.stringify({"#type":GLM[b].prototype.$type_name,"#floats":GLM[b].componentLength,"#bytes":GLM[b].BYTES_PER_ELEMENT}))})};
+GLM.$init=function(a){a.prefix&&(GLMJS_PREFIX=a.prefix);GLM.$prefix=GLMJS_PREFIX;var b=a.log||function(){};try{b("GLM-js: ENV: "+_ENV._VERSION)}catch(c){}b("GLM-JS: initializing: "+JSON.stringify(a,0,2));b(JSON.stringify({functions:Object.keys(GLM.$outer.functions)}));var e=GLM.mat4,d=GLM.$outer;GLM.toMat4=function(a){return new e(d.mat4_array_from_quat(a))};GLM.$template.extend(GLM.rotation.$template,{$quat:GLM.quat,$dot:GLM.dot.link("vec3,vec3"),$epsilon:GLM.epsilon(),$m:GLM.mat3(),$pi:GLM.pi(),
+$length2:GLM.length2.link("vec3"),$cross:GLM.cross.link("vec3,vec3"),$normalize:GLM.normalize.link("vec3"),$angleAxis:GLM.angleAxis.link("float,vec3"),$sqrt:GLM.sqrt});GLM.$symbols=[];for(var h in GLM)"function"===typeof GLM[h]&&/^[a-z]/.test(h)&&GLM.$symbols.push(h);GLM.$types.forEach(function(a){var b=GLM[a].prototype.$type,c;for(c in GLM.$outer.functions){var d=GLM.$outer.functions[c];d.$op&&(GLM.$DEBUG&&GLM.$outer.console.debug("mapping operator<"+b+"> "+c+" / "+d.$op),GLM[a].prototype[c]=d,GLM[a].prototype[d.$op]=
+d)}});b("GLM-JS: "+GLM.version+" emulating GLM_VERSION="+GLM.GLM_VERSION+" vendor_name="+a.vendor_name+" vendor_version="+a.vendor_version);glm.vendor=a};
+GLM.using_namespace=function(a){GLM.$DEBUG&&GLM.$outer.console.debug("GLM.using_namespace munges globals; it should probably not be used!");GLM.using_namespace.$tmp={ret:void 0,tpl:a,names:GLM.$symbols,saved:{},evals:[],restore:[],before:[],after:[]};eval(GLM.using_namespace.$tmp.names.map(function(a,c){return"GLM.using_namespace.$tmp.saved['"+a+"'] = GLM.using_namespace.$tmp.before["+c+"] = 'undefined' !== typeof "+a+";"}).join("\n"));GLM.$DEBUG&&console.warn("GLM.using_namespace before #globals: "+
+GLM.using_namespace.$tmp.before.length);GLM.using_namespace.$tmp.names.map(function(a){GLM.using_namespace.$tmp.restore.push(a+"=GLM.using_namespace.$tmp.saved['"+a+"'];"+("GLM.using_namespace.$tmp.saved['"+a+"']=undefined;delete GLM.using_namespace.$tmp.saved['"+a+"'];"));GLM.using_namespace.$tmp.evals.push(a+"=GLM."+a+";")});eval(GLM.using_namespace.$tmp.evals.join("\n"));GLM.using_namespace.$tmp.ret=a();eval(GLM.using_namespace.$tmp.restore.join("\n"));eval(GLM.using_namespace.$tmp.names.map(function(a,
+c){return"GLM.using_namespace.$tmp.after["+c+"] = 'undefined' !== typeof "+a+";"}).join("\n"));GLM.$DEBUG&&console.warn("GLM.using_namespace after #globals: "+GLM.using_namespace.$tmp.after.length);a=GLM.using_namespace.$tmp.ret;delete GLM.using_namespace.$tmp;return a};
+function $GLM_extern(a,b){b=b||a;return function(){GLM[b]=GLM.$outer.functions[a]||GLM.$outer[a];if(!GLM[b])throw new GLM.GLMJSError("$GLM_extern: unresolved external symbol: "+a);GLM.$DEBUG&&GLM.$outer.console.debug("$GLM_extern: resolved external symbol "+a+" "+typeof GLM[b]);return GLM[b].apply(this,arguments)}}
+function GLM_polyfills(){var a={};"bind"in Function.prototype||(a.bind=Function.prototype.bind=function(a){function c(){}if("function"!==typeof this)throw new TypeError("not callable");var e=[].slice,d=e.call(arguments,1),h=this,j=function(){return h.apply(this instanceof c?this:a||global,d.concat(e.call(arguments)))};c.prototype=this.prototype||c.prototype;j.prototype=new c;return j});return a}
+$GLM_reset_logging.current=function(){return{$GLM_log:"undefined"!==typeof $GLM_log&&$GLM_log,$GLM_console_log:"undefined"!==typeof $GLM_console_log&&$GLM_console_log,$GLM_console_prefixed:"undefined"!==typeof $GLM_console_prefixed&&$GLM_console_prefixed,console:GLM.$outer.console}};
+function $GLM_reset_logging(a){a&&"object"===typeof a&&($GLM_log=a.$GLM_log,$GLM_console_log=a.$GLM_console_log,$GLM_console_factory=a.$GLM_console_factory,GLM.$outer.console=a.console,a=!1);if(a||"undefined"===typeof $GLM_log)$GLM_log=function(a,b){GLM.$outer.console.log.apply(GLM.$outer.console,[].slice.call(arguments).map(function(a){var b=typeof a;return"xboolean"===b||"string"===b?a+"":GLM.$isGLMObject(a)||!isNaN(a)?GLM.to_string(a):a+""}))};if(a||"undefined"===typeof $GLM_console_log)$GLM_console_log=
+function(a,b){(console[a]||function(){}).apply(console,[].slice.call(arguments,1))};if(a||"undefined"===typeof $GLM_console_factory)$GLM_console_factory=function(a){return $GLM_console_log.bind($GLM_console_log,a)};var b=$GLM_console_factory,c={};"debug,warn,info,error,log,write".replace(/\w+/g,function(a){c[a]=b(a)});"object"===typeof GLM&&(GLM.$outer&&(GLM.$outer.console=c),GLM.$log=$GLM_log);return c}try{window.$GLM_reset_logging=this.$GLM_reset_logging=$GLM_reset_logging}catch(e$$19){}
+GLM.$reset_logging=$GLM_reset_logging;GLM.$log=GLM.$log||$GLM_log;function $GLM_GLMJSError(a,b){function c(c){this.name=a;this.stack=Error().stack;Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);this.message=c;b&&b.apply(this,arguments)}c.prototype=Error();c.prototype.name=a;return c.prototype.constructor=c}GLMAT.mat4.exists;glm=GLM;var DLL={_version:"0.0.2",_name:"glm.gl-matrix.js",_glm_version:glm.version,prefix:"glm-js[glMatrix]: ",vendor_version:GLMAT.VERSION,vendor_name:"glMatrix"};
+DLL.statics={$outer:GLM.$outer,$typeArray:function(a){return new this.$outer.Float32Array(a)},$mat4:GLM.mat4,$quat:GLM.quat,$mat4$perspective:GLMAT.mat4.perspective,$mat4$ortho:GLMAT.mat4.ortho,mat4_perspective:function(a,b,c,e){return new this.$mat4(this.$mat4$perspective(this.$typeArray(16),a,b,c,e))},mat4_ortho:function(a,b,c,e,d,h){return new this.$mat4(this.$mat4$ortho(this.$typeArray(16),a,b,c,e,d||-1,h||1))},$quat$setAxisAngle:GLMAT.quat.setAxisAngle,$mat4$fromQuat:GLMAT.mat4.fromQuat,mat4_angleAxis:function(a,
+b){var c=this.$quat$setAxisAngle(this.$typeArray(4),b,a);return new this.$mat4(this.$mat4$fromQuat(this.$typeArray(16),c))},quat_angleAxis:function(a,b){return new this.$quat(this.$quat$setAxisAngle(this.$typeArray(4),b,a))},$mat4$translate:GLMAT.mat4.translate,mat4_translation:function(a){var b=new this.$mat4;this.$mat4$translate(b.elements,b.elements,a.elements);return b},$mat4$scale:GLMAT.mat4.scale,mat4_scale:function(a){var b=new this.$mat4;this.$mat4$scale(b.elements,b.elements,a.elements);
+return b},toJSON:function(){var a={},b;for(b in this)0!==b.indexOf("$")&&(a[b]=this[b]);return a},$vec3:GLM.vec3,$clamp:GLM.clamp,mat4_array_from_quat:function(a){return this.$mat4$fromQuat(this.$typeArray(16),a.elements)},$qtmp:new GLM.$outer.Float32Array(9),$quat$fromMat3:GLMAT.quat.fromMat3,$mat3$fromMat4:GLMAT.mat3.fromMat4,quat_array_from_mat4:function(a){return this.$quat$fromMat3(this.$typeArray(4),this.$mat3$fromMat4(this.$qtmp,a.elements))}};
+DLL["declare<T,V,...>"]={mul:{$op:"*",$typeArray:function(a){return new this.GLM.$outer.Float32Array(a)},$vec3$transformQuat:GLMAT.vec3.transformQuat,"quat,vec3":function(a,b){return new this.GLM.vec3(this.$vec3$transformQuat(this.$typeArray(3),b.elements,a.elements))},"vec3,quat":function(a,b){return this["quat,vec3"](this.GLM.inverse(b),a)},"quat,vec4":function(a,b){return this["mat4,vec4"](this.GLM.toMat4(a),b)},"vec4,quat":function(a,b){return this["quat,vec4"](this.GLM.inverse(b),a)},"$vec<N>$scale":"GLMAT.vecN.scale",
+"vec<N>,float":function(a,b){return new this.GLM.vecN(this.$vecN$scale(this.$typeArray(N),a.elements,b))},"quat,float":function(a,b){return new a.constructor(this["vec4,float"](a,b).elements)},$vec4$transformMat4:GLMAT.vec4.transformMat4,"mat4,vec4":function(a,b){return new GLM.vec4(this.$vec4$transformMat4(this.$typeArray(4),b.elements,a.elements))},"vec4,mat4":function(a,b){return this["mat4,vec4"](GLM.inverse(b),a)},"$mat<N>mul":"GLMAT.matN.mul","mat<N>,mat<N>":function(a,b){return new a.constructor(this.$matNmul(this.$typeArray(N*
+N),a.elements,b.elements))},$quat$multiply:GLMAT.quat.multiply,"quat,quat":function(a,b){return new a.constructor(this.$quat$multiply(this.$typeArray(4),a.elements,b.elements))}},mul_eq:{$op:"*=","$mat<N>$multiply":"GLMAT.matN.multiply","mat<N>,mat<N>":function(a,b){this.$matN$multiply(a.elements,a.elements,b.elements);return a},"$vec<N>$scale":"GLMAT.vecN.scale","vec<N>,float":function(a,b){this.$vecN$scale(a.elements,a.elements,b);return a},$quat$multiply:GLMAT.quat.multiply,"quat,quat":function(a,
+b){this.$quat$multiply(a.elements,a.elements,b.elements);return a},$quat$invert:GLMAT.quat.invert,$vec3$transformQuat:GLMAT.vec3.transformQuat,"inplace:vec3,quat":function(a,b){var c=this.$quat$invert(new this.GLM.$outer.Float32Array(4),b.elements);this.$vec3$transformQuat(a.elements,a.elements,c);return a},$mat4$invert:GLMAT.mat4.invert,$vec4$transformMat4:GLMAT.vec4.transformMat4,"inplace:vec4,mat4":function(a,b){var c=this.$mat4$invert(new this.GLM.$outer.Float32Array(16),b.elements);this.$vec4$transformMat4(a.elements,
+a.elements,c);return a}},cross:{$vec2$cross:GLMAT.vec2.cross,"vec2,vec2":function(a,b){return new this.GLM.vec3(this.$vec2$cross(new this.GLM.$outer.Float32Array(3),a,b))},$vec3$cross:GLMAT.vec3.cross,"vec3,vec3":function(a,b){return new this.GLM.vec3(this.$vec3$cross(new this.GLM.$outer.Float32Array(3),a,b))}},dot:{"$vec<N>$dot":"GLMAT.vecN.dot","vec<N>,vec<N>":function(a,b){return this.$vecN$dot(a,b)}},lookAt:{$mat4$lookAt:GLMAT.mat4.lookAt,"vec3,vec3":function(a,b,c){return new this.GLM.mat4(this.$mat4$lookAt(new this.GLM.$outer.Float32Array(16),
+a.elements,b.elements,c.elements))}}};DLL["declare<T,V,number>"]={mix:{$quat$slerp:GLMAT.quat.slerp,"quat,quat":function(a,b,c){return new GLM.quat(this.$quat$slerp(new GLM.$outer.Float32Array(4),a.elements,b.elements,c))}}};DLL["declare<T,V,number>"].slerp=DLL["declare<T,V,number>"].mix;
+DLL["declare<T>"]={normalize:{"$vec<N>normalize":"GLMAT.vecN.normalize",$typeArray:function(a){return new this.GLM.$outer.Float32Array(a)},"vec<N>":function(a){return new this.GLM.vecN(this.$vecNnormalize(this.$typeArray(N),a))},$quat$normalize:GLMAT.quat.normalize,quat:function(a){return new this.GLM.quat(this.$quat$normalize(new this.GLM.$outer.Float32Array(4),a.elements))}},length:{$quat$length:GLMAT.quat.length,quat:function(a){return this.$quat$length(a.elements)},"$vec<N>$length":"GLMAT.vecN.length",
+"vec<N>":function(a){return this.$vecN$length(a.elements)}},length2:{$quat$squaredLength:GLMAT.quat.squaredLength,quat:function(a){return this.$quat$squaredLength(a.elements)},"$vec<N>$squaredLength":"GLMAT.vecN.squaredLength","vec<N>":function(a){return this.$vecN$squaredLength(a.elements)}},inverse:{$quatinvert:GLMAT.quat.invert,quat:function(a){return this.GLM.quat(this.$quatinvert(new this.GLM.$outer.Float32Array(4),a.elements))},$mat4invert:GLMAT.mat4.invert,mat4:function(a){a=a.clone();return null===
+this.$mat4invert(a.elements,a.elements)?a["="](this.GLM.mat4()):a}},transpose:{$mat4$transpose:GLMAT.mat4.transpose,mat4:function(a){a=a.clone();this.$mat4$transpose(a.elements,a.elements);return a}}};glm.$outer.$import(DLL);try{module.exports=glm}catch(e$$20){}
+function $GLMVector(a,b,c){this.typearray=c=c||GLM.$outer.Float32Array;if(!(this instanceof $GLMVector))throw new GLM.GLMJSError("use new");if("function"!==typeof a||!GLM.$isGLMConstructor(a))throw new GLM.GLMJSError("expecting typ to be GLM.$isGLMConstructor: "+[typeof a,a?a.$type:a]+" // "+GLM.$isGLMConstructor(a));if(1===a.componentLength&&GLM[a.prototype.$type.replace("$","$$v")])throw new GLM.GLMJSError("unsupported argtype to glm.$vectorType - for single-value types use glm."+a.prototype.$type.replace("$",
+"$$v")+"..."+a.prototype.$type);this.glmtype=a;if(!this.glmtype.componentLength)throw Error("need .componentLength "+[a,b,c]);this.componentLength=this.glmtype.componentLength;this.BYTES_PER_ELEMENT=this.glmtype.BYTES_PER_ELEMENT;this._set_$elements=function(a){Object.defineProperty(this,"$elements",{enumerable:!1,configurable:!0,value:a});return this.$elements};Object.defineProperty(this,"elements",{enumerable:!0,configurable:!0,get:function(){return this.$elements},set:function(a){this._kv&&!this._kv.dynamic&&
+GLM.$DEBUG&&GLM.$outer.console.warn("WARNING: setting .elements on frozen (non-dynamic) GLMVector...");if(a){var b=this.length;this.length=a.length/this.componentLength;this.byteLength=this.length*this.BYTES_PER_ELEMENT;if(this.length!==Math.round(this.length))throw new GLM.GLMJSError("$vectorType.length alignment mismatch "+JSON.stringify({componentLength:this.componentLength,length:this.length,rounded_length:Math.round(this.length),elements_length:a.length,old_length:b}));}else this.length=this.byteLength=
+0;return this._set_$elements(a)}});this.elements=b&&new c(b*a.componentLength)}GLM.$vectorType=$GLMVector;GLM.$vectorType.version="0.0.2";
+$GLMVector.prototype=GLM.$template.extend(new GLM.$GLMBaseType($GLMVector,"$vectorType"),{toString:function(){return"[$GLMVector .elements=#"+(this.elements&&this.elements.length)+" .elements[0]="+(this.elements&&this.elements[0])+" ->[0]"+(this["->"]&&this["->"][0])+"]"},"=":function(a){if(a instanceof this.constructor||glm.$isGLMObject(a))a=a.elements;return this._set(new this.typearray(a))},_typed_concat:function(a,b,c){var e=a.length+b.length;c=c||new a.constructor(e);c.set(a);c.set(b,a.length);
+return c},"+":function(a){if(a instanceof this.constructor||glm.$isGLMObject(a))a=a.elements;return new this.constructor(this._typed_concat(this.elements,a))},"+=":function(a){if(a instanceof this.constructor||glm.$isGLMObject(a))a=a.elements;return this._set(this._typed_concat(this.elements,a))},_set:function(a){a instanceof this.constructor&&(a=new this.typearray(a.elements));if(!(a instanceof this.typearray))throw new GLM.GLMJSError("unsupported argtype to $GLMVector._set "+(a&&a.constructor));
+GLM.$DEBUG&&GLM.$outer.console.debug("$GLMVector.prototype.set...this.elements:"+[this.elements&&this.elements.constructor.name,this.elements&&this.elements.length]+"elements:"+[a.constructor.name,a.length]);var b=this._kv;this._kv=void 0;this.elements=a;if(this.elements!==a)throw new GLM.GLMJSError("err with .elements: "+[this.glmtype.prototype.$type,this.elements,a]);b&&this._setup(b);return this},arrayize:function(a,b){return this._setup({dynamic:b,setters:a},this.length)},$destroy:function(a){if(a){for(var b=
+Array.isArray(a),c=function(c){Object.defineProperty(a,c,{enumerable:!0,configurable:!0,value:void 0});delete a[c];b||(a[c]=void 0,delete a[c])},e=0;e<a.length;e++)e in a&&c(e);for(;e in a;)GLM.$DEBUG&&GLM.$outer.console.debug("$destroy",this.name,e),c(e++);b&&(a.length=0)}},_arrlike_toJSON:function(){return this.slice(0)},_mixinArray:function(a){a.toJSON=this._arrlike_toJSON;"forEach map slice filter join reduce".split(" ").forEach(function(b){a[b]=Array.prototype[b]});return a},_setup:function(a,
+b){var c=this.glmtype,e=this.typearray,d=this.length;this._kv=a;var h=a.stride||this.glmtype.BYTES_PER_ELEMENT,j=a.offset||this.elements.byteOffset,g=a.elements||this.elements,k=a.container||this.arr||[],i=a.setters||!1,w=a.dynamic||!1;"self"===k&&(k=this);if(!g)throw new GLMJSError("GLMVector._setup - neither kv.elements nor this.elements...");this.$destroy(this.arr,b);var r=this.arr=this["->"]=k;Array.isArray(r)||this._mixinArray(r);var m=this.componentLength;if(!m)throw new GLM.GLMJSError("no componentLength!?"+
+Object.keys(this));for(var q=g.buffer.byteLength,s=this,t=0;t<d;t++){var k=j+t*h,z=k+this.glmtype.BYTES_PER_ELEMENT,y=function(){a.i=t;a.next=z;a.last=q;a.offset=a.offset||j;a.stride=a.stride||h;return JSON.stringify(a)};if(k>q)throw Error("["+t+"] off "+k+" > last "+q+" "+y());if(z>q)throw Error("["+t+"] next "+z+" > last "+q+" "+y());r[t]=null;var f=function(a,b){var d=new c(new e(a.buffer,b,m));w&&Object.defineProperty(d,"$elements",{value:a});return d},y=f(g,k);!i&&!w?r[t]=y:function(a,b,c){Object.defineProperty(r,
+b,{enumerable:!0,configurable:!0,get:w?function(){a.$elements!==s.elements&&(GLM.$log("dynoget rebinding ti",b,c,a.$elements===s.elements),a=f(s.elements,c));return a}:function(){return a},set:i&&(w?function(d){GLM.$log("dynoset",b,c,a.$elements===s.elements);a.$elements!==s.elements&&(GLM.$log("dynoset rebinding ti",b,c,a.$elements===s.elements),a=f(s.elements,c));return a.copy(d)}:function(b){return a.copy(b)})||void 0})}(y,t,k)}return this},setFromBuffers:function(a){var b=this.elements,c=0;a.forEach(function(a){var d=
+a.length;if(c+d>b.length){d=Math.min(b.length-c,a.length);if(0>=d)return;a=glm.$subarray(a,0,d);d=a.length}if(c+d>b.length)throw new glm.GLMJSError("$vectorType.fromBuffers mismatch "+[c,d,b.length]);b.set(a,c);c+=a.length});return c},setFromPointer:function(a){if(!(a instanceof GLM.$outer.ArrayBuffer))throw new glm.GLMJSError("unsupported argtype "+[typeof a]+" - $GLMVector.setFromPointer");return this._set(new this.typearray(a))}});GLM.exists;GLM.$vectorType.exists;
+if(GLM.$toTypedArray)throw"error: glm.experimental.js double-included";
+GLM.$toTypedArray=function(a,b,c){var e=b||0,d=typeof e;if("number"===d){if("number"!==typeof c)throw new GLM.GLMJSError("GLM.$toTypedArray: unsupported argtype for componentLength ("+typeof c+")");return new a(e*c)}if("object"!==d)throw new GLM.GLMJSError("GLM.$toTypedArray: unsupported arrayType: "+[typeof a,a]);if(e instanceof a)return e;if(e instanceof GLM.$outer.ArrayBuffer||Array.isArray(e))return new a(e);GLM.$isGLMObject(e)&&(d=e.elements,e=new a(d.length),e.set(d));if(!(e instanceof a)&&
+"byteOffset"in e&&"buffer"in e)return GLM.$DEBUG&&GLM.$outer.console.warn("coercing "+e.constructor.name+".buffer into "+[a.name,e.byteOffset,e.byteLength+" bytes","~"+e.byteLength/a.BYTES_PER_ELEMENT+" coerced elements"]+"...",{byteOffset:e.byteOffset,byteLength:e.byteLength,ecount:e.byteLength/a.BYTES_PER_ELEMENT}),new a(e.buffer,e.byteOffset,e.byteLength/a.BYTES_PER_ELEMENT);if(e instanceof a)return e;throw new GLM.GLMJSError("GLM.$toTypedArray: unsupported argtype initializers: "+[a,b,c]);};
+GLM.$make_primitive=function(a,b){GLM[a]=function(c){if(!(this instanceof GLM[a]))return new GLM[a](c);"object"!==typeof c&&(c=[c]);this.elements=GLM.$toTypedArray(b,c,1)};GLM[a]=eval(GLM.$template._traceable("glm_"+a+"$class",GLM[a]))();GLM.$template._add_overrides(a,{$to_string:function(a){return a.$type.replace(/[^a-z]/g,"")+"("+a.elements[0]+")"},$to_object:function(a){return a.elements[0]},$to_glsl:function(a){return a.$type.replace(/[^a-z]/g,"")+"("+a.elements[0]+")"}});GLM.$template._add_overrides(a.substr(1),
+{$to_string:!(a.substr(1)in GLM.$to_string.$template)&&function(a){return a.$type.replace(/[^a-z]/g,"")+"("+a.elements[0]+")"},$to_object:function(a){return a},$to_glsl:function(a){return a.$type.replace(/[^a-z]/g,"")+"("+a+")"}});GLM.$template.extend(GLM[a],{componentLength:1,BYTES_PER_ELEMENT:b.BYTES_PER_ELEMENT,prototype:GLM.$template.extend(new GLM.$GLMBaseType(GLM[a],a),{copy:function(a){this.elements.set(GLM.$isGLMObject(a)?a.elements:[a]);return this},valueOf:function(){return this.elements[0]}})});
+GLM[a].prototype["="]=GLM[a].prototype.copy;return GLM[a]};GLM.$make_primitive("$bool",GLM.$outer.Int32Array);GLM.$template._add_overrides("$bool",{$to_object:function(a){return!!a}});GLM.$make_primitive("$int32",GLM.$outer.Int32Array);GLM.$make_primitive("$uint32",GLM.$outer.Uint32Array);GLM.$make_primitive("$uint16",GLM.$outer.Uint16Array);GLM.$make_primitive("$uint8",GLM.$outer.Uint8Array);GLM.$float32=GLM.$make_primitive("$float",GLM.$outer.Float32Array);
+GLM.$make_primitive_vector=function(a,b,c){c=c||(new b).elements.constructor;var e=function(d){if(!(this instanceof e))return new e(d);this.$type=a;this.$type_name="vector<"+a+">";(d=GLM.$toTypedArray(c,d,b.componentLength))&&this._set(d)},e=eval(GLM.$template._traceable("glm_"+a+"$class",e))();e.prototype=new GLM.$vectorType(b,0,c);GLM.$template._add_overrides(a,{$to_string:function(a){return"[GLM."+a.$type+" elements[0]="+(a.elements&&a.elements[0])+"]"},$to_object:function(a){return a.map(GLM.$to_object)},
+$to_glsl:function(a,b){var c=a.$type.substr(2).replace(/[^a-z]/g,"");b="string"===typeof b?b:"example";var e=[];b&&e.push(c+" "+b+"["+a.length+"]");return e.concat(a.map(function(a,c){return b+"["+c+"] = "+a})).join(";")+";"}});GLM.$types.push(a);GLM.$template.extend(e.prototype,{$type:a,constructor:e,_setup:function(){throw new GLM.GLMJSError("._setup not available on primitive vectors yet...");},_set:function(a){this.elements=a;this.length=!this.elements?0:this.elements.length/this.glmtype.componentLength;
+this.arrayize();return this},arrayize:function(){for(var a=Object.defineProperty.bind(Object,this),b=0;b<this.length;b++)(function(b){a(b,{configurable:!0,enumerable:!0,get:function(){return this.elements[b]},set:function(a){return this.elements[b]=a}})})(b);return this._mixinArray(this)},toString:function(){return"[vector<"+a+"> {"+[].slice.call(this.elements,0,5)+(5<this.elements.length?",...":"")+"}]"}});return e};GLM.$vint32=GLM.$make_primitive_vector("$vint32",GLM.$int32);
+GLM.$vfloat=GLM.$vfloat32=GLM.$make_primitive_vector("$vfloat32",GLM.$float32);GLM.$vuint8=GLM.$make_primitive_vector("$vuint8",GLM.$uint8);GLM.$vuint16=GLM.$make_primitive_vector("$vuint16",GLM.$uint16);GLM.$vuint32=GLM.$make_primitive_vector("$vuint32",GLM.$uint32);
+GLM.$make_componentized_vector=function(a,b,c){c=c||(new b).elements.constructor;var e=function(a,h){if(!(this instanceof e))return new e(a,h);this._set(GLM.$toTypedArray(c,a,b.componentLength));if(!this.elements)throw new GLM.GLMJSError("!this.elements: "+[GLM.$toTypedArray(c,a,b.componentLength)]);this._setup({setters:!0,dynamic:h,container:"self"})},e=eval(GLM.$template._traceable("glm_"+a+"$class",e))();e.prototype=new GLM.$vectorType(b,0,c);GLM.$template._add_overrides(a,{$to_string:function(a){return"[GLM."+
+a.$type+" elements[0]="+(a.elements&&a.elements[0])+"]"},$to_object:function(a){return a.map(GLM.$to_object)},$to_glsl:function(a,b){var c=a.$type.substr(2);b="string"===typeof b?b:"example";var e=[];b&&e.push(c+" "+b+"["+a.length+"]");return e.concat(a.map(GLM.$to_glsl).map(function(a,c){return b+"["+c+"] = "+a})).join(";\n ")+";"}});GLM.$types.push(a);GLM.$template.extend(e.prototype,{$type:a,constructor:e});e.prototype.componentLength||alert("!cmop "+p);return e};
+(function(){var a=GLM.$template.deNify({"$vvec<N>":function(){return GLM.$make_componentized_vector("$vvecN",GLM.vecN)},"$vuvec<N>":function(){return GLM.$make_componentized_vector("$vuvecN",GLM.uvecN)},"$vmat<N>":function(){return GLM.$make_componentized_vector("$vmatN",GLM.matN)},$vquat:function(){return GLM.$make_componentized_vector("$vquat",GLM.quat)}},"$v"),b;for(b in a)GLM[b]=a[b]()})();
+(GLM._redefine_base64_helpers=function define_base64_helpers(b,c){function e(b){return(b+"").replace(/\s/g,"")}function d(b){return new k(b.split("").map(function(b){return b.charCodeAt(0)}))}function h(b){b instanceof k||(b=new k(b));return[].map.call(b,function(b){return String.fromCharCode(b)}).join("")}function j(b){b=b instanceof i?b:d(b).buffer;return GLM.$b64.encode(b,b.byteOffset,b.byteLength)}function g(b){b=new String(h(GLM.$b64.decode(b)));b.array=d(b);b.buffer=b.array.buffer;return b}
+b=define_base64_helpers.atob=b||define_base64_helpers.atob||g;c=define_base64_helpers.btoa=c||define_base64_helpers.btoa||j;var k=GLM.$outer.Uint8Array,i=GLM.$outer.ArrayBuffer,w,r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf.bind("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");w={encode:function(b,c,d){b=new k(b,c,d);d=b.length;var e="";for(c=0;c<d;c+=3)e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[b[c]>>2],e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(b[c]&
+3)<<4|b[c+1]>>4],e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(b[c+1]&15)<<2|b[c+2]>>6],e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[b[c+2]&63];2===d%3?e=e.substring(0,e.length-1)+"=":1===d%3&&(e=e.substring(0,e.length-2)+"==");return e},decode:function(b){b=e(b);var c=b.length,d=0.75*c,g=0,h,j,f,v;"="===b[c-1]&&(d--,"="===b[c-2]&&d--);for(var w=new i(d),R=new k(w),d=0;d<c;d+=4)h=r(b[d]),j=r(b[d+1]),f=r(b[d+2]),v=r(b[d+3]),R[g++]=h<<2|j>>4,R[g++]=
+(j&15)<<4|f>>2,R[g++]=(f&3)<<6|v&63;return w}};GLM.$template.extend(w,{trim:e,atob:b,btoa:c,$atob:g,$btoa:j,toCharCodes:d,fromCharCodes:h,b64_to_utf8:function(c){return decodeURIComponent(escape(b(e(c))))},utf8_to_b64:function(b){return c(unescape(encodeURIComponent(b)))}});GLM.$template.extend(GLM,{$b64:w,$to_base64:function(b){return GLM.$b64.encode(b.elements.buffer,b.elements.byteOffset,b.elements.byteLength)},$from_base64:function(b,c){var d=GLM.$b64.decode(b);if(!0===c||c==GLM.$outer.ArrayBuffer)return d;
+void 0===c&&(c=GLM.$outer.Float32Array);return new c(d);throw new GLM.GLMJSError("TODO: $from_base64 not yet supported second argument type: ("+[typeof c,c]+")");}})})("function"===typeof atob&&atob.bind(this),"function"===typeof btoa&&btoa.bind(this));
+(function(){function a(a,c){return{get:function(){return a.call(this)},set:function(a){if(this.copy)return this.copy(new this.constructor(c.call(this,a)));this.elements.set(c.call(this,a))}}}"$bool $float32 $vfloat32 $vuint8 $vuint16 $vuint32 $vvec2 $vvec3 $vvec4 $vmat3 $vmat4 $vquat vec2 vec3 vec4 mat3 mat4 uvec2 uvec3 uvec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 quat".split(" ").map(GLM.$getGLMType).forEach(function(b){Object.defineProperty(b.prototype,"array",a(function(){return GLM.$to_array(this)},
+function(a){return a}));Object.defineProperty(b.prototype,"base64",a(function(){return GLM.$to_base64(this)},function(a){return GLM.$from_base64(a,this.elements.constructor)}));Object.defineProperty(b.prototype,"buffer",a(function(){return this.elements.buffer},function(a){return new this.elements.constructor(a)}));Object.defineProperty(b.prototype,"json",a(function(){return GLM.$to_json(this)},function(a){return JSON.parse(a)}));Object.defineProperty(b.prototype,"object",a(function(){return GLM.$to_object(this)},
+function(a){return a}));Object.defineProperty(b.prototype,"glsl",a(function(){return GLM.$to_glsl(this)},function(a){return GLM.$from_glsl(a,Array)}))})})();
+glm.GLMAT = GLMAT; globals.glm = glm; try { module.exports = glm; } catch(e) { }; try { window.glm = glm; } catch(e) {} ; try { declare.amd && declare(function() { return glm; }); } catch(e) {}; return this.glm = glm; })(this, typeof $GLM_log !== "undefined" ? $GLM_log : undefined, typeof $GLM_console_log !== "undefined" ? $GLM_console_log : undefined);
diff --git a/basic_course/msaa/.gitkeep b/basic_course/msaa/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/basic_course/msaa/hello.js b/basic_course/msaa/hello.js
new file mode 100644
index 0000000000000000000000000000000000000000..53c0ef1a6481b17b9a02b3855b5899c71f44aacd
--- /dev/null
+++ b/basic_course/msaa/hello.js
@@ -0,0 +1,175 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    /* gl.getError returns the last error that occurred using WebGL for debugging */ 
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl", {antialias: true, depth: true, stencil: false, premultipliedAlpha : true}) 
+			|| canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+		gl.enable(gl.SAMPLE_COVERAGE); 
+		// gl.enable(gl.SAMPLE_ALPHA_TO_COVERAGE); 
+		gl.sampleCoverage(0.5, false);
+		// console.log(gl.isEnabled(gl.SAMPLE_COVERAGE)); 
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+function initialiseBuffer() {
+
+    var vertexData = [
+        -0.4, -0.4, 0.0, // Bottom left
+         0.4, -0.4, 0.0, // Bottom right
+         0.0, 0.4, 0.0  // Top middle
+    ];
+
+    // Generate a buffer object
+    gl.vertexBuffer = gl.createBuffer();
+    // Bind buffer as a vertex buffer so we can fill it with data
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    /* Set the buffer's size, data and usage */
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			void main(void) \
+			{ \
+				gl_FragColor = vec4(1.0, 1.0, 0.66, 1.0); \
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			uniform mediump mat4 transformationMatrix; \
+			void main(void)  \
+			{ \
+				gl_Position = transformationMatrix * myVertex; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+
+    return testGLError("initialiseShaders");
+}
+
+function renderScene() {
+
+    gl.clearColor(0.6, 0.8, 1.0, 1.0);
+
+    gl.clear(gl.COLOR_BUFFER_BIT);
+
+    var matrixLocation = gl.getUniformLocation(gl.programObject, "transformationMatrix");
+    var transformationMatrix = [
+        1.0, 0.0, 0.0, 0.0,
+        0.0, 1.0, 0.0, 0.0,
+        0.0, 0.0, 1.0, 0.0,
+        0.0, 0.0, 0.0, 1.0
+    ];
+
+    gl.uniformMatrix4fv(matrixLocation, gl.FALSE, transformationMatrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+    // Enable the user-defined vertex array
+    gl.enableVertexAttribArray(0);
+    // Set the vertex data to this attribute index, with the number of floats in each position
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 0, 0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+    gl.drawArrays(gl.TRIANGLES, 0, 3);
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/msaa/hello.png b/basic_course/msaa/hello.png
new file mode 100644
index 0000000000000000000000000000000000000000..ef7e045751bcb0cd4dd90555bbc3304b101d898f
Binary files /dev/null and b/basic_course/msaa/hello.png differ
diff --git a/basic_course/msaa/index.html b/basic_course/msaa/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..1ac38e16ff83abddd37c3371f6f8a698dce7bbe9
--- /dev/null
+++ b/basic_course/msaa/index.html
@@ -0,0 +1,17 @@
+<html>
+
+<head>
+<title>WebGLHelloAPI</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+
+<script type="text/javascript" src="hello.js">
+</script>
+
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+</body>
+
+</html>
diff --git a/basic_course/quaternion/.gitkeep b/basic_course/quaternion/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/basic_course/quaternion/gl-matrix.js b/basic_course/quaternion/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..4553f9ea44878e9b79894c1de08af95ea9814317
--- /dev/null
+++ b/basic_course/quaternion/gl-matrix.js
@@ -0,0 +1,7611 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.3.0
+
+Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, (function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Float32ArrayConstructor | ArrayConstructor} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {ReadonlyMat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return "mat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {ReadonlyMat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {ReadonlyMat2} L the lower triangular matrix
+   * @param {ReadonlyMat2} D the diagonal matrix
+   * @param {ReadonlyMat2} U the upper triangular matrix
+   * @param {ReadonlyMat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, b,
+   *  c, d,
+   *  tx, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, b, 0,
+   *  c, d, 0,
+   *  tx, ty, 1]
+   * </pre>
+   * The last column is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {ReadonlyMat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return "mat2d(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {ReadonlyMat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to translate
+   * @param {ReadonlyVec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 matrix from the given quaternion
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyMat4} a Mat4 to derive the normal matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {ReadonlyMat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return "mat3(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {ReadonlyMat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {ReadonlyVec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Rotates a mat4 by the given angle around the given axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {ReadonlyQuat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @param {ReadonlyVec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {ReadonlyMat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {ReadonlyMat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
+    r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
+    r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {ReadonlyVec3} a The first operand
+   * @param {ReadonlyVec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        bx = b[0],
+        by = b[1],
+        bz = b[2],
+        mag1 = Math.sqrt(ax * ax + ay * ay + az * az),
+        mag2 = Math.sqrt(bx * bx + by * by + bz * bz),
+        mag = mag1 * mag2,
+        cosine = mag && dot(a, b) / mag;
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {ReadonlyVec4} result the receiving vector
+   * @param {ReadonlyVec4} U the first vector
+   * @param {ReadonlyVec4} V the second vector
+   * @param {ReadonlyVec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return "vec4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyVec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {ReadonlyQuat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Gets the angular distance between two unit quaternions
+   *
+   * @param  {ReadonlyQuat} a     Origin unit quaternion
+   * @param  {ReadonlyQuat} b     Destination unit quaternion
+   * @return {Number}     Angle, in radians, between the two quaternions
+   */
+
+  function getAngle(a, b) {
+    var dotproduct = dot$2(a, b);
+    return Math.acos(2 * dotproduct * dotproduct - 1);
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Calculate the exponential of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function exp(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var et = Math.exp(w);
+    var s = r > 0 ? et * Math.sin(r) / r : 0;
+    out[0] = x * s;
+    out[1] = y * s;
+    out[2] = z * s;
+    out[3] = et * Math.cos(r);
+    return out;
+  }
+  /**
+   * Calculate the natural logarithm of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function ln(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var t = r > 0 ? Math.atan2(r, w) / r : 0;
+    out[0] = x * t;
+    out[1] = y * t;
+    out[2] = z * t;
+    out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w);
+    return out;
+  }
+  /**
+   * Calculate the scalar power of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @param {Number} b amount to scale the quaternion by
+   * @returns {quat} out
+   */
+
+  function pow(out, a, b) {
+    ln(out, a);
+    scale$6(out, out, b);
+    exp(out, out);
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random unit quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyMat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {ReadonlyQuat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return "quat(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {ReadonlyQuat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat} a The first quaternion.
+   * @param {ReadonlyQuat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat} a The first vector.
+   * @param {ReadonlyQuat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {ReadonlyVec3} a the initial vector
+   * @param {ReadonlyVec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {ReadonlyQuat} c the third operand
+   * @param {ReadonlyQuat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {ReadonlyVec3} view  the vector representing the viewing direction
+   * @param {ReadonlyVec3} right the vector representing the local "right" direction
+   * @param {ReadonlyVec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    getAngle: getAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    exp: exp,
+    ln: ln,
+    pow: pow,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q a normalized quaternion
+   * @param {ReadonlyVec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyVec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {ReadonlyMat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {ReadonlyQuat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return "quat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ")";
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat2} a the first dual quaternion.
+   * @param {ReadonlyQuat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat2} a the first dual quat.
+   * @param {ReadonlyQuat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {ReadonlyVec2} a The vec2 point to rotate
+   * @param {ReadonlyVec2} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, rad) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(rad),
+        cosC = Math.cos(rad); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {ReadonlyVec2} a The first operand
+   * @param {ReadonlyVec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1],
+        // mag is the product of the magnitudes of a and b
+    mag = Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2),
+        // mag &&.. short circuits if mag == 0
+    cosine = mag && (x1 * x2 + y1 * y2) / mag; // Math.min(Math.max(cosine, -1), 1) clamps the cosine between -1 and 1
+
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return "vec2(" + a[0] + ", " + a[1] + ")";
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/basic_course/quaternion/hello.js b/basic_course/quaternion/hello.js
new file mode 100644
index 0000000000000000000000000000000000000000..7c9098a2420f32c71e6388013c388f6da81b8238
--- /dev/null
+++ b/basic_course/quaternion/hello.js
@@ -0,0 +1,296 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+var vertexData = [
+		// Backface (RED/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 1.0, 1.0, 
+		// Front (BLUE/WHITE) -> z = 0.5
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// LEFT (GREEN/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0, 
+		// RIGHT (YELLOE/WHITE) -> z = 0.5
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// BOTTON (MAGENTA/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// TOP (CYAN/WHITE) -> z = 0.5
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0 
+];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color;\
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 mMat; \
+			uniform mediump mat4 vMat; \
+			uniform mediump mat4 pMat; \
+			varying  highp vec4 color;\
+			void main(void)  \
+			{ \
+				gl_Position = pMat * vMat * mMat * myVertex; \
+				gl_PointSize = 8.0; \
+				color = myColor; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    // console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+flag_animation = 0; 
+function toggleAnimation()
+{
+	flag_animation ^= 1; 
+}
+
+var mMat = [1.0, 0.0, 0.0, 0.0, 
+			0.0, 1.0, 0.0, 0.0, 
+			0.0, 0.0, 1.0, 0.0, 
+			0.0, 0.0, 0.0, 1.0]; 
+rotX = 0.0;
+rotY = 0.0;
+xAxis = [1.0, 0.0, 0.0];
+yAxis = [0.0, 1.0, 0.0];
+
+
+// q = quat.create(); // q = [ 0.0, 0.0, 0.0, 1.0]; 
+// q = [0.26, 0.0, 0.0, 0.97];
+
+dragging = false; 
+
+function renderScene() {
+
+	var prevx,prevy;
+	function doMouseDown(evt) {
+		if (dragging)
+           return;
+		dragging = true;
+        document.addEventListener("mousemove", doMouseDrag, false);
+        document.addEventListener("mouseup", doMouseUp, false);
+        var box = canvas.getBoundingClientRect();
+        prevx = window.pageXOffset + evt.clientX - box.left;
+        prevy = window.pageYOffset + evt.clientY - box.top;
+	}
+	function doMouseDrag(evt) {
+        if (!dragging)
+           return;
+		console.log("Here");
+        var box = canvas.getBoundingClientRect();
+        var x = window.pageXOffset + evt.clientX - box.left;
+        var y = window.pageYOffset + evt.clientY - box.top;
+		console.log(x,y, prevx, prevy); 
+		rotY = (x-prevx)/100.0; 
+		rotX = (y-prevy)/100.0;
+
+		// vec3.transformMat4(xAxis, xAxis, mMat); 
+		// vec3.transformMat4(yAxis, yAxis, mMat); 
+		console.log(yAxis, xAxis);
+		mat4.rotate(mMat, mMat, rotY, yAxis); 
+		mat4.rotate(mMat, mMat, rotX, xAxis); 
+
+        prevx = x;
+        prevy = y;
+	}
+	function doMouseUp(evt) {
+		 if (dragging) {
+            document.removeEventListener("mousemove", doMouseDrag, false);
+            document.removeEventListener("mouseup", doMouseUp, false);
+		 }
+		dragging = false; 
+	}
+
+    var canvas = document.getElementById("helloapicanvas");
+	canvas.addEventListener("mousedown", doMouseDown, false);
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+	gl.clearDepth(1.0);										// Added for depth Test 
+
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);	// Added for depth Test 
+	gl.enable(gl.DEPTH_TEST);								// Added for depth Test 
+
+    var mMatLocation = gl.getUniformLocation(gl.programObject, "mMat");
+    var vMatLocation = gl.getUniformLocation(gl.programObject, "vMat");
+    var pMatLocation = gl.getUniformLocation(gl.programObject, "pMat");
+	var q = [];
+	console.log(rotX, rotY); 
+
+	if ( flag_animation ){
+		rotY += 0.01;
+	}
+	var vMat = [];
+	mat4.lookAt(vMat, [0.0, 0.0, 2.0], [0.0,0.0,0.0], [0.0, 1.0, 0.0]);
+	var pMat = [];
+	mat4.identity(pMat); 
+	mat4.perspective(pMat, 3.14/2.0, 800.0/600.0, 0.5, 5);
+	// console.log("pMAT:", pMat);
+
+    gl.uniformMatrix4fv(mMatLocation, gl.FALSE, mMat );
+    gl.uniformMatrix4fv(vMatLocation, gl.FALSE, vMat );
+    gl.uniformMatrix4fv(pMatLocation, gl.FALSE, pMat );
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+	//vertexData[0] += 0.01; 
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    //gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
+	//gl.vertexAttrib4f(1, 1.0, 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+	// gl.drawArrays(gl.LINE_STRIP, 0, 36); 
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+	// renderScene();
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/quaternion/hws/cube-with-rotator.html b/basic_course/quaternion/hws/cube-with-rotator.html
new file mode 100644
index 0000000000000000000000000000000000000000..bc88e0801777287d5cd8c14bb71d3b277b39b08a
--- /dev/null
+++ b/basic_course/quaternion/hws/cube-with-rotator.html
@@ -0,0 +1,242 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<html>
+<head>
+<title>WebGL Cube with Mouse Rotation</title>
+
+<script type="x-shader/x-vertex" id="vshader">
+     attribute vec3 coords;
+     uniform mat4 modelview;
+     uniform mat4 projection;
+     uniform bool lit;
+     uniform vec3 normal;
+     uniform mat3 normalMatrix;
+     uniform vec4 color;
+     varying vec4 vColor;
+     void main() {
+        vec4 coords = vec4(coords,1.0);
+        vec4 transformedVertex = modelview * coords;
+        gl_Position = projection * transformedVertex;
+        if (lit) {
+           vec3 unitNormal = normalize(normalMatrix*normal);
+           float multiplier = abs(unitNormal.z);
+           vColor = vec4( multiplier*color.r, multiplier*color.g, multiplier*color.b, color.a );
+        }
+        else {
+            vColor = color;
+        }
+     }
+</script>
+<script type="x-shader/x-fragment" id="fshader">
+     precision mediump float;
+     varying vec4 vColor;
+     void main() {
+         gl_FragColor = vColor;
+     }
+</script>
+
+
+<script type="text/javascript" src="gl-matrix-min.js"></script>
+<script type="text/javascript" src="simple-rotator.js"></script>
+<script type="text/javascript">
+
+"use strict";
+
+var gl;   // The webgl context.
+
+var aCoords;           // Location of the coords attribute variable in the shader program.
+var aCoordsBuffer;     // Buffer to hold coords.
+var uColor;            // Location of the color uniform variable in the shader program.
+var uProjection;       // Location of the projection uniform matrix in the shader program.
+var uModelview;        // Location of the modelview unifirm matrix in the shader program.
+var uNormal;           // Location of the normal uniform in the shader program.
+var uLit;              // Location of the lit uniform in the shader program.
+var uNormalMatrix;     // Location of the normalMatrix uniform matrix in the shader program.
+
+var projection = mat4.create();   // projection matrix
+var modelview = mat4.create();    // modelview matrix
+var normalMatrix = mat3.create(); // matrix, derived from modelview matrix, for transforming normal vectors
+
+var rotator;   // A SimpleRotator object to enable rotation by mouse dragging.
+
+/* Draws a WebGL primitive.  The first parameter must be one of the constants
+ * that specifiy primitives:  gl.POINTS, gl.LINES, gl.LINE_LOOP, gl.LINE_STRIP,
+ * gl.TRIANGLES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN.  The second parameter must
+ * be an array of 4 numbers in the range 0.0 to 1.0, giving the RGBA color of
+ * the color of the primitive.  The third parameter must be an array of numbers.
+ * The length of the array must be amultiple of 3.  Each triple of numbers provides
+ * xyz-coords for one vertex for the primitive.  This assumes that uColor is the
+ * location of a color uniform in the shader program, aCoords is the location of
+ * the coords attribute, and aCoordsBuffer is a VBO for the coords attribute.
+ */
+function drawPrimitive( primitiveType, color, vertices ) {
+     gl.enableVertexAttribArray(aCoords);
+     gl.bindBuffer(gl.ARRAY_BUFFER,aCoordsBuffer);
+     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STREAM_DRAW);
+     gl.uniform4fv(uColor, color);
+     gl.vertexAttribPointer(aCoords, 3, gl.FLOAT, false, 0, 0);
+     gl.drawArrays(primitiveType, 0, vertices.length/3);
+}
+
+
+/* Draws a colored cube, along with a set of coordinate axes.
+ * (Note that the use of the above drawPrimitive function is not an efficient
+ * way to draw with WebGL.  Here, the geometry is so simple that it doesn't matter.)
+ */
+function draw() { 
+    gl.clearColor(0,0,0,1);
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+    
+    if (document.getElementById("persproj").checked) {
+         mat4.perspective(projection, Math.PI/4, 1, 2, 10);
+    }
+    else {
+         mat4.ortho(projection,-2.5, 2.5, -2.5, 2.5, 2, 10);
+    }
+    gl.uniformMatrix4fv(uProjection, false, projection );
+
+    var modelview = rotator.getViewMatrix();
+    gl.uniformMatrix4fv(uModelview, false, modelview );
+
+    mat3.normalFromMat4(normalMatrix, modelview);
+    gl.uniformMatrix3fv(uNormalMatrix, false, normalMatrix);
+    
+    gl.uniform1i( uLit, 1 );  // Turn on lighting calculations for the cube.
+
+    gl.uniform3f( uNormal, 0, 0, 1 );
+    drawPrimitive( gl.TRIANGLE_FAN, [1,0,0,1], [ -1,-1,1, 1,-1,1, 1,1,1, -1,1,1 ]);
+    gl.uniform3f( uNormal, 0, 0, -1 );
+    drawPrimitive( gl.TRIANGLE_FAN, [0,1,0,1], [ -1,-1,-1, -1,1,-1, 1,1,-1, 1,-1,-1 ]);
+    gl.uniform3f( uNormal, 0, 1, 0 );
+    drawPrimitive( gl.TRIANGLE_FAN, [0,0,1,1], [ -1,1,-1, -1,1,1, 1,1,1, 1,1,-1 ]);
+    gl.uniform3f( uNormal, 0, -1, 0 );
+    drawPrimitive( gl.TRIANGLE_FAN, [1,1,0,1], [ -1,-1,-1, 1,-1,-1, 1,-1,1, -1,-1,1 ]);
+    gl.uniform3f( uNormal, 1, 0, 0 );
+    drawPrimitive( gl.TRIANGLE_FAN, [1,0,1,1], [ 1,-1,-1, 1,1,-1, 1,1,1, 1,-1,1 ]);
+    gl.uniform3f( uNormal, -1, 0, 0 );
+    drawPrimitive( gl.TRIANGLE_FAN, [0,1,1,1], [ -1,-1,-1, -1,-1,1, -1,1,1, -1,1,-1 ]);
+
+    gl.uniform1i( uLit, 0 );  // The lines representing the coordinate axes are not lit.
+
+    gl.lineWidth(4);
+    drawPrimitive( gl.LINES, [1,0,0,1], [ -2,0,0, 2,0,0] );
+    drawPrimitive( gl.LINES, [0,1,0,1], [ 0,-2,0, 0,2,0] );
+    drawPrimitive( gl.LINES, [0,0,1,1], [ 0,0,-2, 0,0,2] );
+    gl.lineWidth(1);
+}
+
+/* Creates a program for use in the WebGL context gl, and returns the
+ * identifier for that program.  If an error occurs while compiling or
+ * linking the program, an exception of type String is thrown.  The error
+ * string contains the compilation or linking error.  If no error occurs,
+ * the program identifier is the return value of the function.
+ */
+function createProgram(gl, vertexShaderSource, fragmentShaderSource) {
+   var vsh = gl.createShader( gl.VERTEX_SHADER );
+   gl.shaderSource(vsh,vertexShaderSource);
+   gl.compileShader(vsh);
+   if ( ! gl.getShaderParameter(vsh, gl.COMPILE_STATUS) ) {
+      throw "Error in vertex shader:  " + gl.getShaderInfoLog(vsh);
+   }
+   var fsh = gl.createShader( gl.FRAGMENT_SHADER );
+   gl.shaderSource(fsh, fragmentShaderSource);
+   gl.compileShader(fsh);
+   if ( ! gl.getShaderParameter(fsh, gl.COMPILE_STATUS) ) {
+      throw "Error in fragment shader:  " + gl.getShaderInfoLog(fsh);
+   }
+   var prog = gl.createProgram();
+   gl.attachShader(prog,vsh);
+   gl.attachShader(prog, fsh);
+   gl.linkProgram(prog);
+   if ( ! gl.getProgramParameter( prog, gl.LINK_STATUS) ) {
+      throw "Link error in program:  " + gl.getProgramInfoLog(prog);
+   }
+   return prog;
+}
+
+
+/* Gets the text content of an HTML element.  This is used
+ * to get the shader source from the script elements that contain
+ * it.  The parameter should be the id of the script element.
+ */
+function getTextContent( elementID ) {
+    var element = document.getElementById(elementID);
+    var fsource = "";
+    var node = element.firstChild;
+    var str = "";
+    while (node) {
+        if (node.nodeType == 3) // this is a text node
+            str += node.textContent;
+        node = node.nextSibling;
+    }
+    return str;
+}
+
+
+/**
+ * Initializes the WebGL program including the relevant global variables
+ * and the WebGL state.  Creates a SimpleView3D object for viewing the
+ * cube and installs a mouse handler that lets the user rotate the cube.
+ */
+function init() {
+   try {
+        var canvas = document.getElementById("glcanvas");
+        gl = canvas.getContext("webgl");
+        if ( ! gl ) {
+            gl = canvas.getContext("experimental-webgl");
+        }
+        if ( ! gl ) {
+            throw "Could not create WebGL context.";
+        }
+        var vertexShaderSource = getTextContent("vshader"); 
+        var fragmentShaderSource = getTextContent("fshader");
+        var prog = createProgram(gl,vertexShaderSource,fragmentShaderSource);
+        gl.useProgram(prog);
+        aCoords =  gl.getAttribLocation(prog, "coords");
+        uModelview = gl.getUniformLocation(prog, "modelview");
+        uProjection = gl.getUniformLocation(prog, "projection");
+        uColor =  gl.getUniformLocation(prog, "color");
+        uLit =  gl.getUniformLocation(prog, "lit");
+        uNormal =  gl.getUniformLocation(prog, "normal");
+        uNormalMatrix =  gl.getUniformLocation(prog, "normalMatrix");
+        aCoordsBuffer = gl.createBuffer();
+        gl.enable(gl.DEPTH_TEST);
+        gl.enable(gl.CULL_FACE);  // no need to draw back faces
+        document.getElementById("persproj").checked = true;
+        rotator = new SimpleRotator(canvas,draw);
+        rotator.setView( [2,2,5], [0,1,0], 6 );
+   }
+   catch (e) {
+      document.getElementById("message").innerHTML =
+           "Could not initialize WebGL: " + e;
+      return;
+   }
+   draw();
+}
+
+</script>
+</head>
+<body onload="init()" style="background-color:#DDD">
+
+<h2>A Cube With Rotator</h2>
+
+<p id=message>Drag the mouse on the canvas to rotate the view.</p>
+
+<p>
+  <input type="radio" name="projectionType" id="persproj" value="perspective" onchange="draw()">
+      <label for="persproj">Perspective projection</label>
+  <input type="radio" name="projectionType" id="orthproj" value="orthogonal" onchange="draw()" style="margin-left:1cm">
+      <label for="orthproj">Orthogonal projection</label>
+  <button onclick="rotator.setView( [2,2,5], [0,1,0], 6 ); draw()" style="margin-left:1cm">Reset View</button>
+</p>
+
+<noscript><hr><h3>This page requires Javascript and a web browser that supports WebGL</h3><hr></noscript>
+
+<div>
+   <canvas width=600 height=600 id="glcanvas" style="background-color:red"></canvas>
+</div>
+
+
+</body>
+</html>
+
diff --git a/basic_course/quaternion/hws/gl-matrix-min.js b/basic_course/quaternion/hws/gl-matrix-min.js
new file mode 100644
index 0000000000000000000000000000000000000000..436c6aabe32b032f0be2c86deaa9b5c4700eabee
--- /dev/null
+++ b/basic_course/quaternion/hws/gl-matrix-min.js
@@ -0,0 +1,28 @@
+/**
+ * @fileoverview gl-matrix - High performance matrix and vector operations
+ * @author Brandon Jones
+ * @author Colin MacKenzie IV
+ * @version 2.2.0
+ */
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this
+    list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation 
+    and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+(function(e){"use strict";var t={};typeof exports=="undefined"?typeof define=="function"&&typeof define.amd=="object"&&define.amd?(t.exports={},define(function(){return t.exports})):t.exports=typeof window!="undefined"?window:e:t.exports=exports,function(e){if(!t)var t=1e-6;if(!n)var n=typeof Float32Array!="undefined"?Float32Array:Array;if(!r)var r=Math.random;var i={};i.setMatrixArrayType=function(e){n=e},typeof e!="undefined"&&(e.glMatrix=i);var s={};s.create=function(){var e=new n(2);return e[0]=0,e[1]=0,e},s.clone=function(e){var t=new n(2);return t[0]=e[0],t[1]=e[1],t},s.fromValues=function(e,t){var r=new n(2);return r[0]=e,r[1]=t,r},s.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e},s.set=function(e,t,n){return e[0]=t,e[1]=n,e},s.add=function(e,t,n){return e[0]=t[0]+n[0],e[1]=t[1]+n[1],e},s.subtract=function(e,t,n){return e[0]=t[0]-n[0],e[1]=t[1]-n[1],e},s.sub=s.subtract,s.multiply=function(e,t,n){return e[0]=t[0]*n[0],e[1]=t[1]*n[1],e},s.mul=s.multiply,s.divide=function(e,t,n){return e[0]=t[0]/n[0],e[1]=t[1]/n[1],e},s.div=s.divide,s.min=function(e,t,n){return e[0]=Math.min(t[0],n[0]),e[1]=Math.min(t[1],n[1]),e},s.max=function(e,t,n){return e[0]=Math.max(t[0],n[0]),e[1]=Math.max(t[1],n[1]),e},s.scale=function(e,t,n){return e[0]=t[0]*n,e[1]=t[1]*n,e},s.scaleAndAdd=function(e,t,n,r){return e[0]=t[0]+n[0]*r,e[1]=t[1]+n[1]*r,e},s.distance=function(e,t){var n=t[0]-e[0],r=t[1]-e[1];return Math.sqrt(n*n+r*r)},s.dist=s.distance,s.squaredDistance=function(e,t){var n=t[0]-e[0],r=t[1]-e[1];return n*n+r*r},s.sqrDist=s.squaredDistance,s.length=function(e){var t=e[0],n=e[1];return Math.sqrt(t*t+n*n)},s.len=s.length,s.squaredLength=function(e){var t=e[0],n=e[1];return t*t+n*n},s.sqrLen=s.squaredLength,s.negate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e},s.normalize=function(e,t){var n=t[0],r=t[1],i=n*n+r*r;return i>0&&(i=1/Math.sqrt(i),e[0]=t[0]*i,e[1]=t[1]*i),e},s.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]},s.cross=function(e,t,n){var r=t[0]*n[1]-t[1]*n[0];return e[0]=e[1]=0,e[2]=r,e},s.lerp=function(e,t,n,r){var i=t[0],s=t[1];return e[0]=i+r*(n[0]-i),e[1]=s+r*(n[1]-s),e},s.random=function(e,t){t=t||1;var n=r()*2*Math.PI;return e[0]=Math.cos(n)*t,e[1]=Math.sin(n)*t,e},s.transformMat2=function(e,t,n){var r=t[0],i=t[1];return e[0]=n[0]*r+n[2]*i,e[1]=n[1]*r+n[3]*i,e},s.transformMat2d=function(e,t,n){var r=t[0],i=t[1];return e[0]=n[0]*r+n[2]*i+n[4],e[1]=n[1]*r+n[3]*i+n[5],e},s.transformMat3=function(e,t,n){var r=t[0],i=t[1];return e[0]=n[0]*r+n[3]*i+n[6],e[1]=n[1]*r+n[4]*i+n[7],e},s.transformMat4=function(e,t,n){var r=t[0],i=t[1];return e[0]=n[0]*r+n[4]*i+n[12],e[1]=n[1]*r+n[5]*i+n[13],e},s.forEach=function(){var e=s.create();return function(t,n,r,i,s,o){var u,a;n||(n=2),r||(r=0),i?a=Math.min(i*n+r,t.length):a=t.length;for(u=r;u<a;u+=n)e[0]=t[u],e[1]=t[u+1],s(e,e,o),t[u]=e[0],t[u+1]=e[1];return t}}(),s.str=function(e){return"vec2("+e[0]+", "+e[1]+")"},typeof e!="undefined"&&(e.vec2=s);var o={};o.create=function(){var e=new n(3);return e[0]=0,e[1]=0,e[2]=0,e},o.clone=function(e){var t=new n(3);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t},o.fromValues=function(e,t,r){var i=new n(3);return i[0]=e,i[1]=t,i[2]=r,i},o.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e},o.set=function(e,t,n,r){return e[0]=t,e[1]=n,e[2]=r,e},o.add=function(e,t,n){return e[0]=t[0]+n[0],e[1]=t[1]+n[1],e[2]=t[2]+n[2],e},o.subtract=function(e,t,n){return e[0]=t[0]-n[0],e[1]=t[1]-n[1],e[2]=t[2]-n[2],e},o.sub=o.subtract,o.multiply=function(e,t,n){return e[0]=t[0]*n[0],e[1]=t[1]*n[1],e[2]=t[2]*n[2],e},o.mul=o.multiply,o.divide=function(e,t,n){return e[0]=t[0]/n[0],e[1]=t[1]/n[1],e[2]=t[2]/n[2],e},o.div=o.divide,o.min=function(e,t,n){return e[0]=Math.min(t[0],n[0]),e[1]=Math.min(t[1],n[1]),e[2]=Math.min(t[2],n[2]),e},o.max=function(e,t,n){return e[0]=Math.max(t[0],n[0]),e[1]=Math.max(t[1],n[1]),e[2]=Math.max(t[2],n[2]),e},o.scale=function(e,t,n){return e[0]=t[0]*n,e[1]=t[1]*n,e[2]=t[2]*n,e},o.scaleAndAdd=function(e,t,n,r){return e[0]=t[0]+n[0]*r,e[1]=t[1]+n[1]*r,e[2]=t[2]+n[2]*r,e},o.distance=function(e,t){var n=t[0]-e[0],r=t[1]-e[1],i=t[2]-e[2];return Math.sqrt(n*n+r*r+i*i)},o.dist=o.distance,o.squaredDistance=function(e,t){var n=t[0]-e[0],r=t[1]-e[1],i=t[2]-e[2];return n*n+r*r+i*i},o.sqrDist=o.squaredDistance,o.length=function(e){var t=e[0],n=e[1],r=e[2];return Math.sqrt(t*t+n*n+r*r)},o.len=o.length,o.squaredLength=function(e){var t=e[0],n=e[1],r=e[2];return t*t+n*n+r*r},o.sqrLen=o.squaredLength,o.negate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e},o.normalize=function(e,t){var n=t[0],r=t[1],i=t[2],s=n*n+r*r+i*i;return s>0&&(s=1/Math.sqrt(s),e[0]=t[0]*s,e[1]=t[1]*s,e[2]=t[2]*s),e},o.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]},o.cross=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=n[0],u=n[1],a=n[2];return e[0]=i*a-s*u,e[1]=s*o-r*a,e[2]=r*u-i*o,e},o.lerp=function(e,t,n,r){var i=t[0],s=t[1],o=t[2];return e[0]=i+r*(n[0]-i),e[1]=s+r*(n[1]-s),e[2]=o+r*(n[2]-o),e},o.random=function(e,t){t=t||1;var n=r()*2*Math.PI,i=r()*2-1,s=Math.sqrt(1-i*i)*t;return e[0]=Math.cos(n)*s,e[1]=Math.sin(n)*s,e[2]=i*t,e},o.transformMat4=function(e,t,n){var r=t[0],i=t[1],s=t[2];return e[0]=n[0]*r+n[4]*i+n[8]*s+n[12],e[1]=n[1]*r+n[5]*i+n[9]*s+n[13],e[2]=n[2]*r+n[6]*i+n[10]*s+n[14],e},o.transformMat3=function(e,t,n){var r=t[0],i=t[1],s=t[2];return e[0]=r*n[0]+i*n[3]+s*n[6],e[1]=r*n[1]+i*n[4]+s*n[7],e[2]=r*n[2]+i*n[5]+s*n[8],e},o.transformQuat=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=n[0],u=n[1],a=n[2],f=n[3],l=f*r+u*s-a*i,c=f*i+a*r-o*s,h=f*s+o*i-u*r,p=-o*r-u*i-a*s;return e[0]=l*f+p*-o+c*-a-h*-u,e[1]=c*f+p*-u+h*-o-l*-a,e[2]=h*f+p*-a+l*-u-c*-o,e},o.forEach=function(){var e=o.create();return function(t,n,r,i,s,o){var u,a;n||(n=3),r||(r=0),i?a=Math.min(i*n+r,t.length):a=t.length;for(u=r;u<a;u+=n)e[0]=t[u],e[1]=t[u+1],e[2]=t[u+2],s(e,e,o),t[u]=e[0],t[u+1]=e[1],t[u+2]=e[2];return t}}(),o.str=function(e){return"vec3("+e[0]+", "+e[1]+", "+e[2]+")"},typeof e!="undefined"&&(e.vec3=o);var u={};u.create=function(){var e=new n(4);return e[0]=0,e[1]=0,e[2]=0,e[3]=0,e},u.clone=function(e){var t=new n(4);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},u.fromValues=function(e,t,r,i){var s=new n(4);return s[0]=e,s[1]=t,s[2]=r,s[3]=i,s},u.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e},u.set=function(e,t,n,r,i){return e[0]=t,e[1]=n,e[2]=r,e[3]=i,e},u.add=function(e,t,n){return e[0]=t[0]+n[0],e[1]=t[1]+n[1],e[2]=t[2]+n[2],e[3]=t[3]+n[3],e},u.subtract=function(e,t,n){return e[0]=t[0]-n[0],e[1]=t[1]-n[1],e[2]=t[2]-n[2],e[3]=t[3]-n[3],e},u.sub=u.subtract,u.multiply=function(e,t,n){return e[0]=t[0]*n[0],e[1]=t[1]*n[1],e[2]=t[2]*n[2],e[3]=t[3]*n[3],e},u.mul=u.multiply,u.divide=function(e,t,n){return e[0]=t[0]/n[0],e[1]=t[1]/n[1],e[2]=t[2]/n[2],e[3]=t[3]/n[3],e},u.div=u.divide,u.min=function(e,t,n){return e[0]=Math.min(t[0],n[0]),e[1]=Math.min(t[1],n[1]),e[2]=Math.min(t[2],n[2]),e[3]=Math.min(t[3],n[3]),e},u.max=function(e,t,n){return e[0]=Math.max(t[0],n[0]),e[1]=Math.max(t[1],n[1]),e[2]=Math.max(t[2],n[2]),e[3]=Math.max(t[3],n[3]),e},u.scale=function(e,t,n){return e[0]=t[0]*n,e[1]=t[1]*n,e[2]=t[2]*n,e[3]=t[3]*n,e},u.scaleAndAdd=function(e,t,n,r){return e[0]=t[0]+n[0]*r,e[1]=t[1]+n[1]*r,e[2]=t[2]+n[2]*r,e[3]=t[3]+n[3]*r,e},u.distance=function(e,t){var n=t[0]-e[0],r=t[1]-e[1],i=t[2]-e[2],s=t[3]-e[3];return Math.sqrt(n*n+r*r+i*i+s*s)},u.dist=u.distance,u.squaredDistance=function(e,t){var n=t[0]-e[0],r=t[1]-e[1],i=t[2]-e[2],s=t[3]-e[3];return n*n+r*r+i*i+s*s},u.sqrDist=u.squaredDistance,u.length=function(e){var t=e[0],n=e[1],r=e[2],i=e[3];return Math.sqrt(t*t+n*n+r*r+i*i)},u.len=u.length,u.squaredLength=function(e){var t=e[0],n=e[1],r=e[2],i=e[3];return t*t+n*n+r*r+i*i},u.sqrLen=u.squaredLength,u.negate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e[3]=-t[3],e},u.normalize=function(e,t){var n=t[0],r=t[1],i=t[2],s=t[3],o=n*n+r*r+i*i+s*s;return o>0&&(o=1/Math.sqrt(o),e[0]=t[0]*o,e[1]=t[1]*o,e[2]=t[2]*o,e[3]=t[3]*o),e},u.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]+e[3]*t[3]},u.lerp=function(e,t,n,r){var i=t[0],s=t[1],o=t[2],u=t[3];return e[0]=i+r*(n[0]-i),e[1]=s+r*(n[1]-s),e[2]=o+r*(n[2]-o),e[3]=u+r*(n[3]-u),e},u.random=function(e,t){return t=t||1,e[0]=r(),e[1]=r(),e[2]=r(),e[3]=r(),u.normalize(e,e),u.scale(e,e,t),e},u.transformMat4=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3];return e[0]=n[0]*r+n[4]*i+n[8]*s+n[12]*o,e[1]=n[1]*r+n[5]*i+n[9]*s+n[13]*o,e[2]=n[2]*r+n[6]*i+n[10]*s+n[14]*o,e[3]=n[3]*r+n[7]*i+n[11]*s+n[15]*o,e},u.transformQuat=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=n[0],u=n[1],a=n[2],f=n[3],l=f*r+u*s-a*i,c=f*i+a*r-o*s,h=f*s+o*i-u*r,p=-o*r-u*i-a*s;return e[0]=l*f+p*-o+c*-a-h*-u,e[1]=c*f+p*-u+h*-o-l*-a,e[2]=h*f+p*-a+l*-u-c*-o,e},u.forEach=function(){var e=u.create();return function(t,n,r,i,s,o){var u,a;n||(n=4),r||(r=0),i?a=Math.min(i*n+r,t.length):a=t.length;for(u=r;u<a;u+=n)e[0]=t[u],e[1]=t[u+1],e[2]=t[u+2],e[3]=t[u+3],s(e,e,o),t[u]=e[0],t[u+1]=e[1],t[u+2]=e[2],t[u+3]=e[3];return t}}(),u.str=function(e){return"vec4("+e[0]+", "+e[1]+", "+e[2]+", "+e[3]+")"},typeof e!="undefined"&&(e.vec4=u);var a={};a.create=function(){var e=new n(4);return e[0]=1,e[1]=0,e[2]=0,e[3]=1,e},a.clone=function(e){var t=new n(4);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},a.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e},a.identity=function(e){return e[0]=1,e[1]=0,e[2]=0,e[3]=1,e},a.transpose=function(e,t){if(e===t){var n=t[1];e[1]=t[2],e[2]=n}else e[0]=t[0],e[1]=t[2],e[2]=t[1],e[3]=t[3];return e},a.invert=function(e,t){var n=t[0],r=t[1],i=t[2],s=t[3],o=n*s-i*r;return o?(o=1/o,e[0]=s*o,e[1]=-r*o,e[2]=-i*o,e[3]=n*o,e):null},a.adjoint=function(e,t){var n=t[0];return e[0]=t[3],e[1]=-t[1],e[2]=-t[2],e[3]=n,e},a.determinant=function(e){return e[0]*e[3]-e[2]*e[1]},a.multiply=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3],u=n[0],a=n[1],f=n[2],l=n[3];return e[0]=r*u+i*f,e[1]=r*a+i*l,e[2]=s*u+o*f,e[3]=s*a+o*l,e},a.mul=a.multiply,a.rotate=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3],u=Math.sin(n),a=Math.cos(n);return e[0]=r*a+i*u,e[1]=r*-u+i*a,e[2]=s*a+o*u,e[3]=s*-u+o*a,e},a.scale=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3],u=n[0],a=n[1];return e[0]=r*u,e[1]=i*a,e[2]=s*u,e[3]=o*a,e},a.str=function(e){return"mat2("+e[0]+", "+e[1]+", "+e[2]+", "+e[3]+")"},typeof e!="undefined"&&(e.mat2=a);var f={};f.create=function(){var e=new n(6);return e[0]=1,e[1]=0,e[2]=0,e[3]=1,e[4]=0,e[5]=0,e},f.clone=function(e){var t=new n(6);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t},f.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e},f.identity=function(e){return e[0]=1,e[1]=0,e[2]=0,e[3]=1,e[4]=0,e[5]=0,e},f.invert=function(e,t){var n=t[0],r=t[1],i=t[2],s=t[3],o=t[4],u=t[5],a=n*s-r*i;return a?(a=1/a,e[0]=s*a,e[1]=-r*a,e[2]=-i*a,e[3]=n*a,e[4]=(i*u-s*o)*a,e[5]=(r*o-n*u)*a,e):null},f.determinant=function(e){return e[0]*e[3]-e[1]*e[2]},f.multiply=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3],u=t[4],a=t[5],f=n[0],l=n[1],c=n[2],h=n[3],p=n[4],d=n[5];return e[0]=r*f+i*c,e[1]=r*l+i*h,e[2]=s*f+o*c,e[3]=s*l+o*h,e[4]=f*u+c*a+p,e[5]=l*u+h*a+d,e},f.mul=f.multiply,f.rotate=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3],u=t[4],a=t[5],f=Math.sin(n),l=Math.cos(n);return e[0]=r*l+i*f,e[1]=-r*f+i*l,e[2]=s*l+o*f,e[3]=-s*f+l*o,e[4]=l*u+f*a,e[5]=l*a-f*u,e},f.scale=function(e,t,n){var r=n[0],i=n[1];return e[0]=t[0]*r,e[1]=t[1]*i,e[2]=t[2]*r,e[3]=t[3]*i,e[4]=t[4]*r,e[5]=t[5]*i,e},f.translate=function(e,t,n){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4]+n[0],e[5]=t[5]+n[1],e},f.str=function(e){return"mat2d("+e[0]+", "+e[1]+", "+e[2]+", "+e[3]+", "+e[4]+", "+e[5]+")"},typeof e!="undefined"&&(e.mat2d=f);var l={};l.create=function(){var e=new n(9);return e[0]=1,e[1]=0,e[2]=0,e[3]=0,e[4]=1,e[5]=0,e[6]=0,e[7]=0,e[8]=1,e},l.fromMat4=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[4],e[4]=t[5],e[5]=t[6],e[6]=t[8],e[7]=t[9],e[8]=t[10],e},l.clone=function(e){var t=new n(9);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t},l.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e},l.identity=function(e){return e[0]=1,e[1]=0,e[2]=0,e[3]=0,e[4]=1,e[5]=0,e[6]=0,e[7]=0,e[8]=1,e},l.transpose=function(e,t){if(e===t){var n=t[1],r=t[2],i=t[5];e[1]=t[3],e[2]=t[6],e[3]=n,e[5]=t[7],e[6]=r,e[7]=i}else e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8];return e},l.invert=function(e,t){var n=t[0],r=t[1],i=t[2],s=t[3],o=t[4],u=t[5],a=t[6],f=t[7],l=t[8],c=l*o-u*f,h=-l*s+u*a,p=f*s-o*a,d=n*c+r*h+i*p;return d?(d=1/d,e[0]=c*d,e[1]=(-l*r+i*f)*d,e[2]=(u*r-i*o)*d,e[3]=h*d,e[4]=(l*n-i*a)*d,e[5]=(-u*n+i*s)*d,e[6]=p*d,e[7]=(-f*n+r*a)*d,e[8]=(o*n-r*s)*d,e):null},l.adjoint=function(e,t){var n=t[0],r=t[1],i=t[2],s=t[3],o=t[4],u=t[5],a=t[6],f=t[7],l=t[8];return e[0]=o*l-u*f,e[1]=i*f-r*l,e[2]=r*u-i*o,e[3]=u*a-s*l,e[4]=n*l-i*a,e[5]=i*s-n*u,e[6]=s*f-o*a,e[7]=r*a-n*f,e[8]=n*o-r*s,e},l.determinant=function(e){var t=e[0],n=e[1],r=e[2],i=e[3],s=e[4],o=e[5],u=e[6],a=e[7],f=e[8];return t*(f*s-o*a)+n*(-f*i+o*u)+r*(a*i-s*u)},l.multiply=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3],u=t[4],a=t[5],f=t[6],l=t[7],c=t[8],h=n[0],p=n[1],d=n[2],v=n[3],m=n[4],g=n[5],y=n[6],b=n[7],w=n[8];return e[0]=h*r+p*o+d*f,e[1]=h*i+p*u+d*l,e[2]=h*s+p*a+d*c,e[3]=v*r+m*o+g*f,e[4]=v*i+m*u+g*l,e[5]=v*s+m*a+g*c,e[6]=y*r+b*o+w*f,e[7]=y*i+b*u+w*l,e[8]=y*s+b*a+w*c,e},l.mul=l.multiply,l.translate=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3],u=t[4],a=t[5],f=t[6],l=t[7],c=t[8],h=n[0],p=n[1];return e[0]=r,e[1]=i,e[2]=s,e[3]=o,e[4]=u,e[5]=a,e[6]=h*r+p*o+f,e[7]=h*i+p*u+l,e[8]=h*s+p*a+c,e},l.rotate=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3],u=t[4],a=t[5],f=t[6],l=t[7],c=t[8],h=Math.sin(n),p=Math.cos(n);return e[0]=p*r+h*o,e[1]=p*i+h*u,e[2]=p*s+h*a,e[3]=p*o-h*r,e[4]=p*u-h*i,e[5]=p*a-h*s,e[6]=f,e[7]=l,e[8]=c,e},l.scale=function(e,t,n){var r=n[0],i=n[1];return e[0]=r*t[0],e[1]=r*t[1],e[2]=r*t[2],e[3]=i*t[3],e[4]=i*t[4],e[5]=i*t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e},l.fromMat2d=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=0,e[3]=t[2],e[4]=t[3],e[5]=0,e[6]=t[4],e[7]=t[5],e[8]=1,e},l.fromQuat=function(e,t){var n=t[0],r=t[1],i=t[2],s=t[3],o=n+n,u=r+r,a=i+i,f=n*o,l=n*u,c=n*a,h=r*u,p=r*a,d=i*a,v=s*o,m=s*u,g=s*a;return e[0]=1-(h+d),e[3]=l+g,e[6]=c-m,e[1]=l-g,e[4]=1-(f+d),e[7]=p+v,e[2]=c+m,e[5]=p-v,e[8]=1-(f+h),e},l.normalFromMat4=function(e,t){var n=t[0],r=t[1],i=t[2],s=t[3],o=t[4],u=t[5],a=t[6],f=t[7],l=t[8],c=t[9],h=t[10],p=t[11],d=t[12],v=t[13],m=t[14],g=t[15],y=n*u-r*o,b=n*a-i*o,w=n*f-s*o,E=r*a-i*u,S=r*f-s*u,x=i*f-s*a,T=l*v-c*d,N=l*m-h*d,C=l*g-p*d,k=c*m-h*v,L=c*g-p*v,A=h*g-p*m,O=y*A-b*L+w*k+E*C-S*N+x*T;return O?(O=1/O,e[0]=(u*A-a*L+f*k)*O,e[1]=(a*C-o*A-f*N)*O,e[2]=(o*L-u*C+f*T)*O,e[3]=(i*L-r*A-s*k)*O,e[4]=(n*A-i*C+s*N)*O,e[5]=(r*C-n*L-s*T)*O,e[6]=(v*x-m*S+g*E)*O,e[7]=(m*w-d*x-g*b)*O,e[8]=(d*S-v*w+g*y)*O,e):null},l.str=function(e){return"mat3("+e[0]+", "+e[1]+", "+e[2]+", "+e[3]+", "+e[4]+", "+e[5]+", "+e[6]+", "+e[7]+", "+e[8]+")"},typeof e!="undefined"&&(e.mat3=l);var c={};c.create=function(){var e=new n(16);return e[0]=1,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=1,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=1,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,e},c.clone=function(e){var t=new n(16);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t},c.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e[9]=t[9],e[10]=t[10],e[11]=t[11],e[12]=t[12],e[13]=t[13],e[14]=t[14],e[15]=t[15],e},c.identity=function(e){return e[0]=1,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=1,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=1,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,e},c.transpose=function(e,t){if(e===t){var n=t[1],r=t[2],i=t[3],s=t[6],o=t[7],u=t[11];e[1]=t[4],e[2]=t[8],e[3]=t[12],e[4]=n,e[6]=t[9],e[7]=t[13],e[8]=r,e[9]=s,e[11]=t[14],e[12]=i,e[13]=o,e[14]=u}else e[0]=t[0],e[1]=t[4],e[2]=t[8],e[3]=t[12],e[4]=t[1],e[5]=t[5],e[6]=t[9],e[7]=t[13],e[8]=t[2],e[9]=t[6],e[10]=t[10],e[11]=t[14],e[12]=t[3],e[13]=t[7],e[14]=t[11],e[15]=t[15];return e},c.invert=function(e,t){var n=t[0],r=t[1],i=t[2],s=t[3],o=t[4],u=t[5],a=t[6],f=t[7],l=t[8],c=t[9],h=t[10],p=t[11],d=t[12],v=t[13],m=t[14],g=t[15],y=n*u-r*o,b=n*a-i*o,w=n*f-s*o,E=r*a-i*u,S=r*f-s*u,x=i*f-s*a,T=l*v-c*d,N=l*m-h*d,C=l*g-p*d,k=c*m-h*v,L=c*g-p*v,A=h*g-p*m,O=y*A-b*L+w*k+E*C-S*N+x*T;return O?(O=1/O,e[0]=(u*A-a*L+f*k)*O,e[1]=(i*L-r*A-s*k)*O,e[2]=(v*x-m*S+g*E)*O,e[3]=(h*S-c*x-p*E)*O,e[4]=(a*C-o*A-f*N)*O,e[5]=(n*A-i*C+s*N)*O,e[6]=(m*w-d*x-g*b)*O,e[7]=(l*x-h*w+p*b)*O,e[8]=(o*L-u*C+f*T)*O,e[9]=(r*C-n*L-s*T)*O,e[10]=(d*S-v*w+g*y)*O,e[11]=(c*w-l*S-p*y)*O,e[12]=(u*N-o*k-a*T)*O,e[13]=(n*k-r*N+i*T)*O,e[14]=(v*b-d*E-m*y)*O,e[15]=(l*E-c*b+h*y)*O,e):null},c.adjoint=function(e,t){var n=t[0],r=t[1],i=t[2],s=t[3],o=t[4],u=t[5],a=t[6],f=t[7],l=t[8],c=t[9],h=t[10],p=t[11],d=t[12],v=t[13],m=t[14],g=t[15];return e[0]=u*(h*g-p*m)-c*(a*g-f*m)+v*(a*p-f*h),e[1]=-(r*(h*g-p*m)-c*(i*g-s*m)+v*(i*p-s*h)),e[2]=r*(a*g-f*m)-u*(i*g-s*m)+v*(i*f-s*a),e[3]=-(r*(a*p-f*h)-u*(i*p-s*h)+c*(i*f-s*a)),e[4]=-(o*(h*g-p*m)-l*(a*g-f*m)+d*(a*p-f*h)),e[5]=n*(h*g-p*m)-l*(i*g-s*m)+d*(i*p-s*h),e[6]=-(n*(a*g-f*m)-o*(i*g-s*m)+d*(i*f-s*a)),e[7]=n*(a*p-f*h)-o*(i*p-s*h)+l*(i*f-s*a),e[8]=o*(c*g-p*v)-l*(u*g-f*v)+d*(u*p-f*c),e[9]=-(n*(c*g-p*v)-l*(r*g-s*v)+d*(r*p-s*c)),e[10]=n*(u*g-f*v)-o*(r*g-s*v)+d*(r*f-s*u),e[11]=-(n*(u*p-f*c)-o*(r*p-s*c)+l*(r*f-s*u)),e[12]=-(o*(c*m-h*v)-l*(u*m-a*v)+d*(u*h-a*c)),e[13]=n*(c*m-h*v)-l*(r*m-i*v)+d*(r*h-i*c),e[14]=-(n*(u*m-a*v)-o*(r*m-i*v)+d*(r*a-i*u)),e[15]=n*(u*h-a*c)-o*(r*h-i*c)+l*(r*a-i*u),e},c.determinant=function(e){var t=e[0],n=e[1],r=e[2],i=e[3],s=e[4],o=e[5],u=e[6],a=e[7],f=e[8],l=e[9],c=e[10],h=e[11],p=e[12],d=e[13],v=e[14],m=e[15],g=t*o-n*s,y=t*u-r*s,b=t*a-i*s,w=n*u-r*o,E=n*a-i*o,S=r*a-i*u,x=f*d-l*p,T=f*v-c*p,N=f*m-h*p,C=l*v-c*d,k=l*m-h*d,L=c*m-h*v;return g*L-y*k+b*C+w*N-E*T+S*x},c.multiply=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3],u=t[4],a=t[5],f=t[6],l=t[7],c=t[8],h=t[9],p=t[10],d=t[11],v=t[12],m=t[13],g=t[14],y=t[15],b=n[0],w=n[1],E=n[2],S=n[3];return e[0]=b*r+w*u+E*c+S*v,e[1]=b*i+w*a+E*h+S*m,e[2]=b*s+w*f+E*p+S*g,e[3]=b*o+w*l+E*d+S*y,b=n[4],w=n[5],E=n[6],S=n[7],e[4]=b*r+w*u+E*c+S*v,e[5]=b*i+w*a+E*h+S*m,e[6]=b*s+w*f+E*p+S*g,e[7]=b*o+w*l+E*d+S*y,b=n[8],w=n[9],E=n[10],S=n[11],e[8]=b*r+w*u+E*c+S*v,e[9]=b*i+w*a+E*h+S*m,e[10]=b*s+w*f+E*p+S*g,e[11]=b*o+w*l+E*d+S*y,b=n[12],w=n[13],E=n[14],S=n[15],e[12]=b*r+w*u+E*c+S*v,e[13]=b*i+w*a+E*h+S*m,e[14]=b*s+w*f+E*p+S*g,e[15]=b*o+w*l+E*d+S*y,e},c.mul=c.multiply,c.translate=function(e,t,n){var r=n[0],i=n[1],s=n[2],o,u,a,f,l,c,h,p,d,v,m,g;return t===e?(e[12]=t[0]*r+t[4]*i+t[8]*s+t[12],e[13]=t[1]*r+t[5]*i+t[9]*s+t[13],e[14]=t[2]*r+t[6]*i+t[10]*s+t[14],e[15]=t[3]*r+t[7]*i+t[11]*s+t[15]):(o=t[0],u=t[1],a=t[2],f=t[3],l=t[4],c=t[5],h=t[6],p=t[7],d=t[8],v=t[9],m=t[10],g=t[11],e[0]=o,e[1]=u,e[2]=a,e[3]=f,e[4]=l,e[5]=c,e[6]=h,e[7]=p,e[8]=d,e[9]=v,e[10]=m,e[11]=g,e[12]=o*r+l*i+d*s+t[12],e[13]=u*r+c*i+v*s+t[13],e[14]=a*r+h*i+m*s+t[14],e[15]=f*r+p*i+g*s+t[15]),e},c.scale=function(e,t,n){var r=n[0],i=n[1],s=n[2];return e[0]=t[0]*r,e[1]=t[1]*r,e[2]=t[2]*r,e[3]=t[3]*r,e[4]=t[4]*i,e[5]=t[5]*i,e[6]=t[6]*i,e[7]=t[7]*i,e[8]=t[8]*s,e[9]=t[9]*s,e[10]=t[10]*s,e[11]=t[11]*s,e[12]=t[12],e[13]=t[13],e[14]=t[14],e[15]=t[15],e},c.rotate=function(e,n,r,i){var s=i[0],o=i[1],u=i[2],a=Math.sqrt(s*s+o*o+u*u),f,l,c,h,p,d,v,m,g,y,b,w,E,S,x,T,N,C,k,L,A,O,M,_;return Math.abs(a)<t?null:(a=1/a,s*=a,o*=a,u*=a,f=Math.sin(r),l=Math.cos(r),c=1-l,h=n[0],p=n[1],d=n[2],v=n[3],m=n[4],g=n[5],y=n[6],b=n[7],w=n[8],E=n[9],S=n[10],x=n[11],T=s*s*c+l,N=o*s*c+u*f,C=u*s*c-o*f,k=s*o*c-u*f,L=o*o*c+l,A=u*o*c+s*f,O=s*u*c+o*f,M=o*u*c-s*f,_=u*u*c+l,e[0]=h*T+m*N+w*C,e[1]=p*T+g*N+E*C,e[2]=d*T+y*N+S*C,e[3]=v*T+b*N+x*C,e[4]=h*k+m*L+w*A,e[5]=p*k+g*L+E*A,e[6]=d*k+y*L+S*A,e[7]=v*k+b*L+x*A,e[8]=h*O+m*M+w*_,e[9]=p*O+g*M+E*_,e[10]=d*O+y*M+S*_,e[11]=v*O+b*M+x*_,n!==e&&(e[12]=n[12],e[13]=n[13],e[14]=n[14],e[15]=n[15]),e)},c.rotateX=function(e,t,n){var r=Math.sin(n),i=Math.cos(n),s=t[4],o=t[5],u=t[6],a=t[7],f=t[8],l=t[9],c=t[10],h=t[11];return t!==e&&(e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[12]=t[12],e[13]=t[13],e[14]=t[14],e[15]=t[15]),e[4]=s*i+f*r,e[5]=o*i+l*r,e[6]=u*i+c*r,e[7]=a*i+h*r,e[8]=f*i-s*r,e[9]=l*i-o*r,e[10]=c*i-u*r,e[11]=h*i-a*r,e},c.rotateY=function(e,t,n){var r=Math.sin(n),i=Math.cos(n),s=t[0],o=t[1],u=t[2],a=t[3],f=t[8],l=t[9],c=t[10],h=t[11];return t!==e&&(e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[12]=t[12],e[13]=t[13],e[14]=t[14],e[15]=t[15]),e[0]=s*i-f*r,e[1]=o*i-l*r,e[2]=u*i-c*r,e[3]=a*i-h*r,e[8]=s*r+f*i,e[9]=o*r+l*i,e[10]=u*r+c*i,e[11]=a*r+h*i,e},c.rotateZ=function(e,t,n){var r=Math.sin(n),i=Math.cos(n),s=t[0],o=t[1],u=t[2],a=t[3],f=t[4],l=t[5],c=t[6],h=t[7];return t!==e&&(e[8]=t[8],e[9]=t[9],e[10]=t[10],e[11]=t[11],e[12]=t[12],e[13]=t[13],e[14]=t[14],e[15]=t[15]),e[0]=s*i+f*r,e[1]=o*i+l*r,e[2]=u*i+c*r,e[3]=a*i+h*r,e[4]=f*i-s*r,e[5]=l*i-o*r,e[6]=c*i-u*r,e[7]=h*i-a*r,e},c.fromRotationTranslation=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3],u=r+r,a=i+i,f=s+s,l=r*u,c=r*a,h=r*f,p=i*a,d=i*f,v=s*f,m=o*u,g=o*a,y=o*f;return e[0]=1-(p+v),e[1]=c+y,e[2]=h-g,e[3]=0,e[4]=c-y,e[5]=1-(l+v),e[6]=d+m,e[7]=0,e[8]=h+g,e[9]=d-m,e[10]=1-(l+p),e[11]=0,e[12]=n[0],e[13]=n[1],e[14]=n[2],e[15]=1,e},c.fromQuat=function(e,t){var n=t[0],r=t[1],i=t[2],s=t[3],o=n+n,u=r+r,a=i+i,f=n*o,l=n*u,c=n*a,h=r*u,p=r*a,d=i*a,v=s*o,m=s*u,g=s*a;return e[0]=1-(h+d),e[1]=l+g,e[2]=c-m,e[3]=0,e[4]=l-g,e[5]=1-(f+d),e[6]=p+v,e[7]=0,e[8]=c+m,e[9]=p-v,e[10]=1-(f+h),e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,e},c.frustum=function(e,t,n,r,i,s,o){var u=1/(n-t),a=1/(i-r),f=1/(s-o);return e[0]=s*2*u,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=s*2*a,e[6]=0,e[7]=0,e[8]=(n+t)*u,e[9]=(i+r)*a,e[10]=(o+s)*f,e[11]=-1,e[12]=0,e[13]=0,e[14]=o*s*2*f,e[15]=0,e},c.perspective=function(e,t,n,r,i){var s=1/Math.tan(t/2),o=1/(r-i);return e[0]=s/n,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=s,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=(i+r)*o,e[11]=-1,e[12]=0,e[13]=0,e[14]=2*i*r*o,e[15]=0,e},c.ortho=function(e,t,n,r,i,s,o){var u=1/(t-n),a=1/(r-i),f=1/(s-o);return e[0]=-2*u,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=-2*a,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=2*f,e[11]=0,e[12]=(t+n)*u,e[13]=(i+r)*a,e[14]=(o+s)*f,e[15]=1,e},c.lookAt=function(e,n,r,i){var s,o,u,a,f,l,h,p,d,v,m=n[0],g=n[1],y=n[2],b=i[0],w=i[1],E=i[2],S=r[0],x=r[1],T=r[2];return Math.abs(m-S)<t&&Math.abs(g-x)<t&&Math.abs(y-T)<t?c.identity(e):(h=m-S,p=g-x,d=y-T,v=1/Math.sqrt(h*h+p*p+d*d),h*=v,p*=v,d*=v,s=w*d-E*p,o=E*h-b*d,u=b*p-w*h,v=Math.sqrt(s*s+o*o+u*u),v?(v=1/v,s*=v,o*=v,u*=v):(s=0,o=0,u=0),a=p*u-d*o,f=d*s-h*u,l=h*o-p*s,v=Math.sqrt(a*a+f*f+l*l),v?(v=1/v,a*=v,f*=v,l*=v):(a=0,f=0,l=0),e[0]=s,e[1]=a,e[2]=h,e[3]=0,e[4]=o,e[5]=f,e[6]=p,e[7]=0,e[8]=u,e[9]=l,e[10]=d,e[11]=0,e[12]=-(s*m+o*g+u*y),e[13]=-(a*m+f*g+l*y),e[14]=-(h*m+p*g+d*y),e[15]=1,e)},c.str=function(e){return"mat4("+e[0]+", "+e[1]+", "+e[2]+", "+e[3]+", "+e[4]+", "+e[5]+", "+e[6]+", "+e[7]+", "+e[8]+", "+e[9]+", "+e[10]+", "+e[11]+", "+e[12]+", "+e[13]+", "+e[14]+", "+e[15]+")"},typeof e!="undefined"&&(e.mat4=c);var h={};h.create=function(){var e=new n(4);return e[0]=0,e[1]=0,e[2]=0,e[3]=1,e},h.rotationTo=function(){var e=o.create(),t=o.fromValues(1,0,0),n=o.fromValues(0,1,0);return function(r,i,s){var u=o.dot(i,s);return u<-0.999999?(o.cross(e,t,i),o.length(e)<1e-6&&o.cross(e,n,i),o.normalize(e,e),h.setAxisAngle(r,e,Math.PI),r):u>.999999?(r[0]=0,r[1]=0,r[2]=0,r[3]=1,r):(o.cross(e,i,s),r[0]=e[0],r[1]=e[1],r[2]=e[2],r[3]=1+u,h.normalize(r,r))}}(),h.setAxes=function(){var e=l.create();return function(t,n,r,i){return e[0]=r[0],e[3]=r[1],e[6]=r[2],e[1]=i[0],e[4]=i[1],e[7]=i[2],e[2]=n[0],e[5]=n[1],e[8]=n[2],h.normalize(t,h.fromMat3(t,e))}}(),h.clone=u.clone,h.fromValues=u.fromValues,h.copy=u.copy,h.set=u.set,h.identity=function(e){return e[0]=0,e[1]=0,e[2]=0,e[3]=1,e},h.setAxisAngle=function(e,t,n){n*=.5;var r=Math.sin(n);return e[0]=r*t[0],e[1]=r*t[1],e[2]=r*t[2],e[3]=Math.cos(n),e},h.add=u.add,h.multiply=function(e,t,n){var r=t[0],i=t[1],s=t[2],o=t[3],u=n[0],a=n[1],f=n[2],l=n[3];return e[0]=r*l+o*u+i*f-s*a,e[1]=i*l+o*a+s*u-r*f,e[2]=s*l+o*f+r*a-i*u,e[3]=o*l-r*u-i*a-s*f,e},h.mul=h.multiply,h.scale=u.scale,h.rotateX=function(e,t,n){n*=.5;var r=t[0],i=t[1],s=t[2],o=t[3],u=Math.sin(n),a=Math.cos(n);return e[0]=r*a+o*u,e[1]=i*a+s*u,e[2]=s*a-i*u,e[3]=o*a-r*u,e},h.rotateY=function(e,t,n){n*=.5;var r=t[0],i=t[1],s=t[2],o=t[3],u=Math.sin(n),a=Math.cos(n);return e[0]=r*a-s*u,e[1]=i*a+o*u,e[2]=s*a+r*u,e[3]=o*a-i*u,e},h.rotateZ=function(e,t,n){n*=.5;var r=t[0],i=t[1],s=t[2],o=t[3],u=Math.sin(n),a=Math.cos(n);return e[0]=r*a+i*u,e[1]=i*a-r*u,e[2]=s*a+o*u,e[3]=o*a-s*u,e},h.calculateW=function(e,t){var n=t[0],r=t[1],i=t[2];return e[0]=n,e[1]=r,e[2]=i,e[3]=-Math.sqrt(Math.abs(1-n*n-r*r-i*i)),e},h.dot=u.dot,h.lerp=u.lerp,h.slerp=function(e,t,n,r){var i=t[0],s=t[1],o=t[2],u=t[3],a=n[0],f=n[1],l=n[2],c=n[3],h,p,d,v,m;return p=i*a+s*f+o*l+u*c,p<0&&(p=-p,a=-a,f=-f,l=-l,c=-c),1-p>1e-6?(h=Math.acos(p),d=Math.sin(h),v=Math.sin((1-r)*h)/d,m=Math.sin(r*h)/d):(v=1-r,m=r),e[0]=v*i+m*a,e[1]=v*s+m*f,e[2]=v*o+m*l,e[3]=v*u+m*c,e},h.invert=function(e,t){var n=t[0],r=t[1],i=t[2],s=t[3],o=n*n+r*r+i*i+s*s,u=o?1/o:0;return e[0]=-n*u,e[1]=-r*u,e[2]=-i*u,e[3]=s*u,e},h.conjugate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e[3]=t[3],e},h.length=u.length,h.len=h.length,h.squaredLength=u.squaredLength,h.sqrLen=h.squaredLength,h.normalize=u.normalize,h.fromMat3=function(){var e=typeof Int8Array!="undefined"?new Int8Array([1,2,0]):[1,2,0];return function(t,n){var r=n[0]+n[4]+n[8],i;if(r>0)i=Math.sqrt(r+1),t[3]=.5*i,i=.5/i,t[0]=(n[7]-n[5])*i,t[1]=(n[2]-n[6])*i,t[2]=(n[3]-n[1])*i;else{var s=0;n[4]>n[0]&&(s=1),n[8]>n[s*3+s]&&(s=2);var o=e[s],u=e[o];i=Math.sqrt(n[s*3+s]-n[o*3+o]-n[u*3+u]+1),t[s]=.5*i,i=.5/i,t[3]=(n[u*3+o]-n[o*3+u])*i,t[o]=(n[o*3+s]+n[s*3+o])*i,t[u]=(n[u*3+s]+n[s*3+u])*i}return t}}(),h.str=function(e){return"quat("+e[0]+", "+e[1]+", "+e[2]+", "+e[3]+")"},typeof e!="undefined"&&(e.quat=h)}(t.exports)})(this);
diff --git a/basic_course/quaternion/hws/simple-rotator.js b/basic_course/quaternion/hws/simple-rotator.js
new file mode 100644
index 0000000000000000000000000000000000000000..641b692e422546bdcc9b843b65fc1203314861fe
--- /dev/null
+++ b/basic_course/quaternion/hws/simple-rotator.js
@@ -0,0 +1,183 @@
+/**
+ * An object of type SimpleRotator can be used to implement a trackball-like mouse rotation
+ * of a WebGL scene about the origin.  Only the first parameter to the constructor is required.
+ * When an object is created, mouse event handlers are set up on the canvas to respond to rotation.
+ * The class defines the following methods for an object rotator of type SimpleRotator:
+ *    rotator.setView(viewDirectionVector, viewUpVector, viewDistance) set up the view, where the
+ * parameters are optional and are used in the same way as the corresponding parameters in the constructor;
+ *    rotator.setViewDistance(viewDistance) sets the distance of the viewer from the origin without
+ * changing the direction of view;
+ *    rotator.getViewDistance() returns the viewDistance;
+ *    rotator.getViewMatrix() returns a Float32Array representing the viewing transformation matrix
+ * for the current view, suitable for use with gl.uniformMatrix4fv or for further transformation with
+ * the glmatrix library mat4 class;
+ *    rotator.getViewMatrixArray() returns the view transformation matrix as a regular JavaScript
+ * array, but still represents as a 1D array of 16 elements, in column-major order.
+ *
+ * @param canvas the HTML canvas element used for WebGL drawing.  The user will rotate the
+ *    scene by dragging the mouse on this canvas.  This parameter is required.
+ * @param callback if present must be a function, which is called whenever the rotation changes.
+ *    It is typically the function that draws the scene
+ * @param viewDirectionVector if present must be an array of three numbers, not all zero.  The
+ *    view is from the direction of this vector towards the origin (0,0,0).  If not present,
+ *    the value [0,0,10] is used.
+ * @param viewUpVector if present must be an array of three numbers. Gives a vector that will
+ *    be seen as pointing upwards in the view.  If not present, the value is [0,1,0].
+ * @param viewDistance if present must be a positive number.  Gives the distance of the viewer
+ *    from the origin.  If not present, the length of viewDirectionVector is used.
+ */
+function SimpleRotator(canvas, callback, viewDirectionVector, viewUpVector, viewDistance) {
+    var unitx = new Array(3);
+    var unity = new Array(3);
+    var unitz = new Array(3);
+    var viewZ;
+    this.setView = function( viewDirectionVector, viewUpVector, viewDistance ) {
+        var viewpoint = viewDirectionVector || [0,0,10];
+        var viewup = viewUpVector || [0,1,0];
+	if (viewDistance && typeof viewDistance == "number")
+	    viewZ = viewDistance;
+	else
+	    viewZ = length(viewpoint);
+        copy(unitz,viewpoint);
+        normalize(unitz, unitz);
+        copy(unity,unitz);
+        scale(unity, unity, dot(unitz,viewup));
+        subtract(unity,viewup,unity);
+        normalize(unity,unity);
+        cross(unitx,unity,unitz);
+    }
+    this.getViewMatrix = function (){
+        return new Float32Array( this.getViewMatrixArray() );
+    }
+    this.getViewMatrixArray = function() {
+	return [ unitx[0], unity[0], unitz[0], 0,
+            unitx[1], unity[1], unitz[1], 0, 
+            unitx[2], unity[2], unitz[2], 0,
+	    0, 0, -viewZ, 1 ];
+    }
+    this.getViewDistance = function() {
+	return viewZ;
+    }
+    this.setViewDistance = function(viewDistance) {
+	viewZ = viewDistance;
+    }
+    function applyTransvection(e1, e2) {  // rotate vector e1 onto e2
+        function reflectInAxis(axis, source, destination) {
+        	var s = 2 * (axis[0] * source[0] + axis[1] * source[1] + axis[2] * source[2]);
+		    destination[0] = s*axis[0] - source[0];
+		    destination[1] = s*axis[1] - source[1];
+		    destination[2] = s*axis[2] - source[2];
+        }
+        normalize(e1,e1);
+        normalize(e2,e2);
+        var e = [0,0,0];
+        add(e,e1,e2);
+        normalize(e,e);
+        var temp = [0,0,0];
+        reflectInAxis(e,unitz,temp);
+	reflectInAxis(e1,temp,unitz);
+	reflectInAxis(e,unitx,temp);
+	reflectInAxis(e1,temp,unitx);
+	reflectInAxis(e,unity,temp);
+	reflectInAxis(e1,temp,unity);
+    }
+    var centerX = canvas.width/2;
+    var centerY = canvas.height/2;
+    var radius = Math.min(centerX,centerY);
+    var radius2 = radius*radius;
+    var prevx,prevy;
+    var prevRay = [0,0,0];
+    var dragging = false;
+    function doMouseDown(evt) {
+        if (dragging)
+           return;
+        dragging = true;
+        document.addEventListener("mousemove", doMouseDrag, false);
+        document.addEventListener("mouseup", doMouseUp, false);
+        var box = canvas.getBoundingClientRect();
+        prevx = window.pageXOffset + evt.clientX - box.left;
+        prevy = window.pageYOffset + evt.clientY - box.top;
+    }
+    function doMouseDrag(evt) {
+        if (!dragging)
+           return;
+        var box = canvas.getBoundingClientRect();
+        var x = window.pageXOffset + evt.clientX - box.left;
+        var y = window.pageYOffset + evt.clientY - box.top;
+        var ray1 = toRay(prevx,prevy);
+        var ray2 = toRay(x,y);
+        applyTransvection(ray1,ray2);
+        prevx = x;
+        prevy = y;
+	if (callback) {
+		console.log("Draw:");
+	    callback();
+	}
+    }
+    function doMouseUp(evt) {
+        if (dragging) {
+            document.removeEventListener("mousemove", doMouseDrag, false);
+            document.removeEventListener("mouseup", doMouseUp, false);
+	    dragging = false;
+        }
+    }
+    function toRay(x,y) {
+       var dx = x - centerX;
+       var dy = centerY - y;
+       var vx = dx * unitx[0] + dy * unity[0];  // The mouse point as a vector in the image plane.
+       var vy = dx * unitx[1] + dy * unity[1];
+       var vz = dx * unitx[2] + dy * unity[2];
+       var dist2 = vx*vx + vy*vy + vz*vz;
+       if (dist2 > radius2) {
+          return [vx,vy,vz];
+       }
+       else {
+          var z = Math.sqrt(radius2 - dist2);
+          return  [vx+z*unitz[0], vy+z*unitz[1], vz+z*unitz[2]];
+        }
+    }
+    function dot(v,w) {
+	return v[0]*w[0] + v[1]*w[1] + v[2]*w[2];
+    }
+    function length(v) {
+	return Math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+    }
+    function normalize(v,w) {
+	var d = length(w);
+	v[0] = w[0]/d;
+	v[1] = w[1]/d;
+	v[2] = w[2]/d;
+    }
+    function copy(v,w) {
+	v[0] = w[0];
+	v[1] = w[1];
+	v[2] = w[2];
+    }
+    function add(sum,v,w) {
+	sum[0] = v[0] + w[0];
+	sum[1] = v[1] + w[1];
+	sum[2] = v[2] + w[2];
+    }
+    function subtract(dif,v,w) {
+	dif[0] = v[0] - w[0];
+	dif[1] = v[1] - w[1];
+	dif[2] = v[2] - w[2];
+    }
+    function scale(ans,v,num) {
+	ans[0] = v[0] * num;
+	ans[1] = v[1] * num;
+	ans[2] = v[2] * num;
+    }
+    function cross(c,v,w) {
+	var x = v[1]*w[2] - v[2]*w[1];
+	var y = v[2]*w[0] - v[0]*w[2];
+	var z = v[0]*w[1] - v[1]*w[0];
+	c[0] = x;
+	c[1] = y;
+	c[2] = z;
+    }
+    this.setView(viewDirectionVector, viewUpVector, viewDistance);
+    canvas.addEventListener("mousedown", doMouseDown, false);
+}
+
+
diff --git a/basic_course/quaternion/index.html b/basic_course/quaternion/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..e10fd712eafb36e535b28f8ec4be2cad9ff99c6b
--- /dev/null
+++ b/basic_course/quaternion/index.html
@@ -0,0 +1,23 @@
+<html>
+
+<head>
+<title>WebGL Tutorial 07 - Transform Coding</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js"> </script>
+<script> 
+window['mat4'] = glMatrix.mat4;
+window['vec4'] = glMatrix.vec4;
+window['vec3'] = glMatrix.vec3;
+window['quat'] = glMatrix.quat;
+</script>
+<script type="text/javascript" src="hello.js"> </script>
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+	<br>
+<button onclick="toggleAnimation()">Toggle Animation</button>
+</body>
+
+</html>
diff --git a/basic_course/quaternion/index_start.html b/basic_course/quaternion/index_start.html
new file mode 100644
index 0000000000000000000000000000000000000000..167016fa81ae8c07ab45ab98087570541718285c
--- /dev/null
+++ b/basic_course/quaternion/index_start.html
@@ -0,0 +1,22 @@
+<html>
+
+<head>
+<title>WebGL Tutorial 07 - Transform Coding</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js"> </script>
+<script> 
+window['mat4'] = glMatrix.mat4;
+window['vec4'] = glMatrix.vec4;
+window['vec3'] = glMatrix.vec4;
+</script>
+<script type="text/javascript" src="hello_start.js"> </script>
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+	<br>
+<button onclick="toggleAnimation()">Toggle Animation</button>
+</body>
+
+</html>
diff --git a/basic_course/shader/.gitkeep b/basic_course/shader/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/basic_course/shader/GLSL_ES_Specification_1.00.pdf b/basic_course/shader/GLSL_ES_Specification_1.00.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..a85de661faf98df6fab2804d024241365b3778eb
Binary files /dev/null and b/basic_course/shader/GLSL_ES_Specification_1.00.pdf differ
diff --git a/basic_course/shader/hello_shader.js b/basic_course/shader/hello_shader.js
new file mode 100644
index 0000000000000000000000000000000000000000..51d68202d7cc59505ec084f30e02f8aef314c657
--- /dev/null
+++ b/basic_course/shader/hello_shader.js
@@ -0,0 +1,192 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    /* gl.getError returns the last error that occurred using WebGL for debugging */ 
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+var vertexData = [
+        -0.4, -0.4, 0.0, 1.0, 0.0, 1.0, 1.0,// Bottom left
+         0.4, -0.4, 0.0, 1.0, 1.0, 1.0, 1.0,// Bottom right
+         0.0, 0.4, 0.0,  1.0, 0.0, 0.0, 1.0,// Top middle
+         0.6, 0.6, -0.5,  1.0, 1.0, 1.0, 1.0,// Bottom left
+         0.8, 0.6, -0.5,  1.0, 0.0, 1.0, 1.0,// Bottom right
+         0.7, 0.8, -0.5,   0.0, 0.0, 1.0, 1.0 // Top middle
+];
+var elementData = [ 0,1,2,3,4,5]; 
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+	gl.elementBuffer = gl.createBuffer(); 
+	gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.elementBuffer);
+	gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(elementData),gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color; \
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 transformationMatrix; \
+			uniform mediump mat4 virwMatrix; \
+			uniform mediump mat4 projMatrix; \
+			varying highp vec4 color;\
+			void main(void)  \
+			{ \
+				gl_Position = transformationMatrix * myVertex; \
+				color = myColor; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+
+    gl.clear(gl.COLOR_BUFFER_BIT);
+
+    var matrixLocation = gl.getUniformLocation(gl.programObject, "transformationMatrix");
+    var transformationMatrix = [
+        1.0, 0.0, 0.0, 0.0,
+        0.0, 1.0, 0.0, 0.0,
+        0.0, 0.0, 1.0, 0.5,
+        0.0, 0.0, 0.0, 1.0
+    ];
+
+
+    gl.uniformMatrix4fv(matrixLocation, gl.FALSE, transformationMatrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
+	// gl.vertexAttrib4f(1, Math.random(), 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	// gl.lineWidth(6.0);  // It is not working at Chrome!
+    // gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT,0);
+    // gl.drawArrays(gl.POINTS, 0, 6);
+    // gl.drawArrays(gl.LINES, 0, 6);
+	gl.drawArrays(gl.TRIANGLES, 0, 6); 
+	console.log("Enum for Primitive Assumbly", gl.TRIANGLES, gl.TRIANGLE, gl.POINTS);  
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/shader/index.html b/basic_course/shader/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..e4b210e0f2eb49fc62b722fc1422402912e03bc1
--- /dev/null
+++ b/basic_course/shader/index.html
@@ -0,0 +1,17 @@
+<html>
+
+<head>
+<title>WebGLHelloAPI</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+
+<script type="text/javascript" src="hello_shader.js">
+</script>
+
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+</body>
+
+</html>
diff --git a/basic_course/shader/webgl-reference-card-1_0.pdf b/basic_course/shader/webgl-reference-card-1_0.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..d403b50d349b7fa525a5e50b776960e769cc5733
Binary files /dev/null and b/basic_course/shader/webgl-reference-card-1_0.pdf differ
diff --git a/basic_course/shader_basic/.gitignores b/basic_course/shader_basic/.gitignores
new file mode 100644
index 0000000000000000000000000000000000000000..b883f1fdc6d69146f477bba77c117fbbd33714af
--- /dev/null
+++ b/basic_course/shader_basic/.gitignores
@@ -0,0 +1 @@
+*.exe
diff --git a/basic_course/shader_basic/gl-matrix.js b/basic_course/shader_basic/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..4553f9ea44878e9b79894c1de08af95ea9814317
--- /dev/null
+++ b/basic_course/shader_basic/gl-matrix.js
@@ -0,0 +1,7611 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.3.0
+
+Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, (function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Float32ArrayConstructor | ArrayConstructor} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {ReadonlyMat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return "mat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {ReadonlyMat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {ReadonlyMat2} L the lower triangular matrix
+   * @param {ReadonlyMat2} D the diagonal matrix
+   * @param {ReadonlyMat2} U the upper triangular matrix
+   * @param {ReadonlyMat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, b,
+   *  c, d,
+   *  tx, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, b, 0,
+   *  c, d, 0,
+   *  tx, ty, 1]
+   * </pre>
+   * The last column is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {ReadonlyMat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return "mat2d(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {ReadonlyMat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to translate
+   * @param {ReadonlyVec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 matrix from the given quaternion
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyMat4} a Mat4 to derive the normal matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {ReadonlyMat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return "mat3(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {ReadonlyMat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {ReadonlyVec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Rotates a mat4 by the given angle around the given axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {ReadonlyQuat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @param {ReadonlyVec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {ReadonlyMat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {ReadonlyMat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
+    r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
+    r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {ReadonlyVec3} a The first operand
+   * @param {ReadonlyVec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        bx = b[0],
+        by = b[1],
+        bz = b[2],
+        mag1 = Math.sqrt(ax * ax + ay * ay + az * az),
+        mag2 = Math.sqrt(bx * bx + by * by + bz * bz),
+        mag = mag1 * mag2,
+        cosine = mag && dot(a, b) / mag;
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {ReadonlyVec4} result the receiving vector
+   * @param {ReadonlyVec4} U the first vector
+   * @param {ReadonlyVec4} V the second vector
+   * @param {ReadonlyVec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return "vec4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyVec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {ReadonlyQuat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Gets the angular distance between two unit quaternions
+   *
+   * @param  {ReadonlyQuat} a     Origin unit quaternion
+   * @param  {ReadonlyQuat} b     Destination unit quaternion
+   * @return {Number}     Angle, in radians, between the two quaternions
+   */
+
+  function getAngle(a, b) {
+    var dotproduct = dot$2(a, b);
+    return Math.acos(2 * dotproduct * dotproduct - 1);
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Calculate the exponential of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function exp(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var et = Math.exp(w);
+    var s = r > 0 ? et * Math.sin(r) / r : 0;
+    out[0] = x * s;
+    out[1] = y * s;
+    out[2] = z * s;
+    out[3] = et * Math.cos(r);
+    return out;
+  }
+  /**
+   * Calculate the natural logarithm of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function ln(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var t = r > 0 ? Math.atan2(r, w) / r : 0;
+    out[0] = x * t;
+    out[1] = y * t;
+    out[2] = z * t;
+    out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w);
+    return out;
+  }
+  /**
+   * Calculate the scalar power of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @param {Number} b amount to scale the quaternion by
+   * @returns {quat} out
+   */
+
+  function pow(out, a, b) {
+    ln(out, a);
+    scale$6(out, out, b);
+    exp(out, out);
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random unit quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyMat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {ReadonlyQuat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return "quat(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {ReadonlyQuat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat} a The first quaternion.
+   * @param {ReadonlyQuat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat} a The first vector.
+   * @param {ReadonlyQuat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {ReadonlyVec3} a the initial vector
+   * @param {ReadonlyVec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {ReadonlyQuat} c the third operand
+   * @param {ReadonlyQuat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {ReadonlyVec3} view  the vector representing the viewing direction
+   * @param {ReadonlyVec3} right the vector representing the local "right" direction
+   * @param {ReadonlyVec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    getAngle: getAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    exp: exp,
+    ln: ln,
+    pow: pow,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q a normalized quaternion
+   * @param {ReadonlyVec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyVec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {ReadonlyMat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {ReadonlyQuat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return "quat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ")";
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat2} a the first dual quaternion.
+   * @param {ReadonlyQuat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat2} a the first dual quat.
+   * @param {ReadonlyQuat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {ReadonlyVec2} a The vec2 point to rotate
+   * @param {ReadonlyVec2} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, rad) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(rad),
+        cosC = Math.cos(rad); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {ReadonlyVec2} a The first operand
+   * @param {ReadonlyVec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1],
+        // mag is the product of the magnitudes of a and b
+    mag = Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2),
+        // mag &&.. short circuits if mag == 0
+    cosine = mag && (x1 * x2 + y1 * y2) / mag; // Math.min(Math.max(cosine, -1), 1) clamps the cosine between -1 and 1
+
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return "vec2(" + a[0] + ", " + a[1] + ")";
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/basic_course/shader_basic/hello.js b/basic_course/shader_basic/hello.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b125088701f112e82f92d0ed6cc31c266bab655
--- /dev/null
+++ b/basic_course/shader_basic/hello.js
@@ -0,0 +1,273 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+var vertexData = [
+		// Backface (RED/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,  0.0,  0.0,  
+         0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,  1.0,  1.0, 
+         0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,  1.0, -0.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0, -0.0, -0.0, 
+        -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0, -0.0,  1.0, 
+         0.5,  0.5, -0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0,  
+		// Front (BLUE/WHITE) -> z = 0.5      
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,  1.0, -0.0, 
+         0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,  0.0,  1.0, 
+         0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,  1.0,  1.0, 
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0, -0.0, -0.0, 
+        -0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0, -0.0,  1.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0,  
+		// LEFT (GREEN/WHITE) -> z = 0.5     
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0, -0.0, -0.0, 
+        -0.5,  0.5,  0.5,  0.0, 1.0, 0.0, 1.0,  1.0,  1.0, 
+        -0.5,  0.5, -0.5,  0.0, 1.0, 0.0, 1.0,  1.0,  0.0, 
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0, -0.0, -0.0, 
+        -0.5, -0.5,  0.5,  0.0, 1.0, 0.0, 1.0, -0.0,  1.0, 
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,  1.0,  1.0,  
+		// RIGHT (YELLOE/WHITE) -> z = 0.5    
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0, -0.0, -0.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 0.0, 1.0,  1.0,  1.0, 
+         0.5,  0.5, -0.5,  1.0, 1.0, 0.0, 1.0,  1.0,  0.0, 
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0, -0.0, -0.0, 
+         0.5, -0.5,  0.5,  1.0, 1.0, 0.0, 1.0, -0.0,  1.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0,  
+		// BOTTON (MAGENTA/WHITE) -> z = 0.5 
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0, -0.0, -0.0, 
+         0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,  1.0,  1.0, 
+         0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,  1.0,  0.0, 
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0, -0.0, -0.0, 
+        -0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0, -0.0,  1.0, 
+         0.5, -0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0,  
+		// TOP (CYAN/WHITE) -> z = 0.5       
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0, -0.0, -0.0, 
+         0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,  1.0,  1.0, 
+         0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,  1.0,  0.0, 
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0, -0.0, -0.0, 
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0, -0.0,  1.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0 
+];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+	var texture = gl.createTexture(); 
+	gl.bindTexture(gl.TEXTURE_2D, texture);
+	// Fill the texture with a 1x1 red pixel.
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
+	var image = new Image();
+	image.src = "hylee_128.png";
+	image.addEventListener('load', function() {
+		// Now that the image has loaded make copy it to the texture.
+		gl.bindTexture(gl.TEXTURE_2D, texture);
+		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,gl.UNSIGNED_BYTE, image);
+		gl.generateMipmap(gl.TEXTURE_2D);
+		});
+	console.log(image);
+    return testGLError("initialiseBuffers and texture initialize");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			varying mediump vec2 texCoord;\
+			uniform sampler2D sampler2d;\
+			void main(void) \
+			{ \
+				gl_FragColor = texture2D(sampler2d, texCoord); \
+				gl_FragColor = pow(gl_FragColor, vec4(1.0, 1.0, 1.0, 1.0)); \
+				gl_FragColor.r = gl_FragColor.r * 0.299 + gl_FragColor.g * 0.587 + gl_FragColor.b * 0.114; \
+				gl_FragColor.g = gl_FragColor.r; \
+				gl_FragColor.b = gl_FragColor.r; \
+			    gl_FragColor.a = 1.0; \
+			}';
+
+	/*
+				gl_FragColor.r = gl_FragColor.g * 0.72 + gl_FragColor.r * 0.21 + 0.07 * gl_FragColor.b; \
+				gl_FragColor.g = gl_FragColor.r; \
+				gl_FragColor.b = gl_FragColor.r; \
+				*/
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			attribute highp vec2 myUV; \
+			uniform mediump mat4 mMat; \
+			uniform mediump mat4 vMat; \
+			uniform mediump mat4 pMat; \
+			varying  highp vec4 color;\
+			varying mediump vec2 texCoord;\
+			void main(void)  \
+			{ \
+				gl_Position = pMat * vMat * mMat * myVertex; \
+				gl_PointSize = 8.0; \
+				color = myColor; \
+				texCoord = myUV*2.0; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    gl.bindAttribLocation(gl.programObject, 2, "myUV");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    // console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+flag_animation = 0; 
+function toggleAnimation()
+{
+	flag_animation ^= 1; 
+}
+
+rotY = 0.0;
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+	gl.clearDepth(1.0);										// Added for depth Test 
+
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);	// Added for depth Test 
+	gl.enable(gl.DEPTH_TEST);								// Added for depth Test 
+
+    var mMatLocation = gl.getUniformLocation(gl.programObject, "mMat");
+    var vMatLocation = gl.getUniformLocation(gl.programObject, "vMat");
+    var pMatLocation = gl.getUniformLocation(gl.programObject, "pMat");
+    var mMat = []; 
+	mat4.translate(mMat, mMat, [0.5, 0.0, 0.0]); 
+	mat4.fromYRotation(mMat, rotY); 
+	if ( flag_animation ){
+		rotY += 0.01;
+	}
+	var vMat = [];
+	mat4.lookAt(vMat, [0.0, 0.0, 2.0], [0.0,0.0,0.0], [0.0, 1.0, 0.0]);
+	var pMat = [];
+	mat4.identity(pMat); 
+	mat4.perspective(pMat, 3.14/3.0, 800.0/600.0, 0.5, 5);
+
+    gl.uniformMatrix4fv(mMatLocation, gl.FALSE, mMat );
+    gl.uniformMatrix4fv(vMatLocation, gl.FALSE, vMat );
+    gl.uniformMatrix4fv(pMatLocation, gl.FALSE, pMat );
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+	//vertexData[0] += 0.01; 
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 36, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 36, 12);
+    gl.enableVertexAttribArray(2);
+    gl.vertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 36, 28);
+	//gl.vertexAttrib4f(1, 1.0, 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+	// gl.drawArrays(gl.LINE_STRIP, 0, 36); 
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+	// renderScene();
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/shader_basic/hylee_128.png b/basic_course/shader_basic/hylee_128.png
new file mode 100644
index 0000000000000000000000000000000000000000..defb2ed012c97f18b13109eb514f2438e10a93f9
Binary files /dev/null and b/basic_course/shader_basic/hylee_128.png differ
diff --git a/basic_course/shader_basic/index.html b/basic_course/shader_basic/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..d6fbd85e6f44b041cb3268e8d4c763536d79c2ca
--- /dev/null
+++ b/basic_course/shader_basic/index.html
@@ -0,0 +1,22 @@
+<html>
+
+<head>
+<title>WebGL Tutorial 11 - Texture Mapping</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js"> </script>
+<script> 
+window['mat4'] = glMatrix.mat4;
+window['vec4'] = glMatrix.vec4;
+window['vec3'] = glMatrix.vec4;
+</script>
+<script type="text/javascript" src="hello.js"> </script>
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+	<br>
+<button onclick="toggleAnimation()">Toggle Animation</button>
+</body>
+
+</html>
diff --git a/basic_course/shader_basic/mongoose-free-6.5.exe b/basic_course/shader_basic/mongoose-free-6.5.exe
new file mode 100644
index 0000000000000000000000000000000000000000..687772ef24c5d70c5fdd4e3aa0a9a020406e0dd3
Binary files /dev/null and b/basic_course/shader_basic/mongoose-free-6.5.exe differ
diff --git a/basic_course/shader_flat/.gitignore b/basic_course/shader_flat/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..b883f1fdc6d69146f477bba77c117fbbd33714af
--- /dev/null
+++ b/basic_course/shader_flat/.gitignore
@@ -0,0 +1 @@
+*.exe
diff --git a/basic_course/shader_flat/gl-matrix.js b/basic_course/shader_flat/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..4553f9ea44878e9b79894c1de08af95ea9814317
--- /dev/null
+++ b/basic_course/shader_flat/gl-matrix.js
@@ -0,0 +1,7611 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.3.0
+
+Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, (function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Float32ArrayConstructor | ArrayConstructor} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {ReadonlyMat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return "mat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {ReadonlyMat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {ReadonlyMat2} L the lower triangular matrix
+   * @param {ReadonlyMat2} D the diagonal matrix
+   * @param {ReadonlyMat2} U the upper triangular matrix
+   * @param {ReadonlyMat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, b,
+   *  c, d,
+   *  tx, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, b, 0,
+   *  c, d, 0,
+   *  tx, ty, 1]
+   * </pre>
+   * The last column is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {ReadonlyMat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return "mat2d(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {ReadonlyMat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to translate
+   * @param {ReadonlyVec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 matrix from the given quaternion
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyMat4} a Mat4 to derive the normal matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {ReadonlyMat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return "mat3(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {ReadonlyMat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {ReadonlyVec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Rotates a mat4 by the given angle around the given axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {ReadonlyQuat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @param {ReadonlyVec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {ReadonlyMat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {ReadonlyMat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
+    r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
+    r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {ReadonlyVec3} a The first operand
+   * @param {ReadonlyVec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        bx = b[0],
+        by = b[1],
+        bz = b[2],
+        mag1 = Math.sqrt(ax * ax + ay * ay + az * az),
+        mag2 = Math.sqrt(bx * bx + by * by + bz * bz),
+        mag = mag1 * mag2,
+        cosine = mag && dot(a, b) / mag;
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {ReadonlyVec4} result the receiving vector
+   * @param {ReadonlyVec4} U the first vector
+   * @param {ReadonlyVec4} V the second vector
+   * @param {ReadonlyVec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return "vec4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyVec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {ReadonlyQuat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Gets the angular distance between two unit quaternions
+   *
+   * @param  {ReadonlyQuat} a     Origin unit quaternion
+   * @param  {ReadonlyQuat} b     Destination unit quaternion
+   * @return {Number}     Angle, in radians, between the two quaternions
+   */
+
+  function getAngle(a, b) {
+    var dotproduct = dot$2(a, b);
+    return Math.acos(2 * dotproduct * dotproduct - 1);
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Calculate the exponential of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function exp(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var et = Math.exp(w);
+    var s = r > 0 ? et * Math.sin(r) / r : 0;
+    out[0] = x * s;
+    out[1] = y * s;
+    out[2] = z * s;
+    out[3] = et * Math.cos(r);
+    return out;
+  }
+  /**
+   * Calculate the natural logarithm of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function ln(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var t = r > 0 ? Math.atan2(r, w) / r : 0;
+    out[0] = x * t;
+    out[1] = y * t;
+    out[2] = z * t;
+    out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w);
+    return out;
+  }
+  /**
+   * Calculate the scalar power of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @param {Number} b amount to scale the quaternion by
+   * @returns {quat} out
+   */
+
+  function pow(out, a, b) {
+    ln(out, a);
+    scale$6(out, out, b);
+    exp(out, out);
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random unit quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyMat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {ReadonlyQuat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return "quat(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {ReadonlyQuat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat} a The first quaternion.
+   * @param {ReadonlyQuat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat} a The first vector.
+   * @param {ReadonlyQuat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {ReadonlyVec3} a the initial vector
+   * @param {ReadonlyVec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {ReadonlyQuat} c the third operand
+   * @param {ReadonlyQuat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {ReadonlyVec3} view  the vector representing the viewing direction
+   * @param {ReadonlyVec3} right the vector representing the local "right" direction
+   * @param {ReadonlyVec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    getAngle: getAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    exp: exp,
+    ln: ln,
+    pow: pow,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q a normalized quaternion
+   * @param {ReadonlyVec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyVec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {ReadonlyMat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {ReadonlyQuat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return "quat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ")";
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat2} a the first dual quaternion.
+   * @param {ReadonlyQuat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat2} a the first dual quat.
+   * @param {ReadonlyQuat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {ReadonlyVec2} a The vec2 point to rotate
+   * @param {ReadonlyVec2} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, rad) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(rad),
+        cosC = Math.cos(rad); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {ReadonlyVec2} a The first operand
+   * @param {ReadonlyVec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1],
+        // mag is the product of the magnitudes of a and b
+    mag = Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2),
+        // mag &&.. short circuits if mag == 0
+    cosine = mag && (x1 * x2 + y1 * y2) / mag; // Math.min(Math.max(cosine, -1), 1) clamps the cosine between -1 and 1
+
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return "vec2(" + a[0] + ", " + a[1] + ")";
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/basic_course/shader_flat/hello.js b/basic_course/shader_flat/hello.js
new file mode 100644
index 0000000000000000000000000000000000000000..5450a8f5e74f39a967868367fa036d0f156f88f2
--- /dev/null
+++ b/basic_course/shader_flat/hello.js
@@ -0,0 +1,283 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+var vertexData = [
+		// Backface (RED/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,  0.0,  0.0, 0.0, 0.0, -1.0, 
+         0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,  1.0,  1.0, 0.0, 0.0, -1.0, 
+         0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,  1.0, -0.0, 0.0, 0.0, -1.0, 
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0, -0.0, -0.0, 0.0, 0.0, -1.0, 
+        -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0, -0.0,  1.0, 0.0, 0.0, -1.0, 
+         0.5,  0.5, -0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0, 0.0, 0.0, -1.0, 
+		// Front (BLUE/WHITE) -> z = 0.5      
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,  1.0, -0.0, 0.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,  0.0,  1.0, 0.0, 0.0, 1.0,
+         0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,  1.0,  1.0, 0.0, 0.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0, -0.0, -0.0, 0.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0, -0.0,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0, 0.0, 0.0, 1.0,
+		// LEFT (GREEN/WHITE) -> z = 0.5     
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0, -0.0, -0.0, -1.0, 0.0, 0.0, 
+        -0.5,  0.5,  0.5,  0.0, 1.0, 0.0, 1.0,  1.0,  1.0, -1.0, 0.0, 0.0, 
+        -0.5,  0.5, -0.5,  0.0, 1.0, 0.0, 1.0,  1.0,  0.0, -1.0, 0.0, 0.0, 
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0, -0.0, -0.0, -1.0, 0.0, 0.0, 
+        -0.5, -0.5,  0.5,  0.0, 1.0, 0.0, 1.0, -0.0,  1.0, -1.0, 0.0, 0.0, 
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,  1.0,  1.0, -1.0, 0.0, 0.0, 
+		// RIGHT (YELLOE/WHITE) -> z = 0.5    
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0, -0.0, -0.0, 1.0, 0.0, 0.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 0.0, 1.0,  1.0,  1.0, 1.0, 0.0, 0.0, 
+         0.5,  0.5, -0.5,  1.0, 1.0, 0.0, 1.0,  1.0,  0.0, 1.0, 0.0, 0.0, 
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0, -0.0, -0.0, 1.0, 0.0, 0.0, 
+         0.5, -0.5,  0.5,  1.0, 1.0, 0.0, 1.0, -0.0,  1.0, 1.0, 0.0, 0.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0, 1.0, 0.0, 0.0, 
+		// BOTTON (MAGENTA/WHITE) -> z = 0.5 
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0, -0.0, -0.0, 0.0, -1.0, 0.0, 
+         0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,  1.0,  1.0, 0.0, -1.0, 0.0, 
+         0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,  1.0,  0.0, 0.0, -1.0, 0.0, 
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0, -0.0, -0.0, 0.0, -1.0, 0.0, 
+        -0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0, -0.0,  1.0, 0.0, -1.0, 0.0, 
+         0.5, -0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0, 0.0, -1.0, 0.0, 
+		// TOP (CYAN/WHITE) -> z = 0.5       
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0, -0.0, -0.0, 0.0, 1.0, 0.0, 
+         0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,  1.0,  1.0, 0.0, 1.0, 0.0, 
+         0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,  1.0,  0.0, 0.0, 1.0, 0.0, 
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0, -0.0, -0.0, 0.0, 1.0, 0.0, 
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0, -0.0,  1.0, 0.0, 1.0, 0.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0,  0.0, 1.0, 0.0 
+];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+	var texture = gl.createTexture(); 
+	gl.bindTexture(gl.TEXTURE_2D, texture);
+	// Fill the texture with a 1x1 red pixel.
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
+	var image = new Image();
+	image.src = "hylee_128.png";
+	image.addEventListener('load', function() {
+		// Now that the image has loaded make copy it to the texture.
+		gl.bindTexture(gl.TEXTURE_2D, texture);
+		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,gl.UNSIGNED_BYTE, image);
+		gl.generateMipmap(gl.TEXTURE_2D);
+		});
+	console.log(image);
+    return testGLError("initialiseBuffers and texture initialize");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			varying mediump vec2 texCoord;\
+			varying highp vec3 v; \
+			varying highp vec3 n; \
+			uniform sampler2D sampler2d;\
+			void main(void) \
+			{ \
+				gl_FragColor = color + 0.0 * texture2D(sampler2d, texCoord); \
+			    gl_FragColor.a = 1.0; \
+			}';
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			attribute highp vec2 myUV; \
+			attribute highp vec3 myNormal; \
+			uniform mediump mat4 mMat; \
+			uniform mediump mat4 vMat; \
+			uniform mediump mat4 pMat; \
+			uniform mediump mat4 normalMat; \
+			varying  highp vec4 color;\
+			varying mediump vec2 texCoord;\
+			varying highp vec3 v; \
+			varying highp vec3 n; \
+			void main(void)  \
+			{ \
+				vec3 light; \
+				vec4 light_color; \
+				light = vec3(1.0, 1.0, 1.0); \
+				light_color = vec4 (1.0, 1.0, 1.0, 1.0); \
+				normalize(light); \
+				n = vec3(normalMat * vec4(myNormal, 1.0)); \
+				normalize(n); \
+				gl_Position = pMat * vMat * mMat * myVertex; \
+				color = light_color * myColor * max(dot(light, n), 0.3);  \
+				texCoord = myUV*2.0; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    gl.bindAttribLocation(gl.programObject, 2, "myUV");
+    gl.bindAttribLocation(gl.programObject, 3, "myNormal");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    // console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+flag_animation = 0; 
+function toggleAnimation()
+{
+	flag_animation ^= 1; 
+}
+
+rotY = 0.0;
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+	gl.clearDepth(1.0);										// Added for depth Test 
+
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);	// Added for depth Test 
+	gl.enable(gl.DEPTH_TEST);								// Added for depth Test 
+
+    var mMatLocation = gl.getUniformLocation(gl.programObject, "mMat");
+    var vMatLocation = gl.getUniformLocation(gl.programObject, "vMat");
+    var pMatLocation = gl.getUniformLocation(gl.programObject, "pMat");
+    var normalMatLocation = gl.getUniformLocation(gl.programObject, "normalMat");
+    var mMat = []; 
+	mat4.fromYRotation(mMat, rotY); 
+	mat4.rotateX(mMat, mMat, rotY*2); 
+	if ( flag_animation ){
+		rotY += 0.01;
+	}
+	var vMat = [];
+	mat4.lookAt(vMat, [0.0, 0.0, 2.0], [0.0,0.0,0.0], [0.0, 1.0, 0.0]);
+	//console.log(vMat); 
+	var pMat = [];
+	mat4.identity(pMat); 
+	mat4.perspective(pMat, 3.14/3.0, 800.0/600.0, 0.5, 5);
+	var normalMat = []; 
+	mat4.invert(normalMat, mMat); 
+	mat4.transpose(normalMat, normalMat); 
+
+    gl.uniformMatrix4fv(mMatLocation, gl.FALSE, mMat );
+    gl.uniformMatrix4fv(vMatLocation, gl.FALSE, vMat );
+    gl.uniformMatrix4fv(pMatLocation, gl.FALSE, pMat );
+    gl.uniformMatrix4fv(normalMatLocation, gl.FALSE, normalMat );
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+	//vertexData[0] += 0.01; 
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 48, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 48, 12);
+    gl.enableVertexAttribArray(2);
+    gl.vertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 48, 28);
+    gl.enableVertexAttribArray(3);
+    gl.vertexAttribPointer(3, 3, gl.FLOAT, gl.FALSE, 48, 36);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+	// gl.drawArrays(gl.LINE_STRIP, 0, 36); 
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+	// renderScene();
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/shader_flat/hylee_128.png b/basic_course/shader_flat/hylee_128.png
new file mode 100644
index 0000000000000000000000000000000000000000..defb2ed012c97f18b13109eb514f2438e10a93f9
Binary files /dev/null and b/basic_course/shader_flat/hylee_128.png differ
diff --git a/basic_course/shader_flat/index.html b/basic_course/shader_flat/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..d6fbd85e6f44b041cb3268e8d4c763536d79c2ca
--- /dev/null
+++ b/basic_course/shader_flat/index.html
@@ -0,0 +1,22 @@
+<html>
+
+<head>
+<title>WebGL Tutorial 11 - Texture Mapping</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js"> </script>
+<script> 
+window['mat4'] = glMatrix.mat4;
+window['vec4'] = glMatrix.vec4;
+window['vec3'] = glMatrix.vec4;
+</script>
+<script type="text/javascript" src="hello.js"> </script>
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+	<br>
+<button onclick="toggleAnimation()">Toggle Animation</button>
+</body>
+
+</html>
diff --git a/basic_course/shader_phong/.gitignore b/basic_course/shader_phong/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..b883f1fdc6d69146f477bba77c117fbbd33714af
--- /dev/null
+++ b/basic_course/shader_phong/.gitignore
@@ -0,0 +1 @@
+*.exe
diff --git a/basic_course/shader_phong/gl-matrix.js b/basic_course/shader_phong/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..4553f9ea44878e9b79894c1de08af95ea9814317
--- /dev/null
+++ b/basic_course/shader_phong/gl-matrix.js
@@ -0,0 +1,7611 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.3.0
+
+Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, (function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Float32ArrayConstructor | ArrayConstructor} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {ReadonlyMat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return "mat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {ReadonlyMat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {ReadonlyMat2} L the lower triangular matrix
+   * @param {ReadonlyMat2} D the diagonal matrix
+   * @param {ReadonlyMat2} U the upper triangular matrix
+   * @param {ReadonlyMat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, b,
+   *  c, d,
+   *  tx, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, b, 0,
+   *  c, d, 0,
+   *  tx, ty, 1]
+   * </pre>
+   * The last column is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {ReadonlyMat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return "mat2d(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {ReadonlyMat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to translate
+   * @param {ReadonlyVec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 matrix from the given quaternion
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyMat4} a Mat4 to derive the normal matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {ReadonlyMat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return "mat3(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {ReadonlyMat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {ReadonlyVec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Rotates a mat4 by the given angle around the given axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {ReadonlyQuat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @param {ReadonlyVec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {ReadonlyMat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {ReadonlyMat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
+    r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
+    r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {ReadonlyVec3} a The first operand
+   * @param {ReadonlyVec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        bx = b[0],
+        by = b[1],
+        bz = b[2],
+        mag1 = Math.sqrt(ax * ax + ay * ay + az * az),
+        mag2 = Math.sqrt(bx * bx + by * by + bz * bz),
+        mag = mag1 * mag2,
+        cosine = mag && dot(a, b) / mag;
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {ReadonlyVec4} result the receiving vector
+   * @param {ReadonlyVec4} U the first vector
+   * @param {ReadonlyVec4} V the second vector
+   * @param {ReadonlyVec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return "vec4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyVec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {ReadonlyQuat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Gets the angular distance between two unit quaternions
+   *
+   * @param  {ReadonlyQuat} a     Origin unit quaternion
+   * @param  {ReadonlyQuat} b     Destination unit quaternion
+   * @return {Number}     Angle, in radians, between the two quaternions
+   */
+
+  function getAngle(a, b) {
+    var dotproduct = dot$2(a, b);
+    return Math.acos(2 * dotproduct * dotproduct - 1);
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Calculate the exponential of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function exp(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var et = Math.exp(w);
+    var s = r > 0 ? et * Math.sin(r) / r : 0;
+    out[0] = x * s;
+    out[1] = y * s;
+    out[2] = z * s;
+    out[3] = et * Math.cos(r);
+    return out;
+  }
+  /**
+   * Calculate the natural logarithm of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function ln(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var t = r > 0 ? Math.atan2(r, w) / r : 0;
+    out[0] = x * t;
+    out[1] = y * t;
+    out[2] = z * t;
+    out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w);
+    return out;
+  }
+  /**
+   * Calculate the scalar power of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @param {Number} b amount to scale the quaternion by
+   * @returns {quat} out
+   */
+
+  function pow(out, a, b) {
+    ln(out, a);
+    scale$6(out, out, b);
+    exp(out, out);
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random unit quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyMat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {ReadonlyQuat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return "quat(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {ReadonlyQuat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat} a The first quaternion.
+   * @param {ReadonlyQuat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat} a The first vector.
+   * @param {ReadonlyQuat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {ReadonlyVec3} a the initial vector
+   * @param {ReadonlyVec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {ReadonlyQuat} c the third operand
+   * @param {ReadonlyQuat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {ReadonlyVec3} view  the vector representing the viewing direction
+   * @param {ReadonlyVec3} right the vector representing the local "right" direction
+   * @param {ReadonlyVec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    getAngle: getAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    exp: exp,
+    ln: ln,
+    pow: pow,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q a normalized quaternion
+   * @param {ReadonlyVec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyVec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {ReadonlyMat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {ReadonlyQuat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return "quat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ")";
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat2} a the first dual quaternion.
+   * @param {ReadonlyQuat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat2} a the first dual quat.
+   * @param {ReadonlyQuat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {ReadonlyVec2} a The vec2 point to rotate
+   * @param {ReadonlyVec2} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, rad) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(rad),
+        cosC = Math.cos(rad); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {ReadonlyVec2} a The first operand
+   * @param {ReadonlyVec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1],
+        // mag is the product of the magnitudes of a and b
+    mag = Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2),
+        // mag &&.. short circuits if mag == 0
+    cosine = mag && (x1 * x2 + y1 * y2) / mag; // Math.min(Math.max(cosine, -1), 1) clamps the cosine between -1 and 1
+
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return "vec2(" + a[0] + ", " + a[1] + ")";
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/basic_course/shader_phong/hello.js b/basic_course/shader_phong/hello.js
new file mode 100644
index 0000000000000000000000000000000000000000..b499f9648fe29881addb6b49fdb12fd498d632c8
--- /dev/null
+++ b/basic_course/shader_phong/hello.js
@@ -0,0 +1,291 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+var vertexData = [
+		// Backface (RED/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,  0.0,  0.0, 0.0, 0.0, -1.0, 
+         0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,  1.0,  1.0, 0.0, 0.0, -1.0, 
+         0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,  1.0, -0.0, 0.0, 0.0, -1.0, 
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0, -0.0, -0.0, 0.0, 0.0, -1.0, 
+        -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0, -0.0,  1.0, 0.0, 0.0, -1.0, 
+         0.5,  0.5, -0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0, 0.0, 0.0, -1.0, 
+		// Front (BLUE/WHITE) -> z = 0.5      
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,  1.0, -0.0, 0.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,  0.0,  1.0, 0.0, 0.0, 1.0,
+         0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,  1.0,  1.0, 0.0, 0.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0, -0.0, -0.0, 0.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0, -0.0,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0, 0.0, 0.0, 1.0,
+		// LEFT (GREEN/WHITE) -> z = 0.5     
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0, -0.0, -0.0, -1.0, 0.0, 0.0, 
+        -0.5,  0.5,  0.5,  0.0, 1.0, 0.0, 1.0,  1.0,  1.0, -1.0, 0.0, 0.0, 
+        -0.5,  0.5, -0.5,  0.0, 1.0, 0.0, 1.0,  1.0,  0.0, -1.0, 0.0, 0.0, 
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0, -0.0, -0.0, -1.0, 0.0, 0.0, 
+        -0.5, -0.5,  0.5,  0.0, 1.0, 0.0, 1.0, -0.0,  1.0, -1.0, 0.0, 0.0, 
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,  1.0,  1.0, -1.0, 0.0, 0.0, 
+		// RIGHT (YELLOE/WHITE) -> z = 0.5    
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0, -0.0, -0.0, 1.0, 0.0, 0.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 0.0, 1.0,  1.0,  1.0, 1.0, 0.0, 0.0, 
+         0.5,  0.5, -0.5,  1.0, 1.0, 0.0, 1.0,  1.0,  0.0, 1.0, 0.0, 0.0, 
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0, -0.0, -0.0, 1.0, 0.0, 0.0, 
+         0.5, -0.5,  0.5,  1.0, 1.0, 0.0, 1.0, -0.0,  1.0, 1.0, 0.0, 0.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0, 1.0, 0.0, 0.0, 
+		// BOTTON (MAGENTA/WHITE) -> z = 0.5 
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0, -0.0, -0.0, 0.0, -1.0, 0.0, 
+         0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,  1.0,  1.0, 0.0, -1.0, 0.0, 
+         0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,  1.0,  0.0, 0.0, -1.0, 0.0, 
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0, -0.0, -0.0, 0.0, -1.0, 0.0, 
+        -0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0, -0.0,  1.0, 0.0, -1.0, 0.0, 
+         0.5, -0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0, 0.0, -1.0, 0.0, 
+		// TOP (CYAN/WHITE) -> z = 0.5       
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0, -0.0, -0.0, 0.0, 1.0, 0.0, 
+         0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,  1.0,  1.0, 0.0, 1.0, 0.0, 
+         0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,  1.0,  0.0, 0.0, 1.0, 0.0, 
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0, -0.0, -0.0, 0.0, 1.0, 0.0, 
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0, -0.0,  1.0, 0.0, 1.0, 0.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0,  0.0, 1.0, 0.0 
+];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+	var texture = gl.createTexture(); 
+	gl.bindTexture(gl.TEXTURE_2D, texture);
+	// Fill the texture with a 1x1 red pixel.
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
+	var image = new Image();
+	image.src = "hylee_128.png";
+	image.addEventListener('load', function() {
+		// Now that the image has loaded make copy it to the texture.
+		gl.bindTexture(gl.TEXTURE_2D, texture);
+		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,gl.UNSIGNED_BYTE, image);
+		gl.generateMipmap(gl.TEXTURE_2D);
+		});
+	console.log(image);
+    return testGLError("initialiseBuffers and texture initialize");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			varying mediump vec2 texCoord;\
+			varying highp vec3 v,n; \
+			uniform sampler2D sampler2d;\
+			void main(void) \
+			{ \
+				highp vec3 L, E, R; \
+				highp vec3 light; \
+				highp vec4 light_color; \
+				highp float dist;\
+				highp vec4 diffuse; \
+				highp vec4 specular;\
+				highp vec4 specular_color;\
+				light = vec3(1.0, 1.0, +2.8); \
+				light_color = vec4 (1.0, 1.0, 1.0, 1.0); \
+				specular_color = vec4 (1.0, 1.0, 1.0, 1.0); \
+				L = normalize(light - v);\
+				E = normalize(-v);\
+				R = normalize(-reflect(L, n)); \
+				normalize(light); \
+				dist = distance(v, light); \
+				dist = 2.0 / (dist*dist); \
+				diffuse = light_color * color * dist * max(dot(light, n), 0.3); \
+				specular = specular_color * pow(max(dot(R,E), 0.05), 1.0); \
+				gl_FragColor = specular + diffuse + 0.0 * texture2D(sampler2d, texCoord); \
+			    gl_FragColor.a = 1.0; \
+			}';
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			attribute highp vec2 myUV; \
+			attribute highp vec3 myNormal; \
+			uniform mediump mat4 vmMat; \
+			uniform mediump mat4 pMat; \
+			uniform mediump mat4 normalMat; \
+			varying highp vec4 color;\
+			varying mediump vec2 texCoord;\
+			varying highp vec3 v; \
+			varying highp vec3 n; \
+			void main(void)  \
+			{ \
+				n = vec3(normalMat * vec4(myNormal, 1.0)); \
+				normalize(n); \
+				v = vec3(vmMat * myVertex); \
+				gl_Position = pMat * vec4(v,1.0); \
+				color = myColor ; \
+				texCoord = myUV*2.0; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    gl.bindAttribLocation(gl.programObject, 2, "myUV");
+    gl.bindAttribLocation(gl.programObject, 3, "myNormal");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    // console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+flag_animation = 0; 
+function toggleAnimation()
+{
+	flag_animation ^= 1; 
+}
+
+rotY = 0.0;
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+	gl.clearDepth(1.0);										// Added for depth Test 
+
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);	// Added for depth Test 
+	gl.enable(gl.DEPTH_TEST);								// Added for depth Test 
+
+    var vmMatLocation = gl.getUniformLocation(gl.programObject, "vmMat");
+    var pMatLocation = gl.getUniformLocation(gl.programObject, "pMat");
+    var normalMatLocation = gl.getUniformLocation(gl.programObject, "normalMat");
+    var vmMat = []; 
+	mat4.lookAt(vmMat, [0.0, 0.0, 2.0], [0.0,0.0,0.0], [0.0, 1.0, 0.0]);
+	mat4.rotateY(vmMat, vmMat, rotY); 
+	mat4.rotateX(vmMat, vmMat, rotY*2); 
+	if ( flag_animation ){
+		rotY += 0.01;
+	}
+	var pMat = [];
+	mat4.identity(pMat); 
+	mat4.perspective(pMat, 3.14/3.0, 800.0/600.0, 0.5, 5);
+	var normalMat = []; 
+	mat4.invert(normalMat, vmMat); 
+	mat4.transpose(normalMat, normalMat); 
+
+    gl.uniformMatrix4fv(vmMatLocation, gl.FALSE, vmMat );
+    gl.uniformMatrix4fv(pMatLocation, gl.FALSE, pMat );
+    gl.uniformMatrix4fv(normalMatLocation, gl.FALSE, normalMat );
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+	//vertexData[0] += 0.01; 
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 48, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 48, 12);
+    gl.enableVertexAttribArray(2);
+    gl.vertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 48, 28);
+    gl.enableVertexAttribArray(3);
+    gl.vertexAttribPointer(3, 3, gl.FLOAT, gl.FALSE, 48, 36);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+	// gl.drawArrays(gl.LINE_STRIP, 0, 36); 
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+	// renderScene();
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/shader_phong/hylee_128.png b/basic_course/shader_phong/hylee_128.png
new file mode 100644
index 0000000000000000000000000000000000000000..defb2ed012c97f18b13109eb514f2438e10a93f9
Binary files /dev/null and b/basic_course/shader_phong/hylee_128.png differ
diff --git a/basic_course/shader_phong/index.html b/basic_course/shader_phong/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..d6fbd85e6f44b041cb3268e8d4c763536d79c2ca
--- /dev/null
+++ b/basic_course/shader_phong/index.html
@@ -0,0 +1,22 @@
+<html>
+
+<head>
+<title>WebGL Tutorial 11 - Texture Mapping</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js"> </script>
+<script> 
+window['mat4'] = glMatrix.mat4;
+window['vec4'] = glMatrix.vec4;
+window['vec3'] = glMatrix.vec4;
+</script>
+<script type="text/javascript" src="hello.js"> </script>
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+	<br>
+<button onclick="toggleAnimation()">Toggle Animation</button>
+</body>
+
+</html>
diff --git a/basic_course/texture/gl-matrix.js b/basic_course/texture/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..4553f9ea44878e9b79894c1de08af95ea9814317
--- /dev/null
+++ b/basic_course/texture/gl-matrix.js
@@ -0,0 +1,7611 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.3.0
+
+Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, (function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Float32ArrayConstructor | ArrayConstructor} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {ReadonlyMat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return "mat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {ReadonlyMat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {ReadonlyMat2} L the lower triangular matrix
+   * @param {ReadonlyMat2} D the diagonal matrix
+   * @param {ReadonlyMat2} U the upper triangular matrix
+   * @param {ReadonlyMat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, b,
+   *  c, d,
+   *  tx, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, b, 0,
+   *  c, d, 0,
+   *  tx, ty, 1]
+   * </pre>
+   * The last column is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {ReadonlyMat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return "mat2d(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {ReadonlyMat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to translate
+   * @param {ReadonlyVec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 matrix from the given quaternion
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyMat4} a Mat4 to derive the normal matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {ReadonlyMat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return "mat3(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {ReadonlyMat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {ReadonlyVec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Rotates a mat4 by the given angle around the given axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {ReadonlyQuat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @param {ReadonlyVec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {ReadonlyMat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {ReadonlyMat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
+    r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
+    r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {ReadonlyVec3} a The first operand
+   * @param {ReadonlyVec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        bx = b[0],
+        by = b[1],
+        bz = b[2],
+        mag1 = Math.sqrt(ax * ax + ay * ay + az * az),
+        mag2 = Math.sqrt(bx * bx + by * by + bz * bz),
+        mag = mag1 * mag2,
+        cosine = mag && dot(a, b) / mag;
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {ReadonlyVec4} result the receiving vector
+   * @param {ReadonlyVec4} U the first vector
+   * @param {ReadonlyVec4} V the second vector
+   * @param {ReadonlyVec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return "vec4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyVec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {ReadonlyQuat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Gets the angular distance between two unit quaternions
+   *
+   * @param  {ReadonlyQuat} a     Origin unit quaternion
+   * @param  {ReadonlyQuat} b     Destination unit quaternion
+   * @return {Number}     Angle, in radians, between the two quaternions
+   */
+
+  function getAngle(a, b) {
+    var dotproduct = dot$2(a, b);
+    return Math.acos(2 * dotproduct * dotproduct - 1);
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Calculate the exponential of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function exp(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var et = Math.exp(w);
+    var s = r > 0 ? et * Math.sin(r) / r : 0;
+    out[0] = x * s;
+    out[1] = y * s;
+    out[2] = z * s;
+    out[3] = et * Math.cos(r);
+    return out;
+  }
+  /**
+   * Calculate the natural logarithm of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function ln(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var t = r > 0 ? Math.atan2(r, w) / r : 0;
+    out[0] = x * t;
+    out[1] = y * t;
+    out[2] = z * t;
+    out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w);
+    return out;
+  }
+  /**
+   * Calculate the scalar power of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @param {Number} b amount to scale the quaternion by
+   * @returns {quat} out
+   */
+
+  function pow(out, a, b) {
+    ln(out, a);
+    scale$6(out, out, b);
+    exp(out, out);
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random unit quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyMat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {ReadonlyQuat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return "quat(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {ReadonlyQuat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat} a The first quaternion.
+   * @param {ReadonlyQuat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat} a The first vector.
+   * @param {ReadonlyQuat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {ReadonlyVec3} a the initial vector
+   * @param {ReadonlyVec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {ReadonlyQuat} c the third operand
+   * @param {ReadonlyQuat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {ReadonlyVec3} view  the vector representing the viewing direction
+   * @param {ReadonlyVec3} right the vector representing the local "right" direction
+   * @param {ReadonlyVec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    getAngle: getAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    exp: exp,
+    ln: ln,
+    pow: pow,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q a normalized quaternion
+   * @param {ReadonlyVec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyVec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {ReadonlyMat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {ReadonlyQuat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return "quat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ")";
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat2} a the first dual quaternion.
+   * @param {ReadonlyQuat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat2} a the first dual quat.
+   * @param {ReadonlyQuat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {ReadonlyVec2} a The vec2 point to rotate
+   * @param {ReadonlyVec2} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, rad) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(rad),
+        cosC = Math.cos(rad); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {ReadonlyVec2} a The first operand
+   * @param {ReadonlyVec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1],
+        // mag is the product of the magnitudes of a and b
+    mag = Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2),
+        // mag &&.. short circuits if mag == 0
+    cosine = mag && (x1 * x2 + y1 * y2) / mag; // Math.min(Math.max(cosine, -1), 1) clamps the cosine between -1 and 1
+
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return "vec2(" + a[0] + ", " + a[1] + ")";
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/basic_course/texture/hello.js b/basic_course/texture/hello.js
new file mode 100644
index 0000000000000000000000000000000000000000..7a83403b6f61aabd07561de77a2411ad4849fa25
--- /dev/null
+++ b/basic_course/texture/hello.js
@@ -0,0 +1,268 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+var vertexData = [
+		// Backface (RED/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,  0.0,  0.0,  
+         0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,  1.0,  1.0, 
+         0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,  1.0, -0.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0, -0.0, -0.0, 
+        -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0, -0.0,  1.0, 
+         0.5,  0.5, -0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0,  
+		// Front (BLUE/WHITE) -> z = 0.5      
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0, -0.0, -0.0, 
+         0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,  1.0,  1.0, 
+         0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,  1.0, -0.0, 
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0, -0.0, -0.0, 
+        -0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0, -0.0,  1.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0,  
+		// LEFT (GREEN/WHITE) -> z = 0.5     
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0, -0.0, -0.0, 
+        -0.5,  0.5,  0.5,  0.0, 1.0, 0.0, 1.0,  1.0,  1.0, 
+        -0.5,  0.5, -0.5,  0.0, 1.0, 0.0, 1.0,  1.0,  0.0, 
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0, -0.0, -0.0, 
+        -0.5, -0.5,  0.5,  0.0, 1.0, 0.0, 1.0, -0.0,  1.0, 
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,  1.0,  1.0,  
+		// RIGHT (YELLOE/WHITE) -> z = 0.5    
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0, -0.0, -0.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 0.0, 1.0,  1.0,  1.0, 
+         0.5,  0.5, -0.5,  1.0, 1.0, 0.0, 1.0,  1.0,  0.0, 
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0, -0.0, -0.0, 
+         0.5, -0.5,  0.5,  1.0, 1.0, 0.0, 1.0, -0.0,  1.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0,  
+		// BOTTON (MAGENTA/WHITE) -> z = 0.5 
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0, -0.0, -0.0, 
+         0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,  1.0,  1.0, 
+         0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,  1.0,  0.0, 
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0, -0.0, -0.0, 
+        -0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0, -0.0,  1.0, 
+         0.5, -0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0,  
+		// TOP (CYAN/WHITE) -> z = 0.5       
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0, -0.0, -0.0, 
+         0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,  1.0,  1.0, 
+         0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,  1.0,  0.0, 
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0, -0.0, -0.0, 
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0, -0.0,  1.0, 
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0,  1.0,  1.0 
+];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+	var texture = gl.createTexture(); 
+	gl.bindTexture(gl.TEXTURE_2D, texture);
+	// Fill the texture with a 1x1 red pixel.
+	const texData = new Uint8Array([255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 255, 255, 0, 255]);
+	gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, texData); 
+	//gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST); // It is default
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
+	// Asynchronously load an image
+	/*
+	var image = new Image();
+	image.src = "hylee_128.png";
+	image.addEventListener('load', function() {
+		// Now that the image has loaded make copy it to the texture.
+		gl.bindTexture(gl.TEXTURE_2D, texture);
+		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,gl.UNSIGNED_BYTE, image);
+		gl.generateMipmap(gl.TEXTURE_2D);
+		});
+	*/
+    return testGLError("initialiseBuffers and texture initialize");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			varying mediump vec2 texCoord;\
+			uniform sampler2D sampler2d;\
+			void main(void) \
+			{ \
+				gl_FragColor = 0.0 * color + 1.0 * texture2D(sampler2d, texCoord); \
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			attribute highp vec2 myUV; \
+			uniform mediump mat4 mMat; \
+			uniform mediump mat4 vMat; \
+			uniform mediump mat4 pMat; \
+			varying  highp vec4 color;\
+			varying mediump vec2 texCoord;\
+			void main(void)  \
+			{ \
+				gl_Position = pMat * vMat * mMat * myVertex; \
+				gl_PointSize = 8.0; \
+				color = myColor; \
+				texCoord = myUV*3.0; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    gl.bindAttribLocation(gl.programObject, 2, "myUV");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    // console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+flag_animation = 0; 
+function toggleAnimation()
+{
+	flag_animation ^= 1; 
+}
+
+rotY = 0.0;
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+	gl.clearDepth(1.0);										// Added for depth Test 
+
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);	// Added for depth Test 
+	gl.enable(gl.DEPTH_TEST);								// Added for depth Test 
+
+    var mMatLocation = gl.getUniformLocation(gl.programObject, "mMat");
+    var vMatLocation = gl.getUniformLocation(gl.programObject, "vMat");
+    var pMatLocation = gl.getUniformLocation(gl.programObject, "pMat");
+    var mMat = []; 
+	mat4.translate(mMat, mMat, [0.5, 0.0, 0.0]); 
+	mat4.fromYRotation(mMat, rotY); 
+	if ( flag_animation ){
+		rotY += 0.01;
+	}
+	var vMat = [];
+	mat4.lookAt(vMat, [0.0, 0.0, 2.0], [0.0,0.0,0.0], [0.0, 1.0, 0.0]);
+	var pMat = [];
+	mat4.identity(pMat); 
+	mat4.perspective(pMat, 3.14/2.0, 800.0/600.0, 0.5, 5);
+
+    gl.uniformMatrix4fv(mMatLocation, gl.FALSE, mMat );
+    gl.uniformMatrix4fv(vMatLocation, gl.FALSE, vMat );
+    gl.uniformMatrix4fv(pMatLocation, gl.FALSE, pMat );
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+	//vertexData[0] += 0.01; 
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 36, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 36, 12);
+    gl.enableVertexAttribArray(2);
+    gl.vertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 36, 28);
+	//gl.vertexAttrib4f(1, 1.0, 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+	// gl.drawArrays(gl.LINE_STRIP, 0, 36); 
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+	// renderScene();
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/texture/hylee_128.png b/basic_course/texture/hylee_128.png
new file mode 100644
index 0000000000000000000000000000000000000000..defb2ed012c97f18b13109eb514f2438e10a93f9
Binary files /dev/null and b/basic_course/texture/hylee_128.png differ
diff --git a/basic_course/texture/index.html b/basic_course/texture/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..d6fbd85e6f44b041cb3268e8d4c763536d79c2ca
--- /dev/null
+++ b/basic_course/texture/index.html
@@ -0,0 +1,22 @@
+<html>
+
+<head>
+<title>WebGL Tutorial 11 - Texture Mapping</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js"> </script>
+<script> 
+window['mat4'] = glMatrix.mat4;
+window['vec4'] = glMatrix.vec4;
+window['vec3'] = glMatrix.vec4;
+</script>
+<script type="text/javascript" src="hello.js"> </script>
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+	<br>
+<button onclick="toggleAnimation()">Toggle Animation</button>
+</body>
+
+</html>
diff --git a/basic_course/transform-coding/.gitkeep b/basic_course/transform-coding/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/basic_course/transform-coding/gl-matrix.js b/basic_course/transform-coding/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..4553f9ea44878e9b79894c1de08af95ea9814317
--- /dev/null
+++ b/basic_course/transform-coding/gl-matrix.js
@@ -0,0 +1,7611 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.3.0
+
+Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, (function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Float32ArrayConstructor | ArrayConstructor} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {ReadonlyMat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return "mat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {ReadonlyMat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {ReadonlyMat2} L the lower triangular matrix
+   * @param {ReadonlyMat2} D the diagonal matrix
+   * @param {ReadonlyMat2} U the upper triangular matrix
+   * @param {ReadonlyMat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, b,
+   *  c, d,
+   *  tx, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, b, 0,
+   *  c, d, 0,
+   *  tx, ty, 1]
+   * </pre>
+   * The last column is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {ReadonlyMat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return "mat2d(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {ReadonlyMat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to translate
+   * @param {ReadonlyVec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 matrix from the given quaternion
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyMat4} a Mat4 to derive the normal matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {ReadonlyMat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return "mat3(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {ReadonlyMat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {ReadonlyVec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Rotates a mat4 by the given angle around the given axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {ReadonlyQuat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @param {ReadonlyVec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {ReadonlyMat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {ReadonlyMat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
+    r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
+    r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {ReadonlyVec3} a The first operand
+   * @param {ReadonlyVec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        bx = b[0],
+        by = b[1],
+        bz = b[2],
+        mag1 = Math.sqrt(ax * ax + ay * ay + az * az),
+        mag2 = Math.sqrt(bx * bx + by * by + bz * bz),
+        mag = mag1 * mag2,
+        cosine = mag && dot(a, b) / mag;
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {ReadonlyVec4} result the receiving vector
+   * @param {ReadonlyVec4} U the first vector
+   * @param {ReadonlyVec4} V the second vector
+   * @param {ReadonlyVec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return "vec4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyVec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {ReadonlyQuat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Gets the angular distance between two unit quaternions
+   *
+   * @param  {ReadonlyQuat} a     Origin unit quaternion
+   * @param  {ReadonlyQuat} b     Destination unit quaternion
+   * @return {Number}     Angle, in radians, between the two quaternions
+   */
+
+  function getAngle(a, b) {
+    var dotproduct = dot$2(a, b);
+    return Math.acos(2 * dotproduct * dotproduct - 1);
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Calculate the exponential of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function exp(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var et = Math.exp(w);
+    var s = r > 0 ? et * Math.sin(r) / r : 0;
+    out[0] = x * s;
+    out[1] = y * s;
+    out[2] = z * s;
+    out[3] = et * Math.cos(r);
+    return out;
+  }
+  /**
+   * Calculate the natural logarithm of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function ln(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var t = r > 0 ? Math.atan2(r, w) / r : 0;
+    out[0] = x * t;
+    out[1] = y * t;
+    out[2] = z * t;
+    out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w);
+    return out;
+  }
+  /**
+   * Calculate the scalar power of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @param {Number} b amount to scale the quaternion by
+   * @returns {quat} out
+   */
+
+  function pow(out, a, b) {
+    ln(out, a);
+    scale$6(out, out, b);
+    exp(out, out);
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random unit quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyMat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {ReadonlyQuat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return "quat(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {ReadonlyQuat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat} a The first quaternion.
+   * @param {ReadonlyQuat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat} a The first vector.
+   * @param {ReadonlyQuat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {ReadonlyVec3} a the initial vector
+   * @param {ReadonlyVec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {ReadonlyQuat} c the third operand
+   * @param {ReadonlyQuat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {ReadonlyVec3} view  the vector representing the viewing direction
+   * @param {ReadonlyVec3} right the vector representing the local "right" direction
+   * @param {ReadonlyVec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    getAngle: getAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    exp: exp,
+    ln: ln,
+    pow: pow,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q a normalized quaternion
+   * @param {ReadonlyVec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyVec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {ReadonlyMat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {ReadonlyQuat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return "quat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ")";
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat2} a the first dual quaternion.
+   * @param {ReadonlyQuat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat2} a the first dual quat.
+   * @param {ReadonlyQuat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {ReadonlyVec2} a The vec2 point to rotate
+   * @param {ReadonlyVec2} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, rad) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(rad),
+        cosC = Math.cos(rad); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {ReadonlyVec2} a The first operand
+   * @param {ReadonlyVec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1],
+        // mag is the product of the magnitudes of a and b
+    mag = Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2),
+        // mag &&.. short circuits if mag == 0
+    cosine = mag && (x1 * x2 + y1 * y2) / mag; // Math.min(Math.max(cosine, -1), 1) clamps the cosine between -1 and 1
+
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return "vec2(" + a[0] + ", " + a[1] + ")";
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/basic_course/transform-coding/hello.js b/basic_course/transform-coding/hello.js
new file mode 100644
index 0000000000000000000000000000000000000000..eec12f6c63bc3936f715ebc0b56b5ee34aca7566
--- /dev/null
+++ b/basic_course/transform-coding/hello.js
@@ -0,0 +1,241 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+var vertexData = [
+		// Backface (RED/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 1.0, 1.0, 
+		// Front (BLUE/WHITE) -> z = 0.5
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// LEFT (GREEN/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0, 
+		// RIGHT (YELLOE/WHITE) -> z = 0.5
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// BOTTON (MAGENTA/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// TOP (CYAN/WHITE) -> z = 0.5
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0 
+];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color;\
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 mMat; \
+			uniform mediump mat4 vMat; \
+			uniform mediump mat4 pMat; \
+			varying  highp vec4 color;\
+			void main(void)  \
+			{ \
+				gl_Position = pMat * vMat * mMat * myVertex; \
+				gl_PointSize = 8.0; \
+				color = myColor; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    // console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+flag_animation = 0; 
+function toggleAnimation()
+{
+	flag_animation ^= 1; 
+}
+
+rotY = 0.0;
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+	gl.clearDepth(1.0);										// Added for depth Test 
+
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);	// Added for depth Test 
+	gl.enable(gl.DEPTH_TEST);								// Added for depth Test 
+
+    var mMatLocation = gl.getUniformLocation(gl.programObject, "mMat");
+    var vMatLocation = gl.getUniformLocation(gl.programObject, "vMat");
+    var pMatLocation = gl.getUniformLocation(gl.programObject, "pMat");
+    var mMat = []; 
+	mat4.translate(mMat, mMat, [0.5, 0.0, 0.0]); 
+	mat4.fromYRotation(mMat, rotY); 
+	if ( flag_animation ){
+		rotY += 0.01;
+	}
+	var vMat = [];
+	mat4.lookAt(vMat, [0.0, 0.0, 2.0], [0.0,0.0,0.0], [0.0, 1.0, 0.0]);
+	var pMat = [];
+	mat4.identity(pMat); 
+	mat4.perspective(pMat, 3.14/2.0, 800.0/600.0, 0.5, 5);
+	console.log("pMAT:", pMat);
+
+    gl.uniformMatrix4fv(mMatLocation, gl.FALSE, mMat );
+    gl.uniformMatrix4fv(vMatLocation, gl.FALSE, vMat );
+    gl.uniformMatrix4fv(pMatLocation, gl.FALSE, pMat );
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+	//vertexData[0] += 0.01; 
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    //gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
+	//gl.vertexAttrib4f(1, 1.0, 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+	// gl.drawArrays(gl.LINE_STRIP, 0, 36); 
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+	// renderScene();
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/transform-coding/hello_start.js b/basic_course/transform-coding/hello_start.js
new file mode 100644
index 0000000000000000000000000000000000000000..d765ae1c726af72d61c35dabe79759fca302ad65
--- /dev/null
+++ b/basic_course/transform-coding/hello_start.js
@@ -0,0 +1,232 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+var vertexData = [
+		// Backface (RED/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 1.0, 1.0, 
+		// Front (BLUE/WHITE) -> z = 0.5
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// LEFT (GREEN/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0, 
+		// RIGHT (YELLOE/WHITE) -> z = 0.5
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// BOTTON (MAGENTA/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// TOP (CYAN/WHITE) -> z = 0.5
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0 
+];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color;\
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 transformationMatrix; \
+			varying  highp vec4 color;\
+			void main(void)  \
+			{ \
+				gl_Position = transformationMatrix * myVertex; \
+				gl_PointSize = 8.0; \
+				color = myColor; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    // console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+flag_animation = 0; 
+function toggleAnimation()
+{
+	flag_animation ^= 1; 
+}
+
+rotY = 0.0;
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+	// gl.clearDepth(1.0);										// Added for depth Test 
+
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);	// Added for depth Test 
+	// gl.enable(gl.DEPTH_TEST);								// Added for depth Test 
+
+    var matrixLocation = gl.getUniformLocation(gl.programObject, "transformationMatrix");
+    var transformationMatrix = [
+        Math.cos(rotY), 0.0, Math.sin(rotY), 0.0,
+        0.0, 1.0, 0.0, 0.0,
+        -Math.sin(rotY), 0.0, Math.cos(rotY), 0.0,
+        0.0, 0.0, 0.0, 1.0
+    ];
+	if ( flag_animation ){
+		rotY += 0.01;
+	}
+
+    gl.uniformMatrix4fv(matrixLocation, gl.FALSE, transformationMatrix );
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+	//vertexData[0] += 0.01; 
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    //gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
+	//gl.vertexAttrib4f(1, 1.0, 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+	// gl.drawArrays(gl.LINE_STRIP, 0, 36); 
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+	// renderScene();
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/transform-coding/index.html b/basic_course/transform-coding/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..ea3ea9b98e0edd7858516fef6bef03c4f4add9e3
--- /dev/null
+++ b/basic_course/transform-coding/index.html
@@ -0,0 +1,22 @@
+<html>
+
+<head>
+<title>WebGL Tutorial 07 - Transform Coding</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js"> </script>
+<script> 
+window['mat4'] = glMatrix.mat4;
+window['vec4'] = glMatrix.vec4;
+window['vec3'] = glMatrix.vec4;
+</script>
+<script type="text/javascript" src="hello.js"> </script>
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+	<br>
+<button onclick="toggleAnimation()">Toggle Animation</button>
+</body>
+
+</html>
diff --git a/basic_course/transform-coding/index_start.html b/basic_course/transform-coding/index_start.html
new file mode 100644
index 0000000000000000000000000000000000000000..167016fa81ae8c07ab45ab98087570541718285c
--- /dev/null
+++ b/basic_course/transform-coding/index_start.html
@@ -0,0 +1,22 @@
+<html>
+
+<head>
+<title>WebGL Tutorial 07 - Transform Coding</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js"> </script>
+<script> 
+window['mat4'] = glMatrix.mat4;
+window['vec4'] = glMatrix.vec4;
+window['vec3'] = glMatrix.vec4;
+</script>
+<script type="text/javascript" src="hello_start.js"> </script>
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+	<br>
+<button onclick="toggleAnimation()">Toggle Animation</button>
+</body>
+
+</html>
diff --git a/basic_course/transform/.gitkeep b/basic_course/transform/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/basic_course/transform/gl-matrix.js b/basic_course/transform/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..4553f9ea44878e9b79894c1de08af95ea9814317
--- /dev/null
+++ b/basic_course/transform/gl-matrix.js
@@ -0,0 +1,7611 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.3.0
+
+Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, (function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Float32ArrayConstructor | ArrayConstructor} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {ReadonlyMat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return "mat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {ReadonlyMat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {ReadonlyMat2} L the lower triangular matrix
+   * @param {ReadonlyMat2} D the diagonal matrix
+   * @param {ReadonlyMat2} U the upper triangular matrix
+   * @param {ReadonlyMat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, b,
+   *  c, d,
+   *  tx, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, b, 0,
+   *  c, d, 0,
+   *  tx, ty, 1]
+   * </pre>
+   * The last column is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {ReadonlyMat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return "mat2d(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {ReadonlyMat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to translate
+   * @param {ReadonlyVec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 matrix from the given quaternion
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyMat4} a Mat4 to derive the normal matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {ReadonlyMat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return "mat3(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {ReadonlyMat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {ReadonlyVec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Rotates a mat4 by the given angle around the given axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {ReadonlyQuat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @param {ReadonlyVec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {ReadonlyMat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {ReadonlyMat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
+    r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
+    r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {ReadonlyVec3} a The first operand
+   * @param {ReadonlyVec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        bx = b[0],
+        by = b[1],
+        bz = b[2],
+        mag1 = Math.sqrt(ax * ax + ay * ay + az * az),
+        mag2 = Math.sqrt(bx * bx + by * by + bz * bz),
+        mag = mag1 * mag2,
+        cosine = mag && dot(a, b) / mag;
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {ReadonlyVec4} result the receiving vector
+   * @param {ReadonlyVec4} U the first vector
+   * @param {ReadonlyVec4} V the second vector
+   * @param {ReadonlyVec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return "vec4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyVec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {ReadonlyQuat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Gets the angular distance between two unit quaternions
+   *
+   * @param  {ReadonlyQuat} a     Origin unit quaternion
+   * @param  {ReadonlyQuat} b     Destination unit quaternion
+   * @return {Number}     Angle, in radians, between the two quaternions
+   */
+
+  function getAngle(a, b) {
+    var dotproduct = dot$2(a, b);
+    return Math.acos(2 * dotproduct * dotproduct - 1);
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Calculate the exponential of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function exp(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var et = Math.exp(w);
+    var s = r > 0 ? et * Math.sin(r) / r : 0;
+    out[0] = x * s;
+    out[1] = y * s;
+    out[2] = z * s;
+    out[3] = et * Math.cos(r);
+    return out;
+  }
+  /**
+   * Calculate the natural logarithm of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function ln(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var t = r > 0 ? Math.atan2(r, w) / r : 0;
+    out[0] = x * t;
+    out[1] = y * t;
+    out[2] = z * t;
+    out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w);
+    return out;
+  }
+  /**
+   * Calculate the scalar power of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @param {Number} b amount to scale the quaternion by
+   * @returns {quat} out
+   */
+
+  function pow(out, a, b) {
+    ln(out, a);
+    scale$6(out, out, b);
+    exp(out, out);
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random unit quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyMat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {ReadonlyQuat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return "quat(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {ReadonlyQuat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat} a The first quaternion.
+   * @param {ReadonlyQuat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat} a The first vector.
+   * @param {ReadonlyQuat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {ReadonlyVec3} a the initial vector
+   * @param {ReadonlyVec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {ReadonlyQuat} c the third operand
+   * @param {ReadonlyQuat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {ReadonlyVec3} view  the vector representing the viewing direction
+   * @param {ReadonlyVec3} right the vector representing the local "right" direction
+   * @param {ReadonlyVec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    getAngle: getAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    exp: exp,
+    ln: ln,
+    pow: pow,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q a normalized quaternion
+   * @param {ReadonlyVec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyVec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {ReadonlyMat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {ReadonlyQuat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return "quat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ")";
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat2} a the first dual quaternion.
+   * @param {ReadonlyQuat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat2} a the first dual quat.
+   * @param {ReadonlyQuat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {ReadonlyVec2} a The vec2 point to rotate
+   * @param {ReadonlyVec2} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, rad) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(rad),
+        cosC = Math.cos(rad); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {ReadonlyVec2} a The first operand
+   * @param {ReadonlyVec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1],
+        // mag is the product of the magnitudes of a and b
+    mag = Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2),
+        // mag &&.. short circuits if mag == 0
+    cosine = mag && (x1 * x2 + y1 * y2) / mag; // Math.min(Math.max(cosine, -1), 1) clamps the cosine between -1 and 1
+
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return "vec2(" + a[0] + ", " + a[1] + ")";
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/basic_course/transform/hello.js b/basic_course/transform/hello.js
new file mode 100644
index 0000000000000000000000000000000000000000..96b71144230794897b975a679b7c184782584ee6
--- /dev/null
+++ b/basic_course/transform/hello.js
@@ -0,0 +1,233 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    /* gl.getError returns the last error that occurred using WebGL for debugging */ 
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, -100, canvas.width, canvas.width);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+var vertexData = [
+		// Backface (RED/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 1.0, 1.0, 
+		// Front (BLUE/WHITE) -> z = 0.5
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// LEFT (GREEN/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0, 
+		// RIGHT (YELLOE/WHITE) -> z = 0.5
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// BOTTON (MAGENTA/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// TOP (CYAN/WHITE) -> z = 0.5
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0 
+];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color;\
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 transformationMatrix; \
+			varying  highp vec4 color;\
+			void main(void)  \
+			{ \
+				gl_Position = transformationMatrix * myVertex; \
+				gl_PointSize = 8.0; \
+				color = myColor; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    // console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+flag_animation = 0; 
+function toggleAnimation()
+{
+	flag_animation ^= 1; 
+}
+
+rotY = 0.0;
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+	// gl.clearDepth(1.0);										// Added for depth Test 
+
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);	// Added for depth Test 
+	// gl.enable(gl.DEPTH_TEST);								// Added for depth Test 
+
+    var matrixLocation = gl.getUniformLocation(gl.programObject, "transformationMatrix");
+    var transformationMatrix = [
+        Math.cos(rotY), 0.0, Math.sin(rotY), 0.0,
+        0.0, 1.0, 0.0, 0.0,
+        -Math.sin(rotY), 0.0, Math.cos(rotY), 0.0,
+        0.0, 0.0, 0.0, 1.0
+    ];
+	if ( flag_animation ){
+		rotY += 0.01;
+	}
+
+    gl.uniformMatrix4fv(matrixLocation, gl.FALSE, transformationMatrix );
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+	//vertexData[0] += 0.01; 
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    //gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
+	//gl.vertexAttrib4f(1, 1.0, 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+	// gl.drawArrays(gl.LINE_STRIP, 0, 36); 
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+	// renderScene();
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/transform/index.html b/basic_course/transform/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..766b2f11e74b0e47a56fc896888b8b2477d4a467
--- /dev/null
+++ b/basic_course/transform/index.html
@@ -0,0 +1,19 @@
+<html>
+
+<head>
+<title>WebGLHelloAPI</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js">
+</script>
+<script type="text/javascript" src="hello.js">
+</script>
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+	<br>
+<button onclick="toggleAnimation()">Toggle Animation</button>
+</body>
+
+</html>
diff --git a/basic_course/video_texture/201520872/cube.js b/basic_course/video_texture/201520872/cube.js
new file mode 100644
index 0000000000000000000000000000000000000000..ace5c302689044502dbc3134964dd19d89e0b33a
--- /dev/null
+++ b/basic_course/video_texture/201520872/cube.js
@@ -0,0 +1,594 @@
+var cubeRotation = 0.0;
+// will set to true when video can be copied to texture
+var copyVideo = false;
+
+main();
+
+//
+// Start here
+//
+function main() {
+  const canvas = document.querySelector('#glcanvas');
+  const gl = canvas.getContext('webgl');
+
+  // If we don't have a GL context, give up now
+
+  if (!gl) {
+    alert('Unable to initialize WebGL. Your browser or machine may not support it.');
+    return;
+  }
+
+  // Vertex shader program
+
+  const vsSource = `
+    attribute vec4 aVertexPosition;
+    attribute vec3 aVertexNormal;
+    attribute vec2 aTextureCoord;
+
+    uniform mat4 uNormalMatrix;
+    uniform mat4 uModelViewMatrix;
+    uniform mat4 uProjectionMatrix;
+
+    varying highp vec2 vTextureCoord;
+    varying highp vec3 vLighting;
+
+    void main(void) {
+      gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
+      vTextureCoord = aTextureCoord;
+
+      // Apply lighting effect
+
+      highp vec3 ambientLight = vec3(0.3, 0.3, 0.3);
+      highp vec3 directionalLightColor = vec3(1, 1, 1);
+      highp vec3 directionalVector = normalize(vec3(0.85, 0.8, 0.75));
+
+      highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);
+
+      highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);
+      vLighting = ambientLight + (directionalLightColor * directional);
+    }
+  `;
+
+  // Fragment shader program
+
+  const fsSource = `
+    varying highp vec2 vTextureCoord;
+    varying highp vec3 vLighting;
+
+    uniform sampler2D uSampler;
+
+    void main(void) {
+      highp vec4 texelColor = texture2D(uSampler, vTextureCoord);
+
+      gl_FragColor = vec4(texelColor.rgb * vLighting, texelColor.a);
+    }
+  `;
+
+  // Initialize a shader program; this is where all the lighting
+  // for the vertices and so forth is established.
+  const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
+
+  // Collect all the info needed to use the shader program.
+  // Look up which attributes our shader program is using
+  // for aVertexPosition, aVertexNormal, aTextureCoord,
+  // and look up uniform locations.
+  const programInfo = {
+    program: shaderProgram,
+    attribLocations: {
+      vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
+      vertexNormal: gl.getAttribLocation(shaderProgram, 'aVertexNormal'),
+      textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),
+    },
+    uniformLocations: {
+      projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
+      modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
+      normalMatrix: gl.getUniformLocation(shaderProgram, 'uNormalMatrix'),
+      uSampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
+    },
+  };
+
+  // Here's where we call the routine that builds all the
+  // objects we'll be drawing.
+  const buffers = initBuffers(gl);
+
+  const texture = initTexture(gl);
+
+  const video = setupVideo('./memory.mp4');
+
+  var then = 0;
+
+  // Draw the scene repeatedly
+  function render(now) {
+    now *= 0.001;  // convert to seconds
+    const deltaTime = now - then;
+    then = now;
+
+    if (copyVideo) {
+      updateTexture(gl, texture, video);
+    }
+
+    drawScene(gl, programInfo, buffers, texture, deltaTime);
+
+    requestAnimationFrame(render);
+  }
+  requestAnimationFrame(render);
+}
+
+function setupVideo(url) {
+  const video = document.createElement('video');
+
+  var playing = false;
+  var timeupdate = false;
+
+  video.autoplay = true;
+  video.muted = true;
+  video.loop = true;
+  // Waiting for these 2 events ensures
+  // there is data in the video
+
+  video.addEventListener('playing', function() {
+     playing = true;
+     checkReady();
+  }, true);
+
+  video.addEventListener('timeupdate', function() {
+     timeupdate = true;
+     checkReady();
+  }, true);
+
+  video.src = url;
+  // video.crossorigin ='';
+  video.setAttribute('crossorigin','anonymous');
+  video.load();
+  video.play();
+
+  function checkReady() {
+    if (playing && timeupdate) {
+      copyVideo = true;
+    }
+  }
+
+  return video;
+}
+
+//
+// initBuffers
+//
+// Initialize the buffers we'll need. For this demo, we just
+// have one object -- a simple three-dimensional cube.
+//
+function initBuffers(gl) {
+
+  // Create a buffer for the cube's vertex positions.
+
+  const positionBuffer = gl.createBuffer();
+
+  // Select the positionBuffer as the one to apply buffer
+  // operations to from here out.
+
+  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+  // Now create an array of positions for the cube.
+
+  const positions = [
+    // Front face
+    -1.0, -1.0,  1.0,
+     1.0, -1.0,  1.0,
+     1.0,  1.0,  1.0,
+    -1.0,  1.0,  1.0,
+
+    // Back face
+    -1.0, -1.0, -1.0,
+    -1.0,  1.0, -1.0,
+     1.0,  1.0, -1.0,
+     1.0, -1.0, -1.0,
+
+    // Top face
+    -1.0,  1.0, -1.0,
+    -1.0,  1.0,  1.0,
+     1.0,  1.0,  1.0,
+     1.0,  1.0, -1.0,
+
+    // Bottom face
+    -1.0, -1.0, -1.0,
+     1.0, -1.0, -1.0,
+     1.0, -1.0,  1.0,
+    -1.0, -1.0,  1.0,
+
+    // Right face
+     1.0, -1.0, -1.0,
+     1.0,  1.0, -1.0,
+     1.0,  1.0,  1.0,
+     1.0, -1.0,  1.0,
+
+    // Left face
+    -1.0, -1.0, -1.0,
+    -1.0, -1.0,  1.0,
+    -1.0,  1.0,  1.0,
+    -1.0,  1.0, -1.0,
+  ];
+
+  // Now pass the list of positions into WebGL to build the
+  // shape. We do this by creating a Float32Array from the
+  // JavaScript array, then use it to fill the current buffer.
+
+  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
+
+  // Set up the normals for the vertices, so that we can compute lighting.
+
+  const normalBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
+
+  const vertexNormals = [
+    // Front
+     0.0,  0.0,  1.0,
+     0.0,  0.0,  1.0,
+     0.0,  0.0,  1.0,
+     0.0,  0.0,  1.0,
+
+    // Back
+     0.0,  0.0, -1.0,
+     0.0,  0.0, -1.0,
+     0.0,  0.0, -1.0,
+     0.0,  0.0, -1.0,
+
+    // Top
+     0.0,  1.0,  0.0,
+     0.0,  1.0,  0.0,
+     0.0,  1.0,  0.0,
+     0.0,  1.0,  0.0,
+
+    // Bottom
+     0.0, -1.0,  0.0,
+     0.0, -1.0,  0.0,
+     0.0, -1.0,  0.0,
+     0.0, -1.0,  0.0,
+
+    // Right
+     1.0,  0.0,  0.0,
+     1.0,  0.0,  0.0,
+     1.0,  0.0,  0.0,
+     1.0,  0.0,  0.0,
+
+    // Left
+    -1.0,  0.0,  0.0,
+    -1.0,  0.0,  0.0,
+    -1.0,  0.0,  0.0,
+    -1.0,  0.0,  0.0,
+  ];
+
+  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexNormals),
+                gl.STATIC_DRAW);
+
+  // Now set up the texture coordinates for the faces.
+
+  const textureCoordBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
+
+  const textureCoordinates = [
+    // Front
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Back
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Top
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Bottom
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Right
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Left
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+  ];
+
+  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates),
+                gl.STATIC_DRAW);
+
+  // Build the element array buffer; this specifies the indices
+  // into the vertex arrays for each face's vertices.
+
+  const indexBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+
+  // This array defines each face as two triangles, using the
+  // indices into the vertex array to specify each triangle's
+  // position.
+
+  const indices = [
+    0,  1,  2,      0,  2,  3,    // front
+    4,  5,  6,      4,  6,  7,    // back
+    8,  9,  10,     8,  10, 11,   // top
+    12, 13, 14,     12, 14, 15,   // bottom
+    16, 17, 18,     16, 18, 19,   // right
+    20, 21, 22,     20, 22, 23,   // left
+  ];
+
+  // Now send the element array to GL
+
+  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+      new Uint16Array(indices), gl.STATIC_DRAW);
+
+  return {
+    position: positionBuffer,
+    normal: normalBuffer,
+    textureCoord: textureCoordBuffer,
+    indices: indexBuffer,
+  };
+}
+
+//
+// Initialize a texture.
+//
+function initTexture(gl, url) {
+  const texture = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, texture);
+
+  // Because video havs to be download over the internet
+  // they might take a moment until it's ready so
+  // put a single pixel in the texture so we can
+  // use it immediately.
+  const level = 0;
+  const internalFormat = gl.RGBA;
+  const width = 1;
+  const height = 1;
+  const border = 0;
+  const srcFormat = gl.RGBA;
+  const srcType = gl.UNSIGNED_BYTE;
+  const pixel = new Uint8Array([0, 0, 255, 255]);  // opaque blue
+  gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
+                width, height, border, srcFormat, srcType,
+                pixel);
+  // Turn off mips and set  wrapping to clamp to edge so it
+  // will work regardless of the dimensions of the video.
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+
+  return texture;
+}
+
+//
+// copy the video texture
+//
+function updateTexture(gl, texture, video) {
+  const level = 0;
+  const internalFormat = gl.RGBA;
+  const srcFormat = gl.RGBA;
+  const srcType = gl.UNSIGNED_BYTE;
+  gl.bindTexture(gl.TEXTURE_2D, texture);
+  gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
+                srcFormat, srcType, video);
+}
+
+function isPowerOf2(value) {
+  return (value & (value - 1)) == 0;
+}
+
+//
+// Draw the scene.
+//
+function drawScene(gl, programInfo, buffers, texture, deltaTime) {
+  gl.clearColor(0.0, 0.0, 0.0, 1.0);  // Clear to black, fully opaque
+  gl.clearDepth(1.0);                 // Clear everything
+  gl.enable(gl.DEPTH_TEST);           // Enable depth testing
+  gl.depthFunc(gl.LEQUAL);            // Near things obscure far things
+
+  // Clear the canvas before we start drawing on it.
+
+  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+  // Create a perspective matrix, a special matrix that is
+  // used to simulate the distortion of perspective in a camera.
+  // Our field of view is 45 degrees, with a width/height
+  // ratio that matches the display size of the canvas
+  // and we only want to see objects between 0.1 units
+  // and 100 units away from the camera.
+
+  const fieldOfView = 45 * Math.PI / 180;   // in radians
+  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
+  const zNear = 0.1;
+  const zFar = 100.0;
+  const projectionMatrix = mat4.create();
+
+  // note: glmatrix.js always has the first argument
+  // as the destination to receive the result.
+  mat4.perspective(projectionMatrix,
+                   fieldOfView,
+                   aspect,
+                   zNear,
+                   zFar);
+
+  // Set the drawing position to the "identity" point, which is
+  // the center of the scene.
+  const modelViewMatrix = mat4.create();
+
+  // Now move the drawing position a bit to where we want to
+  // start drawing the square.
+
+  mat4.translate(modelViewMatrix,     // destination matrix
+                 modelViewMatrix,     // matrix to translate
+                 [-0.0, 0.0, -6.0]);  // amount to translate
+  mat4.rotate(modelViewMatrix,  // destination matrix
+              modelViewMatrix,  // matrix to rotate
+              cubeRotation,     // amount to rotate in radians
+              [0, 0, 1]);       // axis to rotate around (Z)
+  mat4.rotate(modelViewMatrix,  // destination matrix
+              modelViewMatrix,  // matrix to rotate
+              cubeRotation * .7,// amount to rotate in radians
+              [0, 1, 0]);       // axis to rotate around (X)
+
+  const normalMatrix = mat4.create();
+  mat4.invert(normalMatrix, modelViewMatrix);
+  mat4.transpose(normalMatrix, normalMatrix);
+
+  // Tell WebGL how to pull out the positions from the position
+  // buffer into the vertexPosition attribute
+  {
+    const numComponents = 3;
+    const type = gl.FLOAT;
+    const normalize = false;
+    const stride = 0;
+    const offset = 0;
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
+    gl.vertexAttribPointer(
+        programInfo.attribLocations.vertexPosition,
+        numComponents,
+        type,
+        normalize,
+        stride,
+        offset);
+    gl.enableVertexAttribArray(
+        programInfo.attribLocations.vertexPosition);
+  }
+
+  // Tell WebGL how to pull out the texture coordinates from
+  // the texture coordinate buffer into the textureCoord attribute.
+  {
+    const numComponents = 2;
+    const type = gl.FLOAT;
+    const normalize = false;
+    const stride = 0;
+    const offset = 0;
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureCoord);
+    gl.vertexAttribPointer(
+        programInfo.attribLocations.textureCoord,
+        numComponents,
+        type,
+        normalize,
+        stride,
+        offset);
+    gl.enableVertexAttribArray(
+        programInfo.attribLocations.textureCoord);
+  }
+
+  // Tell WebGL how to pull out the normals from
+  // the normal buffer into the vertexNormal attribute.
+  {
+    const numComponents = 3;
+    const type = gl.FLOAT;
+    const normalize = false;
+    const stride = 0;
+    const offset = 0;
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.normal);
+    gl.vertexAttribPointer(
+        programInfo.attribLocations.vertexNormal,
+        numComponents,
+        type,
+        normalize,
+        stride,
+        offset);
+    gl.enableVertexAttribArray(
+        programInfo.attribLocations.vertexNormal);
+  }
+
+  // Tell WebGL which indices to use to index the vertices
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
+
+  // Tell WebGL to use our program when drawing
+
+  gl.useProgram(programInfo.program);
+
+  // Set the shader uniforms
+
+  gl.uniformMatrix4fv(
+      programInfo.uniformLocations.projectionMatrix,
+      false,
+      projectionMatrix);
+  gl.uniformMatrix4fv(
+      programInfo.uniformLocations.modelViewMatrix,
+      false,
+      modelViewMatrix);
+  gl.uniformMatrix4fv(
+      programInfo.uniformLocations.normalMatrix,
+      false,
+      normalMatrix);
+
+  // Specify the texture to map onto the faces.
+
+  // Tell WebGL we want to affect texture unit 0
+  gl.activeTexture(gl.TEXTURE0);
+
+  // Bind the texture to texture unit 0
+  gl.bindTexture(gl.TEXTURE_2D, texture);
+
+  // Tell the shader we bound the texture to texture unit 0
+  gl.uniform1i(programInfo.uniformLocations.uSampler, 0);
+
+  {
+    const vertexCount = 36;
+    const type = gl.UNSIGNED_SHORT;
+    const offset = 0;
+    gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
+  }
+
+  // Update the rotation for the next draw
+
+  cubeRotation += deltaTime;
+}
+
+//
+// Initialize a shader program, so WebGL knows how to draw our data
+//
+function initShaderProgram(gl, vsSource, fsSource) {
+  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
+  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
+
+  // Create the shader program
+
+  const shaderProgram = gl.createProgram();
+  gl.attachShader(shaderProgram, vertexShader);
+  gl.attachShader(shaderProgram, fragmentShader);
+  gl.linkProgram(shaderProgram);
+
+  // If creating the shader program failed, alert
+
+  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
+    alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
+    return null;
+  }
+
+  return shaderProgram;
+}
+
+//
+// creates a shader of the given type, uploads the source and
+// compiles it.
+//
+function loadShader(gl, type, source) {
+  const shader = gl.createShader(type);
+
+  // Send the source to the shader object
+
+  gl.shaderSource(shader, source);
+
+  // Compile the shader program
+
+  gl.compileShader(shader);
+
+  // See if it compiled successfully
+
+  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+    alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
+    gl.deleteShader(shader);
+    return null;
+  }
+
+  return shader;
+}
diff --git a/basic_course/video_texture/201520872/desktop.ini b/basic_course/video_texture/201520872/desktop.ini
new file mode 100644
index 0000000000000000000000000000000000000000..b1d2ef2b27fa4f4218640e745a925404993b6e54
Binary files /dev/null and b/basic_course/video_texture/201520872/desktop.ini differ
diff --git a/basic_course/video_texture/201520872/gl-matrix.js b/basic_course/video_texture/201520872/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..5bfcb892a7ca60640153b77ce6c9998161417586
--- /dev/null
+++ b/basic_course/video_texture/201520872/gl-matrix.js
@@ -0,0 +1,6888 @@
+/**
+ * @fileoverview gl-matrix - High performance matrix and vector operations
+ * @author Brandon Jones
+ * @author Colin MacKenzie IV
+ * @version 2.4.0
+ */
+
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+(function webpackUniversalModuleDefinition(root, factory) {
+	if(typeof exports === 'object' && typeof module === 'object')
+		module.exports = factory();
+	else if(typeof define === 'function' && define.amd)
+		define([], factory);
+	else {
+		var a = factory();
+		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
+	}
+})(this, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+/******/
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+/******/
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId]) {
+/******/ 			return installedModules[moduleId].exports;
+/******/ 		}
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			i: moduleId,
+/******/ 			l: false,
+/******/ 			exports: {}
+/******/ 		};
+/******/
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ 		// Flag the module as loaded
+/******/ 		module.l = true;
+/******/
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+/******/
+/******/
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+/******/
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+/******/
+/******/ 	// define getter function for harmony exports
+/******/ 	__webpack_require__.d = function(exports, name, getter) {
+/******/ 		if(!__webpack_require__.o(exports, name)) {
+/******/ 			Object.defineProperty(exports, name, {
+/******/ 				configurable: false,
+/******/ 				enumerable: true,
+/******/ 				get: getter
+/******/ 			});
+/******/ 		}
+/******/ 	};
+/******/
+/******/ 	// getDefaultExport function for compatibility with non-harmony modules
+/******/ 	__webpack_require__.n = function(module) {
+/******/ 		var getter = module && module.__esModule ?
+/******/ 			function getDefault() { return module['default']; } :
+/******/ 			function getModuleExports() { return module; };
+/******/ 		__webpack_require__.d(getter, 'a', getter);
+/******/ 		return getter;
+/******/ 	};
+/******/
+/******/ 	// Object.prototype.hasOwnProperty.call
+/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+/******/
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(__webpack_require__.s = 4);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.setMatrixArrayType = setMatrixArrayType;
+exports.toRadian = toRadian;
+exports.equals = equals;
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+/**
+ * Common utilities
+ * @module glMatrix
+ */
+
+// Configuration Constants
+var EPSILON = exports.EPSILON = 0.000001;
+var ARRAY_TYPE = exports.ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+var RANDOM = exports.RANDOM = Math.random;
+
+/**
+ * Sets the type of array used when creating new vectors and matrices
+ *
+ * @param {Type} type Array type, such as Float32Array or Array
+ */
+function setMatrixArrayType(type) {
+  exports.ARRAY_TYPE = ARRAY_TYPE = type;
+}
+
+var degree = Math.PI / 180;
+
+/**
+ * Convert Degree To Radian
+ *
+ * @param {Number} a Angle in Degrees
+ */
+function toRadian(a) {
+  return a * degree;
+}
+
+/**
+ * Tests whether or not the arguments have approximately the same value, within an absolute
+ * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+ * than or equal to 1.0, and a relative tolerance is used for larger values)
+ *
+ * @param {Number} a The first number to test.
+ * @param {Number} b The second number to test.
+ * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+ */
+function equals(a, b) {
+  return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+}
+
+/***/ }),
+/* 1 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.sub = exports.mul = undefined;
+exports.create = create;
+exports.fromMat4 = fromMat4;
+exports.clone = clone;
+exports.copy = copy;
+exports.fromValues = fromValues;
+exports.set = set;
+exports.identity = identity;
+exports.transpose = transpose;
+exports.invert = invert;
+exports.adjoint = adjoint;
+exports.determinant = determinant;
+exports.multiply = multiply;
+exports.translate = translate;
+exports.rotate = rotate;
+exports.scale = scale;
+exports.fromTranslation = fromTranslation;
+exports.fromRotation = fromRotation;
+exports.fromScaling = fromScaling;
+exports.fromMat2d = fromMat2d;
+exports.fromQuat = fromQuat;
+exports.normalFromMat4 = normalFromMat4;
+exports.projection = projection;
+exports.str = str;
+exports.frob = frob;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiplyScalar = multiplyScalar;
+exports.multiplyScalarAndAdd = multiplyScalarAndAdd;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 3x3 Matrix
+ * @module mat3
+ */
+
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(9);
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 1;
+  out[5] = 0;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 1;
+  return out;
+}
+
+/**
+ * Copies the upper-left 3x3 values into the given mat3.
+ *
+ * @param {mat3} out the receiving 3x3 matrix
+ * @param {mat4} a   the source 4x4 matrix
+ * @returns {mat3} out
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function fromMat4(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[4];
+  out[4] = a[5];
+  out[5] = a[6];
+  out[6] = a[8];
+  out[7] = a[9];
+  out[8] = a[10];
+  return out;
+}
+
+/**
+ * Creates a new mat3 initialized with values from an existing matrix
+ *
+ * @param {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(9);
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  out[4] = a[4];
+  out[5] = a[5];
+  out[6] = a[6];
+  out[7] = a[7];
+  out[8] = a[8];
+  return out;
+}
+
+/**
+ * Copy the values from one mat3 to another
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  out[4] = a[4];
+  out[5] = a[5];
+  out[6] = a[6];
+  out[7] = a[7];
+  out[8] = a[8];
+  return out;
+}
+
+/**
+ * Create a new mat3 with the given values
+ *
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m10 Component in column 1, row 0 position (index 3)
+ * @param {Number} m11 Component in column 1, row 1 position (index 4)
+ * @param {Number} m12 Component in column 1, row 2 position (index 5)
+ * @param {Number} m20 Component in column 2, row 0 position (index 6)
+ * @param {Number} m21 Component in column 2, row 1 position (index 7)
+ * @param {Number} m22 Component in column 2, row 2 position (index 8)
+ * @returns {mat3} A new mat3
+ */
+function fromValues(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+  var out = new glMatrix.ARRAY_TYPE(9);
+  out[0] = m00;
+  out[1] = m01;
+  out[2] = m02;
+  out[3] = m10;
+  out[4] = m11;
+  out[5] = m12;
+  out[6] = m20;
+  out[7] = m21;
+  out[8] = m22;
+  return out;
+}
+
+/**
+ * Set the components of a mat3 to the given values
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m10 Component in column 1, row 0 position (index 3)
+ * @param {Number} m11 Component in column 1, row 1 position (index 4)
+ * @param {Number} m12 Component in column 1, row 2 position (index 5)
+ * @param {Number} m20 Component in column 2, row 0 position (index 6)
+ * @param {Number} m21 Component in column 2, row 1 position (index 7)
+ * @param {Number} m22 Component in column 2, row 2 position (index 8)
+ * @returns {mat3} out
+ */
+function set(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+  out[0] = m00;
+  out[1] = m01;
+  out[2] = m02;
+  out[3] = m10;
+  out[4] = m11;
+  out[5] = m12;
+  out[6] = m20;
+  out[7] = m21;
+  out[8] = m22;
+  return out;
+}
+
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+function identity(out) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 1;
+  out[5] = 0;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 1;
+  return out;
+}
+
+/**
+ * Transpose the values of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+function transpose(out, a) {
+  // If we are transposing ourselves we can skip a few steps but have to cache some values
+  if (out === a) {
+    var a01 = a[1],
+        a02 = a[2],
+        a12 = a[5];
+    out[1] = a[3];
+    out[2] = a[6];
+    out[3] = a01;
+    out[5] = a[7];
+    out[6] = a02;
+    out[7] = a12;
+  } else {
+    out[0] = a[0];
+    out[1] = a[3];
+    out[2] = a[6];
+    out[3] = a[1];
+    out[4] = a[4];
+    out[5] = a[7];
+    out[6] = a[2];
+    out[7] = a[5];
+    out[8] = a[8];
+  }
+
+  return out;
+}
+
+/**
+ * Inverts a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+function invert(out, a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2];
+  var a10 = a[3],
+      a11 = a[4],
+      a12 = a[5];
+  var a20 = a[6],
+      a21 = a[7],
+      a22 = a[8];
+
+  var b01 = a22 * a11 - a12 * a21;
+  var b11 = -a22 * a10 + a12 * a20;
+  var b21 = a21 * a10 - a11 * a20;
+
+  // Calculate the determinant
+  var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+  if (!det) {
+    return null;
+  }
+  det = 1.0 / det;
+
+  out[0] = b01 * det;
+  out[1] = (-a22 * a01 + a02 * a21) * det;
+  out[2] = (a12 * a01 - a02 * a11) * det;
+  out[3] = b11 * det;
+  out[4] = (a22 * a00 - a02 * a20) * det;
+  out[5] = (-a12 * a00 + a02 * a10) * det;
+  out[6] = b21 * det;
+  out[7] = (-a21 * a00 + a01 * a20) * det;
+  out[8] = (a11 * a00 - a01 * a10) * det;
+  return out;
+}
+
+/**
+ * Calculates the adjugate of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+function adjoint(out, a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2];
+  var a10 = a[3],
+      a11 = a[4],
+      a12 = a[5];
+  var a20 = a[6],
+      a21 = a[7],
+      a22 = a[8];
+
+  out[0] = a11 * a22 - a12 * a21;
+  out[1] = a02 * a21 - a01 * a22;
+  out[2] = a01 * a12 - a02 * a11;
+  out[3] = a12 * a20 - a10 * a22;
+  out[4] = a00 * a22 - a02 * a20;
+  out[5] = a02 * a10 - a00 * a12;
+  out[6] = a10 * a21 - a11 * a20;
+  out[7] = a01 * a20 - a00 * a21;
+  out[8] = a00 * a11 - a01 * a10;
+  return out;
+}
+
+/**
+ * Calculates the determinant of a mat3
+ *
+ * @param {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+function determinant(a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2];
+  var a10 = a[3],
+      a11 = a[4],
+      a12 = a[5];
+  var a20 = a[6],
+      a21 = a[7],
+      a22 = a[8];
+
+  return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+}
+
+/**
+ * Multiplies two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+function multiply(out, a, b) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2];
+  var a10 = a[3],
+      a11 = a[4],
+      a12 = a[5];
+  var a20 = a[6],
+      a21 = a[7],
+      a22 = a[8];
+
+  var b00 = b[0],
+      b01 = b[1],
+      b02 = b[2];
+  var b10 = b[3],
+      b11 = b[4],
+      b12 = b[5];
+  var b20 = b[6],
+      b21 = b[7],
+      b22 = b[8];
+
+  out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+  out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+  out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+
+  out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+  out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+  out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+
+  out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+  out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+  out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+  return out;
+}
+
+/**
+ * Translate a mat3 by the given vector
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to translate
+ * @param {vec2} v vector to translate by
+ * @returns {mat3} out
+ */
+function translate(out, a, v) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a10 = a[3],
+      a11 = a[4],
+      a12 = a[5],
+      a20 = a[6],
+      a21 = a[7],
+      a22 = a[8],
+      x = v[0],
+      y = v[1];
+
+  out[0] = a00;
+  out[1] = a01;
+  out[2] = a02;
+
+  out[3] = a10;
+  out[4] = a11;
+  out[5] = a12;
+
+  out[6] = x * a00 + y * a10 + a20;
+  out[7] = x * a01 + y * a11 + a21;
+  out[8] = x * a02 + y * a12 + a22;
+  return out;
+}
+
+/**
+ * Rotates a mat3 by the given angle
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+function rotate(out, a, rad) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a10 = a[3],
+      a11 = a[4],
+      a12 = a[5],
+      a20 = a[6],
+      a21 = a[7],
+      a22 = a[8],
+      s = Math.sin(rad),
+      c = Math.cos(rad);
+
+  out[0] = c * a00 + s * a10;
+  out[1] = c * a01 + s * a11;
+  out[2] = c * a02 + s * a12;
+
+  out[3] = c * a10 - s * a00;
+  out[4] = c * a11 - s * a01;
+  out[5] = c * a12 - s * a02;
+
+  out[6] = a20;
+  out[7] = a21;
+  out[8] = a22;
+  return out;
+};
+
+/**
+ * Scales the mat3 by the dimensions in the given vec2
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat3} out
+ **/
+function scale(out, a, v) {
+  var x = v[0],
+      y = v[1];
+
+  out[0] = x * a[0];
+  out[1] = x * a[1];
+  out[2] = x * a[2];
+
+  out[3] = y * a[3];
+  out[4] = y * a[4];
+  out[5] = y * a[5];
+
+  out[6] = a[6];
+  out[7] = a[7];
+  out[8] = a[8];
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector translation
+ * This is equivalent to (but much faster than):
+ *
+ *     mat3.identity(dest);
+ *     mat3.translate(dest, dest, vec);
+ *
+ * @param {mat3} out mat3 receiving operation result
+ * @param {vec2} v Translation vector
+ * @returns {mat3} out
+ */
+function fromTranslation(out, v) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 1;
+  out[5] = 0;
+  out[6] = v[0];
+  out[7] = v[1];
+  out[8] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from a given angle
+ * This is equivalent to (but much faster than):
+ *
+ *     mat3.identity(dest);
+ *     mat3.rotate(dest, dest, rad);
+ *
+ * @param {mat3} out mat3 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+function fromRotation(out, rad) {
+  var s = Math.sin(rad),
+      c = Math.cos(rad);
+
+  out[0] = c;
+  out[1] = s;
+  out[2] = 0;
+
+  out[3] = -s;
+  out[4] = c;
+  out[5] = 0;
+
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ *     mat3.identity(dest);
+ *     mat3.scale(dest, dest, vec);
+ *
+ * @param {mat3} out mat3 receiving operation result
+ * @param {vec2} v Scaling vector
+ * @returns {mat3} out
+ */
+function fromScaling(out, v) {
+  out[0] = v[0];
+  out[1] = 0;
+  out[2] = 0;
+
+  out[3] = 0;
+  out[4] = v[1];
+  out[5] = 0;
+
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 1;
+  return out;
+}
+
+/**
+ * Copies the values from a mat2d into a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat2d} a the matrix to copy
+ * @returns {mat3} out
+ **/
+function fromMat2d(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = 0;
+
+  out[3] = a[2];
+  out[4] = a[3];
+  out[5] = 0;
+
+  out[6] = a[4];
+  out[7] = a[5];
+  out[8] = 1;
+  return out;
+}
+
+/**
+* Calculates a 3x3 matrix from the given quaternion
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {quat} q Quaternion to create matrix from
+*
+* @returns {mat3} out
+*/
+function fromQuat(out, q) {
+  var x = q[0],
+      y = q[1],
+      z = q[2],
+      w = q[3];
+  var x2 = x + x;
+  var y2 = y + y;
+  var z2 = z + z;
+
+  var xx = x * x2;
+  var yx = y * x2;
+  var yy = y * y2;
+  var zx = z * x2;
+  var zy = z * y2;
+  var zz = z * z2;
+  var wx = w * x2;
+  var wy = w * y2;
+  var wz = w * z2;
+
+  out[0] = 1 - yy - zz;
+  out[3] = yx - wz;
+  out[6] = zx + wy;
+
+  out[1] = yx + wz;
+  out[4] = 1 - xx - zz;
+  out[7] = zy - wx;
+
+  out[2] = zx - wy;
+  out[5] = zy + wx;
+  out[8] = 1 - xx - yy;
+
+  return out;
+}
+
+/**
+* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {mat4} a Mat4 to derive the normal matrix from
+*
+* @returns {mat3} out
+*/
+function normalFromMat4(out, a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a03 = a[3];
+  var a10 = a[4],
+      a11 = a[5],
+      a12 = a[6],
+      a13 = a[7];
+  var a20 = a[8],
+      a21 = a[9],
+      a22 = a[10],
+      a23 = a[11];
+  var a30 = a[12],
+      a31 = a[13],
+      a32 = a[14],
+      a33 = a[15];
+
+  var b00 = a00 * a11 - a01 * a10;
+  var b01 = a00 * a12 - a02 * a10;
+  var b02 = a00 * a13 - a03 * a10;
+  var b03 = a01 * a12 - a02 * a11;
+  var b04 = a01 * a13 - a03 * a11;
+  var b05 = a02 * a13 - a03 * a12;
+  var b06 = a20 * a31 - a21 * a30;
+  var b07 = a20 * a32 - a22 * a30;
+  var b08 = a20 * a33 - a23 * a30;
+  var b09 = a21 * a32 - a22 * a31;
+  var b10 = a21 * a33 - a23 * a31;
+  var b11 = a22 * a33 - a23 * a32;
+
+  // Calculate the determinant
+  var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+  if (!det) {
+    return null;
+  }
+  det = 1.0 / det;
+
+  out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+  out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+  out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+
+  out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+  out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+  out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+
+  out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+  out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+  out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+
+  return out;
+}
+
+/**
+ * Generates a 2D projection matrix with the given bounds
+ *
+ * @param {mat3} out mat3 frustum matrix will be written into
+ * @param {number} width Width of your gl context
+ * @param {number} height Height of gl context
+ * @returns {mat3} out
+ */
+function projection(out, width, height) {
+  out[0] = 2 / width;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = -2 / height;
+  out[5] = 0;
+  out[6] = -1;
+  out[7] = 1;
+  out[8] = 1;
+  return out;
+}
+
+/**
+ * Returns a string representation of a mat3
+ *
+ * @param {mat3} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+function str(a) {
+  return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+}
+
+/**
+ * Returns Frobenius norm of a mat3
+ *
+ * @param {mat3} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+function frob(a) {
+  return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2));
+}
+
+/**
+ * Adds two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  out[2] = a[2] + b[2];
+  out[3] = a[3] + b[3];
+  out[4] = a[4] + b[4];
+  out[5] = a[5] + b[5];
+  out[6] = a[6] + b[6];
+  out[7] = a[7] + b[7];
+  out[8] = a[8] + b[8];
+  return out;
+}
+
+/**
+ * Subtracts matrix b from matrix a
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  out[2] = a[2] - b[2];
+  out[3] = a[3] - b[3];
+  out[4] = a[4] - b[4];
+  out[5] = a[5] - b[5];
+  out[6] = a[6] - b[6];
+  out[7] = a[7] - b[7];
+  out[8] = a[8] - b[8];
+  return out;
+}
+
+/**
+ * Multiply each element of the matrix by a scalar.
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat3} out
+ */
+function multiplyScalar(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  out[2] = a[2] * b;
+  out[3] = a[3] * b;
+  out[4] = a[4] * b;
+  out[5] = a[5] * b;
+  out[6] = a[6] * b;
+  out[7] = a[7] * b;
+  out[8] = a[8] * b;
+  return out;
+}
+
+/**
+ * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+ *
+ * @param {mat3} out the receiving vector
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat3} out
+ */
+function multiplyScalarAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  out[2] = a[2] + b[2] * scale;
+  out[3] = a[3] + b[3] * scale;
+  out[4] = a[4] + b[4] * scale;
+  out[5] = a[5] + b[5] * scale;
+  out[6] = a[6] + b[6] * scale;
+  out[7] = a[7] + b[7] * scale;
+  out[8] = a[8] + b[8] * scale;
+  return out;
+}
+
+/**
+ * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {mat3} a The first matrix.
+ * @param {mat3} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+}
+
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat3} a The first matrix.
+ * @param {mat3} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3],
+      a4 = a[4],
+      a5 = a[5],
+      a6 = a[6],
+      a7 = a[7],
+      a8 = a[8];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3],
+      b4 = b[4],
+      b5 = b[5],
+      b6 = b[6],
+      b7 = b[7],
+      b8 = b[8];
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+}
+
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link mat3.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/***/ }),
+/* 2 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.forEach = exports.sqrLen = exports.len = exports.sqrDist = exports.dist = exports.div = exports.mul = exports.sub = undefined;
+exports.create = create;
+exports.clone = clone;
+exports.length = length;
+exports.fromValues = fromValues;
+exports.copy = copy;
+exports.set = set;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiply = multiply;
+exports.divide = divide;
+exports.ceil = ceil;
+exports.floor = floor;
+exports.min = min;
+exports.max = max;
+exports.round = round;
+exports.scale = scale;
+exports.scaleAndAdd = scaleAndAdd;
+exports.distance = distance;
+exports.squaredDistance = squaredDistance;
+exports.squaredLength = squaredLength;
+exports.negate = negate;
+exports.inverse = inverse;
+exports.normalize = normalize;
+exports.dot = dot;
+exports.cross = cross;
+exports.lerp = lerp;
+exports.hermite = hermite;
+exports.bezier = bezier;
+exports.random = random;
+exports.transformMat4 = transformMat4;
+exports.transformMat3 = transformMat3;
+exports.transformQuat = transformQuat;
+exports.rotateX = rotateX;
+exports.rotateY = rotateY;
+exports.rotateZ = rotateZ;
+exports.angle = angle;
+exports.str = str;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 3 Dimensional Vector
+ * @module vec3
+ */
+
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(3);
+  out[0] = 0;
+  out[1] = 0;
+  out[2] = 0;
+  return out;
+}
+
+/**
+ * Creates a new vec3 initialized with values from an existing vector
+ *
+ * @param {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(3);
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  return out;
+}
+
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+function length(a) {
+  var x = a[0];
+  var y = a[1];
+  var z = a[2];
+  return Math.sqrt(x * x + y * y + z * z);
+}
+
+/**
+ * Creates a new vec3 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} a new 3D vector
+ */
+function fromValues(x, y, z) {
+  var out = new glMatrix.ARRAY_TYPE(3);
+  out[0] = x;
+  out[1] = y;
+  out[2] = z;
+  return out;
+}
+
+/**
+ * Copy the values from one vec3 to another
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the source vector
+ * @returns {vec3} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  return out;
+}
+
+/**
+ * Set the components of a vec3 to the given values
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} out
+ */
+function set(out, x, y, z) {
+  out[0] = x;
+  out[1] = y;
+  out[2] = z;
+  return out;
+}
+
+/**
+ * Adds two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  out[2] = a[2] + b[2];
+  return out;
+}
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  out[2] = a[2] - b[2];
+  return out;
+}
+
+/**
+ * Multiplies two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function multiply(out, a, b) {
+  out[0] = a[0] * b[0];
+  out[1] = a[1] * b[1];
+  out[2] = a[2] * b[2];
+  return out;
+}
+
+/**
+ * Divides two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function divide(out, a, b) {
+  out[0] = a[0] / b[0];
+  out[1] = a[1] / b[1];
+  out[2] = a[2] / b[2];
+  return out;
+}
+
+/**
+ * Math.ceil the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to ceil
+ * @returns {vec3} out
+ */
+function ceil(out, a) {
+  out[0] = Math.ceil(a[0]);
+  out[1] = Math.ceil(a[1]);
+  out[2] = Math.ceil(a[2]);
+  return out;
+}
+
+/**
+ * Math.floor the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to floor
+ * @returns {vec3} out
+ */
+function floor(out, a) {
+  out[0] = Math.floor(a[0]);
+  out[1] = Math.floor(a[1]);
+  out[2] = Math.floor(a[2]);
+  return out;
+}
+
+/**
+ * Returns the minimum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function min(out, a, b) {
+  out[0] = Math.min(a[0], b[0]);
+  out[1] = Math.min(a[1], b[1]);
+  out[2] = Math.min(a[2], b[2]);
+  return out;
+}
+
+/**
+ * Returns the maximum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function max(out, a, b) {
+  out[0] = Math.max(a[0], b[0]);
+  out[1] = Math.max(a[1], b[1]);
+  out[2] = Math.max(a[2], b[2]);
+  return out;
+}
+
+/**
+ * Math.round the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to round
+ * @returns {vec3} out
+ */
+function round(out, a) {
+  out[0] = Math.round(a[0]);
+  out[1] = Math.round(a[1]);
+  out[2] = Math.round(a[2]);
+  return out;
+}
+
+/**
+ * Scales a vec3 by a scalar number
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec3} out
+ */
+function scale(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  out[2] = a[2] * b;
+  return out;
+}
+
+/**
+ * Adds two vec3's after scaling the second operand by a scalar value
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec3} out
+ */
+function scaleAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  out[2] = a[2] + b[2] * scale;
+  return out;
+}
+
+/**
+ * Calculates the euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} distance between a and b
+ */
+function distance(a, b) {
+  var x = b[0] - a[0];
+  var y = b[1] - a[1];
+  var z = b[2] - a[2];
+  return Math.sqrt(x * x + y * y + z * z);
+}
+
+/**
+ * Calculates the squared euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+function squaredDistance(a, b) {
+  var x = b[0] - a[0];
+  var y = b[1] - a[1];
+  var z = b[2] - a[2];
+  return x * x + y * y + z * z;
+}
+
+/**
+ * Calculates the squared length of a vec3
+ *
+ * @param {vec3} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+function squaredLength(a) {
+  var x = a[0];
+  var y = a[1];
+  var z = a[2];
+  return x * x + y * y + z * z;
+}
+
+/**
+ * Negates the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to negate
+ * @returns {vec3} out
+ */
+function negate(out, a) {
+  out[0] = -a[0];
+  out[1] = -a[1];
+  out[2] = -a[2];
+  return out;
+}
+
+/**
+ * Returns the inverse of the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to invert
+ * @returns {vec3} out
+ */
+function inverse(out, a) {
+  out[0] = 1.0 / a[0];
+  out[1] = 1.0 / a[1];
+  out[2] = 1.0 / a[2];
+  return out;
+}
+
+/**
+ * Normalize a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to normalize
+ * @returns {vec3} out
+ */
+function normalize(out, a) {
+  var x = a[0];
+  var y = a[1];
+  var z = a[2];
+  var len = x * x + y * y + z * z;
+  if (len > 0) {
+    //TODO: evaluate use of glm_invsqrt here?
+    len = 1 / Math.sqrt(len);
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+  }
+  return out;
+}
+
+/**
+ * Calculates the dot product of two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+function dot(a, b) {
+  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+
+/**
+ * Computes the cross product of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function cross(out, a, b) {
+  var ax = a[0],
+      ay = a[1],
+      az = a[2];
+  var bx = b[0],
+      by = b[1],
+      bz = b[2];
+
+  out[0] = ay * bz - az * by;
+  out[1] = az * bx - ax * bz;
+  out[2] = ax * by - ay * bx;
+  return out;
+}
+
+/**
+ * Performs a linear interpolation between two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+function lerp(out, a, b, t) {
+  var ax = a[0];
+  var ay = a[1];
+  var az = a[2];
+  out[0] = ax + t * (b[0] - ax);
+  out[1] = ay + t * (b[1] - ay);
+  out[2] = az + t * (b[2] - az);
+  return out;
+}
+
+/**
+ * Performs a hermite interpolation with two control points
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {vec3} c the third operand
+ * @param {vec3} d the fourth operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+function hermite(out, a, b, c, d, t) {
+  var factorTimes2 = t * t;
+  var factor1 = factorTimes2 * (2 * t - 3) + 1;
+  var factor2 = factorTimes2 * (t - 2) + t;
+  var factor3 = factorTimes2 * (t - 1);
+  var factor4 = factorTimes2 * (3 - 2 * t);
+
+  out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+  out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+  out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+
+  return out;
+}
+
+/**
+ * Performs a bezier interpolation with two control points
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {vec3} c the third operand
+ * @param {vec3} d the fourth operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+function bezier(out, a, b, c, d, t) {
+  var inverseFactor = 1 - t;
+  var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+  var factorTimes2 = t * t;
+  var factor1 = inverseFactorTimesTwo * inverseFactor;
+  var factor2 = 3 * t * inverseFactorTimesTwo;
+  var factor3 = 3 * factorTimes2 * inverseFactor;
+  var factor4 = factorTimes2 * t;
+
+  out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+  out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+  out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+
+  return out;
+}
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec3} out
+ */
+function random(out, scale) {
+  scale = scale || 1.0;
+
+  var r = glMatrix.RANDOM() * 2.0 * Math.PI;
+  var z = glMatrix.RANDOM() * 2.0 - 1.0;
+  var zScale = Math.sqrt(1.0 - z * z) * scale;
+
+  out[0] = Math.cos(r) * zScale;
+  out[1] = Math.sin(r) * zScale;
+  out[2] = z * scale;
+  return out;
+}
+
+/**
+ * Transforms the vec3 with a mat4.
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec3} out
+ */
+function transformMat4(out, a, m) {
+  var x = a[0],
+      y = a[1],
+      z = a[2];
+  var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+  w = w || 1.0;
+  out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+  out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+  out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+  return out;
+}
+
+/**
+ * Transforms the vec3 with a mat3.
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat3} m the 3x3 matrix to transform with
+ * @returns {vec3} out
+ */
+function transformMat3(out, a, m) {
+  var x = a[0],
+      y = a[1],
+      z = a[2];
+  out[0] = x * m[0] + y * m[3] + z * m[6];
+  out[1] = x * m[1] + y * m[4] + z * m[7];
+  out[2] = x * m[2] + y * m[5] + z * m[8];
+  return out;
+}
+
+/**
+ * Transforms the vec3 with a quat
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec3} out
+ */
+function transformQuat(out, a, q) {
+  // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
+
+  var x = a[0],
+      y = a[1],
+      z = a[2];
+  var qx = q[0],
+      qy = q[1],
+      qz = q[2],
+      qw = q[3];
+
+  // calculate quat * vec
+  var ix = qw * x + qy * z - qz * y;
+  var iy = qw * y + qz * x - qx * z;
+  var iz = qw * z + qx * y - qy * x;
+  var iw = -qx * x - qy * y - qz * z;
+
+  // calculate result * inverse quat
+  out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+  out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+  out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+  return out;
+}
+
+/**
+ * Rotate a 3D vector around the x-axis
+ * @param {vec3} out The receiving vec3
+ * @param {vec3} a The vec3 point to rotate
+ * @param {vec3} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec3} out
+ */
+function rotateX(out, a, b, c) {
+  var p = [],
+      r = [];
+  //Translate point to the origin
+  p[0] = a[0] - b[0];
+  p[1] = a[1] - b[1];
+  p[2] = a[2] - b[2];
+
+  //perform rotation
+  r[0] = p[0];
+  r[1] = p[1] * Math.cos(c) - p[2] * Math.sin(c);
+  r[2] = p[1] * Math.sin(c) + p[2] * Math.cos(c);
+
+  //translate to correct position
+  out[0] = r[0] + b[0];
+  out[1] = r[1] + b[1];
+  out[2] = r[2] + b[2];
+
+  return out;
+}
+
+/**
+ * Rotate a 3D vector around the y-axis
+ * @param {vec3} out The receiving vec3
+ * @param {vec3} a The vec3 point to rotate
+ * @param {vec3} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec3} out
+ */
+function rotateY(out, a, b, c) {
+  var p = [],
+      r = [];
+  //Translate point to the origin
+  p[0] = a[0] - b[0];
+  p[1] = a[1] - b[1];
+  p[2] = a[2] - b[2];
+
+  //perform rotation
+  r[0] = p[2] * Math.sin(c) + p[0] * Math.cos(c);
+  r[1] = p[1];
+  r[2] = p[2] * Math.cos(c) - p[0] * Math.sin(c);
+
+  //translate to correct position
+  out[0] = r[0] + b[0];
+  out[1] = r[1] + b[1];
+  out[2] = r[2] + b[2];
+
+  return out;
+}
+
+/**
+ * Rotate a 3D vector around the z-axis
+ * @param {vec3} out The receiving vec3
+ * @param {vec3} a The vec3 point to rotate
+ * @param {vec3} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec3} out
+ */
+function rotateZ(out, a, b, c) {
+  var p = [],
+      r = [];
+  //Translate point to the origin
+  p[0] = a[0] - b[0];
+  p[1] = a[1] - b[1];
+  p[2] = a[2] - b[2];
+
+  //perform rotation
+  r[0] = p[0] * Math.cos(c) - p[1] * Math.sin(c);
+  r[1] = p[0] * Math.sin(c) + p[1] * Math.cos(c);
+  r[2] = p[2];
+
+  //translate to correct position
+  out[0] = r[0] + b[0];
+  out[1] = r[1] + b[1];
+  out[2] = r[2] + b[2];
+
+  return out;
+}
+
+/**
+ * Get the angle between two 3D vectors
+ * @param {vec3} a The first operand
+ * @param {vec3} b The second operand
+ * @returns {Number} The angle in radians
+ */
+function angle(a, b) {
+  var tempA = fromValues(a[0], a[1], a[2]);
+  var tempB = fromValues(b[0], b[1], b[2]);
+
+  normalize(tempA, tempA);
+  normalize(tempB, tempB);
+
+  var cosine = dot(tempA, tempB);
+
+  if (cosine > 1.0) {
+    return 0;
+  } else if (cosine < -1.0) {
+    return Math.PI;
+  } else {
+    return Math.acos(cosine);
+  }
+}
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec3} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+function str(a) {
+  return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+}
+
+/**
+ * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {vec3} a The first vector.
+ * @param {vec3} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+}
+
+/**
+ * Returns whether or not the vectors have approximately the same elements in the same position.
+ *
+ * @param {vec3} a The first vector.
+ * @param {vec3} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2];
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+}
+
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+var div = exports.div = divide;
+
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+var dist = exports.dist = distance;
+
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+var sqrDist = exports.sqrDist = squaredDistance;
+
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+var len = exports.len = length;
+
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+var sqrLen = exports.sqrLen = squaredLength;
+
+/**
+ * Perform some operation over an array of vec3s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+var forEach = exports.forEach = function () {
+  var vec = create();
+
+  return function (a, stride, offset, count, fn, arg) {
+    var i = void 0,
+        l = void 0;
+    if (!stride) {
+      stride = 3;
+    }
+
+    if (!offset) {
+      offset = 0;
+    }
+
+    if (count) {
+      l = Math.min(count * stride + offset, a.length);
+    } else {
+      l = a.length;
+    }
+
+    for (i = offset; i < l; i += stride) {
+      vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2];
+      fn(vec, vec, arg);
+      a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2];
+    }
+
+    return a;
+  };
+}();
+
+/***/ }),
+/* 3 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.forEach = exports.sqrLen = exports.len = exports.sqrDist = exports.dist = exports.div = exports.mul = exports.sub = undefined;
+exports.create = create;
+exports.clone = clone;
+exports.fromValues = fromValues;
+exports.copy = copy;
+exports.set = set;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiply = multiply;
+exports.divide = divide;
+exports.ceil = ceil;
+exports.floor = floor;
+exports.min = min;
+exports.max = max;
+exports.round = round;
+exports.scale = scale;
+exports.scaleAndAdd = scaleAndAdd;
+exports.distance = distance;
+exports.squaredDistance = squaredDistance;
+exports.length = length;
+exports.squaredLength = squaredLength;
+exports.negate = negate;
+exports.inverse = inverse;
+exports.normalize = normalize;
+exports.dot = dot;
+exports.lerp = lerp;
+exports.random = random;
+exports.transformMat4 = transformMat4;
+exports.transformQuat = transformQuat;
+exports.str = str;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 4 Dimensional Vector
+ * @module vec4
+ */
+
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = 0;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  return out;
+}
+
+/**
+ * Creates a new vec4 initialized with values from an existing vector
+ *
+ * @param {vec4} a vector to clone
+ * @returns {vec4} a new 4D vector
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  return out;
+}
+
+/**
+ * Creates a new vec4 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
+ */
+function fromValues(x, y, z, w) {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = x;
+  out[1] = y;
+  out[2] = z;
+  out[3] = w;
+  return out;
+}
+
+/**
+ * Copy the values from one vec4 to another
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the source vector
+ * @returns {vec4} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  return out;
+}
+
+/**
+ * Set the components of a vec4 to the given values
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} out
+ */
+function set(out, x, y, z, w) {
+  out[0] = x;
+  out[1] = y;
+  out[2] = z;
+  out[3] = w;
+  return out;
+}
+
+/**
+ * Adds two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  out[2] = a[2] + b[2];
+  out[3] = a[3] + b[3];
+  return out;
+}
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  out[2] = a[2] - b[2];
+  out[3] = a[3] - b[3];
+  return out;
+}
+
+/**
+ * Multiplies two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function multiply(out, a, b) {
+  out[0] = a[0] * b[0];
+  out[1] = a[1] * b[1];
+  out[2] = a[2] * b[2];
+  out[3] = a[3] * b[3];
+  return out;
+}
+
+/**
+ * Divides two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function divide(out, a, b) {
+  out[0] = a[0] / b[0];
+  out[1] = a[1] / b[1];
+  out[2] = a[2] / b[2];
+  out[3] = a[3] / b[3];
+  return out;
+}
+
+/**
+ * Math.ceil the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to ceil
+ * @returns {vec4} out
+ */
+function ceil(out, a) {
+  out[0] = Math.ceil(a[0]);
+  out[1] = Math.ceil(a[1]);
+  out[2] = Math.ceil(a[2]);
+  out[3] = Math.ceil(a[3]);
+  return out;
+}
+
+/**
+ * Math.floor the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to floor
+ * @returns {vec4} out
+ */
+function floor(out, a) {
+  out[0] = Math.floor(a[0]);
+  out[1] = Math.floor(a[1]);
+  out[2] = Math.floor(a[2]);
+  out[3] = Math.floor(a[3]);
+  return out;
+}
+
+/**
+ * Returns the minimum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function min(out, a, b) {
+  out[0] = Math.min(a[0], b[0]);
+  out[1] = Math.min(a[1], b[1]);
+  out[2] = Math.min(a[2], b[2]);
+  out[3] = Math.min(a[3], b[3]);
+  return out;
+}
+
+/**
+ * Returns the maximum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function max(out, a, b) {
+  out[0] = Math.max(a[0], b[0]);
+  out[1] = Math.max(a[1], b[1]);
+  out[2] = Math.max(a[2], b[2]);
+  out[3] = Math.max(a[3], b[3]);
+  return out;
+}
+
+/**
+ * Math.round the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to round
+ * @returns {vec4} out
+ */
+function round(out, a) {
+  out[0] = Math.round(a[0]);
+  out[1] = Math.round(a[1]);
+  out[2] = Math.round(a[2]);
+  out[3] = Math.round(a[3]);
+  return out;
+}
+
+/**
+ * Scales a vec4 by a scalar number
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec4} out
+ */
+function scale(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  out[2] = a[2] * b;
+  out[3] = a[3] * b;
+  return out;
+}
+
+/**
+ * Adds two vec4's after scaling the second operand by a scalar value
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec4} out
+ */
+function scaleAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  out[2] = a[2] + b[2] * scale;
+  out[3] = a[3] + b[3] * scale;
+  return out;
+}
+
+/**
+ * Calculates the euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} distance between a and b
+ */
+function distance(a, b) {
+  var x = b[0] - a[0];
+  var y = b[1] - a[1];
+  var z = b[2] - a[2];
+  var w = b[3] - a[3];
+  return Math.sqrt(x * x + y * y + z * z + w * w);
+}
+
+/**
+ * Calculates the squared euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+function squaredDistance(a, b) {
+  var x = b[0] - a[0];
+  var y = b[1] - a[1];
+  var z = b[2] - a[2];
+  var w = b[3] - a[3];
+  return x * x + y * y + z * z + w * w;
+}
+
+/**
+ * Calculates the length of a vec4
+ *
+ * @param {vec4} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+function length(a) {
+  var x = a[0];
+  var y = a[1];
+  var z = a[2];
+  var w = a[3];
+  return Math.sqrt(x * x + y * y + z * z + w * w);
+}
+
+/**
+ * Calculates the squared length of a vec4
+ *
+ * @param {vec4} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+function squaredLength(a) {
+  var x = a[0];
+  var y = a[1];
+  var z = a[2];
+  var w = a[3];
+  return x * x + y * y + z * z + w * w;
+}
+
+/**
+ * Negates the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to negate
+ * @returns {vec4} out
+ */
+function negate(out, a) {
+  out[0] = -a[0];
+  out[1] = -a[1];
+  out[2] = -a[2];
+  out[3] = -a[3];
+  return out;
+}
+
+/**
+ * Returns the inverse of the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to invert
+ * @returns {vec4} out
+ */
+function inverse(out, a) {
+  out[0] = 1.0 / a[0];
+  out[1] = 1.0 / a[1];
+  out[2] = 1.0 / a[2];
+  out[3] = 1.0 / a[3];
+  return out;
+}
+
+/**
+ * Normalize a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+function normalize(out, a) {
+  var x = a[0];
+  var y = a[1];
+  var z = a[2];
+  var w = a[3];
+  var len = x * x + y * y + z * z + w * w;
+  if (len > 0) {
+    len = 1 / Math.sqrt(len);
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+  }
+  return out;
+}
+
+/**
+ * Calculates the dot product of two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+function dot(a, b) {
+  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+}
+
+/**
+ * Performs a linear interpolation between two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec4} out
+ */
+function lerp(out, a, b, t) {
+  var ax = a[0];
+  var ay = a[1];
+  var az = a[2];
+  var aw = a[3];
+  out[0] = ax + t * (b[0] - ax);
+  out[1] = ay + t * (b[1] - ay);
+  out[2] = az + t * (b[2] - az);
+  out[3] = aw + t * (b[3] - aw);
+  return out;
+}
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec4} out
+ */
+function random(out, vectorScale) {
+  vectorScale = vectorScale || 1.0;
+
+  //TODO: This is a pretty awful way of doing this. Find something better.
+  out[0] = glMatrix.RANDOM();
+  out[1] = glMatrix.RANDOM();
+  out[2] = glMatrix.RANDOM();
+  out[3] = glMatrix.RANDOM();
+  normalize(out, out);
+  scale(out, out, vectorScale);
+  return out;
+}
+
+/**
+ * Transforms the vec4 with a mat4.
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
+ */
+function transformMat4(out, a, m) {
+  var x = a[0],
+      y = a[1],
+      z = a[2],
+      w = a[3];
+  out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+  out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+  out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+  out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+  return out;
+}
+
+/**
+ * Transforms the vec4 with a quat
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
+ */
+function transformQuat(out, a, q) {
+  var x = a[0],
+      y = a[1],
+      z = a[2];
+  var qx = q[0],
+      qy = q[1],
+      qz = q[2],
+      qw = q[3];
+
+  // calculate quat * vec
+  var ix = qw * x + qy * z - qz * y;
+  var iy = qw * y + qz * x - qx * z;
+  var iz = qw * z + qx * y - qy * x;
+  var iw = -qx * x - qy * y - qz * z;
+
+  // calculate result * inverse quat
+  out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+  out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+  out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+  out[3] = a[3];
+  return out;
+}
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec4} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+function str(a) {
+  return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+}
+
+/**
+ * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {vec4} a The first vector.
+ * @param {vec4} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+}
+
+/**
+ * Returns whether or not the vectors have approximately the same elements in the same position.
+ *
+ * @param {vec4} a The first vector.
+ * @param {vec4} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3];
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+}
+
+/**
+ * Alias for {@link vec4.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/**
+ * Alias for {@link vec4.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link vec4.divide}
+ * @function
+ */
+var div = exports.div = divide;
+
+/**
+ * Alias for {@link vec4.distance}
+ * @function
+ */
+var dist = exports.dist = distance;
+
+/**
+ * Alias for {@link vec4.squaredDistance}
+ * @function
+ */
+var sqrDist = exports.sqrDist = squaredDistance;
+
+/**
+ * Alias for {@link vec4.length}
+ * @function
+ */
+var len = exports.len = length;
+
+/**
+ * Alias for {@link vec4.squaredLength}
+ * @function
+ */
+var sqrLen = exports.sqrLen = squaredLength;
+
+/**
+ * Perform some operation over an array of vec4s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+var forEach = exports.forEach = function () {
+  var vec = create();
+
+  return function (a, stride, offset, count, fn, arg) {
+    var i = void 0,
+        l = void 0;
+    if (!stride) {
+      stride = 4;
+    }
+
+    if (!offset) {
+      offset = 0;
+    }
+
+    if (count) {
+      l = Math.min(count * stride + offset, a.length);
+    } else {
+      l = a.length;
+    }
+
+    for (i = offset; i < l; i += stride) {
+      vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2];vec[3] = a[i + 3];
+      fn(vec, vec, arg);
+      a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2];a[i + 3] = vec[3];
+    }
+
+    return a;
+  };
+}();
+
+/***/ }),
+/* 4 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.vec4 = exports.vec3 = exports.vec2 = exports.quat = exports.mat4 = exports.mat3 = exports.mat2d = exports.mat2 = exports.glMatrix = undefined;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+var _mat = __webpack_require__(5);
+
+var mat2 = _interopRequireWildcard(_mat);
+
+var _mat2d = __webpack_require__(6);
+
+var mat2d = _interopRequireWildcard(_mat2d);
+
+var _mat2 = __webpack_require__(1);
+
+var mat3 = _interopRequireWildcard(_mat2);
+
+var _mat3 = __webpack_require__(7);
+
+var mat4 = _interopRequireWildcard(_mat3);
+
+var _quat = __webpack_require__(8);
+
+var quat = _interopRequireWildcard(_quat);
+
+var _vec = __webpack_require__(9);
+
+var vec2 = _interopRequireWildcard(_vec);
+
+var _vec2 = __webpack_require__(2);
+
+var vec3 = _interopRequireWildcard(_vec2);
+
+var _vec3 = __webpack_require__(3);
+
+var vec4 = _interopRequireWildcard(_vec3);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+exports.glMatrix = glMatrix;
+exports.mat2 = mat2;
+exports.mat2d = mat2d;
+exports.mat3 = mat3;
+exports.mat4 = mat4;
+exports.quat = quat;
+exports.vec2 = vec2;
+exports.vec3 = vec3;
+exports.vec4 = vec4; /**
+                      * @fileoverview gl-matrix - High performance matrix and vector operations
+                      * @author Brandon Jones
+                      * @author Colin MacKenzie IV
+                      * @version 2.4.0
+                      */
+
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+// END HEADER
+
+/***/ }),
+/* 5 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.sub = exports.mul = undefined;
+exports.create = create;
+exports.clone = clone;
+exports.copy = copy;
+exports.identity = identity;
+exports.fromValues = fromValues;
+exports.set = set;
+exports.transpose = transpose;
+exports.invert = invert;
+exports.adjoint = adjoint;
+exports.determinant = determinant;
+exports.multiply = multiply;
+exports.rotate = rotate;
+exports.scale = scale;
+exports.fromRotation = fromRotation;
+exports.fromScaling = fromScaling;
+exports.str = str;
+exports.frob = frob;
+exports.LDU = LDU;
+exports.add = add;
+exports.subtract = subtract;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+exports.multiplyScalar = multiplyScalar;
+exports.multiplyScalarAndAdd = multiplyScalarAndAdd;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 2x2 Matrix
+ * @module mat2
+ */
+
+/**
+ * Creates a new identity mat2
+ *
+ * @returns {mat2} a new 2x2 matrix
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  return out;
+}
+
+/**
+ * Creates a new mat2 initialized with values from an existing matrix
+ *
+ * @param {mat2} a matrix to clone
+ * @returns {mat2} a new 2x2 matrix
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  return out;
+}
+
+/**
+ * Copy the values from one mat2 to another
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  return out;
+}
+
+/**
+ * Set a mat2 to the identity matrix
+ *
+ * @param {mat2} out the receiving matrix
+ * @returns {mat2} out
+ */
+function identity(out) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  return out;
+}
+
+/**
+ * Create a new mat2 with the given values
+ *
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m10 Component in column 1, row 0 position (index 2)
+ * @param {Number} m11 Component in column 1, row 1 position (index 3)
+ * @returns {mat2} out A new 2x2 matrix
+ */
+function fromValues(m00, m01, m10, m11) {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = m00;
+  out[1] = m01;
+  out[2] = m10;
+  out[3] = m11;
+  return out;
+}
+
+/**
+ * Set the components of a mat2 to the given values
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m10 Component in column 1, row 0 position (index 2)
+ * @param {Number} m11 Component in column 1, row 1 position (index 3)
+ * @returns {mat2} out
+ */
+function set(out, m00, m01, m10, m11) {
+  out[0] = m00;
+  out[1] = m01;
+  out[2] = m10;
+  out[3] = m11;
+  return out;
+}
+
+/**
+ * Transpose the values of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+function transpose(out, a) {
+  // If we are transposing ourselves we can skip a few steps but have to cache
+  // some values
+  if (out === a) {
+    var a1 = a[1];
+    out[1] = a[2];
+    out[2] = a1;
+  } else {
+    out[0] = a[0];
+    out[1] = a[2];
+    out[2] = a[1];
+    out[3] = a[3];
+  }
+
+  return out;
+}
+
+/**
+ * Inverts a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+function invert(out, a) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+
+  // Calculate the determinant
+  var det = a0 * a3 - a2 * a1;
+
+  if (!det) {
+    return null;
+  }
+  det = 1.0 / det;
+
+  out[0] = a3 * det;
+  out[1] = -a1 * det;
+  out[2] = -a2 * det;
+  out[3] = a0 * det;
+
+  return out;
+}
+
+/**
+ * Calculates the adjugate of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+function adjoint(out, a) {
+  // Caching this value is nessecary if out == a
+  var a0 = a[0];
+  out[0] = a[3];
+  out[1] = -a[1];
+  out[2] = -a[2];
+  out[3] = a0;
+
+  return out;
+}
+
+/**
+ * Calculates the determinant of a mat2
+ *
+ * @param {mat2} a the source matrix
+ * @returns {Number} determinant of a
+ */
+function determinant(a) {
+  return a[0] * a[3] - a[2] * a[1];
+}
+
+/**
+ * Multiplies two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+function multiply(out, a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3];
+  out[0] = a0 * b0 + a2 * b1;
+  out[1] = a1 * b0 + a3 * b1;
+  out[2] = a0 * b2 + a2 * b3;
+  out[3] = a1 * b2 + a3 * b3;
+  return out;
+}
+
+/**
+ * Rotates a mat2 by the given angle
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+function rotate(out, a, rad) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+  out[0] = a0 * c + a2 * s;
+  out[1] = a1 * c + a3 * s;
+  out[2] = a0 * -s + a2 * c;
+  out[3] = a1 * -s + a3 * c;
+  return out;
+}
+
+/**
+ * Scales the mat2 by the dimensions in the given vec2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2} out
+ **/
+function scale(out, a, v) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var v0 = v[0],
+      v1 = v[1];
+  out[0] = a0 * v0;
+  out[1] = a1 * v0;
+  out[2] = a2 * v1;
+  out[3] = a3 * v1;
+  return out;
+}
+
+/**
+ * Creates a matrix from a given angle
+ * This is equivalent to (but much faster than):
+ *
+ *     mat2.identity(dest);
+ *     mat2.rotate(dest, dest, rad);
+ *
+ * @param {mat2} out mat2 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+function fromRotation(out, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+  out[0] = c;
+  out[1] = s;
+  out[2] = -s;
+  out[3] = c;
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ *     mat2.identity(dest);
+ *     mat2.scale(dest, dest, vec);
+ *
+ * @param {mat2} out mat2 receiving operation result
+ * @param {vec2} v Scaling vector
+ * @returns {mat2} out
+ */
+function fromScaling(out, v) {
+  out[0] = v[0];
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = v[1];
+  return out;
+}
+
+/**
+ * Returns a string representation of a mat2
+ *
+ * @param {mat2} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+function str(a) {
+  return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+}
+
+/**
+ * Returns Frobenius norm of a mat2
+ *
+ * @param {mat2} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+function frob(a) {
+  return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2));
+}
+
+/**
+ * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+ * @param {mat2} L the lower triangular matrix
+ * @param {mat2} D the diagonal matrix
+ * @param {mat2} U the upper triangular matrix
+ * @param {mat2} a the input matrix to factorize
+ */
+
+function LDU(L, D, U, a) {
+  L[2] = a[2] / a[0];
+  U[0] = a[0];
+  U[1] = a[1];
+  U[3] = a[3] - L[2] * U[1];
+  return [L, D, U];
+}
+
+/**
+ * Adds two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  out[2] = a[2] + b[2];
+  out[3] = a[3] + b[3];
+  return out;
+}
+
+/**
+ * Subtracts matrix b from matrix a
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  out[2] = a[2] - b[2];
+  out[3] = a[3] - b[3];
+  return out;
+}
+
+/**
+ * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {mat2} a The first matrix.
+ * @param {mat2} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+}
+
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat2} a The first matrix.
+ * @param {mat2} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3];
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+}
+
+/**
+ * Multiply each element of the matrix by a scalar.
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat2} out
+ */
+function multiplyScalar(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  out[2] = a[2] * b;
+  out[3] = a[3] * b;
+  return out;
+}
+
+/**
+ * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+ *
+ * @param {mat2} out the receiving vector
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat2} out
+ */
+function multiplyScalarAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  out[2] = a[2] + b[2] * scale;
+  out[3] = a[3] + b[3] * scale;
+  return out;
+}
+
+/**
+ * Alias for {@link mat2.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link mat2.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/***/ }),
+/* 6 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.sub = exports.mul = undefined;
+exports.create = create;
+exports.clone = clone;
+exports.copy = copy;
+exports.identity = identity;
+exports.fromValues = fromValues;
+exports.set = set;
+exports.invert = invert;
+exports.determinant = determinant;
+exports.multiply = multiply;
+exports.rotate = rotate;
+exports.scale = scale;
+exports.translate = translate;
+exports.fromRotation = fromRotation;
+exports.fromScaling = fromScaling;
+exports.fromTranslation = fromTranslation;
+exports.str = str;
+exports.frob = frob;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiplyScalar = multiplyScalar;
+exports.multiplyScalarAndAdd = multiplyScalarAndAdd;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 2x3 Matrix
+ * @module mat2d
+ *
+ * @description
+ * A mat2d contains six elements defined as:
+ * <pre>
+ * [a, c, tx,
+ *  b, d, ty]
+ * </pre>
+ * This is a short form for the 3x3 matrix:
+ * <pre>
+ * [a, c, tx,
+ *  b, d, ty,
+ *  0, 0, 1]
+ * </pre>
+ * The last row is ignored so the array is shorter and operations are faster.
+ */
+
+/**
+ * Creates a new identity mat2d
+ *
+ * @returns {mat2d} a new 2x3 matrix
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(6);
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  out[4] = 0;
+  out[5] = 0;
+  return out;
+}
+
+/**
+ * Creates a new mat2d initialized with values from an existing matrix
+ *
+ * @param {mat2d} a matrix to clone
+ * @returns {mat2d} a new 2x3 matrix
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(6);
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  out[4] = a[4];
+  out[5] = a[5];
+  return out;
+}
+
+/**
+ * Copy the values from one mat2d to another
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  out[4] = a[4];
+  out[5] = a[5];
+  return out;
+}
+
+/**
+ * Set a mat2d to the identity matrix
+ *
+ * @param {mat2d} out the receiving matrix
+ * @returns {mat2d} out
+ */
+function identity(out) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  out[4] = 0;
+  out[5] = 0;
+  return out;
+}
+
+/**
+ * Create a new mat2d with the given values
+ *
+ * @param {Number} a Component A (index 0)
+ * @param {Number} b Component B (index 1)
+ * @param {Number} c Component C (index 2)
+ * @param {Number} d Component D (index 3)
+ * @param {Number} tx Component TX (index 4)
+ * @param {Number} ty Component TY (index 5)
+ * @returns {mat2d} A new mat2d
+ */
+function fromValues(a, b, c, d, tx, ty) {
+  var out = new glMatrix.ARRAY_TYPE(6);
+  out[0] = a;
+  out[1] = b;
+  out[2] = c;
+  out[3] = d;
+  out[4] = tx;
+  out[5] = ty;
+  return out;
+}
+
+/**
+ * Set the components of a mat2d to the given values
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {Number} a Component A (index 0)
+ * @param {Number} b Component B (index 1)
+ * @param {Number} c Component C (index 2)
+ * @param {Number} d Component D (index 3)
+ * @param {Number} tx Component TX (index 4)
+ * @param {Number} ty Component TY (index 5)
+ * @returns {mat2d} out
+ */
+function set(out, a, b, c, d, tx, ty) {
+  out[0] = a;
+  out[1] = b;
+  out[2] = c;
+  out[3] = d;
+  out[4] = tx;
+  out[5] = ty;
+  return out;
+}
+
+/**
+ * Inverts a mat2d
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+function invert(out, a) {
+  var aa = a[0],
+      ab = a[1],
+      ac = a[2],
+      ad = a[3];
+  var atx = a[4],
+      aty = a[5];
+
+  var det = aa * ad - ab * ac;
+  if (!det) {
+    return null;
+  }
+  det = 1.0 / det;
+
+  out[0] = ad * det;
+  out[1] = -ab * det;
+  out[2] = -ac * det;
+  out[3] = aa * det;
+  out[4] = (ac * aty - ad * atx) * det;
+  out[5] = (ab * atx - aa * aty) * det;
+  return out;
+}
+
+/**
+ * Calculates the determinant of a mat2d
+ *
+ * @param {mat2d} a the source matrix
+ * @returns {Number} determinant of a
+ */
+function determinant(a) {
+  return a[0] * a[3] - a[1] * a[2];
+}
+
+/**
+ * Multiplies two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+function multiply(out, a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3],
+      a4 = a[4],
+      a5 = a[5];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3],
+      b4 = b[4],
+      b5 = b[5];
+  out[0] = a0 * b0 + a2 * b1;
+  out[1] = a1 * b0 + a3 * b1;
+  out[2] = a0 * b2 + a2 * b3;
+  out[3] = a1 * b2 + a3 * b3;
+  out[4] = a0 * b4 + a2 * b5 + a4;
+  out[5] = a1 * b4 + a3 * b5 + a5;
+  return out;
+}
+
+/**
+ * Rotates a mat2d by the given angle
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+function rotate(out, a, rad) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3],
+      a4 = a[4],
+      a5 = a[5];
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+  out[0] = a0 * c + a2 * s;
+  out[1] = a1 * c + a3 * s;
+  out[2] = a0 * -s + a2 * c;
+  out[3] = a1 * -s + a3 * c;
+  out[4] = a4;
+  out[5] = a5;
+  return out;
+}
+
+/**
+ * Scales the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2d} out
+ **/
+function scale(out, a, v) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3],
+      a4 = a[4],
+      a5 = a[5];
+  var v0 = v[0],
+      v1 = v[1];
+  out[0] = a0 * v0;
+  out[1] = a1 * v0;
+  out[2] = a2 * v1;
+  out[3] = a3 * v1;
+  out[4] = a4;
+  out[5] = a5;
+  return out;
+}
+
+/**
+ * Translates the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to translate the matrix by
+ * @returns {mat2d} out
+ **/
+function translate(out, a, v) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3],
+      a4 = a[4],
+      a5 = a[5];
+  var v0 = v[0],
+      v1 = v[1];
+  out[0] = a0;
+  out[1] = a1;
+  out[2] = a2;
+  out[3] = a3;
+  out[4] = a0 * v0 + a2 * v1 + a4;
+  out[5] = a1 * v0 + a3 * v1 + a5;
+  return out;
+}
+
+/**
+ * Creates a matrix from a given angle
+ * This is equivalent to (but much faster than):
+ *
+ *     mat2d.identity(dest);
+ *     mat2d.rotate(dest, dest, rad);
+ *
+ * @param {mat2d} out mat2d receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+function fromRotation(out, rad) {
+  var s = Math.sin(rad),
+      c = Math.cos(rad);
+  out[0] = c;
+  out[1] = s;
+  out[2] = -s;
+  out[3] = c;
+  out[4] = 0;
+  out[5] = 0;
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ *     mat2d.identity(dest);
+ *     mat2d.scale(dest, dest, vec);
+ *
+ * @param {mat2d} out mat2d receiving operation result
+ * @param {vec2} v Scaling vector
+ * @returns {mat2d} out
+ */
+function fromScaling(out, v) {
+  out[0] = v[0];
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = v[1];
+  out[4] = 0;
+  out[5] = 0;
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector translation
+ * This is equivalent to (but much faster than):
+ *
+ *     mat2d.identity(dest);
+ *     mat2d.translate(dest, dest, vec);
+ *
+ * @param {mat2d} out mat2d receiving operation result
+ * @param {vec2} v Translation vector
+ * @returns {mat2d} out
+ */
+function fromTranslation(out, v) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  out[4] = v[0];
+  out[5] = v[1];
+  return out;
+}
+
+/**
+ * Returns a string representation of a mat2d
+ *
+ * @param {mat2d} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+function str(a) {
+  return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+}
+
+/**
+ * Returns Frobenius norm of a mat2d
+ *
+ * @param {mat2d} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+function frob(a) {
+  return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1);
+}
+
+/**
+ * Adds two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  out[2] = a[2] + b[2];
+  out[3] = a[3] + b[3];
+  out[4] = a[4] + b[4];
+  out[5] = a[5] + b[5];
+  return out;
+}
+
+/**
+ * Subtracts matrix b from matrix a
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  out[2] = a[2] - b[2];
+  out[3] = a[3] - b[3];
+  out[4] = a[4] - b[4];
+  out[5] = a[5] - b[5];
+  return out;
+}
+
+/**
+ * Multiply each element of the matrix by a scalar.
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat2d} out
+ */
+function multiplyScalar(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  out[2] = a[2] * b;
+  out[3] = a[3] * b;
+  out[4] = a[4] * b;
+  out[5] = a[5] * b;
+  return out;
+}
+
+/**
+ * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+ *
+ * @param {mat2d} out the receiving vector
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat2d} out
+ */
+function multiplyScalarAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  out[2] = a[2] + b[2] * scale;
+  out[3] = a[3] + b[3] * scale;
+  out[4] = a[4] + b[4] * scale;
+  out[5] = a[5] + b[5] * scale;
+  return out;
+}
+
+/**
+ * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {mat2d} a The first matrix.
+ * @param {mat2d} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+}
+
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat2d} a The first matrix.
+ * @param {mat2d} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3],
+      a4 = a[4],
+      a5 = a[5];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3],
+      b4 = b[4],
+      b5 = b[5];
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+}
+
+/**
+ * Alias for {@link mat2d.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link mat2d.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/***/ }),
+/* 7 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.sub = exports.mul = undefined;
+exports.create = create;
+exports.clone = clone;
+exports.copy = copy;
+exports.fromValues = fromValues;
+exports.set = set;
+exports.identity = identity;
+exports.transpose = transpose;
+exports.invert = invert;
+exports.adjoint = adjoint;
+exports.determinant = determinant;
+exports.multiply = multiply;
+exports.translate = translate;
+exports.scale = scale;
+exports.rotate = rotate;
+exports.rotateX = rotateX;
+exports.rotateY = rotateY;
+exports.rotateZ = rotateZ;
+exports.fromTranslation = fromTranslation;
+exports.fromScaling = fromScaling;
+exports.fromRotation = fromRotation;
+exports.fromXRotation = fromXRotation;
+exports.fromYRotation = fromYRotation;
+exports.fromZRotation = fromZRotation;
+exports.fromRotationTranslation = fromRotationTranslation;
+exports.getTranslation = getTranslation;
+exports.getScaling = getScaling;
+exports.getRotation = getRotation;
+exports.fromRotationTranslationScale = fromRotationTranslationScale;
+exports.fromRotationTranslationScaleOrigin = fromRotationTranslationScaleOrigin;
+exports.fromQuat = fromQuat;
+exports.frustum = frustum;
+exports.perspective = perspective;
+exports.perspectiveFromFieldOfView = perspectiveFromFieldOfView;
+exports.ortho = ortho;
+exports.lookAt = lookAt;
+exports.targetTo = targetTo;
+exports.str = str;
+exports.frob = frob;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiplyScalar = multiplyScalar;
+exports.multiplyScalarAndAdd = multiplyScalarAndAdd;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 4x4 Matrix
+ * @module mat4
+ */
+
+/**
+ * Creates a new identity mat4
+ *
+ * @returns {mat4} a new 4x4 matrix
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(16);
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = 1;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = 1;
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a new mat4 initialized with values from an existing matrix
+ *
+ * @param {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(16);
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  out[4] = a[4];
+  out[5] = a[5];
+  out[6] = a[6];
+  out[7] = a[7];
+  out[8] = a[8];
+  out[9] = a[9];
+  out[10] = a[10];
+  out[11] = a[11];
+  out[12] = a[12];
+  out[13] = a[13];
+  out[14] = a[14];
+  out[15] = a[15];
+  return out;
+}
+
+/**
+ * Copy the values from one mat4 to another
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  out[4] = a[4];
+  out[5] = a[5];
+  out[6] = a[6];
+  out[7] = a[7];
+  out[8] = a[8];
+  out[9] = a[9];
+  out[10] = a[10];
+  out[11] = a[11];
+  out[12] = a[12];
+  out[13] = a[13];
+  out[14] = a[14];
+  out[15] = a[15];
+  return out;
+}
+
+/**
+ * Create a new mat4 with the given values
+ *
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m03 Component in column 0, row 3 position (index 3)
+ * @param {Number} m10 Component in column 1, row 0 position (index 4)
+ * @param {Number} m11 Component in column 1, row 1 position (index 5)
+ * @param {Number} m12 Component in column 1, row 2 position (index 6)
+ * @param {Number} m13 Component in column 1, row 3 position (index 7)
+ * @param {Number} m20 Component in column 2, row 0 position (index 8)
+ * @param {Number} m21 Component in column 2, row 1 position (index 9)
+ * @param {Number} m22 Component in column 2, row 2 position (index 10)
+ * @param {Number} m23 Component in column 2, row 3 position (index 11)
+ * @param {Number} m30 Component in column 3, row 0 position (index 12)
+ * @param {Number} m31 Component in column 3, row 1 position (index 13)
+ * @param {Number} m32 Component in column 3, row 2 position (index 14)
+ * @param {Number} m33 Component in column 3, row 3 position (index 15)
+ * @returns {mat4} A new mat4
+ */
+function fromValues(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+  var out = new glMatrix.ARRAY_TYPE(16);
+  out[0] = m00;
+  out[1] = m01;
+  out[2] = m02;
+  out[3] = m03;
+  out[4] = m10;
+  out[5] = m11;
+  out[6] = m12;
+  out[7] = m13;
+  out[8] = m20;
+  out[9] = m21;
+  out[10] = m22;
+  out[11] = m23;
+  out[12] = m30;
+  out[13] = m31;
+  out[14] = m32;
+  out[15] = m33;
+  return out;
+}
+
+/**
+ * Set the components of a mat4 to the given values
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m03 Component in column 0, row 3 position (index 3)
+ * @param {Number} m10 Component in column 1, row 0 position (index 4)
+ * @param {Number} m11 Component in column 1, row 1 position (index 5)
+ * @param {Number} m12 Component in column 1, row 2 position (index 6)
+ * @param {Number} m13 Component in column 1, row 3 position (index 7)
+ * @param {Number} m20 Component in column 2, row 0 position (index 8)
+ * @param {Number} m21 Component in column 2, row 1 position (index 9)
+ * @param {Number} m22 Component in column 2, row 2 position (index 10)
+ * @param {Number} m23 Component in column 2, row 3 position (index 11)
+ * @param {Number} m30 Component in column 3, row 0 position (index 12)
+ * @param {Number} m31 Component in column 3, row 1 position (index 13)
+ * @param {Number} m32 Component in column 3, row 2 position (index 14)
+ * @param {Number} m33 Component in column 3, row 3 position (index 15)
+ * @returns {mat4} out
+ */
+function set(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+  out[0] = m00;
+  out[1] = m01;
+  out[2] = m02;
+  out[3] = m03;
+  out[4] = m10;
+  out[5] = m11;
+  out[6] = m12;
+  out[7] = m13;
+  out[8] = m20;
+  out[9] = m21;
+  out[10] = m22;
+  out[11] = m23;
+  out[12] = m30;
+  out[13] = m31;
+  out[14] = m32;
+  out[15] = m33;
+  return out;
+}
+
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+ */
+function identity(out) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = 1;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = 1;
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Transpose the values of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+function transpose(out, a) {
+  // If we are transposing ourselves we can skip a few steps but have to cache some values
+  if (out === a) {
+    var a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a12 = a[6],
+        a13 = a[7];
+    var a23 = a[11];
+
+    out[1] = a[4];
+    out[2] = a[8];
+    out[3] = a[12];
+    out[4] = a01;
+    out[6] = a[9];
+    out[7] = a[13];
+    out[8] = a02;
+    out[9] = a12;
+    out[11] = a[14];
+    out[12] = a03;
+    out[13] = a13;
+    out[14] = a23;
+  } else {
+    out[0] = a[0];
+    out[1] = a[4];
+    out[2] = a[8];
+    out[3] = a[12];
+    out[4] = a[1];
+    out[5] = a[5];
+    out[6] = a[9];
+    out[7] = a[13];
+    out[8] = a[2];
+    out[9] = a[6];
+    out[10] = a[10];
+    out[11] = a[14];
+    out[12] = a[3];
+    out[13] = a[7];
+    out[14] = a[11];
+    out[15] = a[15];
+  }
+
+  return out;
+}
+
+/**
+ * Inverts a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+function invert(out, a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a03 = a[3];
+  var a10 = a[4],
+      a11 = a[5],
+      a12 = a[6],
+      a13 = a[7];
+  var a20 = a[8],
+      a21 = a[9],
+      a22 = a[10],
+      a23 = a[11];
+  var a30 = a[12],
+      a31 = a[13],
+      a32 = a[14],
+      a33 = a[15];
+
+  var b00 = a00 * a11 - a01 * a10;
+  var b01 = a00 * a12 - a02 * a10;
+  var b02 = a00 * a13 - a03 * a10;
+  var b03 = a01 * a12 - a02 * a11;
+  var b04 = a01 * a13 - a03 * a11;
+  var b05 = a02 * a13 - a03 * a12;
+  var b06 = a20 * a31 - a21 * a30;
+  var b07 = a20 * a32 - a22 * a30;
+  var b08 = a20 * a33 - a23 * a30;
+  var b09 = a21 * a32 - a22 * a31;
+  var b10 = a21 * a33 - a23 * a31;
+  var b11 = a22 * a33 - a23 * a32;
+
+  // Calculate the determinant
+  var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+  if (!det) {
+    return null;
+  }
+  det = 1.0 / det;
+
+  out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+  out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+  out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+  out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+  out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+  out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+  out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+  out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+  out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+  out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+  out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+  out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+  out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+  out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+  out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+  out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+
+  return out;
+}
+
+/**
+ * Calculates the adjugate of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+function adjoint(out, a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a03 = a[3];
+  var a10 = a[4],
+      a11 = a[5],
+      a12 = a[6],
+      a13 = a[7];
+  var a20 = a[8],
+      a21 = a[9],
+      a22 = a[10],
+      a23 = a[11];
+  var a30 = a[12],
+      a31 = a[13],
+      a32 = a[14],
+      a33 = a[15];
+
+  out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+  out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+  out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+  out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+  out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+  out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+  out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+  out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+  out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+  out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+  out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+  out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+  out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+  out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+  out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+  out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+  return out;
+}
+
+/**
+ * Calculates the determinant of a mat4
+ *
+ * @param {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+function determinant(a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a03 = a[3];
+  var a10 = a[4],
+      a11 = a[5],
+      a12 = a[6],
+      a13 = a[7];
+  var a20 = a[8],
+      a21 = a[9],
+      a22 = a[10],
+      a23 = a[11];
+  var a30 = a[12],
+      a31 = a[13],
+      a32 = a[14],
+      a33 = a[15];
+
+  var b00 = a00 * a11 - a01 * a10;
+  var b01 = a00 * a12 - a02 * a10;
+  var b02 = a00 * a13 - a03 * a10;
+  var b03 = a01 * a12 - a02 * a11;
+  var b04 = a01 * a13 - a03 * a11;
+  var b05 = a02 * a13 - a03 * a12;
+  var b06 = a20 * a31 - a21 * a30;
+  var b07 = a20 * a32 - a22 * a30;
+  var b08 = a20 * a33 - a23 * a30;
+  var b09 = a21 * a32 - a22 * a31;
+  var b10 = a21 * a33 - a23 * a31;
+  var b11 = a22 * a33 - a23 * a32;
+
+  // Calculate the determinant
+  return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+}
+
+/**
+ * Multiplies two mat4s
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+function multiply(out, a, b) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a03 = a[3];
+  var a10 = a[4],
+      a11 = a[5],
+      a12 = a[6],
+      a13 = a[7];
+  var a20 = a[8],
+      a21 = a[9],
+      a22 = a[10],
+      a23 = a[11];
+  var a30 = a[12],
+      a31 = a[13],
+      a32 = a[14],
+      a33 = a[15];
+
+  // Cache only the current line of the second matrix
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3];
+  out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+  out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+  out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+  out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+
+  b0 = b[4];b1 = b[5];b2 = b[6];b3 = b[7];
+  out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+  out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+  out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+  out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+
+  b0 = b[8];b1 = b[9];b2 = b[10];b3 = b[11];
+  out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+  out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+  out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+  out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+
+  b0 = b[12];b1 = b[13];b2 = b[14];b3 = b[15];
+  out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+  out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+  out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+  out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+  return out;
+}
+
+/**
+ * Translate a mat4 by the given vector
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to translate
+ * @param {vec3} v vector to translate by
+ * @returns {mat4} out
+ */
+function translate(out, a, v) {
+  var x = v[0],
+      y = v[1],
+      z = v[2];
+  var a00 = void 0,
+      a01 = void 0,
+      a02 = void 0,
+      a03 = void 0;
+  var a10 = void 0,
+      a11 = void 0,
+      a12 = void 0,
+      a13 = void 0;
+  var a20 = void 0,
+      a21 = void 0,
+      a22 = void 0,
+      a23 = void 0;
+
+  if (a === out) {
+    out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+    out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+    out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+    out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+  } else {
+    a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3];
+    a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7];
+    a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11];
+
+    out[0] = a00;out[1] = a01;out[2] = a02;out[3] = a03;
+    out[4] = a10;out[5] = a11;out[6] = a12;out[7] = a13;
+    out[8] = a20;out[9] = a21;out[10] = a22;out[11] = a23;
+
+    out[12] = a00 * x + a10 * y + a20 * z + a[12];
+    out[13] = a01 * x + a11 * y + a21 * z + a[13];
+    out[14] = a02 * x + a12 * y + a22 * z + a[14];
+    out[15] = a03 * x + a13 * y + a23 * z + a[15];
+  }
+
+  return out;
+}
+
+/**
+ * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {vec3} v the vec3 to scale the matrix by
+ * @returns {mat4} out
+ **/
+function scale(out, a, v) {
+  var x = v[0],
+      y = v[1],
+      z = v[2];
+
+  out[0] = a[0] * x;
+  out[1] = a[1] * x;
+  out[2] = a[2] * x;
+  out[3] = a[3] * x;
+  out[4] = a[4] * y;
+  out[5] = a[5] * y;
+  out[6] = a[6] * y;
+  out[7] = a[7] * y;
+  out[8] = a[8] * z;
+  out[9] = a[9] * z;
+  out[10] = a[10] * z;
+  out[11] = a[11] * z;
+  out[12] = a[12];
+  out[13] = a[13];
+  out[14] = a[14];
+  out[15] = a[15];
+  return out;
+}
+
+/**
+ * Rotates a mat4 by the given angle around the given axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+function rotate(out, a, rad, axis) {
+  var x = axis[0],
+      y = axis[1],
+      z = axis[2];
+  var len = Math.sqrt(x * x + y * y + z * z);
+  var s = void 0,
+      c = void 0,
+      t = void 0;
+  var a00 = void 0,
+      a01 = void 0,
+      a02 = void 0,
+      a03 = void 0;
+  var a10 = void 0,
+      a11 = void 0,
+      a12 = void 0,
+      a13 = void 0;
+  var a20 = void 0,
+      a21 = void 0,
+      a22 = void 0,
+      a23 = void 0;
+  var b00 = void 0,
+      b01 = void 0,
+      b02 = void 0;
+  var b10 = void 0,
+      b11 = void 0,
+      b12 = void 0;
+  var b20 = void 0,
+      b21 = void 0,
+      b22 = void 0;
+
+  if (Math.abs(len) < glMatrix.EPSILON) {
+    return null;
+  }
+
+  len = 1 / len;
+  x *= len;
+  y *= len;
+  z *= len;
+
+  s = Math.sin(rad);
+  c = Math.cos(rad);
+  t = 1 - c;
+
+  a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3];
+  a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7];
+  a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11];
+
+  // Construct the elements of the rotation matrix
+  b00 = x * x * t + c;b01 = y * x * t + z * s;b02 = z * x * t - y * s;
+  b10 = x * y * t - z * s;b11 = y * y * t + c;b12 = z * y * t + x * s;
+  b20 = x * z * t + y * s;b21 = y * z * t - x * s;b22 = z * z * t + c;
+
+  // Perform rotation-specific matrix multiplication
+  out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+  out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+  out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+  out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+  out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+  out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+  out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+  out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+  out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+  out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+  out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+  out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+  if (a !== out) {
+    // If the source and destination differ, copy the unchanged last row
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+  }
+  return out;
+}
+
+/**
+ * Rotates a matrix by the given angle around the X axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function rotateX(out, a, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+  var a10 = a[4];
+  var a11 = a[5];
+  var a12 = a[6];
+  var a13 = a[7];
+  var a20 = a[8];
+  var a21 = a[9];
+  var a22 = a[10];
+  var a23 = a[11];
+
+  if (a !== out) {
+    // If the source and destination differ, copy the unchanged rows
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+  }
+
+  // Perform axis-specific matrix multiplication
+  out[4] = a10 * c + a20 * s;
+  out[5] = a11 * c + a21 * s;
+  out[6] = a12 * c + a22 * s;
+  out[7] = a13 * c + a23 * s;
+  out[8] = a20 * c - a10 * s;
+  out[9] = a21 * c - a11 * s;
+  out[10] = a22 * c - a12 * s;
+  out[11] = a23 * c - a13 * s;
+  return out;
+}
+
+/**
+ * Rotates a matrix by the given angle around the Y axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function rotateY(out, a, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+  var a00 = a[0];
+  var a01 = a[1];
+  var a02 = a[2];
+  var a03 = a[3];
+  var a20 = a[8];
+  var a21 = a[9];
+  var a22 = a[10];
+  var a23 = a[11];
+
+  if (a !== out) {
+    // If the source and destination differ, copy the unchanged rows
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+  }
+
+  // Perform axis-specific matrix multiplication
+  out[0] = a00 * c - a20 * s;
+  out[1] = a01 * c - a21 * s;
+  out[2] = a02 * c - a22 * s;
+  out[3] = a03 * c - a23 * s;
+  out[8] = a00 * s + a20 * c;
+  out[9] = a01 * s + a21 * c;
+  out[10] = a02 * s + a22 * c;
+  out[11] = a03 * s + a23 * c;
+  return out;
+}
+
+/**
+ * Rotates a matrix by the given angle around the Z axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function rotateZ(out, a, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+  var a00 = a[0];
+  var a01 = a[1];
+  var a02 = a[2];
+  var a03 = a[3];
+  var a10 = a[4];
+  var a11 = a[5];
+  var a12 = a[6];
+  var a13 = a[7];
+
+  if (a !== out) {
+    // If the source and destination differ, copy the unchanged last row
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+  }
+
+  // Perform axis-specific matrix multiplication
+  out[0] = a00 * c + a10 * s;
+  out[1] = a01 * c + a11 * s;
+  out[2] = a02 * c + a12 * s;
+  out[3] = a03 * c + a13 * s;
+  out[4] = a10 * c - a00 * s;
+  out[5] = a11 * c - a01 * s;
+  out[6] = a12 * c - a02 * s;
+  out[7] = a13 * c - a03 * s;
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector translation
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.translate(dest, dest, vec);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+function fromTranslation(out, v) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = 1;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = 1;
+  out[11] = 0;
+  out[12] = v[0];
+  out[13] = v[1];
+  out[14] = v[2];
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.scale(dest, dest, vec);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {vec3} v Scaling vector
+ * @returns {mat4} out
+ */
+function fromScaling(out, v) {
+  out[0] = v[0];
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = v[1];
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = v[2];
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from a given angle around a given axis
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.rotate(dest, dest, rad, axis);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+function fromRotation(out, rad, axis) {
+  var x = axis[0],
+      y = axis[1],
+      z = axis[2];
+  var len = Math.sqrt(x * x + y * y + z * z);
+  var s = void 0,
+      c = void 0,
+      t = void 0;
+
+  if (Math.abs(len) < glMatrix.EPSILON) {
+    return null;
+  }
+
+  len = 1 / len;
+  x *= len;
+  y *= len;
+  z *= len;
+
+  s = Math.sin(rad);
+  c = Math.cos(rad);
+  t = 1 - c;
+
+  // Perform rotation-specific matrix multiplication
+  out[0] = x * x * t + c;
+  out[1] = y * x * t + z * s;
+  out[2] = z * x * t - y * s;
+  out[3] = 0;
+  out[4] = x * y * t - z * s;
+  out[5] = y * y * t + c;
+  out[6] = z * y * t + x * s;
+  out[7] = 0;
+  out[8] = x * z * t + y * s;
+  out[9] = y * z * t - x * s;
+  out[10] = z * z * t + c;
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from the given angle around the X axis
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.rotateX(dest, dest, rad);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function fromXRotation(out, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+
+  // Perform axis-specific matrix multiplication
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = c;
+  out[6] = s;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = -s;
+  out[10] = c;
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from the given angle around the Y axis
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.rotateY(dest, dest, rad);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function fromYRotation(out, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+
+  // Perform axis-specific matrix multiplication
+  out[0] = c;
+  out[1] = 0;
+  out[2] = -s;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = 1;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = s;
+  out[9] = 0;
+  out[10] = c;
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from the given angle around the Z axis
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.rotateZ(dest, dest, rad);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function fromZRotation(out, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+
+  // Perform axis-specific matrix multiplication
+  out[0] = c;
+  out[1] = s;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = -s;
+  out[5] = c;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = 1;
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from a quaternion rotation and vector translation
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.translate(dest, vec);
+ *     let quatMat = mat4.create();
+ *     quat4.toMat4(quat, quatMat);
+ *     mat4.multiply(dest, quatMat);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+function fromRotationTranslation(out, q, v) {
+  // Quaternion math
+  var x = q[0],
+      y = q[1],
+      z = q[2],
+      w = q[3];
+  var x2 = x + x;
+  var y2 = y + y;
+  var z2 = z + z;
+
+  var xx = x * x2;
+  var xy = x * y2;
+  var xz = x * z2;
+  var yy = y * y2;
+  var yz = y * z2;
+  var zz = z * z2;
+  var wx = w * x2;
+  var wy = w * y2;
+  var wz = w * z2;
+
+  out[0] = 1 - (yy + zz);
+  out[1] = xy + wz;
+  out[2] = xz - wy;
+  out[3] = 0;
+  out[4] = xy - wz;
+  out[5] = 1 - (xx + zz);
+  out[6] = yz + wx;
+  out[7] = 0;
+  out[8] = xz + wy;
+  out[9] = yz - wx;
+  out[10] = 1 - (xx + yy);
+  out[11] = 0;
+  out[12] = v[0];
+  out[13] = v[1];
+  out[14] = v[2];
+  out[15] = 1;
+
+  return out;
+}
+
+/**
+ * Returns the translation vector component of a transformation
+ *  matrix. If a matrix is built with fromRotationTranslation,
+ *  the returned vector will be the same as the translation vector
+ *  originally supplied.
+ * @param  {vec3} out Vector to receive translation component
+ * @param  {mat4} mat Matrix to be decomposed (input)
+ * @return {vec3} out
+ */
+function getTranslation(out, mat) {
+  out[0] = mat[12];
+  out[1] = mat[13];
+  out[2] = mat[14];
+
+  return out;
+}
+
+/**
+ * Returns the scaling factor component of a transformation
+ *  matrix. If a matrix is built with fromRotationTranslationScale
+ *  with a normalized Quaternion paramter, the returned vector will be
+ *  the same as the scaling vector
+ *  originally supplied.
+ * @param  {vec3} out Vector to receive scaling factor component
+ * @param  {mat4} mat Matrix to be decomposed (input)
+ * @return {vec3} out
+ */
+function getScaling(out, mat) {
+  var m11 = mat[0];
+  var m12 = mat[1];
+  var m13 = mat[2];
+  var m21 = mat[4];
+  var m22 = mat[5];
+  var m23 = mat[6];
+  var m31 = mat[8];
+  var m32 = mat[9];
+  var m33 = mat[10];
+
+  out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);
+  out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);
+  out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);
+
+  return out;
+}
+
+/**
+ * Returns a quaternion representing the rotational component
+ *  of a transformation matrix. If a matrix is built with
+ *  fromRotationTranslation, the returned quaternion will be the
+ *  same as the quaternion originally supplied.
+ * @param {quat} out Quaternion to receive the rotation component
+ * @param {mat4} mat Matrix to be decomposed (input)
+ * @return {quat} out
+ */
+function getRotation(out, mat) {
+  // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
+  var trace = mat[0] + mat[5] + mat[10];
+  var S = 0;
+
+  if (trace > 0) {
+    S = Math.sqrt(trace + 1.0) * 2;
+    out[3] = 0.25 * S;
+    out[0] = (mat[6] - mat[9]) / S;
+    out[1] = (mat[8] - mat[2]) / S;
+    out[2] = (mat[1] - mat[4]) / S;
+  } else if (mat[0] > mat[5] & mat[0] > mat[10]) {
+    S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2;
+    out[3] = (mat[6] - mat[9]) / S;
+    out[0] = 0.25 * S;
+    out[1] = (mat[1] + mat[4]) / S;
+    out[2] = (mat[8] + mat[2]) / S;
+  } else if (mat[5] > mat[10]) {
+    S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2;
+    out[3] = (mat[8] - mat[2]) / S;
+    out[0] = (mat[1] + mat[4]) / S;
+    out[1] = 0.25 * S;
+    out[2] = (mat[6] + mat[9]) / S;
+  } else {
+    S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2;
+    out[3] = (mat[1] - mat[4]) / S;
+    out[0] = (mat[8] + mat[2]) / S;
+    out[1] = (mat[6] + mat[9]) / S;
+    out[2] = 0.25 * S;
+  }
+
+  return out;
+}
+
+/**
+ * Creates a matrix from a quaternion rotation, vector translation and vector scale
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.translate(dest, vec);
+ *     let quatMat = mat4.create();
+ *     quat4.toMat4(quat, quatMat);
+ *     mat4.multiply(dest, quatMat);
+ *     mat4.scale(dest, scale)
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @param {vec3} s Scaling vector
+ * @returns {mat4} out
+ */
+function fromRotationTranslationScale(out, q, v, s) {
+  // Quaternion math
+  var x = q[0],
+      y = q[1],
+      z = q[2],
+      w = q[3];
+  var x2 = x + x;
+  var y2 = y + y;
+  var z2 = z + z;
+
+  var xx = x * x2;
+  var xy = x * y2;
+  var xz = x * z2;
+  var yy = y * y2;
+  var yz = y * z2;
+  var zz = z * z2;
+  var wx = w * x2;
+  var wy = w * y2;
+  var wz = w * z2;
+  var sx = s[0];
+  var sy = s[1];
+  var sz = s[2];
+
+  out[0] = (1 - (yy + zz)) * sx;
+  out[1] = (xy + wz) * sx;
+  out[2] = (xz - wy) * sx;
+  out[3] = 0;
+  out[4] = (xy - wz) * sy;
+  out[5] = (1 - (xx + zz)) * sy;
+  out[6] = (yz + wx) * sy;
+  out[7] = 0;
+  out[8] = (xz + wy) * sz;
+  out[9] = (yz - wx) * sz;
+  out[10] = (1 - (xx + yy)) * sz;
+  out[11] = 0;
+  out[12] = v[0];
+  out[13] = v[1];
+  out[14] = v[2];
+  out[15] = 1;
+
+  return out;
+}
+
+/**
+ * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.translate(dest, vec);
+ *     mat4.translate(dest, origin);
+ *     let quatMat = mat4.create();
+ *     quat4.toMat4(quat, quatMat);
+ *     mat4.multiply(dest, quatMat);
+ *     mat4.scale(dest, scale)
+ *     mat4.translate(dest, negativeOrigin);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @param {vec3} s Scaling vector
+ * @param {vec3} o The origin vector around which to scale and rotate
+ * @returns {mat4} out
+ */
+function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+  // Quaternion math
+  var x = q[0],
+      y = q[1],
+      z = q[2],
+      w = q[3];
+  var x2 = x + x;
+  var y2 = y + y;
+  var z2 = z + z;
+
+  var xx = x * x2;
+  var xy = x * y2;
+  var xz = x * z2;
+  var yy = y * y2;
+  var yz = y * z2;
+  var zz = z * z2;
+  var wx = w * x2;
+  var wy = w * y2;
+  var wz = w * z2;
+
+  var sx = s[0];
+  var sy = s[1];
+  var sz = s[2];
+
+  var ox = o[0];
+  var oy = o[1];
+  var oz = o[2];
+
+  out[0] = (1 - (yy + zz)) * sx;
+  out[1] = (xy + wz) * sx;
+  out[2] = (xz - wy) * sx;
+  out[3] = 0;
+  out[4] = (xy - wz) * sy;
+  out[5] = (1 - (xx + zz)) * sy;
+  out[6] = (yz + wx) * sy;
+  out[7] = 0;
+  out[8] = (xz + wy) * sz;
+  out[9] = (yz - wx) * sz;
+  out[10] = (1 - (xx + yy)) * sz;
+  out[11] = 0;
+  out[12] = v[0] + ox - (out[0] * ox + out[4] * oy + out[8] * oz);
+  out[13] = v[1] + oy - (out[1] * ox + out[5] * oy + out[9] * oz);
+  out[14] = v[2] + oz - (out[2] * ox + out[6] * oy + out[10] * oz);
+  out[15] = 1;
+
+  return out;
+}
+
+/**
+ * Calculates a 4x4 matrix from the given quaternion
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat} q Quaternion to create matrix from
+ *
+ * @returns {mat4} out
+ */
+function fromQuat(out, q) {
+  var x = q[0],
+      y = q[1],
+      z = q[2],
+      w = q[3];
+  var x2 = x + x;
+  var y2 = y + y;
+  var z2 = z + z;
+
+  var xx = x * x2;
+  var yx = y * x2;
+  var yy = y * y2;
+  var zx = z * x2;
+  var zy = z * y2;
+  var zz = z * z2;
+  var wx = w * x2;
+  var wy = w * y2;
+  var wz = w * z2;
+
+  out[0] = 1 - yy - zz;
+  out[1] = yx + wz;
+  out[2] = zx - wy;
+  out[3] = 0;
+
+  out[4] = yx - wz;
+  out[5] = 1 - xx - zz;
+  out[6] = zy + wx;
+  out[7] = 0;
+
+  out[8] = zx + wy;
+  out[9] = zy - wx;
+  out[10] = 1 - xx - yy;
+  out[11] = 0;
+
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+
+  return out;
+}
+
+/**
+ * Generates a frustum matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Number} left Left bound of the frustum
+ * @param {Number} right Right bound of the frustum
+ * @param {Number} bottom Bottom bound of the frustum
+ * @param {Number} top Top bound of the frustum
+ * @param {Number} near Near bound of the frustum
+ * @param {Number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+function frustum(out, left, right, bottom, top, near, far) {
+  var rl = 1 / (right - left);
+  var tb = 1 / (top - bottom);
+  var nf = 1 / (near - far);
+  out[0] = near * 2 * rl;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = near * 2 * tb;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = (right + left) * rl;
+  out[9] = (top + bottom) * tb;
+  out[10] = (far + near) * nf;
+  out[11] = -1;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = far * near * 2 * nf;
+  out[15] = 0;
+  return out;
+}
+
+/**
+ * Generates a perspective projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} fovy Vertical field of view in radians
+ * @param {number} aspect Aspect ratio. typically viewport width/height
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+function perspective(out, fovy, aspect, near, far) {
+  var f = 1.0 / Math.tan(fovy / 2);
+  var nf = 1 / (near - far);
+  out[0] = f / aspect;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = f;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = (far + near) * nf;
+  out[11] = -1;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 2 * far * near * nf;
+  out[15] = 0;
+  return out;
+}
+
+/**
+ * Generates a perspective projection matrix with the given field of view.
+ * This is primarily useful for generating projection matrices to be used
+ * with the still experiemental WebVR API.
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+function perspectiveFromFieldOfView(out, fov, near, far) {
+  var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+  var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+  var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+  var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+  var xScale = 2.0 / (leftTan + rightTan);
+  var yScale = 2.0 / (upTan + downTan);
+
+  out[0] = xScale;
+  out[1] = 0.0;
+  out[2] = 0.0;
+  out[3] = 0.0;
+  out[4] = 0.0;
+  out[5] = yScale;
+  out[6] = 0.0;
+  out[7] = 0.0;
+  out[8] = -((leftTan - rightTan) * xScale * 0.5);
+  out[9] = (upTan - downTan) * yScale * 0.5;
+  out[10] = far / (near - far);
+  out[11] = -1.0;
+  out[12] = 0.0;
+  out[13] = 0.0;
+  out[14] = far * near / (near - far);
+  out[15] = 0.0;
+  return out;
+}
+
+/**
+ * Generates a orthogonal projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} left Left bound of the frustum
+ * @param {number} right Right bound of the frustum
+ * @param {number} bottom Bottom bound of the frustum
+ * @param {number} top Top bound of the frustum
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+function ortho(out, left, right, bottom, top, near, far) {
+  var lr = 1 / (left - right);
+  var bt = 1 / (bottom - top);
+  var nf = 1 / (near - far);
+  out[0] = -2 * lr;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = -2 * bt;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = 2 * nf;
+  out[11] = 0;
+  out[12] = (left + right) * lr;
+  out[13] = (top + bottom) * bt;
+  out[14] = (far + near) * nf;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Generates a look-at matrix with the given eye position, focal point, and up axis
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+function lookAt(out, eye, center, up) {
+  var x0 = void 0,
+      x1 = void 0,
+      x2 = void 0,
+      y0 = void 0,
+      y1 = void 0,
+      y2 = void 0,
+      z0 = void 0,
+      z1 = void 0,
+      z2 = void 0,
+      len = void 0;
+  var eyex = eye[0];
+  var eyey = eye[1];
+  var eyez = eye[2];
+  var upx = up[0];
+  var upy = up[1];
+  var upz = up[2];
+  var centerx = center[0];
+  var centery = center[1];
+  var centerz = center[2];
+
+  if (Math.abs(eyex - centerx) < glMatrix.EPSILON && Math.abs(eyey - centery) < glMatrix.EPSILON && Math.abs(eyez - centerz) < glMatrix.EPSILON) {
+    return mat4.identity(out);
+  }
+
+  z0 = eyex - centerx;
+  z1 = eyey - centery;
+  z2 = eyez - centerz;
+
+  len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
+  z0 *= len;
+  z1 *= len;
+  z2 *= len;
+
+  x0 = upy * z2 - upz * z1;
+  x1 = upz * z0 - upx * z2;
+  x2 = upx * z1 - upy * z0;
+  len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
+  if (!len) {
+    x0 = 0;
+    x1 = 0;
+    x2 = 0;
+  } else {
+    len = 1 / len;
+    x0 *= len;
+    x1 *= len;
+    x2 *= len;
+  }
+
+  y0 = z1 * x2 - z2 * x1;
+  y1 = z2 * x0 - z0 * x2;
+  y2 = z0 * x1 - z1 * x0;
+
+  len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
+  if (!len) {
+    y0 = 0;
+    y1 = 0;
+    y2 = 0;
+  } else {
+    len = 1 / len;
+    y0 *= len;
+    y1 *= len;
+    y2 *= len;
+  }
+
+  out[0] = x0;
+  out[1] = y0;
+  out[2] = z0;
+  out[3] = 0;
+  out[4] = x1;
+  out[5] = y1;
+  out[6] = z1;
+  out[7] = 0;
+  out[8] = x2;
+  out[9] = y2;
+  out[10] = z2;
+  out[11] = 0;
+  out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+  out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+  out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+  out[15] = 1;
+
+  return out;
+}
+
+/**
+ * Generates a matrix that makes something look at something else.
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+function targetTo(out, eye, target, up) {
+  var eyex = eye[0],
+      eyey = eye[1],
+      eyez = eye[2],
+      upx = up[0],
+      upy = up[1],
+      upz = up[2];
+
+  var z0 = eyex - target[0],
+      z1 = eyey - target[1],
+      z2 = eyez - target[2];
+
+  var len = z0 * z0 + z1 * z1 + z2 * z2;
+  if (len > 0) {
+    len = 1 / Math.sqrt(len);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+  }
+
+  var x0 = upy * z2 - upz * z1,
+      x1 = upz * z0 - upx * z2,
+      x2 = upx * z1 - upy * z0;
+
+  out[0] = x0;
+  out[1] = x1;
+  out[2] = x2;
+  out[3] = 0;
+  out[4] = z1 * x2 - z2 * x1;
+  out[5] = z2 * x0 - z0 * x2;
+  out[6] = z0 * x1 - z1 * x0;
+  out[7] = 0;
+  out[8] = z0;
+  out[9] = z1;
+  out[10] = z2;
+  out[11] = 0;
+  out[12] = eyex;
+  out[13] = eyey;
+  out[14] = eyez;
+  out[15] = 1;
+  return out;
+};
+
+/**
+ * Returns a string representation of a mat4
+ *
+ * @param {mat4} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+function str(a) {
+  return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+}
+
+/**
+ * Returns Frobenius norm of a mat4
+ *
+ * @param {mat4} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+function frob(a) {
+  return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2));
+}
+
+/**
+ * Adds two mat4's
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  out[2] = a[2] + b[2];
+  out[3] = a[3] + b[3];
+  out[4] = a[4] + b[4];
+  out[5] = a[5] + b[5];
+  out[6] = a[6] + b[6];
+  out[7] = a[7] + b[7];
+  out[8] = a[8] + b[8];
+  out[9] = a[9] + b[9];
+  out[10] = a[10] + b[10];
+  out[11] = a[11] + b[11];
+  out[12] = a[12] + b[12];
+  out[13] = a[13] + b[13];
+  out[14] = a[14] + b[14];
+  out[15] = a[15] + b[15];
+  return out;
+}
+
+/**
+ * Subtracts matrix b from matrix a
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  out[2] = a[2] - b[2];
+  out[3] = a[3] - b[3];
+  out[4] = a[4] - b[4];
+  out[5] = a[5] - b[5];
+  out[6] = a[6] - b[6];
+  out[7] = a[7] - b[7];
+  out[8] = a[8] - b[8];
+  out[9] = a[9] - b[9];
+  out[10] = a[10] - b[10];
+  out[11] = a[11] - b[11];
+  out[12] = a[12] - b[12];
+  out[13] = a[13] - b[13];
+  out[14] = a[14] - b[14];
+  out[15] = a[15] - b[15];
+  return out;
+}
+
+/**
+ * Multiply each element of the matrix by a scalar.
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat4} out
+ */
+function multiplyScalar(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  out[2] = a[2] * b;
+  out[3] = a[3] * b;
+  out[4] = a[4] * b;
+  out[5] = a[5] * b;
+  out[6] = a[6] * b;
+  out[7] = a[7] * b;
+  out[8] = a[8] * b;
+  out[9] = a[9] * b;
+  out[10] = a[10] * b;
+  out[11] = a[11] * b;
+  out[12] = a[12] * b;
+  out[13] = a[13] * b;
+  out[14] = a[14] * b;
+  out[15] = a[15] * b;
+  return out;
+}
+
+/**
+ * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+ *
+ * @param {mat4} out the receiving vector
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat4} out
+ */
+function multiplyScalarAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  out[2] = a[2] + b[2] * scale;
+  out[3] = a[3] + b[3] * scale;
+  out[4] = a[4] + b[4] * scale;
+  out[5] = a[5] + b[5] * scale;
+  out[6] = a[6] + b[6] * scale;
+  out[7] = a[7] + b[7] * scale;
+  out[8] = a[8] + b[8] * scale;
+  out[9] = a[9] + b[9] * scale;
+  out[10] = a[10] + b[10] * scale;
+  out[11] = a[11] + b[11] * scale;
+  out[12] = a[12] + b[12] * scale;
+  out[13] = a[13] + b[13] * scale;
+  out[14] = a[14] + b[14] * scale;
+  out[15] = a[15] + b[15] * scale;
+  return out;
+}
+
+/**
+ * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {mat4} a The first matrix.
+ * @param {mat4} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+}
+
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat4} a The first matrix.
+ * @param {mat4} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var a4 = a[4],
+      a5 = a[5],
+      a6 = a[6],
+      a7 = a[7];
+  var a8 = a[8],
+      a9 = a[9],
+      a10 = a[10],
+      a11 = a[11];
+  var a12 = a[12],
+      a13 = a[13],
+      a14 = a[14],
+      a15 = a[15];
+
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3];
+  var b4 = b[4],
+      b5 = b[5],
+      b6 = b[6],
+      b7 = b[7];
+  var b8 = b[8],
+      b9 = b[9],
+      b10 = b[10],
+      b11 = b[11];
+  var b12 = b[12],
+      b13 = b[13],
+      b14 = b[14],
+      b15 = b[15];
+
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+}
+
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link mat4.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/***/ }),
+/* 8 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.setAxes = exports.sqlerp = exports.rotationTo = exports.equals = exports.exactEquals = exports.normalize = exports.sqrLen = exports.squaredLength = exports.len = exports.length = exports.lerp = exports.dot = exports.scale = exports.mul = exports.add = exports.set = exports.copy = exports.fromValues = exports.clone = undefined;
+exports.create = create;
+exports.identity = identity;
+exports.setAxisAngle = setAxisAngle;
+exports.getAxisAngle = getAxisAngle;
+exports.multiply = multiply;
+exports.rotateX = rotateX;
+exports.rotateY = rotateY;
+exports.rotateZ = rotateZ;
+exports.calculateW = calculateW;
+exports.slerp = slerp;
+exports.invert = invert;
+exports.conjugate = conjugate;
+exports.fromMat3 = fromMat3;
+exports.fromEuler = fromEuler;
+exports.str = str;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+var _mat = __webpack_require__(1);
+
+var mat3 = _interopRequireWildcard(_mat);
+
+var _vec = __webpack_require__(2);
+
+var vec3 = _interopRequireWildcard(_vec);
+
+var _vec2 = __webpack_require__(3);
+
+var vec4 = _interopRequireWildcard(_vec2);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * Quaternion
+ * @module quat
+ */
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = 0;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  return out;
+}
+
+/**
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+function identity(out) {
+  out[0] = 0;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  return out;
+}
+
+/**
+ * Sets a quat from the given angle and rotation axis,
+ * then returns it.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {vec3} axis the axis around which to rotate
+ * @param {Number} rad the angle in radians
+ * @returns {quat} out
+ **/
+function setAxisAngle(out, axis, rad) {
+  rad = rad * 0.5;
+  var s = Math.sin(rad);
+  out[0] = s * axis[0];
+  out[1] = s * axis[1];
+  out[2] = s * axis[2];
+  out[3] = Math.cos(rad);
+  return out;
+}
+
+/**
+ * Gets the rotation axis and angle for a given
+ *  quaternion. If a quaternion is created with
+ *  setAxisAngle, this method will return the same
+ *  values as providied in the original parameter list
+ *  OR functionally equivalent values.
+ * Example: The quaternion formed by axis [0, 0, 1] and
+ *  angle -90 is the same as the quaternion formed by
+ *  [0, 0, 1] and 270. This method favors the latter.
+ * @param  {vec3} out_axis  Vector receiving the axis of rotation
+ * @param  {quat} q     Quaternion to be decomposed
+ * @return {Number}     Angle, in radians, of the rotation
+ */
+function getAxisAngle(out_axis, q) {
+  var rad = Math.acos(q[3]) * 2.0;
+  var s = Math.sin(rad / 2.0);
+  if (s != 0.0) {
+    out_axis[0] = q[0] / s;
+    out_axis[1] = q[1] / s;
+    out_axis[2] = q[2] / s;
+  } else {
+    // If s is zero, return any axis (no rotation - axis does not matter)
+    out_axis[0] = 1;
+    out_axis[1] = 0;
+    out_axis[2] = 0;
+  }
+  return rad;
+}
+
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+function multiply(out, a, b) {
+  var ax = a[0],
+      ay = a[1],
+      az = a[2],
+      aw = a[3];
+  var bx = b[0],
+      by = b[1],
+      bz = b[2],
+      bw = b[3];
+
+  out[0] = ax * bw + aw * bx + ay * bz - az * by;
+  out[1] = ay * bw + aw * by + az * bx - ax * bz;
+  out[2] = az * bw + aw * bz + ax * by - ay * bx;
+  out[3] = aw * bw - ax * bx - ay * by - az * bz;
+  return out;
+}
+
+/**
+ * Rotates a quaternion by the given angle about the X axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+function rotateX(out, a, rad) {
+  rad *= 0.5;
+
+  var ax = a[0],
+      ay = a[1],
+      az = a[2],
+      aw = a[3];
+  var bx = Math.sin(rad),
+      bw = Math.cos(rad);
+
+  out[0] = ax * bw + aw * bx;
+  out[1] = ay * bw + az * bx;
+  out[2] = az * bw - ay * bx;
+  out[3] = aw * bw - ax * bx;
+  return out;
+}
+
+/**
+ * Rotates a quaternion by the given angle about the Y axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+function rotateY(out, a, rad) {
+  rad *= 0.5;
+
+  var ax = a[0],
+      ay = a[1],
+      az = a[2],
+      aw = a[3];
+  var by = Math.sin(rad),
+      bw = Math.cos(rad);
+
+  out[0] = ax * bw - az * by;
+  out[1] = ay * bw + aw * by;
+  out[2] = az * bw + ax * by;
+  out[3] = aw * bw - ay * by;
+  return out;
+}
+
+/**
+ * Rotates a quaternion by the given angle about the Z axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+function rotateZ(out, a, rad) {
+  rad *= 0.5;
+
+  var ax = a[0],
+      ay = a[1],
+      az = a[2],
+      aw = a[3];
+  var bz = Math.sin(rad),
+      bw = Math.cos(rad);
+
+  out[0] = ax * bw + ay * bz;
+  out[1] = ay * bw - ax * bz;
+  out[2] = az * bw + aw * bz;
+  out[3] = aw * bw - az * bz;
+  return out;
+}
+
+/**
+ * Calculates the W component of a quat from the X, Y, and Z components.
+ * Assumes that quaternion is 1 unit in length.
+ * Any existing W component will be ignored.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate W component of
+ * @returns {quat} out
+ */
+function calculateW(out, a) {
+  var x = a[0],
+      y = a[1],
+      z = a[2];
+
+  out[0] = x;
+  out[1] = y;
+  out[2] = z;
+  out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+  return out;
+}
+
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ */
+function slerp(out, a, b, t) {
+  // benchmarks:
+  //    http://jsperf.com/quaternion-slerp-implementations
+  var ax = a[0],
+      ay = a[1],
+      az = a[2],
+      aw = a[3];
+  var bx = b[0],
+      by = b[1],
+      bz = b[2],
+      bw = b[3];
+
+  var omega = void 0,
+      cosom = void 0,
+      sinom = void 0,
+      scale0 = void 0,
+      scale1 = void 0;
+
+  // calc cosine
+  cosom = ax * bx + ay * by + az * bz + aw * bw;
+  // adjust signs (if necessary)
+  if (cosom < 0.0) {
+    cosom = -cosom;
+    bx = -bx;
+    by = -by;
+    bz = -bz;
+    bw = -bw;
+  }
+  // calculate coefficients
+  if (1.0 - cosom > 0.000001) {
+    // standard case (slerp)
+    omega = Math.acos(cosom);
+    sinom = Math.sin(omega);
+    scale0 = Math.sin((1.0 - t) * omega) / sinom;
+    scale1 = Math.sin(t * omega) / sinom;
+  } else {
+    // "from" and "to" quaternions are very close
+    //  ... so we can do a linear interpolation
+    scale0 = 1.0 - t;
+    scale1 = t;
+  }
+  // calculate final values
+  out[0] = scale0 * ax + scale1 * bx;
+  out[1] = scale0 * ay + scale1 * by;
+  out[2] = scale0 * az + scale1 * bz;
+  out[3] = scale0 * aw + scale1 * bw;
+
+  return out;
+}
+
+/**
+ * Calculates the inverse of a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate inverse of
+ * @returns {quat} out
+ */
+function invert(out, a) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+  var invDot = dot ? 1.0 / dot : 0;
+
+  // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+  out[0] = -a0 * invDot;
+  out[1] = -a1 * invDot;
+  out[2] = -a2 * invDot;
+  out[3] = a3 * invDot;
+  return out;
+}
+
+/**
+ * Calculates the conjugate of a quat
+ * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate conjugate of
+ * @returns {quat} out
+ */
+function conjugate(out, a) {
+  out[0] = -a[0];
+  out[1] = -a[1];
+  out[2] = -a[2];
+  out[3] = a[3];
+  return out;
+}
+
+/**
+ * Creates a quaternion from the given 3x3 rotation matrix.
+ *
+ * NOTE: The resultant quaternion is not normalized, so you should be sure
+ * to renormalize the quaternion yourself where necessary.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {mat3} m rotation matrix
+ * @returns {quat} out
+ * @function
+ */
+function fromMat3(out, m) {
+  // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+  // article "Quaternion Calculus and Fast Animation".
+  var fTrace = m[0] + m[4] + m[8];
+  var fRoot = void 0;
+
+  if (fTrace > 0.0) {
+    // |w| > 1/2, may as well choose w > 1/2
+    fRoot = Math.sqrt(fTrace + 1.0); // 2w
+    out[3] = 0.5 * fRoot;
+    fRoot = 0.5 / fRoot; // 1/(4w)
+    out[0] = (m[5] - m[7]) * fRoot;
+    out[1] = (m[6] - m[2]) * fRoot;
+    out[2] = (m[1] - m[3]) * fRoot;
+  } else {
+    // |w| <= 1/2
+    var i = 0;
+    if (m[4] > m[0]) i = 1;
+    if (m[8] > m[i * 3 + i]) i = 2;
+    var j = (i + 1) % 3;
+    var k = (i + 2) % 3;
+
+    fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+    out[i] = 0.5 * fRoot;
+    fRoot = 0.5 / fRoot;
+    out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+    out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+    out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+  }
+
+  return out;
+}
+
+/**
+ * Creates a quaternion from the given euler angle x, y, z.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {x} Angle to rotate around X axis in degrees.
+ * @param {y} Angle to rotate around Y axis in degrees.
+ * @param {z} Angle to rotate around Z axis in degrees.
+ * @returns {quat} out
+ * @function
+ */
+function fromEuler(out, x, y, z) {
+  var halfToRad = 0.5 * Math.PI / 180.0;
+  x *= halfToRad;
+  y *= halfToRad;
+  z *= halfToRad;
+
+  var sx = Math.sin(x);
+  var cx = Math.cos(x);
+  var sy = Math.sin(y);
+  var cy = Math.cos(y);
+  var sz = Math.sin(z);
+  var cz = Math.cos(z);
+
+  out[0] = sx * cy * cz - cx * sy * sz;
+  out[1] = cx * sy * cz + sx * cy * sz;
+  out[2] = cx * cy * sz - sx * sy * cz;
+  out[3] = cx * cy * cz + sx * sy * sz;
+
+  return out;
+}
+
+/**
+ * Returns a string representation of a quatenion
+ *
+ * @param {quat} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+function str(a) {
+  return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+}
+
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
+ * @function
+ */
+var clone = exports.clone = vec4.clone;
+
+/**
+ * Creates a new quat initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} a new quaternion
+ * @function
+ */
+var fromValues = exports.fromValues = vec4.fromValues;
+
+/**
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
+ */
+var copy = exports.copy = vec4.copy;
+
+/**
+ * Set the components of a quat to the given values
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} out
+ * @function
+ */
+var set = exports.set = vec4.set;
+
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+var add = exports.add = vec4.add;
+
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {quat} out
+ * @function
+ */
+var scale = exports.scale = vec4.scale;
+
+/**
+ * Calculates the dot product of two quat's
+ *
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+var dot = exports.dot = vec4.dot;
+
+/**
+ * Performs a linear interpolation between two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ * @function
+ */
+var lerp = exports.lerp = vec4.lerp;
+
+/**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+var length = exports.length = vec4.length;
+
+/**
+ * Alias for {@link quat.length}
+ * @function
+ */
+var len = exports.len = length;
+
+/**
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+var squaredLength = exports.squaredLength = vec4.squaredLength;
+
+/**
+ * Alias for {@link quat.squaredLength}
+ * @function
+ */
+var sqrLen = exports.sqrLen = squaredLength;
+
+/**
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
+ */
+var normalize = exports.normalize = vec4.normalize;
+
+/**
+ * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {quat} a The first quaternion.
+ * @param {quat} b The second quaternion.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+var exactEquals = exports.exactEquals = vec4.exactEquals;
+
+/**
+ * Returns whether or not the quaternions have approximately the same elements in the same position.
+ *
+ * @param {quat} a The first vector.
+ * @param {quat} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+var equals = exports.equals = vec4.equals;
+
+/**
+ * Sets a quaternion to represent the shortest rotation from one
+ * vector to another.
+ *
+ * Both vectors are assumed to be unit length.
+ *
+ * @param {quat} out the receiving quaternion.
+ * @param {vec3} a the initial vector
+ * @param {vec3} b the destination vector
+ * @returns {quat} out
+ */
+var rotationTo = exports.rotationTo = function () {
+  var tmpvec3 = vec3.create();
+  var xUnitVec3 = vec3.fromValues(1, 0, 0);
+  var yUnitVec3 = vec3.fromValues(0, 1, 0);
+
+  return function (out, a, b) {
+    var dot = vec3.dot(a, b);
+    if (dot < -0.999999) {
+      vec3.cross(tmpvec3, xUnitVec3, a);
+      if (vec3.len(tmpvec3) < 0.000001) vec3.cross(tmpvec3, yUnitVec3, a);
+      vec3.normalize(tmpvec3, tmpvec3);
+      setAxisAngle(out, tmpvec3, Math.PI);
+      return out;
+    } else if (dot > 0.999999) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 1;
+      return out;
+    } else {
+      vec3.cross(tmpvec3, a, b);
+      out[0] = tmpvec3[0];
+      out[1] = tmpvec3[1];
+      out[2] = tmpvec3[2];
+      out[3] = 1 + dot;
+      return normalize(out, out);
+    }
+  };
+}();
+
+/**
+ * Performs a spherical linear interpolation with two control points
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {quat} c the third operand
+ * @param {quat} d the fourth operand
+ * @param {Number} t interpolation amount
+ * @returns {quat} out
+ */
+var sqlerp = exports.sqlerp = function () {
+  var temp1 = create();
+  var temp2 = create();
+
+  return function (out, a, b, c, d, t) {
+    slerp(temp1, a, d, t);
+    slerp(temp2, b, c, t);
+    slerp(out, temp1, temp2, 2 * t * (1 - t));
+
+    return out;
+  };
+}();
+
+/**
+ * Sets the specified quaternion with values corresponding to the given
+ * axes. Each axis is a vec3 and is expected to be unit length and
+ * perpendicular to all other specified axes.
+ *
+ * @param {vec3} view  the vector representing the viewing direction
+ * @param {vec3} right the vector representing the local "right" direction
+ * @param {vec3} up    the vector representing the local "up" direction
+ * @returns {quat} out
+ */
+var setAxes = exports.setAxes = function () {
+  var matr = mat3.create();
+
+  return function (out, view, right, up) {
+    matr[0] = right[0];
+    matr[3] = right[1];
+    matr[6] = right[2];
+
+    matr[1] = up[0];
+    matr[4] = up[1];
+    matr[7] = up[2];
+
+    matr[2] = -view[0];
+    matr[5] = -view[1];
+    matr[8] = -view[2];
+
+    return normalize(out, fromMat3(out, matr));
+  };
+}();
+
+/***/ }),
+/* 9 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.forEach = exports.sqrLen = exports.sqrDist = exports.dist = exports.div = exports.mul = exports.sub = exports.len = undefined;
+exports.create = create;
+exports.clone = clone;
+exports.fromValues = fromValues;
+exports.copy = copy;
+exports.set = set;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiply = multiply;
+exports.divide = divide;
+exports.ceil = ceil;
+exports.floor = floor;
+exports.min = min;
+exports.max = max;
+exports.round = round;
+exports.scale = scale;
+exports.scaleAndAdd = scaleAndAdd;
+exports.distance = distance;
+exports.squaredDistance = squaredDistance;
+exports.length = length;
+exports.squaredLength = squaredLength;
+exports.negate = negate;
+exports.inverse = inverse;
+exports.normalize = normalize;
+exports.dot = dot;
+exports.cross = cross;
+exports.lerp = lerp;
+exports.random = random;
+exports.transformMat2 = transformMat2;
+exports.transformMat2d = transformMat2d;
+exports.transformMat3 = transformMat3;
+exports.transformMat4 = transformMat4;
+exports.str = str;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 2 Dimensional Vector
+ * @module vec2
+ */
+
+/**
+ * Creates a new, empty vec2
+ *
+ * @returns {vec2} a new 2D vector
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(2);
+  out[0] = 0;
+  out[1] = 0;
+  return out;
+}
+
+/**
+ * Creates a new vec2 initialized with values from an existing vector
+ *
+ * @param {vec2} a vector to clone
+ * @returns {vec2} a new 2D vector
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(2);
+  out[0] = a[0];
+  out[1] = a[1];
+  return out;
+}
+
+/**
+ * Creates a new vec2 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} a new 2D vector
+ */
+function fromValues(x, y) {
+  var out = new glMatrix.ARRAY_TYPE(2);
+  out[0] = x;
+  out[1] = y;
+  return out;
+}
+
+/**
+ * Copy the values from one vec2 to another
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the source vector
+ * @returns {vec2} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  return out;
+}
+
+/**
+ * Set the components of a vec2 to the given values
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} out
+ */
+function set(out, x, y) {
+  out[0] = x;
+  out[1] = y;
+  return out;
+}
+
+/**
+ * Adds two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  return out;
+}
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  return out;
+}
+
+/**
+ * Multiplies two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function multiply(out, a, b) {
+  out[0] = a[0] * b[0];
+  out[1] = a[1] * b[1];
+  return out;
+};
+
+/**
+ * Divides two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function divide(out, a, b) {
+  out[0] = a[0] / b[0];
+  out[1] = a[1] / b[1];
+  return out;
+};
+
+/**
+ * Math.ceil the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to ceil
+ * @returns {vec2} out
+ */
+function ceil(out, a) {
+  out[0] = Math.ceil(a[0]);
+  out[1] = Math.ceil(a[1]);
+  return out;
+};
+
+/**
+ * Math.floor the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to floor
+ * @returns {vec2} out
+ */
+function floor(out, a) {
+  out[0] = Math.floor(a[0]);
+  out[1] = Math.floor(a[1]);
+  return out;
+};
+
+/**
+ * Returns the minimum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function min(out, a, b) {
+  out[0] = Math.min(a[0], b[0]);
+  out[1] = Math.min(a[1], b[1]);
+  return out;
+};
+
+/**
+ * Returns the maximum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function max(out, a, b) {
+  out[0] = Math.max(a[0], b[0]);
+  out[1] = Math.max(a[1], b[1]);
+  return out;
+};
+
+/**
+ * Math.round the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to round
+ * @returns {vec2} out
+ */
+function round(out, a) {
+  out[0] = Math.round(a[0]);
+  out[1] = Math.round(a[1]);
+  return out;
+};
+
+/**
+ * Scales a vec2 by a scalar number
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec2} out
+ */
+function scale(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  return out;
+};
+
+/**
+ * Adds two vec2's after scaling the second operand by a scalar value
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec2} out
+ */
+function scaleAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} distance between a and b
+ */
+function distance(a, b) {
+  var x = b[0] - a[0],
+      y = b[1] - a[1];
+  return Math.sqrt(x * x + y * y);
+};
+
+/**
+ * Calculates the squared euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+function squaredDistance(a, b) {
+  var x = b[0] - a[0],
+      y = b[1] - a[1];
+  return x * x + y * y;
+};
+
+/**
+ * Calculates the length of a vec2
+ *
+ * @param {vec2} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+function length(a) {
+  var x = a[0],
+      y = a[1];
+  return Math.sqrt(x * x + y * y);
+};
+
+/**
+ * Calculates the squared length of a vec2
+ *
+ * @param {vec2} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+function squaredLength(a) {
+  var x = a[0],
+      y = a[1];
+  return x * x + y * y;
+};
+
+/**
+ * Negates the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to negate
+ * @returns {vec2} out
+ */
+function negate(out, a) {
+  out[0] = -a[0];
+  out[1] = -a[1];
+  return out;
+};
+
+/**
+ * Returns the inverse of the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to invert
+ * @returns {vec2} out
+ */
+function inverse(out, a) {
+  out[0] = 1.0 / a[0];
+  out[1] = 1.0 / a[1];
+  return out;
+};
+
+/**
+ * Normalize a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to normalize
+ * @returns {vec2} out
+ */
+function normalize(out, a) {
+  var x = a[0],
+      y = a[1];
+  var len = x * x + y * y;
+  if (len > 0) {
+    //TODO: evaluate use of glm_invsqrt here?
+    len = 1 / Math.sqrt(len);
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+  }
+  return out;
+};
+
+/**
+ * Calculates the dot product of two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+function dot(a, b) {
+  return a[0] * b[0] + a[1] * b[1];
+};
+
+/**
+ * Computes the cross product of two vec2's
+ * Note that the cross product must by definition produce a 3D vector
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec3} out
+ */
+function cross(out, a, b) {
+  var z = a[0] * b[1] - a[1] * b[0];
+  out[0] = out[1] = 0;
+  out[2] = z;
+  return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec2} out
+ */
+function lerp(out, a, b, t) {
+  var ax = a[0],
+      ay = a[1];
+  out[0] = ax + t * (b[0] - ax);
+  out[1] = ay + t * (b[1] - ay);
+  return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec2} out
+ */
+function random(out, scale) {
+  scale = scale || 1.0;
+  var r = glMatrix.RANDOM() * 2.0 * Math.PI;
+  out[0] = Math.cos(r) * scale;
+  out[1] = Math.sin(r) * scale;
+  return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2} m matrix to transform with
+ * @returns {vec2} out
+ */
+function transformMat2(out, a, m) {
+  var x = a[0],
+      y = a[1];
+  out[0] = m[0] * x + m[2] * y;
+  out[1] = m[1] * x + m[3] * y;
+  return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2d
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2d} m matrix to transform with
+ * @returns {vec2} out
+ */
+function transformMat2d(out, a, m) {
+  var x = a[0],
+      y = a[1];
+  out[0] = m[0] * x + m[2] * y + m[4];
+  out[1] = m[1] * x + m[3] * y + m[5];
+  return out;
+};
+
+/**
+ * Transforms the vec2 with a mat3
+ * 3rd vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat3} m matrix to transform with
+ * @returns {vec2} out
+ */
+function transformMat3(out, a, m) {
+  var x = a[0],
+      y = a[1];
+  out[0] = m[0] * x + m[3] * y + m[6];
+  out[1] = m[1] * x + m[4] * y + m[7];
+  return out;
+};
+
+/**
+ * Transforms the vec2 with a mat4
+ * 3rd vector component is implicitly '0'
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec2} out
+ */
+function transformMat4(out, a, m) {
+  var x = a[0];
+  var y = a[1];
+  out[0] = m[0] * x + m[4] * y + m[12];
+  out[1] = m[1] * x + m[5] * y + m[13];
+  return out;
+}
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec2} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+function str(a) {
+  return 'vec2(' + a[0] + ', ' + a[1] + ')';
+}
+
+/**
+ * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+ *
+ * @param {vec2} a The first vector.
+ * @param {vec2} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1];
+}
+
+/**
+ * Returns whether or not the vectors have approximately the same elements in the same position.
+ *
+ * @param {vec2} a The first vector.
+ * @param {vec2} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1];
+  var b0 = b[0],
+      b1 = b[1];
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+}
+
+/**
+ * Alias for {@link vec2.length}
+ * @function
+ */
+var len = exports.len = length;
+
+/**
+ * Alias for {@link vec2.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/**
+ * Alias for {@link vec2.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link vec2.divide}
+ * @function
+ */
+var div = exports.div = divide;
+
+/**
+ * Alias for {@link vec2.distance}
+ * @function
+ */
+var dist = exports.dist = distance;
+
+/**
+ * Alias for {@link vec2.squaredDistance}
+ * @function
+ */
+var sqrDist = exports.sqrDist = squaredDistance;
+
+/**
+ * Alias for {@link vec2.squaredLength}
+ * @function
+ */
+var sqrLen = exports.sqrLen = squaredLength;
+
+/**
+ * Perform some operation over an array of vec2s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+var forEach = exports.forEach = function () {
+  var vec = create();
+
+  return function (a, stride, offset, count, fn, arg) {
+    var i = void 0,
+        l = void 0;
+    if (!stride) {
+      stride = 2;
+    }
+
+    if (!offset) {
+      offset = 0;
+    }
+
+    if (count) {
+      l = Math.min(count * stride + offset, a.length);
+    } else {
+      l = a.length;
+    }
+
+    for (i = offset; i < l; i += stride) {
+      vec[0] = a[i];vec[1] = a[i + 1];
+      fn(vec, vec, arg);
+      a[i] = vec[0];a[i + 1] = vec[1];
+    }
+
+    return a;
+  };
+}();
+
+/***/ })
+/******/ ]);
+});
diff --git a/basic_course/video_texture/201520872/index.html b/basic_course/video_texture/201520872/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..efac3a11286f94fad64176edc780bbf205f227e6
--- /dev/null
+++ b/basic_course/video_texture/201520872/index.html
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>201520872-고현경</title>
+    <link rel="stylesheet" href="./webgl.css" type="text/css">
+  </head>
+
+  <body>
+    <canvas id="glcanvas" width="640" height="480"></canvas>
+  </body>
+
+  <script src="./gl-matrix.js"></script>
+  <script src="./cube.js"></script>
+</html
+cube
diff --git a/basic_course/video_texture/201520872/memory.mp4 b/basic_course/video_texture/201520872/memory.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..8d614b4c88b43fafe742c98b91bfb01b7c014519
Binary files /dev/null and b/basic_course/video_texture/201520872/memory.mp4 differ
diff --git a/basic_course/video_texture/201520872/mongoose-free-6.5.exe b/basic_course/video_texture/201520872/mongoose-free-6.5.exe
new file mode 100644
index 0000000000000000000000000000000000000000..687772ef24c5d70c5fdd4e3aa0a9a020406e0dd3
Binary files /dev/null and b/basic_course/video_texture/201520872/mongoose-free-6.5.exe differ
diff --git a/basic_course/video_texture/201520872/webgl.css b/basic_course/video_texture/201520872/webgl.css
new file mode 100644
index 0000000000000000000000000000000000000000..31f91e36966d56c6868fc4884921ee032d7c47f4
--- /dev/null
+++ b/basic_course/video_texture/201520872/webgl.css
@@ -0,0 +1,7 @@
+canvas {
+	border: 2px solid black;
+	background-color: black;
+}
+video {
+	display: none;
+}
diff --git a/basic_course/video_texture/README.md b/basic_course/video_texture/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ab16b217013b4300a6147543bfc13de39ccf1ebc
--- /dev/null
+++ b/basic_course/video_texture/README.md
@@ -0,0 +1,116 @@
+# 동영상을 텍스쳐로 사용하기
+
+## 실행 전 주의
+- 일부 브라우저에서는 CORS 관련해 보안 상의 이유로 local에 있는 동영상 파일을 표출하는 것이 불가합니다. 
+- 이 경우 동영상 파일을 base64로 바꾸어 코드에 넣어야 하는 등의 방법이 있는데 동영상의 용량이 크고 동영상 변경 기능을 구현할 수 없어 이 코드에는 넣지 않았습니다.
+- 따라서, Chrome 등 일부 브라우저에서는 동영상이 뜨지 않고 파란색 큐브만 돌아가는 등 실행이 어렵습니다.
+- **Microsoft Edge에서는 정상적으로 실행되는 것을 확인하였습니다.**
+
+## 기능
+- 큐브에 동영상 텍스쳐를 입힌다.
+- 동영상을 선택하여 해당 동영상으로 텍스쳐를 변경할 수 있다.
+- 동영상의 재생 속도를 조절하고 멈출 수 있는 버튼을 만든다.
+
+## 의도
+- 동영상 텍스쳐를 입히는 방법과 입힌 동영상의 속성을 조절하는 방법, 다른 동영상을 선택하여 자유자재로 텍스쳐를 변경하는 방법을 학습한다.
+
+<br>
+
+## 코드 설명
+### 큐브에 동영상 텍스쳐 입히기
+- 먼저 Video Element를 생성한다.
+```
+const video = document.createElement('video');
+```
+- 비디오의 속성을 지정한다.
+- autoplay가 true일 경우 비디오는 재생 버튼을 누르지 않아도 자동으로 재생되기 시작한다.
+- muted가 true일 경우 비디오는 음소거로 재생된다.
+- loop가 true일 경우 비디오 종료 시 다시 처음부터 재생된다.
+```
+video.autoplay = true;
+video.muted = true;
+video.loop = true;
+video.play();
+```
+- 비디오가 안전하게 재생되기 위하여 두 개의 이벤트 후 재생시킨다.
+- 두 개의 이벤트 후 copyVideo 변수를 true로 만든다.
+```
+video.addEventListener('playing', function() {
+  playing = true;
+  checkReady();
+}, true);
+
+video.addEventListener('timeupdate', function() {
+  timeupdate = true;
+  checkReady();
+}, true);
+
+function checkReady() {
+  if (playing && timeupdate) {
+    copyVideo = true;
+  }
+}
+```
+- copyVideo 변수가 true가 되면 큐브에 비디오를 텍스쳐로 입혀서 나타나게 한다.
+```
+if (copyVideo) {
+  updateTexture(gl, texture, video);
+}
+function updateTexture(gl, texture, video) {
+  const level = 0;
+  const internalFormat = gl.RGBA;
+  const srcFormat = gl.RGBA;
+  const srcType = gl.UNSIGNED_BYTE;
+  gl.bindTexture(gl.TEXTURE_2D, texture);
+  gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, srcFormat, srcType, video);
+}
+```
+
+### 선택한 동영상으로 재생시키기
+- index.html에 file 타입의 input tag를 만든다.
+```
+<input type="file" id="myVideo">
+```
+- 사용자가 새로운 비디오 파일을 선택하면 이를 감지해 새 동영상으로 바꾼다.
+- 이떄 document.getElementById().value를 사용할 경우 중간 경로가 /fakepath/로 바뀌므로 주의한다.
+```
+changeVideo.addEventListener('change',function() {
+  video.src = document.getElementById('myVideo').files[0].name;
+}, true);
+```
+
+### 비디오 멈추게 하기
+- index.html에 file 타입의 input tag를 만든다.
+```
+<button id="pause">Play/Pause</button>
+```
+
+- 버튼을 클릭하는 것을 감지하여 비디오가 멈추어 있을 경우 재생하고, 비디오가 재생되는 중에는 멈추도록 한다.
+```
+const pauseVideo = document.getElementById('pause');
+pauseVideo.addEventListener('click', function() {
+  if (video.paused)
+    video.play(); 
+  else 
+    video.pause(); 
+}, true);
+```
+
+### 비디오 속도 조절하기
+- index.html에 file 타입의 input tag를 만든다.
+```
+<button id="fast">Faster</button>
+```
+
+- 버튼을 클릭하는 것을 감지하여 비디오가 멈추어 있을 경우 재생하고, 비디오가 재생되는 중에는 멈추도록 한다.
+- document.getElementById('speed').innerHTML을 통해 현재 재생속도를 HTML 화면에 보이도록 한다.
+```
+fastVideo.addEventListener('click', function() {
+  video.playbackRate *= 2;
+  document.getElementById('speed').innerHTML = video.playbackRate;
+}, true);
+```
+
+# 참고한 코드
+- 이 코드는 https://developer.mozilla.org/ko/docs/Web/API/WebGL_API/Tutorial/Animating_textures_in_WebGL 의 예제 코드를 바탕으로 코드를, 수정/추가 하여 만들었습니다.
+- 참고한 코드는 CC0 라이센스로 저작물에 대한 변형, 저작권자와 상의 없이 재배포가 가능하며, 출처 표시의 의무가 없습니다.
\ No newline at end of file
diff --git a/basic_course/video_texture/gl-matrix.js b/basic_course/video_texture/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..45ac91d38cf1317e802be2fe96fde99e00c68397
--- /dev/null
+++ b/basic_course/video_texture/gl-matrix.js
@@ -0,0 +1,7546 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.0.0
+
+Copyright (c) 2015-2019, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Type} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {mat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {mat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the first operand
+   * @param {mat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the matrix to rotate
+   * @param {vec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {vec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {mat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {mat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {mat2} L the lower triangular matrix
+   * @param {mat2} D the diagonal matrix
+   * @param {mat2} U the upper triangular matrix
+   * @param {mat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the first operand
+   * @param {mat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the first operand
+   * @param {mat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {mat2} a The first matrix.
+   * @param {mat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {mat2} a The first matrix.
+   * @param {mat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {mat2} a the first operand
+   * @param {mat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   *
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, c, tx,
+   *  b, d, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, c, tx,
+   *  b, d, ty,
+   *  0, 0, 1]
+   * </pre>
+   * The last row is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {mat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {mat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the first operand
+   * @param {mat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the matrix to translate
+   * @param {vec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the matrix to translate
+   * @param {vec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {vec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {vec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {mat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {mat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the first operand
+   * @param {mat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the first operand
+   * @param {mat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {mat2d} a the first operand
+   * @param {mat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {mat2d} a The first matrix.
+   * @param {mat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {mat2d} a The first matrix.
+   * @param {mat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {mat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {mat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {mat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the first operand
+   * @param {mat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the matrix to translate
+   * @param {vec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the matrix to rotate
+   * @param {vec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {vec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {vec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+  * Calculates a 3x3 matrix from the given quaternion
+  *
+  * @param {mat3} out mat3 receiving operation result
+  * @param {quat} q Quaternion to create matrix from
+  *
+  * @returns {mat3} out
+  */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+  * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+  *
+  * @param {mat3} out mat3 receiving operation result
+  * @param {mat4} a Mat4 to derive the normal matrix from
+  *
+  * @returns {mat3} out
+  */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {mat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {mat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the first operand
+   * @param {mat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the first operand
+   * @param {mat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {mat3} a the first operand
+   * @param {mat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {mat3} a The first matrix.
+   * @param {mat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {mat3} a The first matrix.
+   * @param {mat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {mat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {mat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the first operand
+   * @param {mat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to translate
+   * @param {vec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to scale
+   * @param {vec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Rotates a mat4 by the given angle around the given axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {vec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {vec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {vec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {vec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {vec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {quat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {mat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {mat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {mat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {vec3} v Translation vector
+   * @param {vec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {vec3} v Translation vector
+   * @param {vec3} s Scaling vector
+   * @param {vec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {vec3} eye Position of the viewer
+   * @param {vec3} center Point the viewer is looking at
+   * @param {vec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {vec3} eye Position of the viewer
+   * @param {vec3} center Point the viewer is looking at
+   * @param {vec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {mat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {mat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the first operand
+   * @param {mat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the first operand
+   * @param {mat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {mat4} a the first operand
+   * @param {mat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {mat4} a The first matrix.
+   * @param {mat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {mat4} a The first matrix.
+   * @param {mat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {vec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {vec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {vec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @param {vec3} c the third operand
+   * @param {vec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @param {vec3} c the third operand
+   * @param {vec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the vector to transform
+   * @param {mat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the vector to transform
+   * @param {mat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the vector to transform
+   * @param {quat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {vec3} a The vec3 point to rotate
+   * @param {vec3} b The origin of the rotation
+   * @param {Number} c The angle of rotation
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, c) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(c) - p[2] * Math.sin(c);
+    r[2] = p[1] * Math.sin(c) + p[2] * Math.cos(c); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {vec3} a The vec3 point to rotate
+   * @param {vec3} b The origin of the rotation
+   * @param {Number} c The angle of rotation
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, c) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(c) + p[0] * Math.cos(c);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(c) - p[0] * Math.sin(c); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {vec3} a The vec3 point to rotate
+   * @param {vec3} b The origin of the rotation
+   * @param {Number} c The angle of rotation
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, c) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(c) - p[1] * Math.sin(c);
+    r[1] = p[0] * Math.sin(c) + p[1] * Math.cos(c);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {vec3} a The first operand
+   * @param {vec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var tempA = fromValues$4(a[0], a[1], a[2]);
+    var tempB = fromValues$4(b[0], b[1], b[2]);
+    normalize(tempA, tempA);
+    normalize(tempB, tempB);
+    var cosine = dot(tempA, tempB);
+
+    if (cosine > 1.0) {
+      return 0;
+    } else if (cosine < -1.0) {
+      return Math.PI;
+    } else {
+      return Math.acos(cosine);
+    }
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {vec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {vec3} a The first vector.
+   * @param {vec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {vec3} a The first vector.
+   * @param {vec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {vec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {vec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {vec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {vec4} result the receiving vector
+   * @param {vec4} U the first vector
+   * @param {vec4} V the second vector
+   * @param {vec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the vector to transform
+   * @param {mat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the vector to transform
+   * @param {quat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {vec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {vec4} a The first vector.
+   * @param {vec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {vec4} a The first vector.
+   * @param {vec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {vec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {quat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {quat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {quat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {quat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {mat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {quat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {quat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {quat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {quat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {quat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {quat} a The first quaternion.
+   * @param {quat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {quat} a The first vector.
+   * @param {quat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {vec3} a the initial vector
+   * @param {vec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @param {quat} c the third operand
+   * @param {quat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {vec3} view  the vector representing the viewing direction
+   * @param {vec3} right the vector representing the local "right" direction
+   * @param {vec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {quat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {quat2} dual quaternion receiving operation result
+   * @param {quat} q a normalized quaternion
+   * @param {vec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {quat2} dual quaternion receiving operation result
+   * @param {vec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {quat2} dual quaternion receiving operation result
+   * @param {quat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {mat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {quat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {quat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {quat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {quat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {quat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to translate
+   * @param {vec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {quat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat} q quaternion to rotate by
+   * @param {quat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {vec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the first operand
+   * @param {quat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the first operand
+   * @param {quat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {quat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {quat2} a the first operand
+   * @param {quat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {quat2} a the first operand
+   * @param {quat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {quat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {quat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {quat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {quat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return 'quat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ')';
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {quat2} a the first dual quaternion.
+   * @param {quat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {quat2} a the first dual quat.
+   * @param {quat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {vec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {vec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {vec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to transform
+   * @param {mat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to transform
+   * @param {mat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to transform
+   * @param {mat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to transform
+   * @param {mat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {vec2} a The vec2 point to rotate
+   * @param {vec2} b The origin of the rotation
+   * @param {Number} c The angle of rotation
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, c) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(c),
+        cosC = Math.cos(c); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {vec2} a The first operand
+   * @param {vec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1];
+    var len1 = x1 * x1 + y1 * y1;
+
+    if (len1 > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len1 = 1 / Math.sqrt(len1);
+    }
+
+    var len2 = x2 * x2 + y2 * y2;
+
+    if (len2 > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len2 = 1 / Math.sqrt(len2);
+    }
+
+    var cosine = (x1 * x2 + y1 * y2) * len1 * len2;
+
+    if (cosine > 1.0) {
+      return 0;
+    } else if (cosine < -1.0) {
+      return Math.PI;
+    } else {
+      return Math.acos(cosine);
+    }
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {vec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return 'vec2(' + a[0] + ', ' + a[1] + ')';
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {vec2} a The first vector.
+   * @param {vec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {vec2} a The first vector.
+   * @param {vec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/basic_course/video_texture/mongoose-free-6.5.exe b/basic_course/video_texture/mongoose-free-6.5.exe
new file mode 100644
index 0000000000000000000000000000000000000000..687772ef24c5d70c5fdd4e3aa0a9a020406e0dd3
Binary files /dev/null and b/basic_course/video_texture/mongoose-free-6.5.exe differ
diff --git a/basic_course/video_texture/video.mp4 b/basic_course/video_texture/video.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..0c7cb83c37552f285b0134295611bf468b55d17d
Binary files /dev/null and b/basic_course/video_texture/video.mp4 differ
diff --git a/basic_course/video_texture/video2.mp4 b/basic_course/video_texture/video2.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..66b10fecbd08973ca4ec5b7a57b74d48f73ab6bd
Binary files /dev/null and b/basic_course/video_texture/video2.mp4 differ
diff --git a/basic_course/video_texture/videoTexture.html b/basic_course/video_texture/videoTexture.html
new file mode 100644
index 0000000000000000000000000000000000000000..bef6c93edb93aca615333c52eb5febbeadd3d47e
--- /dev/null
+++ b/basic_course/video_texture/videoTexture.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>WebGL Demo</title>
+    <link rel="stylesheet" href="webgl.css" type="text/css">
+  </head>
+
+  <body>
+    You can change your video. <input type="file" id="myVideo">
+    <br><br>
+    <canvas id="glcanvas" width="640" height="480"></canvas>
+    <br>
+    This button makes video play or pause.
+    <button id="pause">Play/Pause</button>
+    <br>
+    This button makes cube rotates or stop.
+    <button id="stop">Move/Stop</button>
+    <br>
+    This button makes video play faster or slower.
+    <button id="fast">Faster</button>
+    <button id="slow">Slower</button>
+    Video Speed : <span id="speed">1</span>
+    <br>
+    This button makes cube rotates faster or slower.
+    <button id="rFast">Faster</button>
+    <button id="rSlow">Slower</button>
+    Rotate Speed : <span id="rSpeed">1</span>
+  </body>
+
+  <script src="gl-matrix.js"></script>
+  <script src="videoTexture.js"></script>
+</html>
\ No newline at end of file
diff --git a/basic_course/video_texture/videoTexture.js b/basic_course/video_texture/videoTexture.js
new file mode 100644
index 0000000000000000000000000000000000000000..3be17fba828b4017e958818d5bdd237534f29931
--- /dev/null
+++ b/basic_course/video_texture/videoTexture.js
@@ -0,0 +1,565 @@
+// CC-NC-BY So Hyun Seob 2019" 
+
+var cubeRotation = 0.0;
+var copyVideo = false; // will set to true when video can be copied to texture
+var rotateSpeed = 1.0;
+main();
+
+function main() {
+  const canvas = document.querySelector('#glcanvas');
+  const gl = canvas.getContext('webgl');
+
+  if (!gl) {
+    alert("Unable to initialise WebGL. Your browser may not support it");
+    return;
+  }
+
+  // Vertex shader program
+
+  const vsSource = `
+    attribute vec4 aVertexPosition;
+    attribute vec3 aVertexNormal;
+    attribute vec2 aTextureCoord;
+
+    uniform mat4 uNormalMatrix;
+    uniform mat4 uModelViewMatrix;
+    uniform mat4 uProjectionMatrix;
+
+    varying highp vec2 vTextureCoord;
+    varying highp vec3 vLighting;
+
+    void main(void) {
+      gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
+      vTextureCoord = aTextureCoord;
+
+      // Apply lighting effect
+
+      highp vec3 ambientLight = vec3(0.3, 0.3, 0.3);
+      highp vec3 directionalLightColor = vec3(1, 1, 1);
+      highp vec3 directionalVector = normalize(vec3(0.85, 0.8, 0.75));
+
+      highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);
+
+      highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);
+      vLighting = ambientLight + (directionalLightColor * directional);
+    }
+  `;
+
+  // Fragment shader program
+
+  const fsSource = `
+    varying highp vec2 vTextureCoord;
+    varying highp vec3 vLighting;
+
+    uniform sampler2D uSampler;
+
+    void main(void) {
+      highp vec4 texelColor = texture2D(uSampler, vTextureCoord);
+
+      gl_FragColor = vec4(texelColor.rgb * vLighting, texelColor.a);
+    }
+  `;
+
+  // Initialize a shader program; this is where all the lighting
+  // for the vertices and so forth is established.
+  const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
+
+  // Collect all the info needed to use the shader program.
+  // Look up which attributes our shader program is using
+  // for aVertexPosition, aVertexNormal, aTextureCoord,
+  // and look up uniform locations.
+  const programInfo = {
+    program: shaderProgram,
+    attribLocations: {
+      vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
+      vertexNormal: gl.getAttribLocation(shaderProgram, 'aVertexNormal'),
+      textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),
+    },
+    uniformLocations: {
+      projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
+      modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
+      normalMatrix: gl.getUniformLocation(shaderProgram, 'uNormalMatrix'),
+      uSampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
+    },
+  };
+
+  // Here's where we call the routine that builds all the objects we'll be drawing.
+  const buffers = initBuffers(gl);
+  const texture = initTexture(gl);
+  const video = setupVideo();
+
+  var then = 0;
+
+  // event listener for faster rotation
+  const fastRot = document.getElementById('rFast');
+  fastRot.addEventListener('click', function() {
+    rotateSpeed += 1;
+    document.getElementById('rSpeed').innerHTML = rotateSpeed;
+  }, true);
+
+  // event listener for slower rotation
+  const slowRot = document.getElementById('rSlow');
+  slowRot.addEventListener('click', function() {
+    rotateSpeed -= 1;
+    document.getElementById('rSpeed').innerHTML = rotateSpeed;
+  }, true);
+
+  // event listener for stop rotation
+  const stopRot = document.getElementById('stop');
+  stopRot.addEventListener('click', function() {
+    if(rotateSpeed == 0)
+      rotateSpeed = 1;
+    else
+      rotateSpeed = 0;
+    document.getElementById('rSpeed').innerHTML = rotateSpeed;
+  }, true);
+
+  // Draw the scene repeatedly
+  function render(now) {
+    now *= 0.001;  // convert to seconds
+    const deltaTime = (now - then) * rotateSpeed;
+    then = now;
+
+    if (copyVideo) {
+      updateTexture(gl, texture, video);
+    }
+
+    drawScene(gl, programInfo, buffers, texture, deltaTime);
+
+    requestAnimationFrame(render);
+  }
+  requestAnimationFrame(render);
+}
+
+function setupVideo() {
+  const video = document.createElement('video');
+  var playing = false;
+  var timeupdate = false;
+
+  video.autoplay = true;
+  video.muted = true;
+  video.loop = true;
+  video.src = 'video.mp4';
+  const changeVideo = document.getElementById('myVideo');
+  // Waiting for these 2 events ensures
+  video.addEventListener('playing', function() {
+     playing = true;
+     checkReady();
+  }, true);
+
+  video.addEventListener('timeupdate', function() {
+     timeupdate = true;
+     checkReady();
+  }, true);
+
+  //Event listener for change video.
+  changeVideo.addEventListener('change',function() {
+    video.src = document.getElementById('myVideo').files[0].name;
+  }, true);
+
+  //Event listener for pause or play video.
+  const pauseVideo = document.getElementById('pause');
+  pauseVideo.addEventListener('click', function() {
+    if (video.paused)
+      video.play(); 
+    else 
+      video.pause(); 
+  }, true);
+
+  //Event listener for faster video speed.
+  const fastVideo = document.getElementById('fast');
+  fastVideo.addEventListener('click', function() {
+    video.playbackRate *= 2;
+    document.getElementById('speed').innerHTML = video.playbackRate;
+  }, true);
+
+  //Event listener for slower video speed.
+  const slowVideo = document.getElementById('slow');
+  slowVideo.addEventListener('click', function() {
+    video.playbackRate *= 0.5;
+    document.getElementById('speed').innerHTML = video.playbackRate;
+  }, true);
+
+  video.play();
+
+  function checkReady() {
+    if (playing && timeupdate) {
+      copyVideo = true;
+    }
+  }
+
+  return video;
+}
+
+// Initialize the buffers
+function initBuffers(gl) {
+
+  // Create a buffer for the cube's vertex positions.
+
+  const positionBuffer = gl.createBuffer();
+
+  // Select the positionBuffer as the one to apply buffer
+  // operations to from here out.
+
+  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+  // Now create an array of positions for the cube.
+
+  const positions = [
+    // Front face
+    -1.0, -1.0,  1.0,
+     1.0, -1.0,  1.0,
+     1.0,  1.0,  1.0,
+    -1.0,  1.0,  1.0,
+
+    // Back face
+    -1.0, -1.0, -1.0,
+    -1.0,  1.0, -1.0,
+     1.0,  1.0, -1.0,
+     1.0, -1.0, -1.0,
+
+    // Top face
+    -1.0,  1.0, -1.0,
+    -1.0,  1.0,  1.0,
+     1.0,  1.0,  1.0,
+     1.0,  1.0, -1.0,
+
+    // Bottom face
+    -1.0, -1.0, -1.0,
+     1.0, -1.0, -1.0,
+     1.0, -1.0,  1.0,
+    -1.0, -1.0,  1.0,
+
+    // Right face
+     1.0, -1.0, -1.0,
+     1.0,  1.0, -1.0,
+     1.0,  1.0,  1.0,
+     1.0, -1.0,  1.0,
+
+    // Left face
+    -1.0, -1.0, -1.0,
+    -1.0, -1.0,  1.0,
+    -1.0,  1.0,  1.0,
+    -1.0,  1.0, -1.0,
+  ];
+
+  // Now pass the list of positions into WebGL to build the shape. We do this by creating a Float32Array from the JavaScript array, then use it to fill the current buffer.
+
+  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
+
+  // Set up the normals for the vertices, so that we can compute lighting.
+
+  const normalBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
+
+  const vertexNormals = [
+    // Front
+     0.0,  0.0,  1.0,
+     0.0,  0.0,  1.0,
+     0.0,  0.0,  1.0,
+     0.0,  0.0,  1.0,
+
+    // Back
+     0.0,  0.0, -1.0,
+     0.0,  0.0, -1.0,
+     0.0,  0.0, -1.0,
+     0.0,  0.0, -1.0,
+
+    // Top
+     0.0,  1.0,  0.0,
+     0.0,  1.0,  0.0,
+     0.0,  1.0,  0.0,
+     0.0,  1.0,  0.0,
+
+    // Bottom
+     0.0, -1.0,  0.0,
+     0.0, -1.0,  0.0,
+     0.0, -1.0,  0.0,
+     0.0, -1.0,  0.0,
+
+    // Right
+     1.0,  0.0,  0.0,
+     1.0,  0.0,  0.0,
+     1.0,  0.0,  0.0,
+     1.0,  0.0,  0.0,
+
+    // Left
+    -1.0,  0.0,  0.0,
+    -1.0,  0.0,  0.0,
+    -1.0,  0.0,  0.0,
+    -1.0,  0.0,  0.0,
+  ];
+
+  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexNormals),
+                gl.STATIC_DRAW);
+
+  // Now set up the texture coordinates for the faces.
+
+  const textureCoordBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
+
+  const textureCoordinates = [
+    // Front
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Back
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Top
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Bottom
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Right
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Left
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+  ];
+
+  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), gl.STATIC_DRAW);
+
+  // Build the element array buffer; this specifies the indices into the vertex arrays for each face's vertices.
+
+  const indexBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+
+  // This array defines each face as two triangles, using the indices into the vertex array to specify each triangle's position.
+
+  const indices = [
+    0,  1,  2,      0,  2,  3,    // front
+    4,  5,  6,      4,  6,  7,    // back
+    8,  9,  10,     8,  10, 11,   // top
+    12, 13, 14,     12, 14, 15,   // bottom
+    16, 17, 18,     16, 18, 19,   // right
+    20, 21, 22,     20, 22, 23,   // left
+  ];
+
+  // Now send the element array to GL
+
+  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+      new Uint16Array(indices), gl.STATIC_DRAW);
+
+  return {
+    position: positionBuffer,
+    normal: normalBuffer,
+    textureCoord: textureCoordBuffer,
+    indices: indexBuffer,
+  };
+}
+
+// Initialize a texture.
+function initTexture(gl, url) {
+  const texture = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, texture);
+
+  // Because video havs to be download over the internet
+  // they might take a moment until it's ready so
+  // put a single pixel in the texture so we can
+  // use it immediately.
+  const level = 0;
+  const internalFormat = gl.RGBA;
+  const width = 1;
+  const height = 1;
+  const border = 0;
+  const srcFormat = gl.RGBA;
+  const srcType = gl.UNSIGNED_BYTE;
+  const pixel = new Uint8Array([0, 0, 255, 255]);  // opaque blue
+  gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, width, height, border, srcFormat, srcType, pixel);
+
+  // Turn off mips and set  wrapping to clamp to edge so it
+  // will work regardless of the dimensions of the video.
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+
+  return texture;
+}
+
+// copy the video texture
+function updateTexture(gl, texture, video) {
+  const level = 0;
+  const internalFormat = gl.RGBA;
+  const srcFormat = gl.RGBA;
+  const srcType = gl.UNSIGNED_BYTE;
+  gl.bindTexture(gl.TEXTURE_2D, texture);
+  gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, srcFormat, srcType, video);
+}
+
+function isPowerOf2(value) {
+  return (value & (value - 1)) == 0;
+}
+
+// Draw the scene.
+function drawScene(gl, programInfo, buffers, texture, deltaTime) {
+  gl.clearColor(0.0, 0.0, 0.0, 1.0);  // Clear to black, fully opaque
+  gl.clearDepth(1.0);                 // Clear everything
+  gl.enable(gl.DEPTH_TEST);           // Enable depth testing
+  gl.depthFunc(gl.LEQUAL);            // Near things obscure far things
+
+  // Clear the canvas before we start drawing on it.
+
+  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+  const fieldOfView = 45 * Math.PI / 180;   // in radians
+  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
+  const zNear = 0.1;
+  const zFar = 100.0;
+  const projectionMatrix = glMatrix.mat4.create();
+
+  glMatrix.mat4.perspective(projectionMatrix,fieldOfView,aspect,zNear,zFar);
+
+  // Set the drawing position to the "identity" point, which is
+  // the center of the scene.
+  const modelViewMatrix = glMatrix.mat4.create();
+
+  // Now move the drawing position a bit to where we want to
+  // start drawing the square.
+
+  glMatrix.mat4.translate(modelViewMatrix, modelViewMatrix, [-0.0, 0.0, -6.0]);  // amount to translate
+  glMatrix.mat4.rotate(modelViewMatrix,  modelViewMatrix, cubeRotation, [0, 0, 1]);
+  glMatrix.mat4.rotate(modelViewMatrix, modelViewMatrix, cubeRotation * .7,[0, 1, 0]);
+
+  const normalMatrix = glMatrix.mat4.create();
+  glMatrix.mat4.invert(normalMatrix, modelViewMatrix);
+  glMatrix.mat4.transpose(normalMatrix, normalMatrix);
+
+  // Tell WebGL how to pull out the positions from the position
+  // buffer into the vertexPosition attribute
+  {
+    const numComponents = 3;
+    const type = gl.FLOAT;
+    const normalize = false;
+    const stride = 0;
+    const offset = 0;
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
+    gl.vertexAttribPointer(programInfo.attribLocations.vertexPosition, numComponents, type, normalize, stride, offset);
+    gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
+  }
+
+  // Tell WebGL how to pull out the texture coordinates from
+  // the texture coordinate buffer into the textureCoord attribute.
+  {
+    const numComponents = 2;
+    const type = gl.FLOAT;
+    const normalize = false;
+    const stride = 0;
+    const offset = 0;
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureCoord);
+    gl.vertexAttribPointer(programInfo.attribLocations.textureCoord,numComponents,type,normalize,stride,offset);
+    gl.enableVertexAttribArray(programInfo.attribLocations.textureCoord);
+  }
+
+  // Tell WebGL how to pull out the normals from
+  // the normal buffer into the vertexNormal attribute.
+  {
+    const numComponents = 3;
+    const type = gl.FLOAT;
+    const normalize = false;
+    const stride = 0;
+    const offset = 0;
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.normal);
+    gl.vertexAttribPointer(programInfo.attribLocations.vertexNormal,numComponents,type,normalize,stride,offset);
+    gl.enableVertexAttribArray(programInfo.attribLocations.vertexNormal);
+  }
+
+  // Tell WebGL which indices to use to index the vertices
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
+
+  // Tell WebGL to use our program when drawing
+
+  gl.useProgram(programInfo.program);
+
+  // Set the shader uniforms
+
+  gl.uniformMatrix4fv(programInfo.uniformLocations.projectionMatrix,false,projectionMatrix);
+  gl.uniformMatrix4fv(programInfo.uniformLocations.modelViewMatrix,false,modelViewMatrix);
+  gl.uniformMatrix4fv(programInfo.uniformLocations.normalMatrix,false,normalMatrix);
+
+  // Specify the texture to map onto the faces.
+
+  // Tell WebGL we want to affect texture unit 0
+  gl.activeTexture(gl.TEXTURE0);
+
+  // Bind the texture to texture unit 0
+  gl.bindTexture(gl.TEXTURE_2D, texture);
+
+  // Tell the shader we bound the texture to texture unit 0
+  gl.uniform1i(programInfo.uniformLocations.uSampler, 0);
+
+  {
+    const vertexCount = 36;
+    const type = gl.UNSIGNED_SHORT;
+    const offset = 0;
+    gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
+  }
+
+  // Update the rotation for the next draw
+
+  cubeRotation += deltaTime;
+}
+
+//
+// Initialize a shader program, so WebGL knows how to draw our data
+//
+function initShaderProgram(gl, vsSource, fsSource) {
+  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
+  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
+
+  // Create the shader program
+
+  const shaderProgram = gl.createProgram();
+  gl.attachShader(shaderProgram, vertexShader);
+  gl.attachShader(shaderProgram, fragmentShader);
+  gl.linkProgram(shaderProgram);
+
+  // If creating the shader program failed, alert
+
+  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
+    alert("Failed to compile the shader.\n" + gl.getProgramInfoLog(shaderProgram));
+    return null;
+  }
+
+  return shaderProgram;
+}
+
+//
+// creates a shader of the given type, uploads the source and
+// compiles it.
+//
+function loadShader(gl, type, source) {
+  const shader = gl.createShader(type);
+
+  // Send the source to the shader object
+
+  gl.shaderSource(shader, source);
+
+  // Compile the shader program
+
+  gl.compileShader(shader);
+
+  // See if it compiled successfully
+
+  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+    alert("Failed to compile the shader.\n" + gl.getShaderInfoLog(shader));
+    gl.deleteShader(shader);
+    return null;
+  }
+
+  return shader;
+}
+
diff --git a/basic_course/video_texture/webgl.css b/basic_course/video_texture/webgl.css
new file mode 100644
index 0000000000000000000000000000000000000000..71910ba584abf5aae7bc7589ab5c95b77a71e88c
--- /dev/null
+++ b/basic_course/video_texture/webgl.css
@@ -0,0 +1,10 @@
+canvas {
+	border: 2px solid black;
+	background-color: black;
+}
+video {
+	display: none;
+}
+body {
+	font-size: 20px;
+}
\ No newline at end of file
diff --git a/basic_course/view/.gitkeep b/basic_course/view/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/basic_course/view/gl-matrix.js b/basic_course/view/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..4553f9ea44878e9b79894c1de08af95ea9814317
--- /dev/null
+++ b/basic_course/view/gl-matrix.js
@@ -0,0 +1,7611 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.3.0
+
+Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, (function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Float32ArrayConstructor | ArrayConstructor} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {ReadonlyMat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {ReadonlyMat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return "mat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {ReadonlyMat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {ReadonlyMat2} L the lower triangular matrix
+   * @param {ReadonlyMat2} D the diagonal matrix
+   * @param {ReadonlyMat2} U the upper triangular matrix
+   * @param {ReadonlyMat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2} a The first matrix.
+   * @param {ReadonlyMat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {ReadonlyMat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {ReadonlyMat2} a the first operand
+   * @param {ReadonlyMat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, b,
+   *  c, d,
+   *  tx, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, b, 0,
+   *  c, d, 0,
+   *  tx, ty, 1]
+   * </pre>
+   * The last column is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to translate
+   * @param {ReadonlyVec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {ReadonlyMat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return "mat2d(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {ReadonlyMat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {ReadonlyMat2d} a the first operand
+   * @param {ReadonlyMat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat2d} a The first matrix.
+   * @param {ReadonlyMat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {ReadonlyMat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {ReadonlyMat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to translate
+   * @param {ReadonlyVec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to rotate
+   * @param {ReadonlyVec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyVec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 matrix from the given quaternion
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+   * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {ReadonlyMat4} a Mat4 to derive the normal matrix from
+   *
+   * @returns {mat3} out
+   */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {ReadonlyMat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return "mat3(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {ReadonlyMat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {ReadonlyMat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {ReadonlyMat3} a the first operand
+   * @param {ReadonlyMat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat3} a The first matrix.
+   * @param {ReadonlyMat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {ReadonlyMat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {ReadonlyMat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {ReadonlyVec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Rotates a mat4 by the given angle around the given axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyVec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {ReadonlyQuat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {ReadonlyMat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {ReadonlyVec3} v Translation vector
+   * @param {ReadonlyVec3} s Scaling vector
+   * @param {ReadonlyVec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {ReadonlyQuat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {ReadonlyVec3} eye Position of the viewer
+   * @param {ReadonlyVec3} center Point the viewer is looking at
+   * @param {ReadonlyVec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {ReadonlyMat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")";
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {ReadonlyMat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {ReadonlyMat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {ReadonlyMat4} a the first operand
+   * @param {ReadonlyMat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyMat4} a The first matrix.
+   * @param {ReadonlyMat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {ReadonlyVec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the first operand
+   * @param {ReadonlyVec3} b the second operand
+   * @param {ReadonlyVec3} c the third operand
+   * @param {ReadonlyVec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyMat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec3} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
+    r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {ReadonlyVec3} a The vec3 point to rotate
+   * @param {ReadonlyVec3} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, rad) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
+    r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {ReadonlyVec3} a The first operand
+   * @param {ReadonlyVec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        bx = b[0],
+        by = b[1],
+        bz = b[2],
+        mag1 = Math.sqrt(ax * ax + ay * ay + az * az),
+        mag2 = Math.sqrt(bx * bx + by * by + bz * bz),
+        mag = mag1 * mag2,
+        cosine = mag && dot(a, b) / mag;
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec3} a The first vector.
+   * @param {ReadonlyVec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {ReadonlyVec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {ReadonlyVec4} result the receiving vector
+   * @param {ReadonlyVec4} U the first vector
+   * @param {ReadonlyVec4} V the second vector
+   * @param {ReadonlyVec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the first operand
+   * @param {ReadonlyVec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {ReadonlyVec4} a the vector to transform
+   * @param {ReadonlyQuat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return "vec4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec4} a The first vector.
+   * @param {ReadonlyVec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyVec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {ReadonlyQuat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Gets the angular distance between two unit quaternions
+   *
+   * @param  {ReadonlyQuat} a     Origin unit quaternion
+   * @param  {ReadonlyQuat} b     Destination unit quaternion
+   * @return {Number}     Angle, in radians, between the two quaternions
+   */
+
+  function getAngle(a, b) {
+    var dotproduct = dot$2(a, b);
+    return Math.acos(2 * dotproduct * dotproduct - 1);
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {ReadonlyQuat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Calculate the exponential of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function exp(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var et = Math.exp(w);
+    var s = r > 0 ? et * Math.sin(r) / r : 0;
+    out[0] = x * s;
+    out[1] = y * s;
+    out[2] = z * s;
+    out[3] = et * Math.cos(r);
+    return out;
+  }
+  /**
+   * Calculate the natural logarithm of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @returns {quat} out
+   */
+
+  function ln(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var r = Math.sqrt(x * x + y * y + z * z);
+    var t = r > 0 ? Math.atan2(r, w) / r : 0;
+    out[0] = x * t;
+    out[1] = y * t;
+    out[2] = z * t;
+    out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w);
+    return out;
+  }
+  /**
+   * Calculate the scalar power of a unit quaternion.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate the exponential of
+   * @param {Number} b amount to scale the quaternion by
+   * @returns {quat} out
+   */
+
+  function pow(out, a, b) {
+    ln(out, a);
+    scale$6(out, out, b);
+    exp(out, out);
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random unit quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyMat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {ReadonlyQuat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return "quat(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")";
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {ReadonlyQuat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {ReadonlyQuat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat} a The first quaternion.
+   * @param {ReadonlyQuat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat} a The first vector.
+   * @param {ReadonlyQuat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {ReadonlyVec3} a the initial vector
+   * @param {ReadonlyVec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {ReadonlyQuat} a the first operand
+   * @param {ReadonlyQuat} b the second operand
+   * @param {ReadonlyQuat} c the third operand
+   * @param {ReadonlyQuat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {ReadonlyVec3} view  the vector representing the viewing direction
+   * @param {ReadonlyVec3} right the vector representing the local "right" direction
+   * @param {ReadonlyVec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    getAngle: getAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    exp: exp,
+    ln: ln,
+    pow: pow,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q a normalized quaternion
+   * @param {ReadonlyVec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyVec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {ReadonlyQuat2} dual quaternion receiving operation result
+   * @param {ReadonlyQuat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {ReadonlyMat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {ReadonlyQuat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {ReadonlyQuat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to translate
+   * @param {ReadonlyVec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat} q quaternion to rotate by
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the dual quaternion to rotate
+   * @param {ReadonlyVec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {ReadonlyQuat2} a the first operand
+   * @param {ReadonlyQuat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {ReadonlyQuat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {ReadonlyQuat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {ReadonlyQuat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {ReadonlyQuat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return "quat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ")";
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyQuat2} a the first dual quaternion.
+   * @param {ReadonlyQuat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyQuat2} a the first dual quat.
+   * @param {ReadonlyQuat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {ReadonlyVec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {ReadonlyVec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the first operand
+   * @param {ReadonlyVec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {ReadonlyVec2} a the vector to transform
+   * @param {ReadonlyMat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {ReadonlyVec2} a The vec2 point to rotate
+   * @param {ReadonlyVec2} b The origin of the rotation
+   * @param {Number} rad The angle of rotation in radians
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, rad) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(rad),
+        cosC = Math.cos(rad); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {ReadonlyVec2} a The first operand
+   * @param {ReadonlyVec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1],
+        // mag is the product of the magnitudes of a and b
+    mag = Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2),
+        // mag &&.. short circuits if mag == 0
+    cosine = mag && (x1 * x2 + y1 * y2) / mag; // Math.min(Math.max(cosine, -1), 1) clamps the cosine between -1 and 1
+
+    return Math.acos(Math.min(Math.max(cosine, -1), 1));
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {ReadonlyVec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return "vec2(" + a[0] + ", " + a[1] + ")";
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {ReadonlyVec2} a The first vector.
+   * @param {ReadonlyVec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/basic_course/view/hello.js b/basic_course/view/hello.js
new file mode 100644
index 0000000000000000000000000000000000000000..5b7be14332a8aea7b407674bd82f5249c2dec843
--- /dev/null
+++ b/basic_course/view/hello.js
@@ -0,0 +1,249 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+var vertexData = [
+		// Backface (RED/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 1.0, 1.0, 
+		// Front (BLUE/WHITE) -> z = 0.5
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// LEFT (GREEN/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0, 
+		// RIGHT (YELLOE/WHITE) -> z = 0.5
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// BOTTON (MAGENTA/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// TOP (CYAN/WHITE) -> z = 0.5
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0 
+];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color;\
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 mMat; \
+			uniform mediump mat4 vMat; \
+			uniform mediump mat4 pMat; \
+			varying  highp vec4 color;\
+			void main(void)  \
+			{ \
+				gl_Position = pMat * vMat * mMat * myVertex; \
+				gl_PointSize = 8.0; \
+				color = myColor; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    // console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+flag_animation = 0; 
+function toggleAnimation()
+{
+	flag_animation ^= 1; 
+}
+
+rotY = 0.0;
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+	gl.clearDepth(1.0);										// Added for depth Test 
+
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);	// Added for depth Test 
+	gl.enable(gl.DEPTH_TEST);								// Added for depth Test 
+
+    var mMatLocation = gl.getUniformLocation(gl.programObject, "mMat");
+    var vMatLocation = gl.getUniformLocation(gl.programObject, "vMat");
+    var pMatLocation = gl.getUniformLocation(gl.programObject, "pMat");
+    var mMat = []; 
+	mat4.translate(mMat, mMat, [0.0, 0.0, 0.0]); 
+	if ( flag_animation ){
+		rotY += 0.01;
+	}
+	var vMat = [];
+	mat4.lookAt(vMat, [0.0, 0.0, 3.0], [0.0,0.0,0.0], [0.0, 1.0, 0.0]);
+	console.log(vMat); 
+	var pMat = [];
+	mat4.identity(pMat); 
+	// mat4.ortho(pMat, -2*800.0/600.0, 2*800.0/600.0, -2, 2, 1, 7.0)
+	mat4.perspective(pMat, 3.64/2.0, 800.0/600.0, 0.5, 9);
+	// console.log("pMAT:", pMat);
+
+    gl.uniformMatrix4fv(vMatLocation, gl.FALSE, vMat );
+    gl.uniformMatrix4fv(pMatLocation, gl.FALSE, pMat );
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+	//vertexData[0] += 0.01; 
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    //gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
+	//gl.vertexAttrib4f(1, 1.0, 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	var i; 
+	mat4.identity(mMat); 
+	console.log("ID", mMat);
+	mat4.rotateY(mMat, mMat, rotY); 
+	console.log("RT", mMat);
+	mat4.translate(mMat, mMat, [0.7, 0.7, 0.7, 0.0]); 
+	console.log("TR", mMat);
+	gl.uniformMatrix4fv(mMatLocation, gl.FALSE, mMat );
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+	// gl.drawArrays(gl.LINE_STRIP, 0, 36); 
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+	// renderScene();
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/view/hello_start.js b/basic_course/view/hello_start.js
new file mode 100644
index 0000000000000000000000000000000000000000..49da2c7a5f46ca2928d872449cb607abe41e33b1
--- /dev/null
+++ b/basic_course/view/hello_start.js
@@ -0,0 +1,241 @@
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+var vertexData = [
+		// Backface (RED/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  1.0, 0.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 1.0, 1.0, 
+		// Front (BLUE/WHITE) -> z = 0.5
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 0.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// LEFT (GREEN/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5, -0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5, -0.5,  0.5,  0.0, 1.0, 0.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0, 
+		// RIGHT (YELLOE/WHITE) -> z = 0.5
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 0.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// BOTTON (MAGENTA/WHITE) -> z = 0.5
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5, -0.5,  1.0, 0.0, 1.0, 1.0,
+        -0.5, -0.5,  0.5,  1.0, 0.0, 1.0, 1.0,
+         0.5, -0.5,  0.5,  1.0, 1.0, 1.0, 1.0, 
+		// TOP (CYAN/WHITE) -> z = 0.5
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5, -0.5,  0.0, 1.0, 1.0, 1.0,
+        -0.5,  0.5,  0.5,  0.0, 1.0, 1.0, 1.0,
+         0.5,  0.5,  0.5,  1.0, 1.0, 1.0, 1.0 
+];
+
+function initialiseBuffer() {
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color;\
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // Vertex shader code
+    var vertexShaderSource = '\
+			attribute highp vec4 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 mMat; \
+			uniform mediump mat4 vMat; \
+			uniform mediump mat4 pMat; \
+			varying  highp vec4 color;\
+			void main(void)  \
+			{ \
+				gl_Position = pMat * vMat * mMat * myVertex; \
+				gl_PointSize = 8.0; \
+				color = myColor; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    // Link the program
+    gl.linkProgram(gl.programObject);
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+    // console.log("myVertex Location is: ", gl.getAttribLocation(gl.programObject, "myColor"));
+
+    return testGLError("initialiseShaders");
+}
+
+flag_animation = 0; 
+function toggleAnimation()
+{
+	flag_animation ^= 1; 
+}
+
+rotY = 0.0;
+
+function renderScene() {
+
+    gl.clearColor(0.0, 0.0, 0.0, 1.0);
+	gl.clearDepth(1.0);										// Added for depth Test 
+
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);	// Added for depth Test 
+	gl.enable(gl.DEPTH_TEST);								// Added for depth Test 
+
+    var mMatLocation = gl.getUniformLocation(gl.programObject, "mMat");
+    var vMatLocation = gl.getUniformLocation(gl.programObject, "vMat");
+    var pMatLocation = gl.getUniformLocation(gl.programObject, "pMat");
+    var mMat = []; 
+	mat4.fromYRotation(mMat, rotY); 
+	mat4.translate(mMat, mMat, [0.5, 0.0, 0.0]); 
+	if ( flag_animation ){
+		rotY += 0.01;
+	}
+	var vMat = [];
+	mat4.lookAt(vMat, [0.0, 0.0, 2.0], [0.0,0.0,0.0], [0.0, 1.0, 0.0]);
+	var pMat = [];
+	mat4.identity(pMat); 
+	mat4.perspective(pMat, 3.14/2.0, 800.0/600.0, 0.5, 5);
+	console.log("pMAT:", pMat);
+
+    gl.uniformMatrix4fv(mMatLocation, gl.FALSE, mMat );
+    gl.uniformMatrix4fv(vMatLocation, gl.FALSE, vMat );
+    gl.uniformMatrix4fv(pMatLocation, gl.FALSE, pMat );
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+	//vertexData[0] += 0.01; 
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.enableVertexAttribArray(0);
+    //gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
+	//gl.vertexAttrib4f(1, 1.0, 0.0, 1.0, 1.0);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+	gl.drawArrays(gl.TRIANGLES, 0, 36); 
+	// gl.drawArrays(gl.LINE_STRIP, 0, 36); 
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+	// renderScene();
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/basic_course/view/index.html b/basic_course/view/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..ea3ea9b98e0edd7858516fef6bef03c4f4add9e3
--- /dev/null
+++ b/basic_course/view/index.html
@@ -0,0 +1,22 @@
+<html>
+
+<head>
+<title>WebGL Tutorial 07 - Transform Coding</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js"> </script>
+<script> 
+window['mat4'] = glMatrix.mat4;
+window['vec4'] = glMatrix.vec4;
+window['vec3'] = glMatrix.vec4;
+</script>
+<script type="text/javascript" src="hello.js"> </script>
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="800" height="600"></canvas>
+	<br>
+<button onclick="toggleAnimation()">Toggle Animation</button>
+</body>
+
+</html>
diff --git a/basic_course/webgl-reference-card-1_0.pdf b/basic_course/webgl-reference-card-1_0.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..d403b50d349b7fa525a5e50b776960e769cc5733
Binary files /dev/null and b/basic_course/webgl-reference-card-1_0.pdf differ
diff --git a/basic_course/webgl_00.pptx b/basic_course/webgl_00.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..dd83d65adac13638f766c9fc82c0d69794c37625
Binary files /dev/null and b/basic_course/webgl_00.pptx differ
diff --git a/basic_course/webgl_01.pptx b/basic_course/webgl_01.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..e2bbe89f11fe3142c32923e1f2fc1b39be22f629
Binary files /dev/null and b/basic_course/webgl_01.pptx differ
diff --git a/basic_course/webgl_02.pptx b/basic_course/webgl_02.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..7f515e538e9356e36a98893ef2cfe087679fbcdc
Binary files /dev/null and b/basic_course/webgl_02.pptx differ
diff --git a/basic_course/webgl_03.pptx b/basic_course/webgl_03.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..07f9b801314583cd872c30264511d69b4c22d193
Binary files /dev/null and b/basic_course/webgl_03.pptx differ
diff --git a/basic_course/webgl_04.pptx b/basic_course/webgl_04.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..d2c088d74fbd5e7801631601ee285ab86c8c1e7a
Binary files /dev/null and b/basic_course/webgl_04.pptx differ
diff --git a/basic_course/webgl_05.pptx b/basic_course/webgl_05.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..59a5054446fae1d79ac4837c035d72dab652d2b0
Binary files /dev/null and b/basic_course/webgl_05.pptx differ
diff --git a/basic_course/webgl_06.pptx b/basic_course/webgl_06.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..23c9f38be155836adc5e5e82f35cf7dc69f14807
Binary files /dev/null and b/basic_course/webgl_06.pptx differ
diff --git a/basic_course/webgl_07.pptx b/basic_course/webgl_07.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..ef9312902a076dea7b9525f309231cda3bff0c6d
Binary files /dev/null and b/basic_course/webgl_07.pptx differ
diff --git a/basic_course/webgl_08.pptx b/basic_course/webgl_08.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..e7ed8453f041b8ad435b0065a9467169a6350fda
Binary files /dev/null and b/basic_course/webgl_08.pptx differ
diff --git a/basic_course/webgl_09.pptx b/basic_course/webgl_09.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..6c8b87b21aa0d4d386ec3b5cd6e8914ecde7ded4
Binary files /dev/null and b/basic_course/webgl_09.pptx differ
diff --git a/basic_course/webgl_10.pptx b/basic_course/webgl_10.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..f54cea66689305aa51d5a2e38bb7bd3381fe123b
Binary files /dev/null and b/basic_course/webgl_10.pptx differ
diff --git a/basic_course/webgl_11a.pptx b/basic_course/webgl_11a.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..a20550eda448a89c6a50671c154b80e715bd09ca
Binary files /dev/null and b/basic_course/webgl_11a.pptx differ
diff --git a/basic_course/webgl_11b.pptx b/basic_course/webgl_11b.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..faa2094de8addb9e31c83567f24ee24b4685aaf3
Binary files /dev/null and b/basic_course/webgl_11b.pptx differ
diff --git a/basic_course/webgl_12a.pptx b/basic_course/webgl_12a.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..0710558920eaeff54eb043358521fc62a7eb14c5
Binary files /dev/null and b/basic_course/webgl_12a.pptx differ
diff --git a/basic_course/webgl_12b.pptx b/basic_course/webgl_12b.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..9ac72b294ca276157200bc66807116de029e16c5
Binary files /dev/null and b/basic_course/webgl_12b.pptx differ
diff --git a/basic_course/webgl_12cd.pptx b/basic_course/webgl_12cd.pptx
new file mode 100644
index 0000000000000000000000000000000000000000..9ebf5e5223f5b70d963a2842f9ec1f01c35c5f09
Binary files /dev/null and b/basic_course/webgl_12cd.pptx differ
diff --git a/student2019/201220913/201220913.html b/student2019/201220913/201220913.html
new file mode 100644
index 0000000000000000000000000000000000000000..f41e5e00b6be3b56010f0da21915e6f20af825f4
--- /dev/null
+++ b/student2019/201220913/201220913.html
@@ -0,0 +1,42 @@
+<!-- (CC_NC_BY) Kunhee Lee 2019 -->
+<html>
+
+<head>
+<title>WebGLHelloAPI</title>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+
+<script type="text/javascript" src="201220913.js"></script>
+
+
+</head>
+
+<body onload="main()">
+	<H2> WebGL - Depth, Culling, Blending </H2>
+    <canvas id="helloapicanvas" style="border: none;" width="400" height="400"></canvas>
+	<br>
+	<button onclick="boxRotate(0)" >Turn!</button>
+	speed(-100 ~ 100)
+  	<input type="number" name="speed" min="-100" max="100">
+	<button onclick="boxRotate(1)" name="run">run</button>
+	<button onclick="boxRotate(2)" name="stop">stop</button>
+	<br><br>
+	<button onclick="animRotate(0.01, 0, 0)">RotateX</button>
+	<button onclick="animRotate(0, 0.01, 0)">RotateY</button>
+	<button onclick="animRotate(0, 0, 0.01)">RotateZ</button>
+	<button onclick="animPause()">Anim Pause</button>
+
+	<br><br>
+	<input type="checkbox" name="chkbox1" value="depth">depth       : 겹치는 픽셀 구간에서 높이(depth)를 비교하여 그릴지 말지 결정을 내린다.
+	<br>
+	<input type="checkbox" name="chkbox2" value="culling">culling   : 앞면인 경우에 그리며 만약 겹칠 경우 그리는 순서를 따른다.
+	<br>
+	<input type="checkbox" name="chkbox3" value="blending">blending : 겹치는 픽셀에 대하여 rgb값을 합성하여 표현한다. 불투명도가 1.0(정규화 된 수치)인 경우에는 불필요하다.
+
+ 	<br><br>
+	<P> reference:</p>
+	<p>Hwanyong Lee's WebGL Lab 04 : Cube Transform</P>
+	<p>https://github.com/toji/gl-matrix/tree/master/dist </p><br>
+	<p> (CC_NC_BY) Kunhee Lee 2019 </p>
+</body>
+
+</html>
diff --git a/student2019/201220913/201220913.js b/student2019/201220913/201220913.js
new file mode 100644
index 0000000000000000000000000000000000000000..154d1c75f9f1547faf74da189f8a41fc9081b3a4
--- /dev/null
+++ b/student2019/201220913/201220913.js
@@ -0,0 +1,487 @@
+// (CC_NC_BY) Kunhee Lee 2019
+// WebGL - Depth, Culling, Blending
+
+
+// 출처: https://github.com/toji/gl-matrix/tree/master/dist
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.0.0
+
+Copyright (c) 2015-2019, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t=t||self).glMatrix={})}(this,function(t){"use strict";var n=1e-6,a="undefined"!=typeof Float32Array?Float32Array:Array,r=Math.random;var u=Math.PI/180;Math.hypot||(Math.hypot=function(){for(var t=0,n=arguments.length;n--;)t+=arguments[n]*arguments[n];return Math.sqrt(t)});var e=Object.freeze({EPSILON:n,get ARRAY_TYPE(){return a},RANDOM:r,setMatrixArrayType:function(t){a=t},toRadian:function(t){return t*u},equals:function(t,a){return Math.abs(t-a)<=n*Math.max(1,Math.abs(t),Math.abs(a))}});function o(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*i+e*c,t[1]=u*i+o*c,t[2]=r*h+e*s,t[3]=u*h+o*s,t}function i(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}var c=o,h=i,s=Object.freeze({create:function(){var t=new a(4);return a!=Float32Array&&(t[1]=0,t[2]=0),t[0]=1,t[3]=1,t},clone:function(t){var n=new a(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t},fromValues:function(t,n,r,u){var e=new a(4);return e[0]=t,e[1]=n,e[2]=r,e[3]=u,e},set:function(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t},transpose:function(t,n){if(t===n){var a=n[1];t[1]=n[2],t[2]=a}else t[0]=n[0],t[1]=n[2],t[2]=n[1],t[3]=n[3];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*e-u*r;return o?(o=1/o,t[0]=e*o,t[1]=-r*o,t[2]=-u*o,t[3]=a*o,t):null},adjoint:function(t,n){var a=n[0];return t[0]=n[3],t[1]=-n[1],t[2]=-n[2],t[3]=a,t},determinant:function(t){return t[0]*t[3]-t[2]*t[1]},multiply:o,rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+e*i,t[1]=u*c+o*i,t[2]=r*-i+e*c,t[3]=u*-i+o*c,t},scale:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1];return t[0]=r*i,t[1]=u*i,t[2]=e*c,t[3]=o*c,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t},str:function(t){return"mat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3])},LDU:function(t,n,a,r){return t[2]=r[2]/r[0],a[0]=r[0],a[1]=r[1],a[3]=r[3]-t[2]*a[1],[t,n,a]},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t},subtract:i,exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=a[0],c=a[1],h=a[2],s=a[3];return Math.abs(r-i)<=n*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-c)<=n*Math.max(1,Math.abs(u),Math.abs(c))&&Math.abs(e-h)<=n*Math.max(1,Math.abs(e),Math.abs(h))&&Math.abs(o-s)<=n*Math.max(1,Math.abs(o),Math.abs(s))},multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t},mul:c,sub:h});function M(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return t[0]=r*h+e*s,t[1]=u*h+o*s,t[2]=r*M+e*f,t[3]=u*M+o*f,t[4]=r*l+e*v+i,t[5]=u*l+o*v+c,t}function f(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t}var l=M,v=f,b=Object.freeze({create:function(){var t=new a(6);return a!=Float32Array&&(t[1]=0,t[2]=0,t[4]=0,t[5]=0),t[0]=1,t[3]=1,t},clone:function(t){var n=new a(6);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t},fromValues:function(t,n,r,u,e,o){var i=new a(6);return i[0]=t,i[1]=n,i[2]=r,i[3]=u,i[4]=e,i[5]=o,i},set:function(t,n,a,r,u,e,o){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=a*e-r*u;return c?(c=1/c,t[0]=e*c,t[1]=-r*c,t[2]=-u*c,t[3]=a*c,t[4]=(u*i-e*o)*c,t[5]=(r*o-a*i)*c,t):null},determinant:function(t){return t[0]*t[3]-t[1]*t[2]},multiply:M,rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=Math.sin(a),s=Math.cos(a);return t[0]=r*s+e*h,t[1]=u*s+o*h,t[2]=r*-h+e*s,t[3]=u*-h+o*s,t[4]=i,t[5]=c,t},scale:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1];return t[0]=r*h,t[1]=u*h,t[2]=e*s,t[3]=o*s,t[4]=i,t[5]=c,t},translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=r*h+e*s+i,t[5]=u*h+o*s+c,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t[4]=0,t[5]=0,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t[4]=0,t[5]=0,t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=n[0],t[5]=n[1],t},str:function(t){return"mat2d("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],1)},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t},subtract:f,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return Math.abs(r-h)<=n*Math.max(1,Math.abs(r),Math.abs(h))&&Math.abs(u-s)<=n*Math.max(1,Math.abs(u),Math.abs(s))&&Math.abs(e-M)<=n*Math.max(1,Math.abs(e),Math.abs(M))&&Math.abs(o-f)<=n*Math.max(1,Math.abs(o),Math.abs(f))&&Math.abs(i-l)<=n*Math.max(1,Math.abs(i),Math.abs(l))&&Math.abs(c-v)<=n*Math.max(1,Math.abs(c),Math.abs(v))},mul:l,sub:v});function m(){var t=new a(9);return a!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function d(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],p=a[7],y=a[8];return t[0]=f*r+l*o+v*h,t[1]=f*u+l*i+v*s,t[2]=f*e+l*c+v*M,t[3]=b*r+m*o+d*h,t[4]=b*u+m*i+d*s,t[5]=b*e+m*c+d*M,t[6]=x*r+p*o+y*h,t[7]=x*u+p*i+y*s,t[8]=x*e+p*c+y*M,t}function x(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t}var p=d,y=x,q=Object.freeze({create:m,fromMat4:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[4],t[4]=n[5],t[5]=n[6],t[6]=n[8],t[7]=n[9],t[8]=n[10],t},clone:function(t){var n=new a(9);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromValues:function(t,n,r,u,e,o,i,c,h){var s=new a(9);return s[0]=t,s[1]=n,s[2]=r,s[3]=u,s[4]=e,s[5]=o,s[6]=i,s[7]=c,s[8]=h,s},set:function(t,n,a,r,u,e,o,i,c,h){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t[8]=h,t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},transpose:function(t,n){if(t===n){var a=n[1],r=n[2],u=n[5];t[1]=n[3],t[2]=n[6],t[3]=a,t[5]=n[7],t[6]=r,t[7]=u}else t[0]=n[0],t[1]=n[3],t[2]=n[6],t[3]=n[1],t[4]=n[4],t[5]=n[7],t[6]=n[2],t[7]=n[5],t[8]=n[8];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=s*o-i*h,f=-s*e+i*c,l=h*e-o*c,v=a*M+r*f+u*l;return v?(v=1/v,t[0]=M*v,t[1]=(-s*r+u*h)*v,t[2]=(i*r-u*o)*v,t[3]=f*v,t[4]=(s*a-u*c)*v,t[5]=(-i*a+u*e)*v,t[6]=l*v,t[7]=(-h*a+r*c)*v,t[8]=(o*a-r*e)*v,t):null},adjoint:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8];return t[0]=o*s-i*h,t[1]=u*h-r*s,t[2]=r*i-u*o,t[3]=i*c-e*s,t[4]=a*s-u*c,t[5]=u*e-a*i,t[6]=e*h-o*c,t[7]=r*c-a*h,t[8]=a*o-r*e,t},determinant:function(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],c=t[7],h=t[8];return n*(h*e-o*c)+a*(-h*u+o*i)+r*(c*u-e*i)},multiply:d,translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=a[0],l=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=c,t[6]=f*r+l*o+h,t[7]=f*u+l*i+s,t[8]=f*e+l*c+M,t},rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=Math.sin(a),l=Math.cos(a);return t[0]=l*r+f*o,t[1]=l*u+f*i,t[2]=l*e+f*c,t[3]=l*o-f*r,t[4]=l*i-f*u,t[5]=l*c-f*e,t[6]=h,t[7]=s,t[8]=M,t},scale:function(t,n,a){var r=a[0],u=a[1];return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=u*n[3],t[4]=u*n[4],t[5]=u*n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=n[0],t[7]=n[1],t[8]=1,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=-a,t[4]=r,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=n[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromMat2d:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=0,t[3]=n[2],t[4]=n[3],t[5]=0,t[6]=n[4],t[7]=n[5],t[8]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,c=u+u,h=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*c,b=e*o,m=e*i,d=e*c;return t[0]=1-M-v,t[3]=s-d,t[6]=f+m,t[1]=s+d,t[4]=1-h-v,t[7]=l-b,t[2]=f-m,t[5]=l+b,t[8]=1-h-M,t},normalFromMat4:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*c-u*o,y=a*h-e*o,q=r*c-u*i,g=r*h-e*i,A=u*h-e*c,w=s*b-M*v,R=s*m-f*v,z=s*d-l*v,P=M*m-f*b,j=M*d-l*b,I=f*d-l*m,S=x*I-p*j+y*P+q*z-g*R+A*w;return S?(S=1/S,t[0]=(i*I-c*j+h*P)*S,t[1]=(c*z-o*I-h*R)*S,t[2]=(o*j-i*z+h*w)*S,t[3]=(u*j-r*I-e*P)*S,t[4]=(a*I-u*z+e*R)*S,t[5]=(r*z-a*j-e*w)*S,t[6]=(b*A-m*g+d*q)*S,t[7]=(m*y-v*A-d*p)*S,t[8]=(v*g-b*y+d*x)*S,t):null},projection:function(t,n,a){return t[0]=2/n,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/a,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t},str:function(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t},subtract:x,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=t[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],p=a[7],y=a[8];return Math.abs(r-f)<=n*Math.max(1,Math.abs(r),Math.abs(f))&&Math.abs(u-l)<=n*Math.max(1,Math.abs(u),Math.abs(l))&&Math.abs(e-v)<=n*Math.max(1,Math.abs(e),Math.abs(v))&&Math.abs(o-b)<=n*Math.max(1,Math.abs(o),Math.abs(b))&&Math.abs(i-m)<=n*Math.max(1,Math.abs(i),Math.abs(m))&&Math.abs(c-d)<=n*Math.max(1,Math.abs(c),Math.abs(d))&&Math.abs(h-x)<=n*Math.max(1,Math.abs(h),Math.abs(x))&&Math.abs(s-p)<=n*Math.max(1,Math.abs(s),Math.abs(p))&&Math.abs(M-y)<=n*Math.max(1,Math.abs(M),Math.abs(y))},mul:p,sub:y});function g(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function A(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],b=n[12],m=n[13],d=n[14],x=n[15],p=a[0],y=a[1],q=a[2],g=a[3];return t[0]=p*r+y*i+q*M+g*b,t[1]=p*u+y*c+q*f+g*m,t[2]=p*e+y*h+q*l+g*d,t[3]=p*o+y*s+q*v+g*x,p=a[4],y=a[5],q=a[6],g=a[7],t[4]=p*r+y*i+q*M+g*b,t[5]=p*u+y*c+q*f+g*m,t[6]=p*e+y*h+q*l+g*d,t[7]=p*o+y*s+q*v+g*x,p=a[8],y=a[9],q=a[10],g=a[11],t[8]=p*r+y*i+q*M+g*b,t[9]=p*u+y*c+q*f+g*m,t[10]=p*e+y*h+q*l+g*d,t[11]=p*o+y*s+q*v+g*x,p=a[12],y=a[13],q=a[14],g=a[15],t[12]=p*r+y*i+q*M+g*b,t[13]=p*u+y*c+q*f+g*m,t[14]=p*e+y*h+q*l+g*d,t[15]=p*o+y*s+q*v+g*x,t}function w(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=r+r,c=u+u,h=e+e,s=r*i,M=r*c,f=r*h,l=u*c,v=u*h,b=e*h,m=o*i,d=o*c,x=o*h;return t[0]=1-(l+b),t[1]=M+x,t[2]=f-d,t[3]=0,t[4]=M-x,t[5]=1-(s+b),t[6]=v+m,t[7]=0,t[8]=f+d,t[9]=v-m,t[10]=1-(s+l),t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t}function R(t,n){return t[0]=n[12],t[1]=n[13],t[2]=n[14],t}function z(t,n){var a=n[0],r=n[1],u=n[2],e=n[4],o=n[5],i=n[6],c=n[8],h=n[9],s=n[10];return t[0]=Math.hypot(a,r,u),t[1]=Math.hypot(e,o,i),t[2]=Math.hypot(c,h,s),t}function P(t,n){var r=new a(3);z(r,n);var u=1/r[0],e=1/r[1],o=1/r[2],i=n[0]*u,c=n[1]*e,h=n[2]*o,s=n[4]*u,M=n[5]*e,f=n[6]*o,l=n[8]*u,v=n[9]*e,b=n[10]*o,m=i+M+b,d=0;return m>0?(d=2*Math.sqrt(m+1),t[3]=.25*d,t[0]=(f-v)/d,t[1]=(l-h)/d,t[2]=(c-s)/d):i>M&&i>b?(d=2*Math.sqrt(1+i-M-b),t[3]=(f-v)/d,t[0]=.25*d,t[1]=(c+s)/d,t[2]=(l+h)/d):M>b?(d=2*Math.sqrt(1+M-i-b),t[3]=(l-h)/d,t[0]=(c+s)/d,t[1]=.25*d,t[2]=(f+v)/d):(d=2*Math.sqrt(1+b-i-M),t[3]=(c-s)/d,t[0]=(l+h)/d,t[1]=(f+v)/d,t[2]=.25*d),t}function j(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t[9]=n[9]-a[9],t[10]=n[10]-a[10],t[11]=n[11]-a[11],t[12]=n[12]-a[12],t[13]=n[13]-a[13],t[14]=n[14]-a[14],t[15]=n[15]-a[15],t}var I=A,S=j,E=Object.freeze({create:function(){var t=new a(16);return a!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0),t[0]=1,t[5]=1,t[10]=1,t[15]=1,t},clone:function(t){var n=new a(16);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n[9]=t[9],n[10]=t[10],n[11]=t[11],n[12]=t[12],n[13]=t[13],n[14]=t[14],n[15]=t[15],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},fromValues:function(t,n,r,u,e,o,i,c,h,s,M,f,l,v,b,m){var d=new a(16);return d[0]=t,d[1]=n,d[2]=r,d[3]=u,d[4]=e,d[5]=o,d[6]=i,d[7]=c,d[8]=h,d[9]=s,d[10]=M,d[11]=f,d[12]=l,d[13]=v,d[14]=b,d[15]=m,d},set:function(t,n,a,r,u,e,o,i,c,h,s,M,f,l,v,b,m){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t[8]=h,t[9]=s,t[10]=M,t[11]=f,t[12]=l,t[13]=v,t[14]=b,t[15]=m,t},identity:g,transpose:function(t,n){if(t===n){var a=n[1],r=n[2],u=n[3],e=n[6],o=n[7],i=n[11];t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=a,t[6]=n[9],t[7]=n[13],t[8]=r,t[9]=e,t[11]=n[14],t[12]=u,t[13]=o,t[14]=i}else t[0]=n[0],t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=n[1],t[5]=n[5],t[6]=n[9],t[7]=n[13],t[8]=n[2],t[9]=n[6],t[10]=n[10],t[11]=n[14],t[12]=n[3],t[13]=n[7],t[14]=n[11],t[15]=n[15];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*c-u*o,y=a*h-e*o,q=r*c-u*i,g=r*h-e*i,A=u*h-e*c,w=s*b-M*v,R=s*m-f*v,z=s*d-l*v,P=M*m-f*b,j=M*d-l*b,I=f*d-l*m,S=x*I-p*j+y*P+q*z-g*R+A*w;return S?(S=1/S,t[0]=(i*I-c*j+h*P)*S,t[1]=(u*j-r*I-e*P)*S,t[2]=(b*A-m*g+d*q)*S,t[3]=(f*g-M*A-l*q)*S,t[4]=(c*z-o*I-h*R)*S,t[5]=(a*I-u*z+e*R)*S,t[6]=(m*y-v*A-d*p)*S,t[7]=(s*A-f*y+l*p)*S,t[8]=(o*j-i*z+h*w)*S,t[9]=(r*z-a*j-e*w)*S,t[10]=(v*g-b*y+d*x)*S,t[11]=(M*y-s*g-l*x)*S,t[12]=(i*R-o*P-c*w)*S,t[13]=(a*P-r*R+u*w)*S,t[14]=(b*p-v*q-m*x)*S,t[15]=(s*q-M*p+f*x)*S,t):null},adjoint:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15];return t[0]=i*(f*d-l*m)-M*(c*d-h*m)+b*(c*l-h*f),t[1]=-(r*(f*d-l*m)-M*(u*d-e*m)+b*(u*l-e*f)),t[2]=r*(c*d-h*m)-i*(u*d-e*m)+b*(u*h-e*c),t[3]=-(r*(c*l-h*f)-i*(u*l-e*f)+M*(u*h-e*c)),t[4]=-(o*(f*d-l*m)-s*(c*d-h*m)+v*(c*l-h*f)),t[5]=a*(f*d-l*m)-s*(u*d-e*m)+v*(u*l-e*f),t[6]=-(a*(c*d-h*m)-o*(u*d-e*m)+v*(u*h-e*c)),t[7]=a*(c*l-h*f)-o*(u*l-e*f)+s*(u*h-e*c),t[8]=o*(M*d-l*b)-s*(i*d-h*b)+v*(i*l-h*M),t[9]=-(a*(M*d-l*b)-s*(r*d-e*b)+v*(r*l-e*M)),t[10]=a*(i*d-h*b)-o*(r*d-e*b)+v*(r*h-e*i),t[11]=-(a*(i*l-h*M)-o*(r*l-e*M)+s*(r*h-e*i)),t[12]=-(o*(M*m-f*b)-s*(i*m-c*b)+v*(i*f-c*M)),t[13]=a*(M*m-f*b)-s*(r*m-u*b)+v*(r*f-u*M),t[14]=-(a*(i*m-c*b)-o*(r*m-u*b)+v*(r*c-u*i)),t[15]=a*(i*f-c*M)-o*(r*f-u*M)+s*(r*c-u*i),t},determinant:function(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],c=t[7],h=t[8],s=t[9],M=t[10],f=t[11],l=t[12],v=t[13],b=t[14],m=t[15];return(n*o-a*e)*(M*m-f*b)-(n*i-r*e)*(s*m-f*v)+(n*c-u*e)*(s*b-M*v)+(a*i-r*o)*(h*m-f*l)-(a*c-u*o)*(h*b-M*l)+(r*c-u*i)*(h*v-s*l)},multiply:A,translate:function(t,n,a){var r,u,e,o,i,c,h,s,M,f,l,v,b=a[0],m=a[1],d=a[2];return n===t?(t[12]=n[0]*b+n[4]*m+n[8]*d+n[12],t[13]=n[1]*b+n[5]*m+n[9]*d+n[13],t[14]=n[2]*b+n[6]*m+n[10]*d+n[14],t[15]=n[3]*b+n[7]*m+n[11]*d+n[15]):(r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=c,t[6]=h,t[7]=s,t[8]=M,t[9]=f,t[10]=l,t[11]=v,t[12]=r*b+i*m+M*d+n[12],t[13]=u*b+c*m+f*d+n[13],t[14]=e*b+h*m+l*d+n[14],t[15]=o*b+s*m+v*d+n[15]),t},scale:function(t,n,a){var r=a[0],u=a[1],e=a[2];return t[0]=n[0]*r,t[1]=n[1]*r,t[2]=n[2]*r,t[3]=n[3]*r,t[4]=n[4]*u,t[5]=n[5]*u,t[6]=n[6]*u,t[7]=n[7]*u,t[8]=n[8]*e,t[9]=n[9]*e,t[10]=n[10]*e,t[11]=n[11]*e,t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},rotate:function(t,a,r,u){var e,o,i,c,h,s,M,f,l,v,b,m,d,x,p,y,q,g,A,w,R,z,P,j,I=u[0],S=u[1],E=u[2],O=Math.hypot(I,S,E);return O<n?null:(I*=O=1/O,S*=O,E*=O,e=Math.sin(r),i=1-(o=Math.cos(r)),c=a[0],h=a[1],s=a[2],M=a[3],f=a[4],l=a[5],v=a[6],b=a[7],m=a[8],d=a[9],x=a[10],p=a[11],y=I*I*i+o,q=S*I*i+E*e,g=E*I*i-S*e,A=I*S*i-E*e,w=S*S*i+o,R=E*S*i+I*e,z=I*E*i+S*e,P=S*E*i-I*e,j=E*E*i+o,t[0]=c*y+f*q+m*g,t[1]=h*y+l*q+d*g,t[2]=s*y+v*q+x*g,t[3]=M*y+b*q+p*g,t[4]=c*A+f*w+m*R,t[5]=h*A+l*w+d*R,t[6]=s*A+v*w+x*R,t[7]=M*A+b*w+p*R,t[8]=c*z+f*P+m*j,t[9]=h*z+l*P+d*j,t[10]=s*z+v*P+x*j,t[11]=M*z+b*P+p*j,a!==t&&(t[12]=a[12],t[13]=a[13],t[14]=a[14],t[15]=a[15]),t)},rotateX:function(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[4],o=n[5],i=n[6],c=n[7],h=n[8],s=n[9],M=n[10],f=n[11];return n!==t&&(t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[4]=e*u+h*r,t[5]=o*u+s*r,t[6]=i*u+M*r,t[7]=c*u+f*r,t[8]=h*u-e*r,t[9]=s*u-o*r,t[10]=M*u-i*r,t[11]=f*u-c*r,t},rotateY:function(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[0],o=n[1],i=n[2],c=n[3],h=n[8],s=n[9],M=n[10],f=n[11];return n!==t&&(t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[0]=e*u-h*r,t[1]=o*u-s*r,t[2]=i*u-M*r,t[3]=c*u-f*r,t[8]=e*r+h*u,t[9]=o*r+s*u,t[10]=i*r+M*u,t[11]=c*r+f*u,t},rotateZ:function(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[0],o=n[1],i=n[2],c=n[3],h=n[4],s=n[5],M=n[6],f=n[7];return n!==t&&(t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[0]=e*u+h*r,t[1]=o*u+s*r,t[2]=i*u+M*r,t[3]=c*u+f*r,t[4]=h*u-e*r,t[5]=s*u-o*r,t[6]=M*u-i*r,t[7]=f*u-c*r,t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=n[0],t[13]=n[1],t[14]=n[2],t[15]=1,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=n[1],t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=n[2],t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromRotation:function(t,a,r){var u,e,o,i=r[0],c=r[1],h=r[2],s=Math.hypot(i,c,h);return s<n?null:(i*=s=1/s,c*=s,h*=s,u=Math.sin(a),o=1-(e=Math.cos(a)),t[0]=i*i*o+e,t[1]=c*i*o+h*u,t[2]=h*i*o-c*u,t[3]=0,t[4]=i*c*o-h*u,t[5]=c*c*o+e,t[6]=h*c*o+i*u,t[7]=0,t[8]=i*h*o+c*u,t[9]=c*h*o-i*u,t[10]=h*h*o+e,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t)},fromXRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=r,t[6]=a,t[7]=0,t[8]=0,t[9]=-a,t[10]=r,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromYRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=0,t[2]=-a,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=a,t[9]=0,t[10]=r,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromZRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=0,t[4]=-a,t[5]=r,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromRotationTranslation:w,fromQuat2:function(t,n){var r=new a(3),u=-n[0],e=-n[1],o=-n[2],i=n[3],c=n[4],h=n[5],s=n[6],M=n[7],f=u*u+e*e+o*o+i*i;return f>0?(r[0]=2*(c*i+M*u+h*o-s*e)/f,r[1]=2*(h*i+M*e+s*u-c*o)/f,r[2]=2*(s*i+M*o+c*e-h*u)/f):(r[0]=2*(c*i+M*u+h*o-s*e),r[1]=2*(h*i+M*e+s*u-c*o),r[2]=2*(s*i+M*o+c*e-h*u)),w(t,n,r),t},getTranslation:R,getScaling:z,getRotation:P,fromRotationTranslationScale:function(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3],c=u+u,h=e+e,s=o+o,M=u*c,f=u*h,l=u*s,v=e*h,b=e*s,m=o*s,d=i*c,x=i*h,p=i*s,y=r[0],q=r[1],g=r[2];return t[0]=(1-(v+m))*y,t[1]=(f+p)*y,t[2]=(l-x)*y,t[3]=0,t[4]=(f-p)*q,t[5]=(1-(M+m))*q,t[6]=(b+d)*q,t[7]=0,t[8]=(l+x)*g,t[9]=(b-d)*g,t[10]=(1-(M+v))*g,t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t},fromRotationTranslationScaleOrigin:function(t,n,a,r,u){var e=n[0],o=n[1],i=n[2],c=n[3],h=e+e,s=o+o,M=i+i,f=e*h,l=e*s,v=e*M,b=o*s,m=o*M,d=i*M,x=c*h,p=c*s,y=c*M,q=r[0],g=r[1],A=r[2],w=u[0],R=u[1],z=u[2],P=(1-(b+d))*q,j=(l+y)*q,I=(v-p)*q,S=(l-y)*g,E=(1-(f+d))*g,O=(m+x)*g,T=(v+p)*A,D=(m-x)*A,F=(1-(f+b))*A;return t[0]=P,t[1]=j,t[2]=I,t[3]=0,t[4]=S,t[5]=E,t[6]=O,t[7]=0,t[8]=T,t[9]=D,t[10]=F,t[11]=0,t[12]=a[0]+w-(P*w+S*R+T*z),t[13]=a[1]+R-(j*w+E*R+D*z),t[14]=a[2]+z-(I*w+O*R+F*z),t[15]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,c=u+u,h=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*c,b=e*o,m=e*i,d=e*c;return t[0]=1-M-v,t[1]=s+d,t[2]=f-m,t[3]=0,t[4]=s-d,t[5]=1-h-v,t[6]=l+b,t[7]=0,t[8]=f+m,t[9]=l-b,t[10]=1-h-M,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},frustum:function(t,n,a,r,u,e,o){var i=1/(a-n),c=1/(u-r),h=1/(e-o);return t[0]=2*e*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*e*c,t[6]=0,t[7]=0,t[8]=(a+n)*i,t[9]=(u+r)*c,t[10]=(o+e)*h,t[11]=-1,t[12]=0,t[13]=0,t[14]=o*e*2*h,t[15]=0,t},perspective:function(t,n,a,r,u){var e,o=1/Math.tan(n/2);return t[0]=o/a,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=o,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=-1,t[12]=0,t[13]=0,t[15]=0,null!=u&&u!==1/0?(e=1/(r-u),t[10]=(u+r)*e,t[14]=2*u*r*e):(t[10]=-1,t[14]=-2*r),t},perspectiveFromFieldOfView:function(t,n,a,r){var u=Math.tan(n.upDegrees*Math.PI/180),e=Math.tan(n.downDegrees*Math.PI/180),o=Math.tan(n.leftDegrees*Math.PI/180),i=Math.tan(n.rightDegrees*Math.PI/180),c=2/(o+i),h=2/(u+e);return t[0]=c,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=h,t[6]=0,t[7]=0,t[8]=-(o-i)*c*.5,t[9]=(u-e)*h*.5,t[10]=r/(a-r),t[11]=-1,t[12]=0,t[13]=0,t[14]=r*a/(a-r),t[15]=0,t},ortho:function(t,n,a,r,u,e,o){var i=1/(n-a),c=1/(r-u),h=1/(e-o);return t[0]=-2*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*c,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*h,t[11]=0,t[12]=(n+a)*i,t[13]=(u+r)*c,t[14]=(o+e)*h,t[15]=1,t},lookAt:function(t,a,r,u){var e,o,i,c,h,s,M,f,l,v,b=a[0],m=a[1],d=a[2],x=u[0],p=u[1],y=u[2],q=r[0],A=r[1],w=r[2];return Math.abs(b-q)<n&&Math.abs(m-A)<n&&Math.abs(d-w)<n?g(t):(M=b-q,f=m-A,l=d-w,e=p*(l*=v=1/Math.hypot(M,f,l))-y*(f*=v),o=y*(M*=v)-x*l,i=x*f-p*M,(v=Math.hypot(e,o,i))?(e*=v=1/v,o*=v,i*=v):(e=0,o=0,i=0),c=f*i-l*o,h=l*e-M*i,s=M*o-f*e,(v=Math.hypot(c,h,s))?(c*=v=1/v,h*=v,s*=v):(c=0,h=0,s=0),t[0]=e,t[1]=c,t[2]=M,t[3]=0,t[4]=o,t[5]=h,t[6]=f,t[7]=0,t[8]=i,t[9]=s,t[10]=l,t[11]=0,t[12]=-(e*b+o*m+i*d),t[13]=-(c*b+h*m+s*d),t[14]=-(M*b+f*m+l*d),t[15]=1,t)},targetTo:function(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=r[0],c=r[1],h=r[2],s=u-a[0],M=e-a[1],f=o-a[2],l=s*s+M*M+f*f;l>0&&(s*=l=1/Math.sqrt(l),M*=l,f*=l);var v=c*f-h*M,b=h*s-i*f,m=i*M-c*s;return(l=v*v+b*b+m*m)>0&&(v*=l=1/Math.sqrt(l),b*=l,m*=l),t[0]=v,t[1]=b,t[2]=m,t[3]=0,t[4]=M*m-f*b,t[5]=f*v-s*m,t[6]=s*b-M*v,t[7]=0,t[8]=s,t[9]=M,t[10]=f,t[11]=0,t[12]=u,t[13]=e,t[14]=o,t[15]=1,t},str:function(t){return"mat4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+", "+t[9]+", "+t[10]+", "+t[11]+", "+t[12]+", "+t[13]+", "+t[14]+", "+t[15]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t[9]=n[9]+a[9],t[10]=n[10]+a[10],t[11]=n[11]+a[11],t[12]=n[12]+a[12],t[13]=n[13]+a[13],t[14]=n[14]+a[14],t[15]=n[15]+a[15],t},subtract:j,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=n[11]*a,t[12]=n[12]*a,t[13]=n[13]*a,t[14]=n[14]*a,t[15]=n[15]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t[9]=n[9]+a[9]*r,t[10]=n[10]+a[10]*r,t[11]=n[11]+a[11]*r,t[12]=n[12]+a[12]*r,t[13]=n[13]+a[13]*r,t[14]=n[14]+a[14]*r,t[15]=n[15]+a[15]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]&&t[9]===n[9]&&t[10]===n[10]&&t[11]===n[11]&&t[12]===n[12]&&t[13]===n[13]&&t[14]===n[14]&&t[15]===n[15]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=t[8],f=t[9],l=t[10],v=t[11],b=t[12],m=t[13],d=t[14],x=t[15],p=a[0],y=a[1],q=a[2],g=a[3],A=a[4],w=a[5],R=a[6],z=a[7],P=a[8],j=a[9],I=a[10],S=a[11],E=a[12],O=a[13],T=a[14],D=a[15];return Math.abs(r-p)<=n*Math.max(1,Math.abs(r),Math.abs(p))&&Math.abs(u-y)<=n*Math.max(1,Math.abs(u),Math.abs(y))&&Math.abs(e-q)<=n*Math.max(1,Math.abs(e),Math.abs(q))&&Math.abs(o-g)<=n*Math.max(1,Math.abs(o),Math.abs(g))&&Math.abs(i-A)<=n*Math.max(1,Math.abs(i),Math.abs(A))&&Math.abs(c-w)<=n*Math.max(1,Math.abs(c),Math.abs(w))&&Math.abs(h-R)<=n*Math.max(1,Math.abs(h),Math.abs(R))&&Math.abs(s-z)<=n*Math.max(1,Math.abs(s),Math.abs(z))&&Math.abs(M-P)<=n*Math.max(1,Math.abs(M),Math.abs(P))&&Math.abs(f-j)<=n*Math.max(1,Math.abs(f),Math.abs(j))&&Math.abs(l-I)<=n*Math.max(1,Math.abs(l),Math.abs(I))&&Math.abs(v-S)<=n*Math.max(1,Math.abs(v),Math.abs(S))&&Math.abs(b-E)<=n*Math.max(1,Math.abs(b),Math.abs(E))&&Math.abs(m-O)<=n*Math.max(1,Math.abs(m),Math.abs(O))&&Math.abs(d-T)<=n*Math.max(1,Math.abs(d),Math.abs(T))&&Math.abs(x-D)<=n*Math.max(1,Math.abs(x),Math.abs(D))},mul:I,sub:S});function O(){var t=new a(3);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function T(t){var n=t[0],a=t[1],r=t[2];return Math.hypot(n,a,r)}function D(t,n,r){var u=new a(3);return u[0]=t,u[1]=n,u[2]=r,u}function F(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t}function L(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t}function V(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t}function Q(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return Math.hypot(a,r,u)}function Y(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return a*a+r*r+u*u}function X(t){var n=t[0],a=t[1],r=t[2];return n*n+a*a+r*r}function Z(t,n){var a=n[0],r=n[1],u=n[2],e=a*a+r*r+u*u;return e>0&&(e=1/Math.sqrt(e)),t[0]=n[0]*e,t[1]=n[1]*e,t[2]=n[2]*e,t}function _(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function B(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],c=a[2];return t[0]=u*c-e*i,t[1]=e*o-r*c,t[2]=r*i-u*o,t}var N,k=F,U=L,W=V,C=Q,G=Y,H=T,J=X,K=(N=O(),function(t,n,a,r,u,e){var o,i;for(n||(n=3),a||(a=0),i=r?Math.min(r*n+a,t.length):t.length,o=a;o<i;o+=n)N[0]=t[o],N[1]=t[o+1],N[2]=t[o+2],u(N,N,e),t[o]=N[0],t[o+1]=N[1],t[o+2]=N[2];return t}),$=Object.freeze({create:O,clone:function(t){var n=new a(3);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n},length:T,fromValues:D,copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t},set:function(t,n,a,r){return t[0]=n,t[1]=a,t[2]=r,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t},subtract:F,multiply:L,divide:V,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t[2]=Math.ceil(n[2]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t[2]=Math.floor(n[2]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t[2]=Math.min(n[2],a[2]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t[2]=Math.max(n[2],a[2]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t[2]=Math.round(n[2]),t},scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t},scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t},distance:Q,squaredDistance:Y,squaredLength:X,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t[2]=1/n[2],t},normalize:Z,dot:_,cross:B,lerp:function(t,n,a,r){var u=n[0],e=n[1],o=n[2];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t[2]=o+r*(a[2]-o),t},hermite:function(t,n,a,r,u,e){var o=e*e,i=o*(2*e-3)+1,c=o*(e-2)+e,h=o*(e-1),s=o*(3-2*e);return t[0]=n[0]*i+a[0]*c+r[0]*h+u[0]*s,t[1]=n[1]*i+a[1]*c+r[1]*h+u[1]*s,t[2]=n[2]*i+a[2]*c+r[2]*h+u[2]*s,t},bezier:function(t,n,a,r,u,e){var o=1-e,i=o*o,c=e*e,h=i*o,s=3*e*i,M=3*c*o,f=c*e;return t[0]=n[0]*h+a[0]*s+r[0]*M+u[0]*f,t[1]=n[1]*h+a[1]*s+r[1]*M+u[1]*f,t[2]=n[2]*h+a[2]*s+r[2]*M+u[2]*f,t},random:function(t,n){n=n||1;var a=2*r()*Math.PI,u=2*r()-1,e=Math.sqrt(1-u*u)*n;return t[0]=Math.cos(a)*e,t[1]=Math.sin(a)*e,t[2]=u*n,t},transformMat4:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[3]*r+a[7]*u+a[11]*e+a[15];return o=o||1,t[0]=(a[0]*r+a[4]*u+a[8]*e+a[12])/o,t[1]=(a[1]*r+a[5]*u+a[9]*e+a[13])/o,t[2]=(a[2]*r+a[6]*u+a[10]*e+a[14])/o,t},transformMat3:function(t,n,a){var r=n[0],u=n[1],e=n[2];return t[0]=r*a[0]+u*a[3]+e*a[6],t[1]=r*a[1]+u*a[4]+e*a[7],t[2]=r*a[2]+u*a[5]+e*a[8],t},transformQuat:function(t,n,a){var r=a[0],u=a[1],e=a[2],o=a[3],i=n[0],c=n[1],h=n[2],s=u*h-e*c,M=e*i-r*h,f=r*c-u*i,l=u*f-e*M,v=e*s-r*f,b=r*M-u*s,m=2*o;return s*=m,M*=m,f*=m,l*=2,v*=2,b*=2,t[0]=i+s+l,t[1]=c+M+v,t[2]=h+f+b,t},rotateX:function(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[0],e[1]=u[1]*Math.cos(r)-u[2]*Math.sin(r),e[2]=u[1]*Math.sin(r)+u[2]*Math.cos(r),t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t},rotateY:function(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[2]*Math.sin(r)+u[0]*Math.cos(r),e[1]=u[1],e[2]=u[2]*Math.cos(r)-u[0]*Math.sin(r),t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t},rotateZ:function(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[0]*Math.cos(r)-u[1]*Math.sin(r),e[1]=u[0]*Math.sin(r)+u[1]*Math.cos(r),e[2]=u[2],t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t},angle:function(t,n){var a=D(t[0],t[1],t[2]),r=D(n[0],n[1],n[2]);Z(a,a),Z(r,r);var u=_(a,r);return u>1?0:u<-1?Math.PI:Math.acos(u)},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t},str:function(t){return"vec3("+t[0]+", "+t[1]+", "+t[2]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=a[0],i=a[1],c=a[2];return Math.abs(r-o)<=n*Math.max(1,Math.abs(r),Math.abs(o))&&Math.abs(u-i)<=n*Math.max(1,Math.abs(u),Math.abs(i))&&Math.abs(e-c)<=n*Math.max(1,Math.abs(e),Math.abs(c))},sub:k,mul:U,div:W,dist:C,sqrDist:G,len:H,sqrLen:J,forEach:K});function tt(){var t=new a(4);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[3]=0),t}function nt(t){var n=new a(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n}function at(t,n,r,u){var e=new a(4);return e[0]=t,e[1]=n,e[2]=r,e[3]=u,e}function rt(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t}function ut(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t}function et(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t}function ot(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}function it(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t[3]=n[3]*a[3],t}function ct(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t[3]=n[3]/a[3],t}function ht(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t}function st(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2],e=n[3]-t[3];return Math.hypot(a,r,u,e)}function Mt(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2],e=n[3]-t[3];return a*a+r*r+u*u+e*e}function ft(t){var n=t[0],a=t[1],r=t[2],u=t[3];return Math.hypot(n,a,r,u)}function lt(t){var n=t[0],a=t[1],r=t[2],u=t[3];return n*n+a*a+r*r+u*u}function vt(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e;return o>0&&(o=1/Math.sqrt(o)),t[0]=a*o,t[1]=r*o,t[2]=u*o,t[3]=e*o,t}function bt(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]+t[3]*n[3]}function mt(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t[2]=o+r*(a[2]-o),t[3]=i+r*(a[3]-i),t}function dt(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]}function xt(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=a[0],c=a[1],h=a[2],s=a[3];return Math.abs(r-i)<=n*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-c)<=n*Math.max(1,Math.abs(u),Math.abs(c))&&Math.abs(e-h)<=n*Math.max(1,Math.abs(e),Math.abs(h))&&Math.abs(o-s)<=n*Math.max(1,Math.abs(o),Math.abs(s))}var pt=ot,yt=it,qt=ct,gt=st,At=Mt,wt=ft,Rt=lt,zt=function(){var t=tt();return function(n,a,r,u,e,o){var i,c;for(a||(a=4),r||(r=0),c=u?Math.min(u*a+r,n.length):n.length,i=r;i<c;i+=a)t[0]=n[i],t[1]=n[i+1],t[2]=n[i+2],t[3]=n[i+3],e(t,t,o),n[i]=t[0],n[i+1]=t[1],n[i+2]=t[2],n[i+3]=t[3];return n}}(),Pt=Object.freeze({create:tt,clone:nt,fromValues:at,copy:rt,set:ut,add:et,subtract:ot,multiply:it,divide:ct,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t[2]=Math.ceil(n[2]),t[3]=Math.ceil(n[3]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t[2]=Math.floor(n[2]),t[3]=Math.floor(n[3]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t[2]=Math.min(n[2],a[2]),t[3]=Math.min(n[3],a[3]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t[2]=Math.max(n[2],a[2]),t[3]=Math.max(n[3],a[3]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t[2]=Math.round(n[2]),t[3]=Math.round(n[3]),t},scale:ht,scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t},distance:st,squaredDistance:Mt,length:ft,squaredLength:lt,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=-n[3],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t[2]=1/n[2],t[3]=1/n[3],t},normalize:vt,dot:bt,cross:function(t,n,a,r){var u=a[0]*r[1]-a[1]*r[0],e=a[0]*r[2]-a[2]*r[0],o=a[0]*r[3]-a[3]*r[0],i=a[1]*r[2]-a[2]*r[1],c=a[1]*r[3]-a[3]*r[1],h=a[2]*r[3]-a[3]*r[2],s=n[0],M=n[1],f=n[2],l=n[3];return t[0]=M*h-f*c+l*i,t[1]=-s*h+f*o-l*e,t[2]=s*c-M*o+l*u,t[3]=-s*i+M*e-f*u,t},lerp:mt,random:function(t,n){var a,u,e,o,i,c;n=n||1;do{i=(a=2*r()-1)*a+(u=2*r()-1)*u}while(i>=1);do{c=(e=2*r()-1)*e+(o=2*r()-1)*o}while(c>=1);var h=Math.sqrt((1-i)/c);return t[0]=n*a,t[1]=n*u,t[2]=n*e*h,t[3]=n*o*h,t},transformMat4:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3];return t[0]=a[0]*r+a[4]*u+a[8]*e+a[12]*o,t[1]=a[1]*r+a[5]*u+a[9]*e+a[13]*o,t[2]=a[2]*r+a[6]*u+a[10]*e+a[14]*o,t[3]=a[3]*r+a[7]*u+a[11]*e+a[15]*o,t},transformQuat:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],c=a[2],h=a[3],s=h*r+i*e-c*u,M=h*u+c*r-o*e,f=h*e+o*u-i*r,l=-o*r-i*u-c*e;return t[0]=s*h+l*-o+M*-c-f*-i,t[1]=M*h+l*-i+f*-o-s*-c,t[2]=f*h+l*-c+s*-i-M*-o,t[3]=n[3],t},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=0,t},str:function(t){return"vec4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},exactEquals:dt,equals:xt,sub:pt,mul:yt,div:qt,dist:gt,sqrDist:At,len:wt,sqrLen:Rt,forEach:zt});function jt(){var t=new a(4);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t[3]=1,t}function It(t,n,a){a*=.5;var r=Math.sin(a);return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=Math.cos(a),t}function St(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*s+o*i+u*h-e*c,t[1]=u*s+o*c+e*i-r*h,t[2]=e*s+o*h+r*c-u*i,t[3]=o*s-r*i-u*c-e*h,t}function Et(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+o*i,t[1]=u*c+e*i,t[2]=e*c-u*i,t[3]=o*c-r*i,t}function Ot(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c-e*i,t[1]=u*c+o*i,t[2]=e*c+r*i,t[3]=o*c-u*i,t}function Tt(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+u*i,t[1]=u*c-r*i,t[2]=e*c+o*i,t[3]=o*c-e*i,t}function Dt(t,a,r,u){var e,o,i,c,h,s=a[0],M=a[1],f=a[2],l=a[3],v=r[0],b=r[1],m=r[2],d=r[3];return(o=s*v+M*b+f*m+l*d)<0&&(o=-o,v=-v,b=-b,m=-m,d=-d),1-o>n?(e=Math.acos(o),i=Math.sin(e),c=Math.sin((1-u)*e)/i,h=Math.sin(u*e)/i):(c=1-u,h=u),t[0]=c*s+h*v,t[1]=c*M+h*b,t[2]=c*f+h*m,t[3]=c*l+h*d,t}function Ft(t,n){var a,r=n[0]+n[4]+n[8];if(r>0)a=Math.sqrt(r+1),t[3]=.5*a,a=.5/a,t[0]=(n[5]-n[7])*a,t[1]=(n[6]-n[2])*a,t[2]=(n[1]-n[3])*a;else{var u=0;n[4]>n[0]&&(u=1),n[8]>n[3*u+u]&&(u=2);var e=(u+1)%3,o=(u+2)%3;a=Math.sqrt(n[3*u+u]-n[3*e+e]-n[3*o+o]+1),t[u]=.5*a,a=.5/a,t[3]=(n[3*e+o]-n[3*o+e])*a,t[e]=(n[3*e+u]+n[3*u+e])*a,t[o]=(n[3*o+u]+n[3*u+o])*a}return t}var Lt,Vt,Qt,Yt,Xt,Zt,_t=nt,Bt=at,Nt=rt,kt=ut,Ut=et,Wt=St,Ct=ht,Gt=bt,Ht=mt,Jt=ft,Kt=Jt,$t=lt,tn=$t,nn=vt,an=dt,rn=xt,un=(Lt=O(),Vt=D(1,0,0),Qt=D(0,1,0),function(t,n,a){var r=_(n,a);return r<-.999999?(B(Lt,Vt,n),H(Lt)<1e-6&&B(Lt,Qt,n),Z(Lt,Lt),It(t,Lt,Math.PI),t):r>.999999?(t[0]=0,t[1]=0,t[2]=0,t[3]=1,t):(B(Lt,n,a),t[0]=Lt[0],t[1]=Lt[1],t[2]=Lt[2],t[3]=1+r,nn(t,t))}),en=(Yt=jt(),Xt=jt(),function(t,n,a,r,u,e){return Dt(Yt,n,u,e),Dt(Xt,a,r,e),Dt(t,Yt,Xt,2*e*(1-e)),t}),on=(Zt=m(),function(t,n,a,r){return Zt[0]=a[0],Zt[3]=a[1],Zt[6]=a[2],Zt[1]=r[0],Zt[4]=r[1],Zt[7]=r[2],Zt[2]=-n[0],Zt[5]=-n[1],Zt[8]=-n[2],nn(t,Ft(t,Zt))}),cn=Object.freeze({create:jt,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t},setAxisAngle:It,getAxisAngle:function(t,a){var r=2*Math.acos(a[3]),u=Math.sin(r/2);return u>n?(t[0]=a[0]/u,t[1]=a[1]/u,t[2]=a[2]/u):(t[0]=1,t[1]=0,t[2]=0),r},multiply:St,rotateX:Et,rotateY:Ot,rotateZ:Tt,calculateW:function(t,n){var a=n[0],r=n[1],u=n[2];return t[0]=a,t[1]=r,t[2]=u,t[3]=Math.sqrt(Math.abs(1-a*a-r*r-u*u)),t},slerp:Dt,random:function(t){var n=r(),a=r(),u=r(),e=Math.sqrt(1-n),o=Math.sqrt(n);return t[0]=e*Math.sin(2*Math.PI*a),t[1]=e*Math.cos(2*Math.PI*a),t[2]=o*Math.sin(2*Math.PI*u),t[3]=o*Math.cos(2*Math.PI*u),t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e,i=o?1/o:0;return t[0]=-a*i,t[1]=-r*i,t[2]=-u*i,t[3]=e*i,t},conjugate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t},fromMat3:Ft,fromEuler:function(t,n,a,r){var u=.5*Math.PI/180;n*=u,a*=u,r*=u;var e=Math.sin(n),o=Math.cos(n),i=Math.sin(a),c=Math.cos(a),h=Math.sin(r),s=Math.cos(r);return t[0]=e*c*s-o*i*h,t[1]=o*i*s+e*c*h,t[2]=o*c*h-e*i*s,t[3]=o*c*s+e*i*h,t},str:function(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},clone:_t,fromValues:Bt,copy:Nt,set:kt,add:Ut,mul:Wt,scale:Ct,dot:Gt,lerp:Ht,length:Jt,len:Kt,squaredLength:$t,sqrLen:tn,normalize:nn,exactEquals:an,equals:rn,rotationTo:un,sqlerp:en,setAxes:on});function hn(t,n,a){var r=.5*a[0],u=.5*a[1],e=.5*a[2],o=n[0],i=n[1],c=n[2],h=n[3];return t[0]=o,t[1]=i,t[2]=c,t[3]=h,t[4]=r*h+u*c-e*i,t[5]=u*h+e*o-r*c,t[6]=e*h+r*i-u*o,t[7]=-r*o-u*i-e*c,t}function sn(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t}var Mn=Nt;var fn=Nt;function ln(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[4],c=a[5],h=a[6],s=a[7],M=n[4],f=n[5],l=n[6],v=n[7],b=a[0],m=a[1],d=a[2],x=a[3];return t[0]=r*x+o*b+u*d-e*m,t[1]=u*x+o*m+e*b-r*d,t[2]=e*x+o*d+r*m-u*b,t[3]=o*x-r*b-u*m-e*d,t[4]=r*s+o*i+u*h-e*c+M*x+v*b+f*d-l*m,t[5]=u*s+o*c+e*i-r*h+f*x+v*m+l*b-M*d,t[6]=e*s+o*h+r*c-u*i+l*x+v*d+M*m-f*b,t[7]=o*s-r*i-u*c-e*h+v*x-M*b-f*m-l*d,t}var vn=ln;var bn=Gt;var mn=Jt,dn=mn,xn=$t,pn=xn;var yn=Object.freeze({create:function(){var t=new a(8);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[4]=0,t[5]=0,t[6]=0,t[7]=0),t[3]=1,t},clone:function(t){var n=new a(8);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n},fromValues:function(t,n,r,u,e,o,i,c){var h=new a(8);return h[0]=t,h[1]=n,h[2]=r,h[3]=u,h[4]=e,h[5]=o,h[6]=i,h[7]=c,h},fromRotationTranslationValues:function(t,n,r,u,e,o,i){var c=new a(8);c[0]=t,c[1]=n,c[2]=r,c[3]=u;var h=.5*e,s=.5*o,M=.5*i;return c[4]=h*u+s*r-M*n,c[5]=s*u+M*t-h*r,c[6]=M*u+h*n-s*t,c[7]=-h*t-s*n-M*r,c},fromRotationTranslation:hn,fromTranslation:function(t,n){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=.5*n[0],t[5]=.5*n[1],t[6]=.5*n[2],t[7]=0,t},fromRotation:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},fromMat4:function(t,n){var r=jt();P(r,n);var u=new a(3);return R(u,n),hn(t,r,u),t},copy:sn,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},set:function(t,n,a,r,u,e,o,i,c){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t},getReal:Mn,getDual:function(t,n){return t[0]=n[4],t[1]=n[5],t[2]=n[6],t[3]=n[7],t},setReal:fn,setDual:function(t,n){return t[4]=n[0],t[5]=n[1],t[6]=n[2],t[7]=n[3],t},getTranslation:function(t,n){var a=n[4],r=n[5],u=n[6],e=n[7],o=-n[0],i=-n[1],c=-n[2],h=n[3];return t[0]=2*(a*h+e*o+r*c-u*i),t[1]=2*(r*h+e*i+u*o-a*c),t[2]=2*(u*h+e*c+a*i-r*o),t},translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=.5*a[0],c=.5*a[1],h=.5*a[2],s=n[4],M=n[5],f=n[6],l=n[7];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=o*i+u*h-e*c+s,t[5]=o*c+e*i-r*h+M,t[6]=o*h+r*c-u*i+f,t[7]=-r*i-u*c-e*h+l,t},rotateX:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Et(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateY:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Ot(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateZ:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Tt(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateByQuatAppend:function(t,n,a){var r=a[0],u=a[1],e=a[2],o=a[3],i=n[0],c=n[1],h=n[2],s=n[3];return t[0]=i*o+s*r+c*e-h*u,t[1]=c*o+s*u+h*r-i*e,t[2]=h*o+s*e+i*u-c*r,t[3]=s*o-i*r-c*u-h*e,i=n[4],c=n[5],h=n[6],s=n[7],t[4]=i*o+s*r+c*e-h*u,t[5]=c*o+s*u+h*r-i*e,t[6]=h*o+s*e+i*u-c*r,t[7]=s*o-i*r-c*u-h*e,t},rotateByQuatPrepend:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*s+o*i+u*h-e*c,t[1]=u*s+o*c+e*i-r*h,t[2]=e*s+o*h+r*c-u*i,t[3]=o*s-r*i-u*c-e*h,i=a[4],c=a[5],h=a[6],s=a[7],t[4]=r*s+o*i+u*h-e*c,t[5]=u*s+o*c+e*i-r*h,t[6]=e*s+o*h+r*c-u*i,t[7]=o*s-r*i-u*c-e*h,t},rotateAroundAxis:function(t,a,r,u){if(Math.abs(u)<n)return sn(t,a);var e=Math.hypot(r[0],r[1],r[2]);u*=.5;var o=Math.sin(u),i=o*r[0]/e,c=o*r[1]/e,h=o*r[2]/e,s=Math.cos(u),M=a[0],f=a[1],l=a[2],v=a[3];t[0]=M*s+v*i+f*h-l*c,t[1]=f*s+v*c+l*i-M*h,t[2]=l*s+v*h+M*c-f*i,t[3]=v*s-M*i-f*c-l*h;var b=a[4],m=a[5],d=a[6],x=a[7];return t[4]=b*s+x*i+m*h-d*c,t[5]=m*s+x*c+d*i-b*h,t[6]=d*s+x*h+b*c-m*i,t[7]=x*s-b*i-m*c-d*h,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t},multiply:ln,mul:vn,scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t},dot:bn,lerp:function(t,n,a,r){var u=1-r;return bn(n,a)<0&&(r=-r),t[0]=n[0]*u+a[0]*r,t[1]=n[1]*u+a[1]*r,t[2]=n[2]*u+a[2]*r,t[3]=n[3]*u+a[3]*r,t[4]=n[4]*u+a[4]*r,t[5]=n[5]*u+a[5]*r,t[6]=n[6]*u+a[6]*r,t[7]=n[7]*u+a[7]*r,t},invert:function(t,n){var a=xn(n);return t[0]=-n[0]/a,t[1]=-n[1]/a,t[2]=-n[2]/a,t[3]=n[3]/a,t[4]=-n[4]/a,t[5]=-n[5]/a,t[6]=-n[6]/a,t[7]=n[7]/a,t},conjugate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t[4]=-n[4],t[5]=-n[5],t[6]=-n[6],t[7]=n[7],t},length:mn,len:dn,squaredLength:xn,sqrLen:pn,normalize:function(t,n){var a=xn(n);if(a>0){a=Math.sqrt(a);var r=n[0]/a,u=n[1]/a,e=n[2]/a,o=n[3]/a,i=n[4],c=n[5],h=n[6],s=n[7],M=r*i+u*c+e*h+o*s;t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=(i-r*M)/a,t[5]=(c-u*M)/a,t[6]=(h-e*M)/a,t[7]=(s-o*M)/a}return t},str:function(t){return"quat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=a[0],f=a[1],l=a[2],v=a[3],b=a[4],m=a[5],d=a[6],x=a[7];return Math.abs(r-M)<=n*Math.max(1,Math.abs(r),Math.abs(M))&&Math.abs(u-f)<=n*Math.max(1,Math.abs(u),Math.abs(f))&&Math.abs(e-l)<=n*Math.max(1,Math.abs(e),Math.abs(l))&&Math.abs(o-v)<=n*Math.max(1,Math.abs(o),Math.abs(v))&&Math.abs(i-b)<=n*Math.max(1,Math.abs(i),Math.abs(b))&&Math.abs(c-m)<=n*Math.max(1,Math.abs(c),Math.abs(m))&&Math.abs(h-d)<=n*Math.max(1,Math.abs(h),Math.abs(d))&&Math.abs(s-x)<=n*Math.max(1,Math.abs(s),Math.abs(x))}});function qn(){var t=new a(2);return a!=Float32Array&&(t[0]=0,t[1]=0),t}function gn(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t}function An(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t}function wn(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t}function Rn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return Math.hypot(a,r)}function zn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return a*a+r*r}function Pn(t){var n=t[0],a=t[1];return Math.hypot(n,a)}function jn(t){var n=t[0],a=t[1];return n*n+a*a}var In=Pn,Sn=gn,En=An,On=wn,Tn=Rn,Dn=zn,Fn=jn,Ln=function(){var t=qn();return function(n,a,r,u,e,o){var i,c;for(a||(a=2),r||(r=0),c=u?Math.min(u*a+r,n.length):n.length,i=r;i<c;i+=a)t[0]=n[i],t[1]=n[i+1],e(t,t,o),n[i]=t[0],n[i+1]=t[1];return n}}(),Vn=Object.freeze({create:qn,clone:function(t){var n=new a(2);return n[0]=t[0],n[1]=t[1],n},fromValues:function(t,n){var r=new a(2);return r[0]=t,r[1]=n,r},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t},set:function(t,n,a){return t[0]=n,t[1]=a,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t},subtract:gn,multiply:An,divide:wn,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t},scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t},scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t},distance:Rn,squaredDistance:zn,length:Pn,squaredLength:jn,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t},normalize:function(t,n){var a=n[0],r=n[1],u=a*a+r*r;return u>0&&(u=1/Math.sqrt(u)),t[0]=n[0]*u,t[1]=n[1]*u,t},dot:function(t,n){return t[0]*n[0]+t[1]*n[1]},cross:function(t,n,a){var r=n[0]*a[1]-n[1]*a[0];return t[0]=t[1]=0,t[2]=r,t},lerp:function(t,n,a,r){var u=n[0],e=n[1];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t},random:function(t,n){n=n||1;var a=2*r()*Math.PI;return t[0]=Math.cos(a)*n,t[1]=Math.sin(a)*n,t},transformMat2:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u,t[1]=a[1]*r+a[3]*u,t},transformMat2d:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u+a[4],t[1]=a[1]*r+a[3]*u+a[5],t},transformMat3:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[3]*u+a[6],t[1]=a[1]*r+a[4]*u+a[7],t},transformMat4:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[4]*u+a[12],t[1]=a[1]*r+a[5]*u+a[13],t},rotate:function(t,n,a,r){var u=n[0]-a[0],e=n[1]-a[1],o=Math.sin(r),i=Math.cos(r);return t[0]=u*i-e*o+a[0],t[1]=u*o+e*i+a[1],t},angle:function(t,n){var a=t[0],r=t[1],u=n[0],e=n[1],o=a*a+r*r;o>0&&(o=1/Math.sqrt(o));var i=u*u+e*e;i>0&&(i=1/Math.sqrt(i));var c=(a*u+r*e)*o*i;return c>1?0:c<-1?Math.PI:Math.acos(c)},zero:function(t){return t[0]=0,t[1]=0,t},str:function(t){return"vec2("+t[0]+", "+t[1]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]},equals:function(t,a){var r=t[0],u=t[1],e=a[0],o=a[1];return Math.abs(r-e)<=n*Math.max(1,Math.abs(r),Math.abs(e))&&Math.abs(u-o)<=n*Math.max(1,Math.abs(u),Math.abs(o))},len:In,sub:Sn,mul:En,div:On,dist:Tn,sqrDist:Dn,sqrLen:Fn,forEach:Ln});t.glMatrix=e,t.mat2=s,t.mat2d=b,t.mat3=q,t.mat4=E,t.quat=cn,t.quat2=yn,t.vec2=Vn,t.vec3=$,t.vec4=Pt,Object.defineProperty(t,"__esModule",{value:!0})});
+
+
+var gl;
+var mat3 = glMatrix.mat3;
+var mat4 = glMatrix.mat4;
+
+var vec3 = glMatrix.vec3;
+var vec4 = glMatrix.vec4;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }   catch (e) {   }
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+    return true;
+}
+
+var shaderProgram;
+
+function initialiseBuffer() {
+
+    var vertexData = [
+        -0.5, 0.5, 0.5,     1.0, 1.0, 1.0, 0.5,     0.0, 1.0,//3
+        0.5, 0.5, 0.5,      1.0, 1.0, 1.0, 0.5,     1.0, 1.0,//1
+        0.5, 0.5, -0.5,     1.0, 1.0, 1.0, 0.5,     1.0, 1.0,//2
+                
+        -0.5, 0.5, 0.5,     1.0, 1.0, 1.0, 0.5,     0.0, 1.0,//3
+        0.5, 0.5, -0.5,     1.0, 1.0, 1.0, 0.5,     1.0, 1.0,//2
+        -0.5, 0.5, -0.5,    1.0, 1.0, 1.0, 0.5,     0.0, 1.0,//4
+         
+        0.5, 0.5, -0.5,     0.0, 0.0, 0.0, 0.5,     1.0, 1.0,//2
+        0.5, -0.5, -0.5,    0.0, 0.0, 0.0, 0.5,     1.0, 0.0,//6
+        -0.5,-0.5,-0.5,     0.0, 0.0, 0.0, 0.5,     0.0, 0.0,//8
+           
+        -0.5, 0.5, -0.5,    0.0, 0.0, 0.0, 0.5,     0.0, 1.0,//4
+        0.5, 0.5, -0.5,     0.0, 0.0, 0.0, 0.5,     1.0, 1.0,//2
+        -0.5,-0.5,-0.5,     0.0, 0.0, 0.0, 0.5,     0.0, 0.0,//8
+            
+        0.5, -0.5, 0.5,     1.0, 0.5, 0.0, 0.5,     0.0, 1.0,//5
+        0.5, -0.5, -0.5,    1.0, 0.5, 0.0, 0.5,     0.0, 1.0,//6
+        0.5, 0.5, -0.5,     1.0, 0.5, 0.0, 0.5,     1.0, 1.0,//2
+
+        0.5, -0.5, 0.5,     1.0, 0.5, 0.0, 0.5,     0.0, 1.0,//5
+        0.5, 0.5, -0.5,     1.0, 0.5, 0.0, 0.5,     1.0, 1.0,//2
+        0.5, 0.5, 0.5,      1.0, 0.5, 0.0, 0.5,     1.0, 1.0,//1
+                 
+        -0.5, 0.5, -0.5,    1.0, 0.0, 0.0, 0.5,     0.0, 1.0,//4
+        -0.5,-0.5, -0.5,    1.0, 0.0, 0.0, 0.5,     0.0, 0.0,//8
+        -0.5, -0.5, 0.5,    1.0, 0.0, 0.0, 0.5,     0.0, 0.0,//7
+        
+        -0.5, 0.5, 0.5,     1.0, 0.0, 0.0, 0.5,     0.0, 1.0,//3
+        -0.5, 0.5, -0.5,    1.0, 0.0, 0.0, 0.5,     0.0, 1.0,//4
+        -0.5, -0.5, 0.5,    1.0, 0.0, 0.0, 0.5,     0.0, 0.0,//7
+        
+        -0.5, -0.5, 0.5,    0.0, 0.0, 1.0, 0.5,     0.0, 0.0,//7
+        0.5, -0.5, 0.5,     0.0, 0.0, 1.0, 0.5,     1.0, 0.0,//5
+        0.5, 0.5, 0.5,      0.0, 0.0, 1.0, 0.5,     1.0, 1.0,//1
+                 
+        -0.5, -0.5, 0.5,    0.0, 0.0, 1.0, 0.5,     0.0, 0.0,//7
+        0.5, 0.5, 0.5,      0.0, 0.0, 1.0, 0.5,     1.0, 1.0,//1
+        -0.5, 0.5, 0.5,     0.0, 0.0, 1.0, 0.5,     0.0, 1.0,//3
+        
+         0.5, -0.5, -0.5,   0.0, 1.0, 0.0, 0.5,     1.0, 0.0,//6
+         0.5, -0.5, 0.5,    0.0, 1.0, 0.0, 0.5,     1.0, 0.0,//5
+        -0.5, -0.5, 0.5,    0.0, 1.0, 0.0, 0.5,     0.0, 0.0,//7
+        
+        -0.5,-0.5, -0.5,    0.0, 1.0, 0.0, 0.5,     0.0, 0.0,//8
+         0.5, -0.5, -0.5,   0.0, 1.0, 0.0, 0.5,     1.0, 0.0,//6
+        -0.5, -0.5, 0.5,    0.0, 1.0, 0.0, 0.5,     0.0, 0.0,//7
+    ];
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+    var fragmentShaderSource = '\
+			varying mediump vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = 1.0 * color;\
+			}';
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+    var vertexShaderSource = '\
+			attribute highp vec3 myVertex; \
+			attribute highp vec4 myColor; \
+			attribute highp vec2 myUV; \
+			uniform mediump mat4 Pmatrix; \
+			uniform mediump mat4 Vmatrix; \
+			uniform mediump mat4 Mmatrix; \
+			varying mediump vec4 color; \
+			varying mediump vec2 texCoord;\
+			void main(void)  \
+			{ \
+				gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(myVertex, 1.0);\
+				color = myColor;\
+				texCoord = myUV; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+    gl.programObject = gl.createProgram();
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+	gl.bindAttribLocation(gl.programObject, 2, "myUV");
+    gl.linkProgram(gl.programObject);
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+    gl.useProgram(gl.programObject);
+    return testGLError("initialiseShaders");
+}
+
+//perspectiveFromFieldOfView, perspective
+//사용할려고 했으나 depth가 안되길래 쓰지 못함.
+
+// FOV, Aspect Ratio, Near, Far 
+function get_projection(angle, a, zMin, zMax) {
+    var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
+    return [
+    	0.5/ang, 0 , 0, 0,
+        0, 0.5*a/ang, 0, 0,
+        0, 0, -(zMax+zMin)/(zMax-zMin), -5,
+        0, 0, (-2*zMax*zMin)/(zMax-zMin), 0 ];
+}
+			
+var proj_matrix = get_projection(30, 1.0, 1, 10.0);
+var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+// translating z
+
+view_matrix[14] = view_matrix[14]-20;//zoom
+
+
+
+
+
+
+
+
+
+
+/* 
+    rotate_?: ?축으로 회전할 때, 각속도를 의미.
+    rot?: 현재 ?축의 회전한 크기를 의미.
+*/
+var rotate_x = 0, rotx = 0; 
+var rotate_y = 0, roty = 0;
+var rotate_z = 0, rotz = 0;
+
+/*
+    boxes: 후술할 8000개의 박스들의 좌표를 3차원 배열에 vec4 형식으로 저장.
+    boxesR: 8000개의 박스들의 각 x, y, z축에 대한 회전 각도를 저장함. 참고) vec4형식으로 할당했으나 벡터로 쓰이지는 않아요.
+*/
+var boxes = new Array();
+var boxesR = new Array();
+
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+
+    // 처음에 이미 stop 상태이므로 숨김.
+    document.getElementsByName("stop")[0].style.visibility = "hidden";
+
+    // 속도 초기 설정을 10
+    document.getElementsByName("speed")[0].value = 10;
+    console.log("Start");
+
+    if (!initialiseGL(canvas)) { return;}
+    if (!initialiseBuffer())   { return;}
+    if (!initialiseShaders())  { return;}
+
+    //boxes, boxesR에 배열과 데이터를 할당해준다.
+    for(var i = 0; i < 20; i++){ boxes[i] = new Array(); boxesR[i] = new Array();
+        for(var j = 0; j < 20; j++){ boxes[i][j] = new Array(); boxesR[i][j] = new Array();
+            for(var k = 0; k < 20; k++){
+                // boxes의 초기값을 배열에 따라서 부여한다.
+                boxes[i][j][k] = vec4.fromValues(i, j, k, 1);
+                boxesR[i][j][k] = vec4.fromValues(0, 0, 0, 1);
+            }
+        }
+    }
+    // Render loop
+    requestAnimFrame = (
+    function () {
+        return function (callback) {
+                window.setTimeout(callback, 10, 10); };
+    })();
+
+    (function renderLoop(param) {
+        if (renderScene()) {
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
+
+function renderScene() {
+    var locPmatrix = gl.getUniformLocation(gl.programObject, "Pmatrix");
+    var locVmatrix = gl.getUniformLocation(gl.programObject, "Vmatrix");
+    var locMmatrix = gl.getUniformLocation(gl.programObject, "Mmatrix");
+    
+    gl.uniformMatrix4fv(locPmatrix, false, proj_matrix);
+    gl.uniformMatrix4fv(locVmatrix, false, view_matrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) { return false;}
+
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 36, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 36, 12);
+    gl.enableVertexAttribArray(2);
+    gl.vertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 36, 28);
+
+    if (!testGLError("gl.vertexAttribPointer")) {return false;}
+
+
+    pre_fragment();
+    mat4.identity(mov_matrix);
+    rotateMidBox();
+    change();
+    boxes8000drawing(mov_matrix, locMmatrix);
+
+    mat4.identity(mov_matrix);
+    circle2box(mov_matrix, locMmatrix);
+
+    if(onRunning) boxRotate(0);
+    if (!testGLError("gl.drawArrays")) {  return false;}
+    return true;
+}
+
+function pre_fragment(){
+    // depth
+    var chk1 = document.getElementsByName("chkbox1")[0].checked;
+    // culling
+    var chk2 = document.getElementsByName("chkbox2")[0].checked;
+    // blending
+    var chk3 = document.getElementsByName("chkbox3")[0].checked;
+    
+    if(chk1){
+        // DEPTH_TEST를 킨다.
+        // 실행 후 체크해보면 작은 막대기가 큰 막대기를 뚫고 나오는 모습이 보인다.
+        gl.enable(gl.DEPTH_TEST);
+        gl.depthFunc(gl.LEQUAL); 
+    }
+    else{ // DEPTH_TEST 끈다.
+        gl.disable(gl.DEPTH_TEST);
+    }
+
+    if(chk2){
+        // CULL_FACE를 킨다.
+        // 하나의 도형만 존재할 때는 이것이 문제되지 않으나 여러 개 있을 경우 이상해진다.
+        // 막대기를 보면 4개 중 반은 작은 막대기가 큰 막대기보다 뒤로 가고
+        // 나머지 반은 앞으로 나오는데, 두 막대기는 좌표가 겹칠 경우 큰 막대기가 2배길이만큼 더 길다.
+        // 그런데도 위 DEPTH_TEST할 때처럼 뚫고 나오는 그림이 안 보이는 이유는 앞면, 뒷면 여부만 따져서 나타나며
+        // 앞 뒤 순서가 바뀌는 경우는 단지 그린 순서에 따라 바뀐 것이다.
+        gl.enable(gl.CULL_FACE);
+    }
+    else{ // CULL_FACE를 끈다.
+        gl.disable(gl.CULL_FACE);
+    }
+    if(chk3){
+        // blending을 킨다.
+        // 대상이 투명해야 사용이 가능하다. 완전 불투명(a: 1.0)한 경우 투시가 되지 않으므로 의미가 없다.
+        // 두 개의 대상이 겹칠 때, 픽셀 단위로 이미지가 섞여 들어간다.
+        gl.enable(gl.BLEND);
+        gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+        gl.blendEquation(gl.FUNC_ADD);
+    }
+    else{// blending을 끈다.
+        gl.disable(gl.BLEND);
+    }
+
+    // 배경을 초기화한다. a: 불투명도
+    // 아래 값은 정규화 되어서 0.0 ~ 1.0까지 의미를 지닌다.
+    gl.clearColor(0.2, 0.3, 0.4, 1.0);
+    // 배경을 초기화할 때의 깊이를 설정한다.
+    // 마찬가지로 정규화 되었기에 1.0은 가장 뒤를 의미한다.
+    // 참고) 0.6을 주고 depth를 키면 중앙에 있는 박스가 반쯤 짤린다. 주변 막대들은 나타나지 않는다. 가까워보이는데 착시현상일뿐.
+    gl.clearDepth(1.0); 
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+}
+
+/* 
+    중앙에 있는 박스들을 회전시키는 함수이다.
+*/
+function rotateMidBox(){
+    mat4.rotate(mov_matrix, mov_matrix, rotx, vec3.fromValues(1,0,0));
+    mat4.rotate(mov_matrix, mov_matrix, roty, vec3.fromValues(0,1,0));
+    mat4.rotate(mov_matrix, mov_matrix, rotz, vec3.fromValues(0,0,1));
+
+    rotx += rotate_x;
+    roty += rotate_y;
+    rotz += rotate_z;
+}
+
+/*
+    중앙에 있는 박스들이 html 화면에서 버튼'Turn!'을 누르거나 버튼'run'을 누르면 순차적으로 회전하는 모습이 보인다.
+    순차적으로 회전시키는 모습을 어떻게 구현했는지는 아래 간단히 설명한다.
+    1차원 배열로 예를 들어서 
+    0, 0, 0, 0, 0 이 있다고 해보자.
+    여기서 기준(가장 앞)을 10 증가 시켜 그 결과로
+    10, 0, 0, 0, 0 이 되었다.
+    여기서 렌더링이 계속 호출된다는 점을 인식하여
+    기준을 제외한 나머지 값들을 갱신시킬 때, 뒤부터 시작하여 자신과 자신의 앞에 데이터를 합쳐서 반으로 나눈 값으로 갱신하였다.
+    10, 5  , 0  , 0  , 0
+    10, 7.5, 2.5, 0  , 0
+    10, 8.8, 5  , 1.3, 0
+    ...
+*/
+function change(){
+    for(var x = 19; x > 0; x--){ // x 가 0인 박스들은 기준이다.
+        for(var y = 19; y >= 0; y--){
+            for(var z = 19; z >= 0; z--){
+                // x축을 기준으로 회전하므로 x의 값은 변함이 없다.
+                // x를 변경시킨다면 boxes[x][y][z][0]를 갱신 시켜야 한다.
+                boxes[x][y][z][1] = (boxes[x][y][z][1] + boxes[x-1][y][z][1])/2;
+                boxes[x][y][z][2] = (boxes[x][y][z][2] + boxes[x-1][y][z][2])/2;
+
+                boxesR[x][y][z][0] = (boxesR[x][y][z][0] + boxesR[x-1][y][z][0])/2;
+                
+            }
+        }
+    }
+}
+
+/*
+    가로 20, 세로 20, 높이 20으로 8000개 육면체를 만든다.
+*/
+function boxes8000drawing(matrix, locMmatrix){
+    // 그린 후 도형이 중앙에 오도록 처음 그리는 도형을 이동시킨다.
+    mat4.translate(matrix, matrix, vec3.fromValues(-10, -10, +10));
+
+    // matrix를 복사하여 초기값으로 정해준다.
+    var ori = mat4.clone(matrix);
+    for(var x = 0; x < 20; x++){
+        for(var y = 0; y < 20; y++){
+            for(var z = 0; z < 20; z++){
+                // ori에 있는 초기 데이터에서 각 도형들이 가지고 있는 위치값을 꺼내와 이동시킨다.
+                mat4.translate(matrix, ori, vec3.fromValues(boxes[x][y][z][0], boxes[x][y][z][1], -boxes[x][y][z][2]));
+                // 각 도형이 각자 회전하는 수치와 한 면이 회전하는 각도를 일치시킨다
+                // 이 작업을 하지 않을 시, 놀이공원의 관람차처럼 움직이게 된다.
+                mat4.rotateX(matrix, matrix, boxesR[x][y][z][0]);
+
+                gl.uniformMatrix4fv(locMmatrix, false, matrix);
+                gl.drawArrays(gl.TRIANGLES, 0, 36);
+            }
+        }
+    }
+}
+
+/*
+    버튼 콜 함수
+    파라미터: x, y, z
+    중앙에 있는 도형의 각속도를 증가시킨다.
+*/
+function animRotate(x, y, z){
+    rotate_x += x;
+    rotate_y += y;
+    rotate_z += z;
+}
+
+// 중앙에 있는 도형의 각속도를 0으로 초기화한다.
+function animPause(){
+    rotate_x = rotate_y = rotate_z = 0;
+}
+
+// 중앙에 있는 도형이 입력 없이 자동적으로 회전 여부를 제어하는 변수
+var onRunning = false;
+
+/*
+    html에서 각속도(speed)에 따라 기준면을 회전시킨다.
+    이미 눌렀는지 체크하여 일부 버튼을 활성/비활성 한다.  
+*/
+function boxRotate(run){
+    if(run == 1) { // 자동 회전을 시작합니다.
+        document.getElementsByName("run")[0].style.visibility = "hidden";
+        document.getElementsByName("stop")[0].style.visibility = "visible";
+        onRunning = true;
+    }
+    if(run == 2){ // 회전을 중지합니다.
+        document.getElementsByName("run")[0].style.visibility = "visible";
+        document.getElementsByName("stop")[0].style.visibility = "hidden";
+        onRunning = false;
+    }
+    // speed 값을 가져와 적당한 속도로 변경시킵니다.
+    var rad = document.getElementsByName("speed")[0].value/100;
+    if(rad < -1) rad = -1.0;
+    if(rad > 1) rad = 1.0
+
+    // 기준면을 회전시킵니다.
+    for(var y = 0; y < 20; y++)
+        for(var z = 0; z < 20; z++){
+            vec3.rotateX(boxes[0][y][z], boxes[0][y][z],  vec3.fromValues(+10,+10,10), rad);
+            boxesR[0][y][z][0] -= rad
+        }
+} 
+
+/*
+    8개의 도형이 2개 씩, 짝 지어 한 구간을 왕복합니다.
+    depth, cull, blend를 더욱 명확히 확인하기 위하여 추가하였습니다.
+*/
+var dloc = 0.0;
+function circle2box(matrix, locMmatrix){ 
+    // 왕복하는 도형의 좌표 파라미터입니다.
+    dloc+=0.01;
+
+    // 여기서 그리는 순서를 변경할 시 culling 할 때, 그리는 순서가 바뀌는 것을 확인.
+    drawBarBox(mat4.clone(matrix), locMmatrix, 60, 60, -20, 10);
+    drawBarBox(mat4.clone(matrix), locMmatrix, 60, 60, 20, 20);
+    drawBarBox(mat4.clone(matrix), locMmatrix, 60, -60, 20, 20);
+    drawBarBox(mat4.clone(matrix), locMmatrix, 60, -60, -20, 10);
+    drawBarBox(mat4.clone(matrix), locMmatrix, -60, 60, 20, 20);
+    drawBarBox(mat4.clone(matrix), locMmatrix, -60, 60, -20, 10);
+    drawBarBox(mat4.clone(matrix), locMmatrix, -60, -60, -20, 10);
+    drawBarBox(mat4.clone(matrix), locMmatrix, -60, -60, 20, 20);
+}
+
+// circle2box에서 반복 되는 내용이 많아 분리.
+function drawBarBox(matrix, locMmatrix, x, y, z, s){
+    // cos(dloc) 에 따라 z값이 변동됨.
+    mat4.translate(matrix, matrix, vec3.fromValues(x, y, -35+z*Math.cos(dloc)));
+    mat4.scale(matrix, matrix, vec3.fromValues(s,s,s));
+    gl.uniformMatrix4fv(locMmatrix, false, matrix);
+    gl.drawArrays(gl.TRIANGLES, 0, 36);
+}
\ No newline at end of file
diff --git a/student2019/201220913/README.md b/student2019/201220913/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..fda498935ea181289a697ecd56f465c0b659d08a
--- /dev/null
+++ b/student2019/201220913/README.md
@@ -0,0 +1,73 @@
+**컴퓨터 그래픽스
+기말 프로젝트 보고서
+
+WebGL - Depth, Culling, Blending**
+        201220913 이건희
+
+**개요**
+
+기말 프로젝트에 대한 설명을 들을 때, 타인에게 도움이 되는 것을 고려해야한다고 했을 때, 바로 기말 프로젝트 주제로 사용할 만한 것이 생각났다. DEPTH_TEST, 기말 프로젝트에서 보이고자 하는 것은 도형이 앞 뒤, 순서에 따라 그리는 가를 결정하는 부분이다. 어째서 이것을 주제로 선정하였는가? 처음 이 내용을 듣고 실습할 때, 가장 크게 감명받았다. 지금까지는 컴퓨터 그래픽스 수업을 들을 때, 무언가 그리지만 어딘가 이상한 도형이 주를 이루었다. 그러나 여기서부터 온전하게 그릴 수 있게 된 것이다.
+간단한 육면체가 할 수 있는 일은 무궁무진하다. 생물은 세포로 이루어지고 세포는 분자로 이루어진다. 성능과 효율을 떠나서 간단한 육면체가 아주 작게 만들어서 시간만 충분하다면 사람도 만들 수 있고 심지어 게임도 만들 수 있다고 기대할 수 있다. 그렇기에 나는 타인이 만약 컴퓨터 그래픽스를 공부해야 한다면 나에게 있어 최소한의 단위, DEPTH_TEST를 알아야 컴퓨터 그래픽스라고 불릴 수 있는 의미 있는 그래픽을 표현 가능 하다고 생각하고 이 주제로 기말 프로젝트를 진행한다.
+
+**구현**
+
+1.	depth test, culling, blending에 대한 차이를 명확히 하기 위하여 해당 기능을 끄고 킬 수 있게 한다.
+
+2.	프로젝트의 완성도를 높이기 위해서 그리고 기본적인 기능으로 활용 가능한 방법을 제시. 
+
+**상세**
+1.	html에서 check box로 각각 끄고 킬 수 있게 만들었다. 필요할 지 몰라 각 기능을 조합적으로 선택하게 두었다. 화면에 8개의 눕혀진 기둥을 만들어 각 기능을 확인하기 쉽게 만들었다. (연관 함수: pre_fragment, circle2box, drawBarBox) 
+
+  A.	depth: 작은 기둥이 큰 기둥과 겹치면 사라지다가 큰 기둥 중앙에서 나타난다.
+
+  B.	culling: 깊이에 상관없이 다 그린다. 겹칠 때, 가려지는 경우는 그리는 순서에 따라 가려지는 것.
+
+  C.	blending: 겹쳐지는 부분의 픽셀 색이 변화함을 확인할 수 있다.
+
+2.	중앙에 있는 한 개의 육면체 대신 20*20*20(총 8,000)개로 만들어 기준이 변화하면 나머지도 꼬리 물어 변화하도록 한다. 버튼 [Turn!]을 누르면 한 번 움직이며 버튼 [run]을 누르면 버튼 [stop]을 누르기 전까지 지속적으로 회전한다. 속도를 조절할 수 있게 -100 ~ 100까지 입력 가능하다. 변화할 때, 그 8,000개의 육면체들은 고유의 좌표와 회전각을 부여 받아서 개별적으로 처리한다.
+(연관 함수: boxRotate(버튼 이벤트), animRotate(버튼 이벤트), animPause(버튼 이벤트) rotateMidBox, change, boxes8000drawing)
+
+  A.	순차적 변화 방법
+  
+a, b 두 수가 있다. b값이 a값으로 변할 수 있도록 차이가 크면 빠르게 변하게 하고 가까우면 천천히 변하기 위하여 b = (a+b)/2를 무한히 하는 방법이 있다.
+예시를 들어 0, 0, 0에서 10, 0, 0으로 변화했다고 했을 때,
+10, 0, 0 -> 10, 5, 0 -> 10, 7.5, 2.5 -> 10, 8.75, 5 -> … 
+-> 10, 10, 10 에 도달하게 된다.
+처음에는 크게 변하다가 가까워질수록 변화하는 크기가 작아져 자연스럽게 표현된다.
+이것을 y, z값에 따라 적용하여 순차적으로 꼬리 물어 변화하게 한다.
+(x축을 기준으로 잡고 돌린 것이기에 x에는 적용할 필요 없다. x에도 적용시 모든 박스가 기준면으로 수렴하게 된다)
+
+  B.	일부 구현
+  
+본래 구현하고자 했던 것은 x, y, z축에 각자 기준면을 두고 그것을 변화하는 것 이였는데, 결론부터 말하자면 하지 못했다.
+축을 잡고 처음 회전하는 경우에는 어떤 축을 잡더라도 경우도 문제가 없었다. 그러나 조합해서 사용하는 경우(x축으로 돌린 다음, y축으로 돌리는 경우) 매우 예측하기 어렵게 멀리 날라가거나 매우 납작해지거나 여러 가지 문제점이 발생하였다.
+추정하기를 도형 각 면의 법선은 변하는데, 변화하는 축은 x, y, z축으로 고정되어 있기 때문에 발생한 문제로 보았다. 이를 해결하고자 하고자 시도했으나 실패하였다.
+그것에는 3가지 이유, (1)도형이 각자의 고유 값으로 좌표를 정하는 점과 (2) 도형마다 회전 각도를 정하며 (3) 순차적으로 변화하도록 부여하는 것을 모두 충족시키기에는 능력상 어려워 한 면 만을 기준으로 잡게 되었다. 이럴 경우, 데이터는 x값이 모두 고정되어 있고 축이 변하지도 않는다. 전체를 회전을 하더라도 계산 결과 이후에 나오는 값으로 무관하다.
+ 
+**코드**
+이벤트 함수
+boxRotate(a)
+a 파라미터 (0: 중앙 상장의 한 면을 한 번 회전), (1: 지속), (2: 정지)
+animRotate(x, y, z)
+x, y, z 파라미터: 현재 각속도에 (x, y, z)만큼 추가시킨다.
+animPause() : 현재 각속도를 0으로 초기화(즉, 회전을 멈춘다)
+일반 함수
+pre_fragment() : DEPTH_TEST, CULL_FACE, BLEND 를 html에 체크 유무에 따라 사용한다.
+rotateMidBox() : 현재 각속도만큼 중앙 상자들을 회전 시킨다.
+change() : 중앙 상자들이 앞 상자 위치로 따라가게 만드는 함수. 지속적으로 호출 필요
+boxes8000drawing(…): 중앙에 있는 상자 8,000개를 그리는 함수, 8000개를 저장하고 있는 배열으로부터 각자의 위치를 계산 및 회전각을 적용시킨다.
+circle2box(…): 큰 막대 4개, 작은 막대 4개가 각자 2개씩 짝을 지어 서로 왕복하는 함수
+drawBarBox(… , x, y, z, s): circle2box에서 막대 그리는 내용이 중복되어 분리.
+
+**결과물 참고**
+
+버튼[run] 누르고 speed 변경시키면 어떤 기능인지 유추될 거라 생각.
+도형을 꼬는 것과 도형 전체를 회전시키는 것은 서로 간에 독립적.
+depth, culling, blending 중 하나만 체크하기를 권장하나 여러 개 선택할 수 있음.
+
+reference: 
+Hwanyong Lee's WebGL Lab 04 : Cube Transform
+https://github.com/toji/gl-matrix/tree/master/dist (glMatrix, 사용하는 js에 하드카피)
+
+이 프로젝트에 대한 저작권 표시
+(CC_NC_BY) Kunhee Lee 2019
diff --git a/student2019/201220913/gl-matrix-min.js b/student2019/201220913/gl-matrix-min.js
new file mode 100644
index 0000000000000000000000000000000000000000..d9728ef6100e5d2e81aa02786028d6a8c170fcc8
--- /dev/null
+++ b/student2019/201220913/gl-matrix-min.js
@@ -0,0 +1,28 @@
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.0.0
+
+Copyright (c) 2015-2019, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t=t||self).glMatrix={})}(this,function(t){"use strict";var n=1e-6,a="undefined"!=typeof Float32Array?Float32Array:Array,r=Math.random;var u=Math.PI/180;Math.hypot||(Math.hypot=function(){for(var t=0,n=arguments.length;n--;)t+=arguments[n]*arguments[n];return Math.sqrt(t)});var e=Object.freeze({EPSILON:n,get ARRAY_TYPE(){return a},RANDOM:r,setMatrixArrayType:function(t){a=t},toRadian:function(t){return t*u},equals:function(t,a){return Math.abs(t-a)<=n*Math.max(1,Math.abs(t),Math.abs(a))}});function o(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*i+e*c,t[1]=u*i+o*c,t[2]=r*h+e*s,t[3]=u*h+o*s,t}function i(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}var c=o,h=i,s=Object.freeze({create:function(){var t=new a(4);return a!=Float32Array&&(t[1]=0,t[2]=0),t[0]=1,t[3]=1,t},clone:function(t){var n=new a(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t},fromValues:function(t,n,r,u){var e=new a(4);return e[0]=t,e[1]=n,e[2]=r,e[3]=u,e},set:function(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t},transpose:function(t,n){if(t===n){var a=n[1];t[1]=n[2],t[2]=a}else t[0]=n[0],t[1]=n[2],t[2]=n[1],t[3]=n[3];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*e-u*r;return o?(o=1/o,t[0]=e*o,t[1]=-r*o,t[2]=-u*o,t[3]=a*o,t):null},adjoint:function(t,n){var a=n[0];return t[0]=n[3],t[1]=-n[1],t[2]=-n[2],t[3]=a,t},determinant:function(t){return t[0]*t[3]-t[2]*t[1]},multiply:o,rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+e*i,t[1]=u*c+o*i,t[2]=r*-i+e*c,t[3]=u*-i+o*c,t},scale:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1];return t[0]=r*i,t[1]=u*i,t[2]=e*c,t[3]=o*c,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t},str:function(t){return"mat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3])},LDU:function(t,n,a,r){return t[2]=r[2]/r[0],a[0]=r[0],a[1]=r[1],a[3]=r[3]-t[2]*a[1],[t,n,a]},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t},subtract:i,exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=a[0],c=a[1],h=a[2],s=a[3];return Math.abs(r-i)<=n*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-c)<=n*Math.max(1,Math.abs(u),Math.abs(c))&&Math.abs(e-h)<=n*Math.max(1,Math.abs(e),Math.abs(h))&&Math.abs(o-s)<=n*Math.max(1,Math.abs(o),Math.abs(s))},multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t},mul:c,sub:h});function M(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return t[0]=r*h+e*s,t[1]=u*h+o*s,t[2]=r*M+e*f,t[3]=u*M+o*f,t[4]=r*l+e*v+i,t[5]=u*l+o*v+c,t}function f(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t}var l=M,v=f,b=Object.freeze({create:function(){var t=new a(6);return a!=Float32Array&&(t[1]=0,t[2]=0,t[4]=0,t[5]=0),t[0]=1,t[3]=1,t},clone:function(t){var n=new a(6);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t},fromValues:function(t,n,r,u,e,o){var i=new a(6);return i[0]=t,i[1]=n,i[2]=r,i[3]=u,i[4]=e,i[5]=o,i},set:function(t,n,a,r,u,e,o){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=a*e-r*u;return c?(c=1/c,t[0]=e*c,t[1]=-r*c,t[2]=-u*c,t[3]=a*c,t[4]=(u*i-e*o)*c,t[5]=(r*o-a*i)*c,t):null},determinant:function(t){return t[0]*t[3]-t[1]*t[2]},multiply:M,rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=Math.sin(a),s=Math.cos(a);return t[0]=r*s+e*h,t[1]=u*s+o*h,t[2]=r*-h+e*s,t[3]=u*-h+o*s,t[4]=i,t[5]=c,t},scale:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1];return t[0]=r*h,t[1]=u*h,t[2]=e*s,t[3]=o*s,t[4]=i,t[5]=c,t},translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=r*h+e*s+i,t[5]=u*h+o*s+c,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t[4]=0,t[5]=0,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t[4]=0,t[5]=0,t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=n[0],t[5]=n[1],t},str:function(t){return"mat2d("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],1)},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t},subtract:f,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return Math.abs(r-h)<=n*Math.max(1,Math.abs(r),Math.abs(h))&&Math.abs(u-s)<=n*Math.max(1,Math.abs(u),Math.abs(s))&&Math.abs(e-M)<=n*Math.max(1,Math.abs(e),Math.abs(M))&&Math.abs(o-f)<=n*Math.max(1,Math.abs(o),Math.abs(f))&&Math.abs(i-l)<=n*Math.max(1,Math.abs(i),Math.abs(l))&&Math.abs(c-v)<=n*Math.max(1,Math.abs(c),Math.abs(v))},mul:l,sub:v});function m(){var t=new a(9);return a!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function d(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],p=a[7],y=a[8];return t[0]=f*r+l*o+v*h,t[1]=f*u+l*i+v*s,t[2]=f*e+l*c+v*M,t[3]=b*r+m*o+d*h,t[4]=b*u+m*i+d*s,t[5]=b*e+m*c+d*M,t[6]=x*r+p*o+y*h,t[7]=x*u+p*i+y*s,t[8]=x*e+p*c+y*M,t}function x(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t}var p=d,y=x,q=Object.freeze({create:m,fromMat4:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[4],t[4]=n[5],t[5]=n[6],t[6]=n[8],t[7]=n[9],t[8]=n[10],t},clone:function(t){var n=new a(9);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromValues:function(t,n,r,u,e,o,i,c,h){var s=new a(9);return s[0]=t,s[1]=n,s[2]=r,s[3]=u,s[4]=e,s[5]=o,s[6]=i,s[7]=c,s[8]=h,s},set:function(t,n,a,r,u,e,o,i,c,h){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t[8]=h,t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},transpose:function(t,n){if(t===n){var a=n[1],r=n[2],u=n[5];t[1]=n[3],t[2]=n[6],t[3]=a,t[5]=n[7],t[6]=r,t[7]=u}else t[0]=n[0],t[1]=n[3],t[2]=n[6],t[3]=n[1],t[4]=n[4],t[5]=n[7],t[6]=n[2],t[7]=n[5],t[8]=n[8];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=s*o-i*h,f=-s*e+i*c,l=h*e-o*c,v=a*M+r*f+u*l;return v?(v=1/v,t[0]=M*v,t[1]=(-s*r+u*h)*v,t[2]=(i*r-u*o)*v,t[3]=f*v,t[4]=(s*a-u*c)*v,t[5]=(-i*a+u*e)*v,t[6]=l*v,t[7]=(-h*a+r*c)*v,t[8]=(o*a-r*e)*v,t):null},adjoint:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8];return t[0]=o*s-i*h,t[1]=u*h-r*s,t[2]=r*i-u*o,t[3]=i*c-e*s,t[4]=a*s-u*c,t[5]=u*e-a*i,t[6]=e*h-o*c,t[7]=r*c-a*h,t[8]=a*o-r*e,t},determinant:function(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],c=t[7],h=t[8];return n*(h*e-o*c)+a*(-h*u+o*i)+r*(c*u-e*i)},multiply:d,translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=a[0],l=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=c,t[6]=f*r+l*o+h,t[7]=f*u+l*i+s,t[8]=f*e+l*c+M,t},rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=Math.sin(a),l=Math.cos(a);return t[0]=l*r+f*o,t[1]=l*u+f*i,t[2]=l*e+f*c,t[3]=l*o-f*r,t[4]=l*i-f*u,t[5]=l*c-f*e,t[6]=h,t[7]=s,t[8]=M,t},scale:function(t,n,a){var r=a[0],u=a[1];return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=u*n[3],t[4]=u*n[4],t[5]=u*n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=n[0],t[7]=n[1],t[8]=1,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=-a,t[4]=r,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=n[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromMat2d:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=0,t[3]=n[2],t[4]=n[3],t[5]=0,t[6]=n[4],t[7]=n[5],t[8]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,c=u+u,h=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*c,b=e*o,m=e*i,d=e*c;return t[0]=1-M-v,t[3]=s-d,t[6]=f+m,t[1]=s+d,t[4]=1-h-v,t[7]=l-b,t[2]=f-m,t[5]=l+b,t[8]=1-h-M,t},normalFromMat4:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*c-u*o,y=a*h-e*o,q=r*c-u*i,g=r*h-e*i,A=u*h-e*c,w=s*b-M*v,R=s*m-f*v,z=s*d-l*v,P=M*m-f*b,j=M*d-l*b,I=f*d-l*m,S=x*I-p*j+y*P+q*z-g*R+A*w;return S?(S=1/S,t[0]=(i*I-c*j+h*P)*S,t[1]=(c*z-o*I-h*R)*S,t[2]=(o*j-i*z+h*w)*S,t[3]=(u*j-r*I-e*P)*S,t[4]=(a*I-u*z+e*R)*S,t[5]=(r*z-a*j-e*w)*S,t[6]=(b*A-m*g+d*q)*S,t[7]=(m*y-v*A-d*p)*S,t[8]=(v*g-b*y+d*x)*S,t):null},projection:function(t,n,a){return t[0]=2/n,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/a,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t},str:function(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t},subtract:x,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=t[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],p=a[7],y=a[8];return Math.abs(r-f)<=n*Math.max(1,Math.abs(r),Math.abs(f))&&Math.abs(u-l)<=n*Math.max(1,Math.abs(u),Math.abs(l))&&Math.abs(e-v)<=n*Math.max(1,Math.abs(e),Math.abs(v))&&Math.abs(o-b)<=n*Math.max(1,Math.abs(o),Math.abs(b))&&Math.abs(i-m)<=n*Math.max(1,Math.abs(i),Math.abs(m))&&Math.abs(c-d)<=n*Math.max(1,Math.abs(c),Math.abs(d))&&Math.abs(h-x)<=n*Math.max(1,Math.abs(h),Math.abs(x))&&Math.abs(s-p)<=n*Math.max(1,Math.abs(s),Math.abs(p))&&Math.abs(M-y)<=n*Math.max(1,Math.abs(M),Math.abs(y))},mul:p,sub:y});function g(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function A(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],b=n[12],m=n[13],d=n[14],x=n[15],p=a[0],y=a[1],q=a[2],g=a[3];return t[0]=p*r+y*i+q*M+g*b,t[1]=p*u+y*c+q*f+g*m,t[2]=p*e+y*h+q*l+g*d,t[3]=p*o+y*s+q*v+g*x,p=a[4],y=a[5],q=a[6],g=a[7],t[4]=p*r+y*i+q*M+g*b,t[5]=p*u+y*c+q*f+g*m,t[6]=p*e+y*h+q*l+g*d,t[7]=p*o+y*s+q*v+g*x,p=a[8],y=a[9],q=a[10],g=a[11],t[8]=p*r+y*i+q*M+g*b,t[9]=p*u+y*c+q*f+g*m,t[10]=p*e+y*h+q*l+g*d,t[11]=p*o+y*s+q*v+g*x,p=a[12],y=a[13],q=a[14],g=a[15],t[12]=p*r+y*i+q*M+g*b,t[13]=p*u+y*c+q*f+g*m,t[14]=p*e+y*h+q*l+g*d,t[15]=p*o+y*s+q*v+g*x,t}function w(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=r+r,c=u+u,h=e+e,s=r*i,M=r*c,f=r*h,l=u*c,v=u*h,b=e*h,m=o*i,d=o*c,x=o*h;return t[0]=1-(l+b),t[1]=M+x,t[2]=f-d,t[3]=0,t[4]=M-x,t[5]=1-(s+b),t[6]=v+m,t[7]=0,t[8]=f+d,t[9]=v-m,t[10]=1-(s+l),t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t}function R(t,n){return t[0]=n[12],t[1]=n[13],t[2]=n[14],t}function z(t,n){var a=n[0],r=n[1],u=n[2],e=n[4],o=n[5],i=n[6],c=n[8],h=n[9],s=n[10];return t[0]=Math.hypot(a,r,u),t[1]=Math.hypot(e,o,i),t[2]=Math.hypot(c,h,s),t}function P(t,n){var r=new a(3);z(r,n);var u=1/r[0],e=1/r[1],o=1/r[2],i=n[0]*u,c=n[1]*e,h=n[2]*o,s=n[4]*u,M=n[5]*e,f=n[6]*o,l=n[8]*u,v=n[9]*e,b=n[10]*o,m=i+M+b,d=0;return m>0?(d=2*Math.sqrt(m+1),t[3]=.25*d,t[0]=(f-v)/d,t[1]=(l-h)/d,t[2]=(c-s)/d):i>M&&i>b?(d=2*Math.sqrt(1+i-M-b),t[3]=(f-v)/d,t[0]=.25*d,t[1]=(c+s)/d,t[2]=(l+h)/d):M>b?(d=2*Math.sqrt(1+M-i-b),t[3]=(l-h)/d,t[0]=(c+s)/d,t[1]=.25*d,t[2]=(f+v)/d):(d=2*Math.sqrt(1+b-i-M),t[3]=(c-s)/d,t[0]=(l+h)/d,t[1]=(f+v)/d,t[2]=.25*d),t}function j(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t[9]=n[9]-a[9],t[10]=n[10]-a[10],t[11]=n[11]-a[11],t[12]=n[12]-a[12],t[13]=n[13]-a[13],t[14]=n[14]-a[14],t[15]=n[15]-a[15],t}var I=A,S=j,E=Object.freeze({create:function(){var t=new a(16);return a!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0),t[0]=1,t[5]=1,t[10]=1,t[15]=1,t},clone:function(t){var n=new a(16);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n[9]=t[9],n[10]=t[10],n[11]=t[11],n[12]=t[12],n[13]=t[13],n[14]=t[14],n[15]=t[15],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},fromValues:function(t,n,r,u,e,o,i,c,h,s,M,f,l,v,b,m){var d=new a(16);return d[0]=t,d[1]=n,d[2]=r,d[3]=u,d[4]=e,d[5]=o,d[6]=i,d[7]=c,d[8]=h,d[9]=s,d[10]=M,d[11]=f,d[12]=l,d[13]=v,d[14]=b,d[15]=m,d},set:function(t,n,a,r,u,e,o,i,c,h,s,M,f,l,v,b,m){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t[8]=h,t[9]=s,t[10]=M,t[11]=f,t[12]=l,t[13]=v,t[14]=b,t[15]=m,t},identity:g,transpose:function(t,n){if(t===n){var a=n[1],r=n[2],u=n[3],e=n[6],o=n[7],i=n[11];t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=a,t[6]=n[9],t[7]=n[13],t[8]=r,t[9]=e,t[11]=n[14],t[12]=u,t[13]=o,t[14]=i}else t[0]=n[0],t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=n[1],t[5]=n[5],t[6]=n[9],t[7]=n[13],t[8]=n[2],t[9]=n[6],t[10]=n[10],t[11]=n[14],t[12]=n[3],t[13]=n[7],t[14]=n[11],t[15]=n[15];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*c-u*o,y=a*h-e*o,q=r*c-u*i,g=r*h-e*i,A=u*h-e*c,w=s*b-M*v,R=s*m-f*v,z=s*d-l*v,P=M*m-f*b,j=M*d-l*b,I=f*d-l*m,S=x*I-p*j+y*P+q*z-g*R+A*w;return S?(S=1/S,t[0]=(i*I-c*j+h*P)*S,t[1]=(u*j-r*I-e*P)*S,t[2]=(b*A-m*g+d*q)*S,t[3]=(f*g-M*A-l*q)*S,t[4]=(c*z-o*I-h*R)*S,t[5]=(a*I-u*z+e*R)*S,t[6]=(m*y-v*A-d*p)*S,t[7]=(s*A-f*y+l*p)*S,t[8]=(o*j-i*z+h*w)*S,t[9]=(r*z-a*j-e*w)*S,t[10]=(v*g-b*y+d*x)*S,t[11]=(M*y-s*g-l*x)*S,t[12]=(i*R-o*P-c*w)*S,t[13]=(a*P-r*R+u*w)*S,t[14]=(b*p-v*q-m*x)*S,t[15]=(s*q-M*p+f*x)*S,t):null},adjoint:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15];return t[0]=i*(f*d-l*m)-M*(c*d-h*m)+b*(c*l-h*f),t[1]=-(r*(f*d-l*m)-M*(u*d-e*m)+b*(u*l-e*f)),t[2]=r*(c*d-h*m)-i*(u*d-e*m)+b*(u*h-e*c),t[3]=-(r*(c*l-h*f)-i*(u*l-e*f)+M*(u*h-e*c)),t[4]=-(o*(f*d-l*m)-s*(c*d-h*m)+v*(c*l-h*f)),t[5]=a*(f*d-l*m)-s*(u*d-e*m)+v*(u*l-e*f),t[6]=-(a*(c*d-h*m)-o*(u*d-e*m)+v*(u*h-e*c)),t[7]=a*(c*l-h*f)-o*(u*l-e*f)+s*(u*h-e*c),t[8]=o*(M*d-l*b)-s*(i*d-h*b)+v*(i*l-h*M),t[9]=-(a*(M*d-l*b)-s*(r*d-e*b)+v*(r*l-e*M)),t[10]=a*(i*d-h*b)-o*(r*d-e*b)+v*(r*h-e*i),t[11]=-(a*(i*l-h*M)-o*(r*l-e*M)+s*(r*h-e*i)),t[12]=-(o*(M*m-f*b)-s*(i*m-c*b)+v*(i*f-c*M)),t[13]=a*(M*m-f*b)-s*(r*m-u*b)+v*(r*f-u*M),t[14]=-(a*(i*m-c*b)-o*(r*m-u*b)+v*(r*c-u*i)),t[15]=a*(i*f-c*M)-o*(r*f-u*M)+s*(r*c-u*i),t},determinant:function(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],c=t[7],h=t[8],s=t[9],M=t[10],f=t[11],l=t[12],v=t[13],b=t[14],m=t[15];return(n*o-a*e)*(M*m-f*b)-(n*i-r*e)*(s*m-f*v)+(n*c-u*e)*(s*b-M*v)+(a*i-r*o)*(h*m-f*l)-(a*c-u*o)*(h*b-M*l)+(r*c-u*i)*(h*v-s*l)},multiply:A,translate:function(t,n,a){var r,u,e,o,i,c,h,s,M,f,l,v,b=a[0],m=a[1],d=a[2];return n===t?(t[12]=n[0]*b+n[4]*m+n[8]*d+n[12],t[13]=n[1]*b+n[5]*m+n[9]*d+n[13],t[14]=n[2]*b+n[6]*m+n[10]*d+n[14],t[15]=n[3]*b+n[7]*m+n[11]*d+n[15]):(r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=c,t[6]=h,t[7]=s,t[8]=M,t[9]=f,t[10]=l,t[11]=v,t[12]=r*b+i*m+M*d+n[12],t[13]=u*b+c*m+f*d+n[13],t[14]=e*b+h*m+l*d+n[14],t[15]=o*b+s*m+v*d+n[15]),t},scale:function(t,n,a){var r=a[0],u=a[1],e=a[2];return t[0]=n[0]*r,t[1]=n[1]*r,t[2]=n[2]*r,t[3]=n[3]*r,t[4]=n[4]*u,t[5]=n[5]*u,t[6]=n[6]*u,t[7]=n[7]*u,t[8]=n[8]*e,t[9]=n[9]*e,t[10]=n[10]*e,t[11]=n[11]*e,t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},rotate:function(t,a,r,u){var e,o,i,c,h,s,M,f,l,v,b,m,d,x,p,y,q,g,A,w,R,z,P,j,I=u[0],S=u[1],E=u[2],O=Math.hypot(I,S,E);return O<n?null:(I*=O=1/O,S*=O,E*=O,e=Math.sin(r),i=1-(o=Math.cos(r)),c=a[0],h=a[1],s=a[2],M=a[3],f=a[4],l=a[5],v=a[6],b=a[7],m=a[8],d=a[9],x=a[10],p=a[11],y=I*I*i+o,q=S*I*i+E*e,g=E*I*i-S*e,A=I*S*i-E*e,w=S*S*i+o,R=E*S*i+I*e,z=I*E*i+S*e,P=S*E*i-I*e,j=E*E*i+o,t[0]=c*y+f*q+m*g,t[1]=h*y+l*q+d*g,t[2]=s*y+v*q+x*g,t[3]=M*y+b*q+p*g,t[4]=c*A+f*w+m*R,t[5]=h*A+l*w+d*R,t[6]=s*A+v*w+x*R,t[7]=M*A+b*w+p*R,t[8]=c*z+f*P+m*j,t[9]=h*z+l*P+d*j,t[10]=s*z+v*P+x*j,t[11]=M*z+b*P+p*j,a!==t&&(t[12]=a[12],t[13]=a[13],t[14]=a[14],t[15]=a[15]),t)},rotateX:function(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[4],o=n[5],i=n[6],c=n[7],h=n[8],s=n[9],M=n[10],f=n[11];return n!==t&&(t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[4]=e*u+h*r,t[5]=o*u+s*r,t[6]=i*u+M*r,t[7]=c*u+f*r,t[8]=h*u-e*r,t[9]=s*u-o*r,t[10]=M*u-i*r,t[11]=f*u-c*r,t},rotateY:function(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[0],o=n[1],i=n[2],c=n[3],h=n[8],s=n[9],M=n[10],f=n[11];return n!==t&&(t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[0]=e*u-h*r,t[1]=o*u-s*r,t[2]=i*u-M*r,t[3]=c*u-f*r,t[8]=e*r+h*u,t[9]=o*r+s*u,t[10]=i*r+M*u,t[11]=c*r+f*u,t},rotateZ:function(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[0],o=n[1],i=n[2],c=n[3],h=n[4],s=n[5],M=n[6],f=n[7];return n!==t&&(t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[0]=e*u+h*r,t[1]=o*u+s*r,t[2]=i*u+M*r,t[3]=c*u+f*r,t[4]=h*u-e*r,t[5]=s*u-o*r,t[6]=M*u-i*r,t[7]=f*u-c*r,t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=n[0],t[13]=n[1],t[14]=n[2],t[15]=1,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=n[1],t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=n[2],t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromRotation:function(t,a,r){var u,e,o,i=r[0],c=r[1],h=r[2],s=Math.hypot(i,c,h);return s<n?null:(i*=s=1/s,c*=s,h*=s,u=Math.sin(a),o=1-(e=Math.cos(a)),t[0]=i*i*o+e,t[1]=c*i*o+h*u,t[2]=h*i*o-c*u,t[3]=0,t[4]=i*c*o-h*u,t[5]=c*c*o+e,t[6]=h*c*o+i*u,t[7]=0,t[8]=i*h*o+c*u,t[9]=c*h*o-i*u,t[10]=h*h*o+e,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t)},fromXRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=r,t[6]=a,t[7]=0,t[8]=0,t[9]=-a,t[10]=r,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromYRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=0,t[2]=-a,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=a,t[9]=0,t[10]=r,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromZRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=0,t[4]=-a,t[5]=r,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromRotationTranslation:w,fromQuat2:function(t,n){var r=new a(3),u=-n[0],e=-n[1],o=-n[2],i=n[3],c=n[4],h=n[5],s=n[6],M=n[7],f=u*u+e*e+o*o+i*i;return f>0?(r[0]=2*(c*i+M*u+h*o-s*e)/f,r[1]=2*(h*i+M*e+s*u-c*o)/f,r[2]=2*(s*i+M*o+c*e-h*u)/f):(r[0]=2*(c*i+M*u+h*o-s*e),r[1]=2*(h*i+M*e+s*u-c*o),r[2]=2*(s*i+M*o+c*e-h*u)),w(t,n,r),t},getTranslation:R,getScaling:z,getRotation:P,fromRotationTranslationScale:function(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3],c=u+u,h=e+e,s=o+o,M=u*c,f=u*h,l=u*s,v=e*h,b=e*s,m=o*s,d=i*c,x=i*h,p=i*s,y=r[0],q=r[1],g=r[2];return t[0]=(1-(v+m))*y,t[1]=(f+p)*y,t[2]=(l-x)*y,t[3]=0,t[4]=(f-p)*q,t[5]=(1-(M+m))*q,t[6]=(b+d)*q,t[7]=0,t[8]=(l+x)*g,t[9]=(b-d)*g,t[10]=(1-(M+v))*g,t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t},fromRotationTranslationScaleOrigin:function(t,n,a,r,u){var e=n[0],o=n[1],i=n[2],c=n[3],h=e+e,s=o+o,M=i+i,f=e*h,l=e*s,v=e*M,b=o*s,m=o*M,d=i*M,x=c*h,p=c*s,y=c*M,q=r[0],g=r[1],A=r[2],w=u[0],R=u[1],z=u[2],P=(1-(b+d))*q,j=(l+y)*q,I=(v-p)*q,S=(l-y)*g,E=(1-(f+d))*g,O=(m+x)*g,T=(v+p)*A,D=(m-x)*A,F=(1-(f+b))*A;return t[0]=P,t[1]=j,t[2]=I,t[3]=0,t[4]=S,t[5]=E,t[6]=O,t[7]=0,t[8]=T,t[9]=D,t[10]=F,t[11]=0,t[12]=a[0]+w-(P*w+S*R+T*z),t[13]=a[1]+R-(j*w+E*R+D*z),t[14]=a[2]+z-(I*w+O*R+F*z),t[15]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,c=u+u,h=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*c,b=e*o,m=e*i,d=e*c;return t[0]=1-M-v,t[1]=s+d,t[2]=f-m,t[3]=0,t[4]=s-d,t[5]=1-h-v,t[6]=l+b,t[7]=0,t[8]=f+m,t[9]=l-b,t[10]=1-h-M,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},frustum:function(t,n,a,r,u,e,o){var i=1/(a-n),c=1/(u-r),h=1/(e-o);return t[0]=2*e*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*e*c,t[6]=0,t[7]=0,t[8]=(a+n)*i,t[9]=(u+r)*c,t[10]=(o+e)*h,t[11]=-1,t[12]=0,t[13]=0,t[14]=o*e*2*h,t[15]=0,t},perspective:function(t,n,a,r,u){var e,o=1/Math.tan(n/2);return t[0]=o/a,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=o,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=-1,t[12]=0,t[13]=0,t[15]=0,null!=u&&u!==1/0?(e=1/(r-u),t[10]=(u+r)*e,t[14]=2*u*r*e):(t[10]=-1,t[14]=-2*r),t},perspectiveFromFieldOfView:function(t,n,a,r){var u=Math.tan(n.upDegrees*Math.PI/180),e=Math.tan(n.downDegrees*Math.PI/180),o=Math.tan(n.leftDegrees*Math.PI/180),i=Math.tan(n.rightDegrees*Math.PI/180),c=2/(o+i),h=2/(u+e);return t[0]=c,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=h,t[6]=0,t[7]=0,t[8]=-(o-i)*c*.5,t[9]=(u-e)*h*.5,t[10]=r/(a-r),t[11]=-1,t[12]=0,t[13]=0,t[14]=r*a/(a-r),t[15]=0,t},ortho:function(t,n,a,r,u,e,o){var i=1/(n-a),c=1/(r-u),h=1/(e-o);return t[0]=-2*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*c,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*h,t[11]=0,t[12]=(n+a)*i,t[13]=(u+r)*c,t[14]=(o+e)*h,t[15]=1,t},lookAt:function(t,a,r,u){var e,o,i,c,h,s,M,f,l,v,b=a[0],m=a[1],d=a[2],x=u[0],p=u[1],y=u[2],q=r[0],A=r[1],w=r[2];return Math.abs(b-q)<n&&Math.abs(m-A)<n&&Math.abs(d-w)<n?g(t):(M=b-q,f=m-A,l=d-w,e=p*(l*=v=1/Math.hypot(M,f,l))-y*(f*=v),o=y*(M*=v)-x*l,i=x*f-p*M,(v=Math.hypot(e,o,i))?(e*=v=1/v,o*=v,i*=v):(e=0,o=0,i=0),c=f*i-l*o,h=l*e-M*i,s=M*o-f*e,(v=Math.hypot(c,h,s))?(c*=v=1/v,h*=v,s*=v):(c=0,h=0,s=0),t[0]=e,t[1]=c,t[2]=M,t[3]=0,t[4]=o,t[5]=h,t[6]=f,t[7]=0,t[8]=i,t[9]=s,t[10]=l,t[11]=0,t[12]=-(e*b+o*m+i*d),t[13]=-(c*b+h*m+s*d),t[14]=-(M*b+f*m+l*d),t[15]=1,t)},targetTo:function(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=r[0],c=r[1],h=r[2],s=u-a[0],M=e-a[1],f=o-a[2],l=s*s+M*M+f*f;l>0&&(s*=l=1/Math.sqrt(l),M*=l,f*=l);var v=c*f-h*M,b=h*s-i*f,m=i*M-c*s;return(l=v*v+b*b+m*m)>0&&(v*=l=1/Math.sqrt(l),b*=l,m*=l),t[0]=v,t[1]=b,t[2]=m,t[3]=0,t[4]=M*m-f*b,t[5]=f*v-s*m,t[6]=s*b-M*v,t[7]=0,t[8]=s,t[9]=M,t[10]=f,t[11]=0,t[12]=u,t[13]=e,t[14]=o,t[15]=1,t},str:function(t){return"mat4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+", "+t[9]+", "+t[10]+", "+t[11]+", "+t[12]+", "+t[13]+", "+t[14]+", "+t[15]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t[9]=n[9]+a[9],t[10]=n[10]+a[10],t[11]=n[11]+a[11],t[12]=n[12]+a[12],t[13]=n[13]+a[13],t[14]=n[14]+a[14],t[15]=n[15]+a[15],t},subtract:j,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=n[11]*a,t[12]=n[12]*a,t[13]=n[13]*a,t[14]=n[14]*a,t[15]=n[15]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t[9]=n[9]+a[9]*r,t[10]=n[10]+a[10]*r,t[11]=n[11]+a[11]*r,t[12]=n[12]+a[12]*r,t[13]=n[13]+a[13]*r,t[14]=n[14]+a[14]*r,t[15]=n[15]+a[15]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]&&t[9]===n[9]&&t[10]===n[10]&&t[11]===n[11]&&t[12]===n[12]&&t[13]===n[13]&&t[14]===n[14]&&t[15]===n[15]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=t[8],f=t[9],l=t[10],v=t[11],b=t[12],m=t[13],d=t[14],x=t[15],p=a[0],y=a[1],q=a[2],g=a[3],A=a[4],w=a[5],R=a[6],z=a[7],P=a[8],j=a[9],I=a[10],S=a[11],E=a[12],O=a[13],T=a[14],D=a[15];return Math.abs(r-p)<=n*Math.max(1,Math.abs(r),Math.abs(p))&&Math.abs(u-y)<=n*Math.max(1,Math.abs(u),Math.abs(y))&&Math.abs(e-q)<=n*Math.max(1,Math.abs(e),Math.abs(q))&&Math.abs(o-g)<=n*Math.max(1,Math.abs(o),Math.abs(g))&&Math.abs(i-A)<=n*Math.max(1,Math.abs(i),Math.abs(A))&&Math.abs(c-w)<=n*Math.max(1,Math.abs(c),Math.abs(w))&&Math.abs(h-R)<=n*Math.max(1,Math.abs(h),Math.abs(R))&&Math.abs(s-z)<=n*Math.max(1,Math.abs(s),Math.abs(z))&&Math.abs(M-P)<=n*Math.max(1,Math.abs(M),Math.abs(P))&&Math.abs(f-j)<=n*Math.max(1,Math.abs(f),Math.abs(j))&&Math.abs(l-I)<=n*Math.max(1,Math.abs(l),Math.abs(I))&&Math.abs(v-S)<=n*Math.max(1,Math.abs(v),Math.abs(S))&&Math.abs(b-E)<=n*Math.max(1,Math.abs(b),Math.abs(E))&&Math.abs(m-O)<=n*Math.max(1,Math.abs(m),Math.abs(O))&&Math.abs(d-T)<=n*Math.max(1,Math.abs(d),Math.abs(T))&&Math.abs(x-D)<=n*Math.max(1,Math.abs(x),Math.abs(D))},mul:I,sub:S});function O(){var t=new a(3);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function T(t){var n=t[0],a=t[1],r=t[2];return Math.hypot(n,a,r)}function D(t,n,r){var u=new a(3);return u[0]=t,u[1]=n,u[2]=r,u}function F(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t}function L(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t}function V(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t}function Q(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return Math.hypot(a,r,u)}function Y(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return a*a+r*r+u*u}function X(t){var n=t[0],a=t[1],r=t[2];return n*n+a*a+r*r}function Z(t,n){var a=n[0],r=n[1],u=n[2],e=a*a+r*r+u*u;return e>0&&(e=1/Math.sqrt(e)),t[0]=n[0]*e,t[1]=n[1]*e,t[2]=n[2]*e,t}function _(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function B(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],c=a[2];return t[0]=u*c-e*i,t[1]=e*o-r*c,t[2]=r*i-u*o,t}var N,k=F,U=L,W=V,C=Q,G=Y,H=T,J=X,K=(N=O(),function(t,n,a,r,u,e){var o,i;for(n||(n=3),a||(a=0),i=r?Math.min(r*n+a,t.length):t.length,o=a;o<i;o+=n)N[0]=t[o],N[1]=t[o+1],N[2]=t[o+2],u(N,N,e),t[o]=N[0],t[o+1]=N[1],t[o+2]=N[2];return t}),$=Object.freeze({create:O,clone:function(t){var n=new a(3);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n},length:T,fromValues:D,copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t},set:function(t,n,a,r){return t[0]=n,t[1]=a,t[2]=r,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t},subtract:F,multiply:L,divide:V,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t[2]=Math.ceil(n[2]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t[2]=Math.floor(n[2]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t[2]=Math.min(n[2],a[2]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t[2]=Math.max(n[2],a[2]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t[2]=Math.round(n[2]),t},scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t},scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t},distance:Q,squaredDistance:Y,squaredLength:X,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t[2]=1/n[2],t},normalize:Z,dot:_,cross:B,lerp:function(t,n,a,r){var u=n[0],e=n[1],o=n[2];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t[2]=o+r*(a[2]-o),t},hermite:function(t,n,a,r,u,e){var o=e*e,i=o*(2*e-3)+1,c=o*(e-2)+e,h=o*(e-1),s=o*(3-2*e);return t[0]=n[0]*i+a[0]*c+r[0]*h+u[0]*s,t[1]=n[1]*i+a[1]*c+r[1]*h+u[1]*s,t[2]=n[2]*i+a[2]*c+r[2]*h+u[2]*s,t},bezier:function(t,n,a,r,u,e){var o=1-e,i=o*o,c=e*e,h=i*o,s=3*e*i,M=3*c*o,f=c*e;return t[0]=n[0]*h+a[0]*s+r[0]*M+u[0]*f,t[1]=n[1]*h+a[1]*s+r[1]*M+u[1]*f,t[2]=n[2]*h+a[2]*s+r[2]*M+u[2]*f,t},random:function(t,n){n=n||1;var a=2*r()*Math.PI,u=2*r()-1,e=Math.sqrt(1-u*u)*n;return t[0]=Math.cos(a)*e,t[1]=Math.sin(a)*e,t[2]=u*n,t},transformMat4:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[3]*r+a[7]*u+a[11]*e+a[15];return o=o||1,t[0]=(a[0]*r+a[4]*u+a[8]*e+a[12])/o,t[1]=(a[1]*r+a[5]*u+a[9]*e+a[13])/o,t[2]=(a[2]*r+a[6]*u+a[10]*e+a[14])/o,t},transformMat3:function(t,n,a){var r=n[0],u=n[1],e=n[2];return t[0]=r*a[0]+u*a[3]+e*a[6],t[1]=r*a[1]+u*a[4]+e*a[7],t[2]=r*a[2]+u*a[5]+e*a[8],t},transformQuat:function(t,n,a){var r=a[0],u=a[1],e=a[2],o=a[3],i=n[0],c=n[1],h=n[2],s=u*h-e*c,M=e*i-r*h,f=r*c-u*i,l=u*f-e*M,v=e*s-r*f,b=r*M-u*s,m=2*o;return s*=m,M*=m,f*=m,l*=2,v*=2,b*=2,t[0]=i+s+l,t[1]=c+M+v,t[2]=h+f+b,t},rotateX:function(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[0],e[1]=u[1]*Math.cos(r)-u[2]*Math.sin(r),e[2]=u[1]*Math.sin(r)+u[2]*Math.cos(r),t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t},rotateY:function(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[2]*Math.sin(r)+u[0]*Math.cos(r),e[1]=u[1],e[2]=u[2]*Math.cos(r)-u[0]*Math.sin(r),t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t},rotateZ:function(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[0]*Math.cos(r)-u[1]*Math.sin(r),e[1]=u[0]*Math.sin(r)+u[1]*Math.cos(r),e[2]=u[2],t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t},angle:function(t,n){var a=D(t[0],t[1],t[2]),r=D(n[0],n[1],n[2]);Z(a,a),Z(r,r);var u=_(a,r);return u>1?0:u<-1?Math.PI:Math.acos(u)},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t},str:function(t){return"vec3("+t[0]+", "+t[1]+", "+t[2]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=a[0],i=a[1],c=a[2];return Math.abs(r-o)<=n*Math.max(1,Math.abs(r),Math.abs(o))&&Math.abs(u-i)<=n*Math.max(1,Math.abs(u),Math.abs(i))&&Math.abs(e-c)<=n*Math.max(1,Math.abs(e),Math.abs(c))},sub:k,mul:U,div:W,dist:C,sqrDist:G,len:H,sqrLen:J,forEach:K});function tt(){var t=new a(4);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[3]=0),t}function nt(t){var n=new a(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n}function at(t,n,r,u){var e=new a(4);return e[0]=t,e[1]=n,e[2]=r,e[3]=u,e}function rt(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t}function ut(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t}function et(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t}function ot(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}function it(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t[3]=n[3]*a[3],t}function ct(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t[3]=n[3]/a[3],t}function ht(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t}function st(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2],e=n[3]-t[3];return Math.hypot(a,r,u,e)}function Mt(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2],e=n[3]-t[3];return a*a+r*r+u*u+e*e}function ft(t){var n=t[0],a=t[1],r=t[2],u=t[3];return Math.hypot(n,a,r,u)}function lt(t){var n=t[0],a=t[1],r=t[2],u=t[3];return n*n+a*a+r*r+u*u}function vt(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e;return o>0&&(o=1/Math.sqrt(o)),t[0]=a*o,t[1]=r*o,t[2]=u*o,t[3]=e*o,t}function bt(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]+t[3]*n[3]}function mt(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t[2]=o+r*(a[2]-o),t[3]=i+r*(a[3]-i),t}function dt(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]}function xt(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=a[0],c=a[1],h=a[2],s=a[3];return Math.abs(r-i)<=n*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-c)<=n*Math.max(1,Math.abs(u),Math.abs(c))&&Math.abs(e-h)<=n*Math.max(1,Math.abs(e),Math.abs(h))&&Math.abs(o-s)<=n*Math.max(1,Math.abs(o),Math.abs(s))}var pt=ot,yt=it,qt=ct,gt=st,At=Mt,wt=ft,Rt=lt,zt=function(){var t=tt();return function(n,a,r,u,e,o){var i,c;for(a||(a=4),r||(r=0),c=u?Math.min(u*a+r,n.length):n.length,i=r;i<c;i+=a)t[0]=n[i],t[1]=n[i+1],t[2]=n[i+2],t[3]=n[i+3],e(t,t,o),n[i]=t[0],n[i+1]=t[1],n[i+2]=t[2],n[i+3]=t[3];return n}}(),Pt=Object.freeze({create:tt,clone:nt,fromValues:at,copy:rt,set:ut,add:et,subtract:ot,multiply:it,divide:ct,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t[2]=Math.ceil(n[2]),t[3]=Math.ceil(n[3]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t[2]=Math.floor(n[2]),t[3]=Math.floor(n[3]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t[2]=Math.min(n[2],a[2]),t[3]=Math.min(n[3],a[3]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t[2]=Math.max(n[2],a[2]),t[3]=Math.max(n[3],a[3]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t[2]=Math.round(n[2]),t[3]=Math.round(n[3]),t},scale:ht,scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t},distance:st,squaredDistance:Mt,length:ft,squaredLength:lt,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=-n[3],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t[2]=1/n[2],t[3]=1/n[3],t},normalize:vt,dot:bt,cross:function(t,n,a,r){var u=a[0]*r[1]-a[1]*r[0],e=a[0]*r[2]-a[2]*r[0],o=a[0]*r[3]-a[3]*r[0],i=a[1]*r[2]-a[2]*r[1],c=a[1]*r[3]-a[3]*r[1],h=a[2]*r[3]-a[3]*r[2],s=n[0],M=n[1],f=n[2],l=n[3];return t[0]=M*h-f*c+l*i,t[1]=-s*h+f*o-l*e,t[2]=s*c-M*o+l*u,t[3]=-s*i+M*e-f*u,t},lerp:mt,random:function(t,n){var a,u,e,o,i,c;n=n||1;do{i=(a=2*r()-1)*a+(u=2*r()-1)*u}while(i>=1);do{c=(e=2*r()-1)*e+(o=2*r()-1)*o}while(c>=1);var h=Math.sqrt((1-i)/c);return t[0]=n*a,t[1]=n*u,t[2]=n*e*h,t[3]=n*o*h,t},transformMat4:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3];return t[0]=a[0]*r+a[4]*u+a[8]*e+a[12]*o,t[1]=a[1]*r+a[5]*u+a[9]*e+a[13]*o,t[2]=a[2]*r+a[6]*u+a[10]*e+a[14]*o,t[3]=a[3]*r+a[7]*u+a[11]*e+a[15]*o,t},transformQuat:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],c=a[2],h=a[3],s=h*r+i*e-c*u,M=h*u+c*r-o*e,f=h*e+o*u-i*r,l=-o*r-i*u-c*e;return t[0]=s*h+l*-o+M*-c-f*-i,t[1]=M*h+l*-i+f*-o-s*-c,t[2]=f*h+l*-c+s*-i-M*-o,t[3]=n[3],t},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=0,t},str:function(t){return"vec4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},exactEquals:dt,equals:xt,sub:pt,mul:yt,div:qt,dist:gt,sqrDist:At,len:wt,sqrLen:Rt,forEach:zt});function jt(){var t=new a(4);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t[3]=1,t}function It(t,n,a){a*=.5;var r=Math.sin(a);return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=Math.cos(a),t}function St(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*s+o*i+u*h-e*c,t[1]=u*s+o*c+e*i-r*h,t[2]=e*s+o*h+r*c-u*i,t[3]=o*s-r*i-u*c-e*h,t}function Et(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+o*i,t[1]=u*c+e*i,t[2]=e*c-u*i,t[3]=o*c-r*i,t}function Ot(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c-e*i,t[1]=u*c+o*i,t[2]=e*c+r*i,t[3]=o*c-u*i,t}function Tt(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+u*i,t[1]=u*c-r*i,t[2]=e*c+o*i,t[3]=o*c-e*i,t}function Dt(t,a,r,u){var e,o,i,c,h,s=a[0],M=a[1],f=a[2],l=a[3],v=r[0],b=r[1],m=r[2],d=r[3];return(o=s*v+M*b+f*m+l*d)<0&&(o=-o,v=-v,b=-b,m=-m,d=-d),1-o>n?(e=Math.acos(o),i=Math.sin(e),c=Math.sin((1-u)*e)/i,h=Math.sin(u*e)/i):(c=1-u,h=u),t[0]=c*s+h*v,t[1]=c*M+h*b,t[2]=c*f+h*m,t[3]=c*l+h*d,t}function Ft(t,n){var a,r=n[0]+n[4]+n[8];if(r>0)a=Math.sqrt(r+1),t[3]=.5*a,a=.5/a,t[0]=(n[5]-n[7])*a,t[1]=(n[6]-n[2])*a,t[2]=(n[1]-n[3])*a;else{var u=0;n[4]>n[0]&&(u=1),n[8]>n[3*u+u]&&(u=2);var e=(u+1)%3,o=(u+2)%3;a=Math.sqrt(n[3*u+u]-n[3*e+e]-n[3*o+o]+1),t[u]=.5*a,a=.5/a,t[3]=(n[3*e+o]-n[3*o+e])*a,t[e]=(n[3*e+u]+n[3*u+e])*a,t[o]=(n[3*o+u]+n[3*u+o])*a}return t}var Lt,Vt,Qt,Yt,Xt,Zt,_t=nt,Bt=at,Nt=rt,kt=ut,Ut=et,Wt=St,Ct=ht,Gt=bt,Ht=mt,Jt=ft,Kt=Jt,$t=lt,tn=$t,nn=vt,an=dt,rn=xt,un=(Lt=O(),Vt=D(1,0,0),Qt=D(0,1,0),function(t,n,a){var r=_(n,a);return r<-.999999?(B(Lt,Vt,n),H(Lt)<1e-6&&B(Lt,Qt,n),Z(Lt,Lt),It(t,Lt,Math.PI),t):r>.999999?(t[0]=0,t[1]=0,t[2]=0,t[3]=1,t):(B(Lt,n,a),t[0]=Lt[0],t[1]=Lt[1],t[2]=Lt[2],t[3]=1+r,nn(t,t))}),en=(Yt=jt(),Xt=jt(),function(t,n,a,r,u,e){return Dt(Yt,n,u,e),Dt(Xt,a,r,e),Dt(t,Yt,Xt,2*e*(1-e)),t}),on=(Zt=m(),function(t,n,a,r){return Zt[0]=a[0],Zt[3]=a[1],Zt[6]=a[2],Zt[1]=r[0],Zt[4]=r[1],Zt[7]=r[2],Zt[2]=-n[0],Zt[5]=-n[1],Zt[8]=-n[2],nn(t,Ft(t,Zt))}),cn=Object.freeze({create:jt,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t},setAxisAngle:It,getAxisAngle:function(t,a){var r=2*Math.acos(a[3]),u=Math.sin(r/2);return u>n?(t[0]=a[0]/u,t[1]=a[1]/u,t[2]=a[2]/u):(t[0]=1,t[1]=0,t[2]=0),r},multiply:St,rotateX:Et,rotateY:Ot,rotateZ:Tt,calculateW:function(t,n){var a=n[0],r=n[1],u=n[2];return t[0]=a,t[1]=r,t[2]=u,t[3]=Math.sqrt(Math.abs(1-a*a-r*r-u*u)),t},slerp:Dt,random:function(t){var n=r(),a=r(),u=r(),e=Math.sqrt(1-n),o=Math.sqrt(n);return t[0]=e*Math.sin(2*Math.PI*a),t[1]=e*Math.cos(2*Math.PI*a),t[2]=o*Math.sin(2*Math.PI*u),t[3]=o*Math.cos(2*Math.PI*u),t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e,i=o?1/o:0;return t[0]=-a*i,t[1]=-r*i,t[2]=-u*i,t[3]=e*i,t},conjugate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t},fromMat3:Ft,fromEuler:function(t,n,a,r){var u=.5*Math.PI/180;n*=u,a*=u,r*=u;var e=Math.sin(n),o=Math.cos(n),i=Math.sin(a),c=Math.cos(a),h=Math.sin(r),s=Math.cos(r);return t[0]=e*c*s-o*i*h,t[1]=o*i*s+e*c*h,t[2]=o*c*h-e*i*s,t[3]=o*c*s+e*i*h,t},str:function(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},clone:_t,fromValues:Bt,copy:Nt,set:kt,add:Ut,mul:Wt,scale:Ct,dot:Gt,lerp:Ht,length:Jt,len:Kt,squaredLength:$t,sqrLen:tn,normalize:nn,exactEquals:an,equals:rn,rotationTo:un,sqlerp:en,setAxes:on});function hn(t,n,a){var r=.5*a[0],u=.5*a[1],e=.5*a[2],o=n[0],i=n[1],c=n[2],h=n[3];return t[0]=o,t[1]=i,t[2]=c,t[3]=h,t[4]=r*h+u*c-e*i,t[5]=u*h+e*o-r*c,t[6]=e*h+r*i-u*o,t[7]=-r*o-u*i-e*c,t}function sn(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t}var Mn=Nt;var fn=Nt;function ln(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[4],c=a[5],h=a[6],s=a[7],M=n[4],f=n[5],l=n[6],v=n[7],b=a[0],m=a[1],d=a[2],x=a[3];return t[0]=r*x+o*b+u*d-e*m,t[1]=u*x+o*m+e*b-r*d,t[2]=e*x+o*d+r*m-u*b,t[3]=o*x-r*b-u*m-e*d,t[4]=r*s+o*i+u*h-e*c+M*x+v*b+f*d-l*m,t[5]=u*s+o*c+e*i-r*h+f*x+v*m+l*b-M*d,t[6]=e*s+o*h+r*c-u*i+l*x+v*d+M*m-f*b,t[7]=o*s-r*i-u*c-e*h+v*x-M*b-f*m-l*d,t}var vn=ln;var bn=Gt;var mn=Jt,dn=mn,xn=$t,pn=xn;var yn=Object.freeze({create:function(){var t=new a(8);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[4]=0,t[5]=0,t[6]=0,t[7]=0),t[3]=1,t},clone:function(t){var n=new a(8);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n},fromValues:function(t,n,r,u,e,o,i,c){var h=new a(8);return h[0]=t,h[1]=n,h[2]=r,h[3]=u,h[4]=e,h[5]=o,h[6]=i,h[7]=c,h},fromRotationTranslationValues:function(t,n,r,u,e,o,i){var c=new a(8);c[0]=t,c[1]=n,c[2]=r,c[3]=u;var h=.5*e,s=.5*o,M=.5*i;return c[4]=h*u+s*r-M*n,c[5]=s*u+M*t-h*r,c[6]=M*u+h*n-s*t,c[7]=-h*t-s*n-M*r,c},fromRotationTranslation:hn,fromTranslation:function(t,n){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=.5*n[0],t[5]=.5*n[1],t[6]=.5*n[2],t[7]=0,t},fromRotation:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},fromMat4:function(t,n){var r=jt();P(r,n);var u=new a(3);return R(u,n),hn(t,r,u),t},copy:sn,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},set:function(t,n,a,r,u,e,o,i,c){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t},getReal:Mn,getDual:function(t,n){return t[0]=n[4],t[1]=n[5],t[2]=n[6],t[3]=n[7],t},setReal:fn,setDual:function(t,n){return t[4]=n[0],t[5]=n[1],t[6]=n[2],t[7]=n[3],t},getTranslation:function(t,n){var a=n[4],r=n[5],u=n[6],e=n[7],o=-n[0],i=-n[1],c=-n[2],h=n[3];return t[0]=2*(a*h+e*o+r*c-u*i),t[1]=2*(r*h+e*i+u*o-a*c),t[2]=2*(u*h+e*c+a*i-r*o),t},translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=.5*a[0],c=.5*a[1],h=.5*a[2],s=n[4],M=n[5],f=n[6],l=n[7];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=o*i+u*h-e*c+s,t[5]=o*c+e*i-r*h+M,t[6]=o*h+r*c-u*i+f,t[7]=-r*i-u*c-e*h+l,t},rotateX:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Et(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateY:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Ot(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateZ:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Tt(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateByQuatAppend:function(t,n,a){var r=a[0],u=a[1],e=a[2],o=a[3],i=n[0],c=n[1],h=n[2],s=n[3];return t[0]=i*o+s*r+c*e-h*u,t[1]=c*o+s*u+h*r-i*e,t[2]=h*o+s*e+i*u-c*r,t[3]=s*o-i*r-c*u-h*e,i=n[4],c=n[5],h=n[6],s=n[7],t[4]=i*o+s*r+c*e-h*u,t[5]=c*o+s*u+h*r-i*e,t[6]=h*o+s*e+i*u-c*r,t[7]=s*o-i*r-c*u-h*e,t},rotateByQuatPrepend:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*s+o*i+u*h-e*c,t[1]=u*s+o*c+e*i-r*h,t[2]=e*s+o*h+r*c-u*i,t[3]=o*s-r*i-u*c-e*h,i=a[4],c=a[5],h=a[6],s=a[7],t[4]=r*s+o*i+u*h-e*c,t[5]=u*s+o*c+e*i-r*h,t[6]=e*s+o*h+r*c-u*i,t[7]=o*s-r*i-u*c-e*h,t},rotateAroundAxis:function(t,a,r,u){if(Math.abs(u)<n)return sn(t,a);var e=Math.hypot(r[0],r[1],r[2]);u*=.5;var o=Math.sin(u),i=o*r[0]/e,c=o*r[1]/e,h=o*r[2]/e,s=Math.cos(u),M=a[0],f=a[1],l=a[2],v=a[3];t[0]=M*s+v*i+f*h-l*c,t[1]=f*s+v*c+l*i-M*h,t[2]=l*s+v*h+M*c-f*i,t[3]=v*s-M*i-f*c-l*h;var b=a[4],m=a[5],d=a[6],x=a[7];return t[4]=b*s+x*i+m*h-d*c,t[5]=m*s+x*c+d*i-b*h,t[6]=d*s+x*h+b*c-m*i,t[7]=x*s-b*i-m*c-d*h,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t},multiply:ln,mul:vn,scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t},dot:bn,lerp:function(t,n,a,r){var u=1-r;return bn(n,a)<0&&(r=-r),t[0]=n[0]*u+a[0]*r,t[1]=n[1]*u+a[1]*r,t[2]=n[2]*u+a[2]*r,t[3]=n[3]*u+a[3]*r,t[4]=n[4]*u+a[4]*r,t[5]=n[5]*u+a[5]*r,t[6]=n[6]*u+a[6]*r,t[7]=n[7]*u+a[7]*r,t},invert:function(t,n){var a=xn(n);return t[0]=-n[0]/a,t[1]=-n[1]/a,t[2]=-n[2]/a,t[3]=n[3]/a,t[4]=-n[4]/a,t[5]=-n[5]/a,t[6]=-n[6]/a,t[7]=n[7]/a,t},conjugate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t[4]=-n[4],t[5]=-n[5],t[6]=-n[6],t[7]=n[7],t},length:mn,len:dn,squaredLength:xn,sqrLen:pn,normalize:function(t,n){var a=xn(n);if(a>0){a=Math.sqrt(a);var r=n[0]/a,u=n[1]/a,e=n[2]/a,o=n[3]/a,i=n[4],c=n[5],h=n[6],s=n[7],M=r*i+u*c+e*h+o*s;t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=(i-r*M)/a,t[5]=(c-u*M)/a,t[6]=(h-e*M)/a,t[7]=(s-o*M)/a}return t},str:function(t){return"quat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=a[0],f=a[1],l=a[2],v=a[3],b=a[4],m=a[5],d=a[6],x=a[7];return Math.abs(r-M)<=n*Math.max(1,Math.abs(r),Math.abs(M))&&Math.abs(u-f)<=n*Math.max(1,Math.abs(u),Math.abs(f))&&Math.abs(e-l)<=n*Math.max(1,Math.abs(e),Math.abs(l))&&Math.abs(o-v)<=n*Math.max(1,Math.abs(o),Math.abs(v))&&Math.abs(i-b)<=n*Math.max(1,Math.abs(i),Math.abs(b))&&Math.abs(c-m)<=n*Math.max(1,Math.abs(c),Math.abs(m))&&Math.abs(h-d)<=n*Math.max(1,Math.abs(h),Math.abs(d))&&Math.abs(s-x)<=n*Math.max(1,Math.abs(s),Math.abs(x))}});function qn(){var t=new a(2);return a!=Float32Array&&(t[0]=0,t[1]=0),t}function gn(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t}function An(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t}function wn(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t}function Rn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return Math.hypot(a,r)}function zn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return a*a+r*r}function Pn(t){var n=t[0],a=t[1];return Math.hypot(n,a)}function jn(t){var n=t[0],a=t[1];return n*n+a*a}var In=Pn,Sn=gn,En=An,On=wn,Tn=Rn,Dn=zn,Fn=jn,Ln=function(){var t=qn();return function(n,a,r,u,e,o){var i,c;for(a||(a=2),r||(r=0),c=u?Math.min(u*a+r,n.length):n.length,i=r;i<c;i+=a)t[0]=n[i],t[1]=n[i+1],e(t,t,o),n[i]=t[0],n[i+1]=t[1];return n}}(),Vn=Object.freeze({create:qn,clone:function(t){var n=new a(2);return n[0]=t[0],n[1]=t[1],n},fromValues:function(t,n){var r=new a(2);return r[0]=t,r[1]=n,r},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t},set:function(t,n,a){return t[0]=n,t[1]=a,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t},subtract:gn,multiply:An,divide:wn,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t},scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t},scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t},distance:Rn,squaredDistance:zn,length:Pn,squaredLength:jn,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t},normalize:function(t,n){var a=n[0],r=n[1],u=a*a+r*r;return u>0&&(u=1/Math.sqrt(u)),t[0]=n[0]*u,t[1]=n[1]*u,t},dot:function(t,n){return t[0]*n[0]+t[1]*n[1]},cross:function(t,n,a){var r=n[0]*a[1]-n[1]*a[0];return t[0]=t[1]=0,t[2]=r,t},lerp:function(t,n,a,r){var u=n[0],e=n[1];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t},random:function(t,n){n=n||1;var a=2*r()*Math.PI;return t[0]=Math.cos(a)*n,t[1]=Math.sin(a)*n,t},transformMat2:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u,t[1]=a[1]*r+a[3]*u,t},transformMat2d:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u+a[4],t[1]=a[1]*r+a[3]*u+a[5],t},transformMat3:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[3]*u+a[6],t[1]=a[1]*r+a[4]*u+a[7],t},transformMat4:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[4]*u+a[12],t[1]=a[1]*r+a[5]*u+a[13],t},rotate:function(t,n,a,r){var u=n[0]-a[0],e=n[1]-a[1],o=Math.sin(r),i=Math.cos(r);return t[0]=u*i-e*o+a[0],t[1]=u*o+e*i+a[1],t},angle:function(t,n){var a=t[0],r=t[1],u=n[0],e=n[1],o=a*a+r*r;o>0&&(o=1/Math.sqrt(o));var i=u*u+e*e;i>0&&(i=1/Math.sqrt(i));var c=(a*u+r*e)*o*i;return c>1?0:c<-1?Math.PI:Math.acos(c)},zero:function(t){return t[0]=0,t[1]=0,t},str:function(t){return"vec2("+t[0]+", "+t[1]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]},equals:function(t,a){var r=t[0],u=t[1],e=a[0],o=a[1];return Math.abs(r-e)<=n*Math.max(1,Math.abs(r),Math.abs(e))&&Math.abs(u-o)<=n*Math.max(1,Math.abs(u),Math.abs(o))},len:In,sub:Sn,mul:En,div:On,dist:Tn,sqrDist:Dn,sqrLen:Fn,forEach:Ln});t.glMatrix=e,t.mat2=s,t.mat2d=b,t.mat3=q,t.mat4=E,t.quat=cn,t.quat2=yn,t.vec2=Vn,t.vec3=$,t.vec4=Pt,Object.defineProperty(t,"__esModule",{value:!0})});
diff --git a/student2019/201220913/gl-matrix.js b/student2019/201220913/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..a6df8d2611909385c5605b206fe42ae06154d2e1
--- /dev/null
+++ b/student2019/201220913/gl-matrix.js
@@ -0,0 +1,7537 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.0.0
+
+Copyright (c) 2015-2019, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Type} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {mat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {mat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the first operand
+   * @param {mat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the matrix to rotate
+   * @param {vec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {vec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {mat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {mat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {mat2} L the lower triangular matrix
+   * @param {mat2} D the diagonal matrix
+   * @param {mat2} U the upper triangular matrix
+   * @param {mat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the first operand
+   * @param {mat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the first operand
+   * @param {mat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {mat2} a The first matrix.
+   * @param {mat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {mat2} a The first matrix.
+   * @param {mat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {mat2} a the first operand
+   * @param {mat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   *
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, c, tx,
+   *  b, d, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, c, tx,
+   *  b, d, ty,
+   *  0, 0, 1]
+   * </pre>
+   * The last row is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {mat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {mat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the first operand
+   * @param {mat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the matrix to translate
+   * @param {vec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the matrix to translate
+   * @param {vec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {vec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {vec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {mat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {mat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the first operand
+   * @param {mat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the first operand
+   * @param {mat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {mat2d} a the first operand
+   * @param {mat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {mat2d} a The first matrix.
+   * @param {mat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {mat2d} a The first matrix.
+   * @param {mat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {mat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {mat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {mat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the first operand
+   * @param {mat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the matrix to translate
+   * @param {vec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the matrix to rotate
+   * @param {vec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {vec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {vec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+  * Calculates a 3x3 matrix from the given quaternion
+  *
+  * @param {mat3} out mat3 receiving operation result
+  * @param {quat} q Quaternion to create matrix from
+  *
+  * @returns {mat3} out
+  */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+  * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+  *
+  * @param {mat3} out mat3 receiving operation result
+  * @param {mat4} a Mat4 to derive the normal matrix from
+  *
+  * @returns {mat3} out
+  */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {mat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {mat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the first operand
+   * @param {mat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the first operand
+   * @param {mat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {mat3} a the first operand
+   * @param {mat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {mat3} a The first matrix.
+   * @param {mat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {mat3} a The first matrix.
+   * @param {mat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {mat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {mat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the first operand
+   * @param {mat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to translate
+   * @param {vec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to scale
+   * @param {vec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {vec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {vec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {vec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {vec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {quat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {mat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {mat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {mat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {vec3} v Translation vector
+   * @param {vec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {vec3} v Translation vector
+   * @param {vec3} s Scaling vector
+   * @param {vec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {vec3} eye Position of the viewer
+   * @param {vec3} center Point the viewer is looking at
+   * @param {vec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {vec3} eye Position of the viewer
+   * @param {vec3} center Point the viewer is looking at
+   * @param {vec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {mat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {mat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the first operand
+   * @param {mat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the first operand
+   * @param {mat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {mat4} a the first operand
+   * @param {mat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {mat4} a The first matrix.
+   * @param {mat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {mat4} a The first matrix.
+   * @param {mat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {vec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {vec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {vec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @param {vec3} c the third operand
+   * @param {vec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @param {vec3} c the third operand
+   * @param {vec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the vector to transform
+   * @param {mat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the vector to transform
+   * @param {mat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the vector to transform
+   * @param {quat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {vec3} a The vec3 point to rotate
+   * @param {vec3} b The origin of the rotation
+   * @param {Number} c The angle of rotation
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, c) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(c) - p[2] * Math.sin(c);
+    r[2] = p[1] * Math.sin(c) + p[2] * Math.cos(c); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {vec3} a The vec3 point to rotate
+   * @param {vec3} b The origin of the rotation
+   * @param {Number} c The angle of rotation
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, c) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(c) + p[0] * Math.cos(c);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(c) - p[0] * Math.sin(c); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {vec3} a The vec3 point to rotate
+   * @param {vec3} b The origin of the rotation
+   * @param {Number} c The angle of rotation
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, c) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(c) - p[1] * Math.sin(c);
+    r[1] = p[0] * Math.sin(c) + p[1] * Math.cos(c);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {vec3} a The first operand
+   * @param {vec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var tempA = fromValues$4(a[0], a[1], a[2]);
+    var tempB = fromValues$4(b[0], b[1], b[2]);
+    normalize(tempA, tempA);
+    normalize(tempB, tempB);
+    var cosine = dot(tempA, tempB);
+
+    if (cosine > 1.0) {
+      return 0;
+    } else if (cosine < -1.0) {
+      return Math.PI;
+    } else {
+      return Math.acos(cosine);
+    }
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {vec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {vec3} a The first vector.
+   * @param {vec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {vec3} a The first vector.
+   * @param {vec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {vec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {vec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {vec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {vec4} result the receiving vector
+   * @param {vec4} U the first vector
+   * @param {vec4} V the second vector
+   * @param {vec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the vector to transform
+   * @param {mat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the vector to transform
+   * @param {quat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {vec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {vec4} a The first vector.
+   * @param {vec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {vec4} a The first vector.
+   * @param {vec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {vec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {quat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {quat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {quat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {quat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {mat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {quat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {quat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {quat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {quat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {quat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {quat} a The first quaternion.
+   * @param {quat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {quat} a The first vector.
+   * @param {quat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {vec3} a the initial vector
+   * @param {vec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @param {quat} c the third operand
+   * @param {quat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {vec3} view  the vector representing the viewing direction
+   * @param {vec3} right the vector representing the local "right" direction
+   * @param {vec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {quat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {quat2} dual quaternion receiving operation result
+   * @param {quat} q a normalized quaternion
+   * @param {vec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {quat2} dual quaternion receiving operation result
+   * @param {vec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {quat2} dual quaternion receiving operation result
+   * @param {quat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {mat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {quat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {quat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {quat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {quat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {quat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to translate
+   * @param {vec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {quat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat} q quaternion to rotate by
+   * @param {quat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {vec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the first operand
+   * @param {quat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the first operand
+   * @param {quat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {quat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {quat2} a the first operand
+   * @param {quat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {quat2} a the first operand
+   * @param {quat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {quat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {quat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {quat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {quat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return 'quat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ')';
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {quat2} a the first dual quaternion.
+   * @param {quat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {quat2} a the first dual quat.
+   * @param {quat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {vec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {vec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {vec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to transform
+   * @param {mat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to transform
+   * @param {mat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to transform
+   * @param {mat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to transform
+   * @param {mat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {vec2} a The vec2 point to rotate
+   * @param {vec2} b The origin of the rotation
+   * @param {Number} c The angle of rotation
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, c) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(c),
+        cosC = Math.cos(c); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {vec2} a The first operand
+   * @param {vec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1];
+    var len1 = x1 * x1 + y1 * y1;
+
+    if (len1 > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len1 = 1 / Math.sqrt(len1);
+    }
+
+    var len2 = x2 * x2 + y2 * y2;
+
+    if (len2 > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len2 = 1 / Math.sqrt(len2);
+    }
+
+    var cosine = (x1 * x2 + y1 * y2) * len1 * len2;
+
+    if (cosine > 1.0) {
+      return 0;
+    } else if (cosine < -1.0) {
+      return Math.PI;
+    } else {
+      return Math.acos(cosine);
+    }
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {vec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return 'vec2(' + a[0] + ', ' + a[1] + ')';
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {vec2} a The first vector.
+   * @param {vec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {vec2} a The first vector.
+   * @param {vec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git "a/student2019/201220913/\354\273\264\352\267\270-\352\270\260\353\247\220 \355\224\204\353\241\234\354\240\235\355\212\270 \353\263\264\352\263\240\354\204\234.docx" "b/student2019/201220913/\354\273\264\352\267\270-\352\270\260\353\247\220 \355\224\204\353\241\234\354\240\235\355\212\270 \353\263\264\352\263\240\354\204\234.docx"
new file mode 100644
index 0000000000000000000000000000000000000000..35f3bde1038e3016790250dbf67a32e6bbdb7a68
Binary files /dev/null and "b/student2019/201220913/\354\273\264\352\267\270-\352\270\260\353\247\220 \355\224\204\353\241\234\354\240\235\355\212\270 \353\263\264\352\263\240\354\204\234.docx" differ
diff --git a/student2019/201320618/video-texture-master/Readme.md b/student2019/201320618/video-texture-master/Readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..689bd3f2588c9550aaf347bd7e79b46459e4a030
--- /dev/null
+++ b/student2019/201320618/video-texture-master/Readme.md
@@ -0,0 +1,93 @@
+# 컴퓨터 그래픽스 프로젝트 VIDEO-TEXTURE
+<br/>
+
+## 1. 프로젝트 이름 
+* vue-calendar
+<br/><br/>
+
+## 2. 이름
+* 전기홍
+<br/><br/>
+
+## 3. 프로젝트 내용
+### 기능 설명
+    교과목에서 배운 WEBGL 이미지 텍스쳐에서 더욱 나아가 비디오 텍스쳐를 통해 정육면체에 비디오를 삽입하여
+    재생시킬 수 잇는 기능을 만들고 이를 토대로 튜토리얼을 만들어 다른 동료들이 배울 수 있도록 작성하였습니다.
+<br/>
+
+### 기능 개선 목록
+    현재 저가 만들었던 코드 부분에서는 video.src을 이용하여 데이터를 data.url식으로 바꾸어 적용하였습니다.
+    그러나 이러한 부분은 코드 부분에 있어 길고 난해한 코드가 될 수 있다고 생각하엿습니다. 추후, 해당 내용에 대해서
+    공부하여 어떻게 개선점을 만들 수 있을지 생각해 보도록 하겠습니다.
+<br/>
+
+
+## 4. 사용되는 Github 오픈소스 SW 목록
+* 교과 과목에서 사용한 CUBE 코드 사용 
+* BASE 64
+<hr />
+<br/>
+
+<hr />
+
+## 목차 <br/>
+[1. Tutorial](#튜토리얼) <br/>
+[2. 해당 비디오 예시](#비디오 예시) <br />
+[3. Video Texture Cube](#비디오 적용) <br />
+
+## 튜토리얼 <br />
+
+##### 1.video load<br/>
+The first thing we need to do is create a video element to be used to query the video frame in HTML file.
+~~~javascript
+<video id="video_id" src="data_url"></video>
+~~~
+
+In video.src you need to convert your video to a data url via "base64 encoding"!!<br />
+<https://base64.guru/converter/encode/video><br />
+
+##### 2. 비디오 재생 설정 <br/>
+In js file, you need to add addEventListener to handle the event through setInterval() when the video is uploaded.<br/>
+~~~javascript
+	videoElement.addEventListener("canplaythrough",function(){
+		videoElement.play();
+		gl.bindTexture(gl.TEXTURE_2D,texture);
+		gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR);
+		gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);
+		gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);
+		gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);
+		intervalID=setInterval(renderScene,3000);
+	},true);
+
+	videoElement.addEventListener("ended",function(){
+		videoElement.play();
+	},true);
+~~~
+
+##### 3. 비디오 renendering <br/>
+In js file, you need to add updateTexture<br />
+~~~javascript
+function updateTexture(){
+	gl.bindTexture(gl.TEXTURE_2D,texture);
+	gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,true);
+	gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,videoElement);
+}
+~~~
+<hr />
+
+
+##### 비디오 예시 <br />
+I wanna load this video in my texture<br />
+![tutorial_img](./video.png)  <br />
+
+
+<br />
+
+<br/>
+
+##### 비디오 적용 <br />
+You can check the video acting if you choose roate button below!!!<br />
+![tutorial_img](./video_texture.png) <br />
+
+
+
diff --git a/student2019/201320618/video-texture-master/Video Texture/trCube.html b/student2019/201320618/video-texture-master/Video Texture/trCube.html
new file mode 100644
index 0000000000000000000000000000000000000000..947bd6ab552e828be99103b16afd79d61a2a057b
--- /dev/null
+++ b/student2019/201320618/video-texture-master/Video Texture/trCube.html	
@@ -0,0 +1,111 @@
+<html>
+<head>
+<title>Video Texture</title>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+		.collapsible {
+		  background-color: #777;
+		  color: white;
+		  cursor: pointer;
+		  padding: 18px;
+		  width: 100%;
+		  border: none;
+		  text-align: left;
+		  outline: none;
+		  font-size: 15px;
+		}
+
+		
+		.active, .collapsible:hover {
+		  background-color: #555;
+		}
+		
+		.content {
+		  padding: 0 18px;
+		  max-height: 0;
+		  overflow: hidden;
+		  transition: max-height 0.2s ease-out;
+		  background-color: #f1f1f1;
+		}
+</style>
+<script type="text/javascript" src="trCube.js">		
+</script>
+</head>
+
+
+<body onload="main()">
+	<h1>WEBGL Video Texture</h1>
+	<div>
+		<p>
+		I made a process of putting an image on the face of a 3D cube and a video insertion process. As an example, let's use a texture instead of solid color on each side of the cube.</p>
+	</div>
+
+	<button class="collapsible">video load</button>
+	<p>The first thing we need to do is create a video element to be used to query the video frame in HTML file.</p>
+	<div style="color:black; background-color:white; border:1px solid black;">
+			<p><.video id="video_id" src="data_url"><./video></p>
+	</div>
+	<p></p>
+	<b>In video.src you need to convert your video to a data url via "base64 encoding"!!</b>
+	<p></p>
+	<a href="https://base64.guru/converter/encode/video">Connect Base64 Server</a>
+	<p></p>
+
+	<button class="collapsible">
+			In js file, you need to add addEventListener to handle the event through setInterval() when the video is uploaded.</button><p></p>
+	<div style="color:black; background-color:white; border:1px solid black;">
+			<p><.videoElement.addEventListener("canplaythrough",function(){ </p>
+				<p>	videoElement.play();</p>
+				<p>gl.bindTexture(gl.TEXTURE_2D,texture);</p>
+
+				<p>gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR);</p>
+				<p>gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);</p>
+				<p>gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);</p>
+				<p>gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);</p>
+				<p>intervalID=setInterval(renderScene,15);</p>
+			<p>},true);</p>
+		
+		
+			<p></p>
+			<p>videoElement.addEventListener("ended",function(){</p>
+				<p>clearInterval(intervalID);</p>
+				<p>},true);</p>
+	</div>
+
+	<button class="collapsible">
+			In js file, you need to add updateTexture</button><p></p>
+	<p>The updateTexture () function to update the most important texture is.</p>
+	<div style="color:black; background-color:white; border:1px solid black;">
+			<p>function updateTexture(){</p>
+				<p>gl.bindTexture(gl.TEXTURE_2D,texture);</p>
+				<p>gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,true);</p>
+				<p>gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,videoElement);</p>
+			
+						<p>	}</p>
+	
+	</div>
+
+	<button class="collapsible">
+			Example</button><p></p>
+	</button>
+
+	<p>I wanna load this video in my texture </p>
+
+	<video id="video" src="data:video/mp4;base64,AAAAGGZ0eXBtcDQyAAAAAGlzb21tcDQyAAAIYG1vb3YAAABsbXZoZAAAAADZH9852R/fOQAAA+gAAArLAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAOhdHJhawAAAFx0a2hkAAAAA9kf3znZH985AAAAAQAAAAAAAAqMAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAIcAAABaAAAAAADPW1kaWEAAAAgbWRoZAAAAADZH9852R/fOQAAPAAAAKIAVcQAAAAAAF9oZGxyAAAAAAAAAAB2aWRlAAAAAAAAAAAAAAAASVNPIE1lZGlhIGZpbGUgcHJvZHVjZWQgYnkgR29vZ2xlIEluYy4gQ3JlYXRlZCBvbjogMDYvMDcvMjAxOS4AAAACtm1pbmYAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAJ2c3RibAAAAJZzdHNkAAAAAAAAAAEAAACGYXZjMQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAIcAWgASAAAAEgAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj//wAAADBhdmNDAULAHv/hABlnQsAe2gIgv7lwEQAAAwABAAADADwPFi6gAQAEaM48gAAAABhzdHRzAAAAAAAAAAEAAABRAAACAAAAAChzdHNjAAAAAAAAAAIAAAABAAAADwAAAAEAAAAGAAAABgAAAAEAAAAoc3RjbwAAAAAAAAAGAAAIgAAAU+wAAKwfAAD/8QABTxIAAbmtAAABWHN0c3oAAAAAAAAAAAAAAFEAAAppAAABbQAAAT4AAAFDAAABJgAAAWMAAAGEAAABpwAAC7MAAAN3AAADJgAAAsIAAANHAAADhQAABKgAAAUbAAAGKAAAA0wAAANRAAADiAAAA3YAAANmAAAC/QAAA1AAAANOAAAGEwAABVoAAAVMAAAErwAABhEAAAaNAAAH3QAACloAAANIAAADfgAAA2sAAANsAAADSgAAA1AAAAMyAAAEZAAAAigAAAJPAAACHQAAAdEAAAIJAAAB9gAAAh0AAAIjAAAE3gAABQIAAAQkAAADZAAAA7MAAAO2AAAEkgAABKkAAAUNAAAE9wAAA/cAABMKAAAD0gAABGgAAATfAAAFMAAABXYAAAVMAAAFygAABUoAAAVfAAAF2QAABaUAAAd3AAAALQAAABUAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAYc3RzcwAAAAAAAAACAAAAAQAAAD0AAAAUdm1oZAAAAAEAAAAAAAAAAAAAA/B0cmFrAAAAXHRraGQAAAAD2R/fOdkf3zkAAAACAAAAAAAACssAAAAAAAAAAAAAAAABAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAOMbWRpYQAAACBtZGhkAAAAANkf3znZH985AACsRAAB3ABVxAAAAAAAX2hkbHIAAAAAAAAAAHNvdW4AAAAAAAAAAAAAAABJU08gTWVkaWEgZmlsZSBwcm9kdWNlZCBieSBHb29nbGUgSW5jLiBDcmVhdGVkIG9uOiAwNi8wNy8yMDE5LgAAAAMFbWluZgAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAslzdGJsAAAAaXN0c2QAAAAAAAAAAQAAAFltcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADVlc2RzAAAAAAMnAAIABB9AFQAAAAAAAAAAAAAABRASEAAAAAAAAAAAAAAAAAAABgECAAAAGHN0dHMAAAAAAAAAAQAAAHcAAAQAAAAAKHN0c2MAAAAAAAAAAgAAAAEAAAAVAAAAAQAAAAYAAAAOAAAAAQAAAChzdGNvAAAAAAAAAAYAAD0RAACVRAAA6RUAATg3AAGi0QABug0AAAHwc3RzegAAAAAAAAAAAAAAdwAAARYAAAEXAAABFgAAARcAAAEXAAABFgAAARcAAAEXAAABFgAAARcAAAEXAAABFgAAARcAAAEWAAABFwAAARcAAAEWAAABFwAAARcAAAEWAAABFwAAARcAAAEWAAABFwAAARYAAAEXAAABFwAAARYAAAEXAAABFwAAARYAAAEXAAABFwAAARYAAAEXAAABFwAAARYAAAEXAAABFgAAARcAAAEXAAABFgAAARcAAAEXAAABFgAAARcAAAEXAAABFgAAARcAAAEWAAABFwAAARcAAAEWAAABFwAAARcAAAEWAAABFwAAARcAAAEWAAABFwAAARcAAAEWAAABFwAAARYAAAEXAAABFwAAARYAAAEXAAABFwAAARYAAAEXAAABFwAAARYAAAEXAAABFgAAARcAAAEXAAABFgAAARcAAAEXAAABFgAAARcAAAEXAAABFgAAARcAAAEWAAABFwAAARcAAAEWAAABFwAAARcAAAEWAAABFwAAARcAAAEWAAABFwAAARcAAAEWAAABFwAAARYAAAEXAAABFwAAARYAAAEXAAABFwAAARYAAAEXAAABFwAAARYAAAEXAAABFgAAARcAAAEXAAABFgAAARcAAAEXAAABFgAAARcAAAEXAAAAEHNtaGQAAAAAAAAAAAAAAFt1ZHRhAAAAU21ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAJmlsc3QAAAAeqXRvbwAAABZkYXRhAAAAAQAAAABHb29nbGUAAcDSbWRhdAAAADIGBS7cRem95tlIt5Ys2CDZI+7veDI2NCAtIGNvcmUgMTU1IHIyOTAxIDdkMGZmMjIAgAAACi9liIR//8fuKAAICH3999x4ZZYnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJ///wQAgwuH2++++++++++++++++++++++++++++++++///+HguWfcXffffffffffffffffffffffffffffffffXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX//kZYwEXAKA0ZAkvxwCEWxDE22CLghDIA5CvQ/6jrU91Au7x7kX4koAnoasjr8aRMV34nD9N//1sDIIWccK7Mhjx8RbHq5XGkrfQpav/qvVK6T2QFo+k8kzTCboaSO6fAM9xWPRdtDTG7ghKBgs3i+z/pT8EAvgMwDJYr2feoZrrrrrrrrrrrrrrrrjoeAARkRmZERGZkR//8AO42OhFL6f+7oPhUwCR635ATF/ziyWE64j1jOPZOWsWY8VzUL/1XqcKwEl+n5ubSzKA2+YBX3GnHqCeuuuuuuuuv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4//8PArf/n/8PhKAf45rrffgqJ//w8GgYYaa6xvXUFtdddddddddddddddfa1ptD9go4CEcgQqD1UcKReOh7snLly8N+z0g+nQUnRZQ//w8Cnn/NF/Ph8Ek5vtr8Az2hVVNPT/CcEHxxZhzpn03+BH/OIcQZkwoJa66666666gsP1BbXXXXXXXXXXXXXXXXXXX///CQYNxxMej6hm+vXXXXXXXXXo2H/4eBQBL7DxmVobWv/9QU36N//w8CgAY6kNb6nr+36gprrrrrrrrrrrrrrrr/9G28EAKoEaRiLn/UFdeH9GH8EAKgFa3JYQ9vZ+oK66//4/BAHsUAd9999999999999999999999999y33x8v/yaTcmk1999///8PBcV9999999999999999999999999999999999dddddddddddddddddddddddddddddddddeAAAAFpQZoj+MxMIwCKwc+Dnwd+DlMEGNDEwksCETXlsIZfSBwHgQiRZf7Lm1YMrCYJ/C/T4TfyQPmKL/L/uE38h4RiT+I6degaa4OfBzjj+X/+Q/FMCD62JBERlCIzBEZgiMwXhOa9gSDGTFxf3HgQkA4g4gjsCRjUBGfugIlkW/coscXgIwNIeHYmDnQnwnDAymENEhovQ0SGi/yCg8wb/goCEfJ2X0YO3/4eCYOOuLFpAQPEHhGlgRNcSCYi8EReCIvBEbhH2f+QLw7D9ejYf0/BAEcIcTHPzP6P1rN/6fhMVvwAMQ016a8GEPWbrGICzBzqDACdwcqEPVY25AQPfg44mCvXwh+iUI6E8UeCwy6PBXngqMuEPm8P/w+FQP5Mfwfa4oQhsaGddDeuh0c8EMVBzuDnn4QeD/n7PwQLvEcuFMR4jxHiPEeI8R4jxHiPEeI8R4jxHiPEeI8R4jxHiPEeI8R4jxHiObwRQAAAATpBmkBf4GD///////////////////////////wHqeJ4OfBz4OevhCBG6yk1+fiz8luEMlvAgYs/676tfsPDaD4Q7EDSZ9jwtjr781NARFO4Ocf44KwT//+OovkBIUU11FU6dORTXFzUfPH04EixowB/8bAjRAQl2QUDs1OBfZc2VyWIH6ligtlixEEtn97x4j5ZARD+P+zDGNpjmAMP/w+CEBwbKmDgAap7PExMHcwJJWDM9J9aIYimRTCPo8J3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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAweiEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAdSEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAcCEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBwIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB1IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIBwIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMH0hEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHYhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHIhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwcyEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAdSEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBzIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB+IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB6IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHchEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHohEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADB1IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB1IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMH4hEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHohEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgH8hEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAweyEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAdSEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAcSEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADB+IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB9IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIBzIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHEhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHMhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHwhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAweiEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAeCEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADB+IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIBxIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIBzIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHkAAAaJQZvAJ8Ag4Tgg//8AMh+mWnyN//ukKm4Abbel5jfZDoEb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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwfiEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAcSEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAeyEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADB+IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB9IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHYhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHQhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHIhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwdyEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAciEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAfCEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADB+IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB/IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIByIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHEhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHEhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBwIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIByIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB2IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHshEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHAhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHwhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwfyEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAfCEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAeiEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADB6IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB8IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHAhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHIhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHkhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwcSEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAdyEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAeyEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADB/IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB8IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB2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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHEhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHMhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAweiEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAfCEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAfiEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADByIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB7IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB9IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHwhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHohEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHshEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwfiEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAcSEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADB1IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB4IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB0IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHEhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHEhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHEAAAAMQZvgJ8AwwjD2WAMTAAAADEGaACfAMMIw9lgDEwAAAAxBmiAnwDDCMPZYAxMAAAAMQZpAJ8AwwjD2WAMTAAAADEGaYCfAMMIw9lgDEwAAAAxBmoAjwDDCMPZYAxMhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwdCEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAdCEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAcCEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADB0IRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIBwIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHUhEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgHohEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgH8hEAUAoBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwfSEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAfiEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCAeiEQBQCgG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBzIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIBxIRAFAKAb/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIB2" autoplay="true" muted="muted">
+		Your browser doesn't appear to support the HTML5 <code>&lt;video&gt;</code> element.
+	</video>
+
+	<button class="collapsible">
+			Video Texture Example</button><p></p>
+	</button>
+
+	<p>You can check the video acting if you choose roate button below!!!</p>
+	
+	<p></p>
+    <canvas id="helloapicanvas" style="border: none;" width="400" height="400"></canvas>
+	<br>
+	<button onclick="trXinc()">Translate X + 0.1</button>
+	<button onclick="animRotate()">Animation Rotate + 0.01</button>
+	<button onclick="stopRotate()">Stop Rotate</button>
+</body>
+</html>
diff --git a/student2019/201320618/video-texture-master/Video Texture/trCube.js b/student2019/201320618/video-texture-master/Video Texture/trCube.js
new file mode 100644
index 0000000000000000000000000000000000000000..200ed05bcda822b30ad50e69556884323324eee4
--- /dev/null
+++ b/student2019/201320618/video-texture-master/Video Texture/trCube.js	
@@ -0,0 +1,474 @@
+//(CC-NC-BY) Jeon Gi Hong 2019
+
+var gl;
+
+function testGLError(functionLastCalled) {
+
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+ // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+
+    return true;
+}
+
+function updateTexture(){
+	gl.bindTexture(gl.TEXTURE_2D,texture);
+	gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,true);
+	gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,videoElement);
+
+}
+
+var shaderProgram;
+var texture;
+var videoElement;
+
+function initialiseBuffer() {
+
+	// Create a texture.
+	texture = gl.createTexture();
+	videoElement=document.getElementById("video");
+
+	gl.bindTexture(gl.TEXTURE_2D, texture);
+	// Fill the texture with a 1x1 blue pixel.
+	gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
+		new Uint8Array([0, 0, 255, 255]));	
+	
+
+	var intervalID;
+
+	//VIDEO 나타났을 때 시작
+	videoElement.addEventListener("canplaythrough",function(){
+		videoElement.play();
+		gl.bindTexture(gl.TEXTURE_2D,texture);
+		gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR);
+		gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);
+		gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);
+		gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);
+		intervalID=setInterval(renderScene,3000);
+	},true);
+
+
+	//비디오 끝났을 때 종료
+	videoElement.addEventListener("ended",function(){
+		videoElement.play();
+	},true);
+
+    var vertexData = [
+		-0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		0.0, 1.0,  0.0, 1.0, 0.0, //3
+        0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		1.0, 1.0,  0.0, 1.0, 0.0, //1
+		0.5, 0.5, -0.5,		1.0, 1.0, 1.0, 0.5,		1.0, 1.0,  0.0, 1.0, 0.0, //2
+				
+		-0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		0.0, 1.0,  0.0, 1.0, 0.0, //3
+		0.5, 0.5, -0.5,		1.0, 1.0, 1.0, 0.5,		1.0, 1.0,  0.0, 1.0, 0.0, //2
+		-0.5, 0.5, -0.5,	1.0, 1.0, 1.0, 0.5,		0.0, 1.0,  0.0, 1.0, 0.0, //4
+		 
+		0.5, 0.5, -0.5,		0.0, 0.0, 0.0, 0.5,		1.0, 1.0,  0.0, 0.0, -1.0, //2
+		0.5, -0.5, -0.5,	0.0, 0.0, 0.0, 0.5,		1.0, 0.0,  0.0, 0.0, -1.0, //6
+		-0.5,-0.5,-0.5,		0.0, 0.0, 0.0, 0.5,		0.0, 0.0,  0.0, 0.0, -1.0, //8
+		   
+		-0.5, 0.5, -0.5,	0.0, 0.0, 0.0, 0.5,		0.0, 1.0,  0.0, 0.0, -1.0, //4
+		0.5, 0.5, -0.5,		0.0, 0.0, 0.0, 0.5,		1.0, 1.0,  0.0, 0.0, -1.0, //2
+		-0.5,-0.5,-0.5,		0.0, 0.0, 0.0, 0.5,		0.0, 0.0,  0.0, 0.0, -1.0, //8
+			
+		0.5, -0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		0.0, 1.0,  1.0, 0.0, 0.0, //5
+		0.5, -0.5, -0.5,	1.0, 0.5, 0.0, 0.5,		0.0, 1.0,  1.0, 0.0, 0.0, //6
+		0.5, 0.5, -0.5,		1.0, 0.5, 0.0, 0.5,		1.0, 1.0,  1.0, 0.0, 0.0, //2
+
+		0.5, -0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		0.0, 1.0,  1.0, 0.0, 0.0, //5
+		0.5, 0.5, -0.5,		1.0, 0.5, 0.0, 0.5,		1.0, 1.0,  1.0, 0.0, 0.0, //2
+		0.5, 0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		1.0, 1.0,  1.0, 0.0, 0.0, //1
+				 
+		-0.5, 0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 1.0,  -1.0, 0.0, 0.0, //4
+		-0.5,-0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 0.0,  -1.0, 0.0, 0.0, //8
+		-0.5, -0.5, 0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 0.0,  -1.0, 0.0, 0.0, //7
+		
+		-0.5, 0.5, 0.5,		1.0, 0.0, 0.0, 0.5,		0.0, 1.0, -1.0, 0.0, 0.0, //3
+		-0.5, 0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 1.0, -1.0, 0.0, 0.0, //4
+		-0.5, -0.5, 0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 0.0, -1.0, 0.0, 0.0, //7
+		
+		-0.5, -0.5, 0.5,	0.0, 0.0, 1.0, 0.5,		0.0, 1.0, 1.0, 2.0, 2.0, //7
+		0.5, -0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		0.0, 1.0, 1.0, -1.0, 2.0, //5
+		0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		0.0, 1.0, 1.0, 2.0, -1.0, //1
+				 
+		-0.5, -0.5, 0.5,	0.0, 0.0, 1.0, 0.5,		0.0, 1.0, 1.0, 1.0, 1.0, //7
+		0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		0.0, 1.0, 1.0, 0.0, 0.0, //1
+		-0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		0.0, 1.0, 1.0, 1.0, 0.0, //3
+		
+		 0.5, -0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		1.0, 0.0, 0.0, -1.0, 0.0, //6
+		 0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		1.0, 0.0, 0.0, -1.0, 0.0, //5
+		-0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		0.0, 0.0, 0.0, -1.0, 0.0, //7
+		
+		-0.5,-0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		0.0, 0.0, 0.0, -1.0, 0.0, //8
+		 0.5, -0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		1.0, 0.0, 0.0, -1.0, 0.0, //6
+		-0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		0.0, 0.0, 0.0, -1.0, 0.0, //7
+    ];
+	
+    // Generate a buffer object
+    gl.vertexBuffer = gl.createBuffer();
+    // Bind buffer as a vertex buffer so we can fill it with data
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+	varying mediump vec4 color; \
+	varying mediump vec2 texCoord;\
+	uniform sampler2D sampler2d; \
+	void main(void) \
+	{ \
+		gl_FragColor = texture2D(sampler2d, texCoord); \
+	}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    var vertexShaderSource = '\
+			attribute highp vec3 myVertex; \
+			attribute highp vec4 myColor; \
+			attribute highp vec2 myUV; \
+			attribute highp vec3 myNormal; \
+			uniform mediump mat4 Pmatrix; \
+			uniform mediump mat4 Vmatrix; \
+			uniform mediump mat4 Mmatrix; \
+			uniform mediump mat4 Nmatrix; \
+			varying mediump vec4 color; \
+			varying mediump vec2 texCoord;\
+			void main(void)  \
+			{ \
+				gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(myVertex, 1.0);\
+				color = myColor;\
+				texCoord = myUV; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    gl.programObject = gl.createProgram();
+
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+	gl.bindAttribLocation(gl.programObject, 2, "myUV");
+
+    // Link the program
+    gl.linkProgram(gl.programObject);
+
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+
+    return testGLError("initialiseShaders");
+}
+
+// FOV, Aspect Ratio, Near, Far 
+function get_projection(angle, a, zMin, zMax) {
+    var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
+    return [
+    	0.5/ang, 0 , 0, 0,
+        0, 0.5*a/ang, 0, 0,
+        0, 0, -(zMax+zMin)/(zMax-zMin), -1,
+        0, 0, (-2*zMax*zMin)/(zMax-zMin), 0 ];
+}
+			
+var proj_matrix = get_projection(30, 1.0, 1, 8.0);
+var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+// translating z
+view_matrix[14] = view_matrix[14]-4;//zoom
+
+function idMatrix(m) {
+    m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 0; 
+    m[4] = 0; m[5] = 1; m[6] = 0; m[7] = 0; 
+    m[8] = 0; m[9] = 0; m[10] = 1; m[11] = 0; 
+    m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; 
+}
+
+function mulStoreMatrix(r, m, k) {
+    m0=m[0];m1=m[1];m2=m[2];m3=m[3];m4=m[4];m5=m[5];m6=m[6];m7=m[7];
+    m8=m[8];m9=m[9];m10=m[10];m11=m[11];m12=m[12];m13=m[13];m14=m[14];m15=m[15];
+    k0=k[0];k1=k[1];k2=k[2];k3=k[3];k4=k[4];k5=k[5];k6=k[6];k7=k[7];
+    k8=k[8];k9=k[9];k10=k[10];k11=k[11];k12=k[12];k13=k[13];k14=k[14];k15=k[15];
+
+    a0 = k0 * m0 + k3 * m12 + k1 * m4 + k2 * m8;
+    a4 = k4 * m0 + k7 * m12 + k5 * m4 + k6 * m8 ;
+    a8 = k8 * m0 + k11 * m12 + k9 * m4 + k10 * m8 ;
+    a12 = k12 * m0 + k15 * m12 + k13 * m4 + k14 * m8;
+
+    a1 = k0 * m1 + k3 * m13 + k1 * m5 + k2 * m9;
+    a5 = k4 * m1 + k7 * m13 + k5 * m5 + k6 * m9;
+    a9 = k8 * m1 + k11 * m13 + k9 * m5 + k10 * m9;
+    a13 = k12 * m1 + k15 * m13 + k13 * m5 + k14 * m9;
+
+    a2 = k2 * m10 + k3 * m14 + k0 * m2 + k1 * m6;
+    a6 =  k6 * m10 + k7 * m14 + k4 * m2 + k5 * m6;
+    a10 =  k10 * m10 + k11 * m14 + k8 * m2 + k9 * m6;
+    a14 = k14 * m10 + k15 * m14 + k12 * m2 + k13 * m6; 
+
+    a3 = k2 * m11 + k3 * m15 + k0 * m3 + k1 * m7;
+    a7 = k6 * m11 + k7 * m15 + k4 * m3 + k5 * m7;
+    a11 = k10 * m11 + k11 * m15 + k8 * m3 + k9 * m7;
+    a15 = k14 * m11 + k15 * m15 + k12 * m3 + k13 * m7;
+
+    r[0]=a0; r[1]=a1; r[2]=a2; r[3]=a3; r[4]=a4; r[5]=a5; r[6]=a6; r[7]=a7;
+    r[8]=a8; r[9]=a9; r[10]=a10; r[11]=a11; r[12]=a12; r[13]=a13; r[14]=a14; r[15]=a15;
+}
+
+function mulMatrix(m,k)
+{
+	mulStoreMatrix(m,m,k);
+}
+
+function translate(m, tx,ty,tz) {
+   var tm = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; 
+   tm[12] = tx; tm[13] = ty; tm[14] = tz; 
+   mulMatrix(m, tm); 
+}
+
+
+function rotateX(m, angle) {
+	var rm = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; 
+    var c = Math.cos(angle);
+    var s = Math.sin(angle);
+
+	rm[5] = c;  rm[6] = s; 
+	rm[9] = -s;  rm[10] = c;
+	mulMatrix(m, rm); 
+}
+
+function rotateY(m, angle) {
+	var rm = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; 
+    var c = Math.cos(angle);
+    var s = Math.sin(angle);
+
+	rm[0] = c;  rm[2] = -s;
+	rm[8] = s;  rm[10] = c; 
+	mulMatrix(m, rm); 
+}
+
+function rotateZ(m, angle) {
+	var rm = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; 
+    var c = Math.cos(angle);
+    var s = Math.sin(angle);
+
+	rm[0] = c;  rm[1] = s;
+	rm[4] = -s;  rm[5] = c; 
+	mulMatrix(m, rm); 
+}
+
+function scale(m, sx,sy,sz) {
+	var rm = [sx,0,0,0, 0,sy,0,0, 0,0,sz,0, 0,0,0,1]; 
+	mulMatrix(m, rm); 
+}
+
+function normalizeVec3(v)
+{
+	sq = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; 
+	sq = Math.sqrt(sq);
+	if (sq < 0.000001 ) // Too Small
+		return -1; 
+	v[0] /= sq; v[1] /= sq; v[2] /= sq; 
+}
+
+function rotateArbAxis(m, angle, axis)
+{
+	var axis_rot = [0,0,0];
+	var ux, uy, uz;
+	var rm = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; 
+    var c = Math.cos(angle);
+	var c1 = 1.0 - c; 
+    var s = Math.sin(angle);
+	axis_rot[0] = axis[0]; 
+	axis_rot[1] = axis[1]; 
+	axis_rot[2] = axis[2]; 
+	if (normalizeVec3(axis_rot) == -1 )
+		return -1; 
+	ux = axis_rot[0]; uy = axis_rot[1]; uz = axis_rot[2];
+	console.log("Log", angle);
+	rm[0] = c + ux * ux * c1;
+	rm[1] = uy * ux * c1 + uz * s;
+	rm[2] = uz * ux * c1 - uy * s;
+	rm[3] = 0;
+
+	rm[4] = ux * uy * c1 - uz * s;
+	rm[5] = c + uy * uy * c1;
+	rm[6] = uz * uy * c1 + ux * s;
+	rm[7] = 0;
+
+	rm[8] = ux * uz * c1 + uy * s;
+	rm[9] = uy * uz * c1 - ux * s;
+	rm[10] = c + uz * uz * c1;
+	rm[11] = 0;
+
+	rm[12] = 0;
+	rm[13] = 0;
+	rm[14] = 0;
+	rm[15] = 1;
+
+	mulMatrix(m, rm);
+}
+
+rotValue = 0.0; 
+rotValueSmall = 0.0; 
+incRotValue = 0.0;
+incRotValueSmall = 0.02; 
+
+transX = 0.0;
+frames = 1;
+tempRotValue = 0.0; 
+function stopRotate()
+{
+	if (incRotValue == 0.0)
+	{
+		incRotValue = tempRotValue; 
+	}
+	else
+	{
+		tempRotValue = incRotValue; 
+		incRotValue = 0.0; 
+	}
+}
+
+function animRotate()
+{
+	incRotValue += 0.01;
+}
+
+function trXinc()
+{
+	transX += 0.01;
+	document.getElementById("webTrX").innerHTML = "transX : " + transX.toFixed(4);
+}
+
+function renderScene() {
+
+	updateTexture();
+    //console.log("Frame "+frames+"\n");
+    frames += 1 ;
+	rotAxis = [1,1,0];
+
+    var Pmatrix = gl.getUniformLocation(gl.programObject, "Pmatrix");
+    var Vmatrix = gl.getUniformLocation(gl.programObject, "Vmatrix");
+    var Mmatrix = gl.getUniformLocation(gl.programObject, "Mmatrix");
+    var Nmatrix = gl.getUniformLocation(gl.programObject, "Nmatrix");
+	
+    idMatrix(mov_matrix); 
+	rotateArbAxis(mov_matrix, rotValue, rotAxis);
+    rotValue += incRotValue; 
+	rotValueSmall += incRotValueSmall;
+    translate(mov_matrix, transX, 0.0, 0.0); 
+
+    gl.uniformMatrix4fv(Pmatrix, false, proj_matrix);
+    gl.uniformMatrix4fv(Vmatrix, false, view_matrix);
+    gl.uniformMatrix4fv(Mmatrix, false, mov_matrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 48, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 48, 12);
+	gl.enableVertexAttribArray(2);
+    gl.vertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 48, 28);
+	gl.enableVertexAttribArray(3);
+    gl.vertexAttribPointer(3, 3, gl.FLOAT, gl.FALSE, 48, 36);
+
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+    gl.enable(gl.DEPTH_TEST);
+    gl.depthFunc(gl.LEQUAL); 
+	// gl.enable(gl.CULL_FACE);
+	gl.enable(gl.BLEND);
+	gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+	gl.blendEquation(gl.FUNC_ADD);
+
+    gl.clearColor(0.6, 0.8, 1.0, 1.0);
+    gl.clearDepth(1.0); 
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+	
+	gl.drawArrays(gl.TRIANGLES, 0, 36);
+	
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+	var canvas = document.getElementById("helloapicanvas");
+
+    console.log("Start");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+    // Render loop
+    requestAnimFrame = (
+	function () {
+        //	return window.requestAnimationFrame || window.webkitRequestAnimationFrame 
+	//	|| window.mozRequestAnimationFrame || 
+	   	return function (callback) {
+			    // console.log("Callback is"+callback); 
+			    window.setTimeout(callback, 10, 10); };
+    })();
+
+    (function renderLoop(param) {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/student2019/201320618/video-texture-master/video.png b/student2019/201320618/video-texture-master/video.png
new file mode 100644
index 0000000000000000000000000000000000000000..243dca74910e9d20a5b3383c32ee988c34ec15c8
Binary files /dev/null and b/student2019/201320618/video-texture-master/video.png differ
diff --git a/student2019/201320618/video-texture-master/video_texture.png b/student2019/201320618/video-texture-master/video_texture.png
new file mode 100644
index 0000000000000000000000000000000000000000..dc5586c0731b0efa001ce413e2f2cddef590c1e1
Binary files /dev/null and b/student2019/201320618/video-texture-master/video_texture.png differ
diff --git a/student2019/201421044/Final_Project b/student2019/201421044/Final_Project
new file mode 160000
index 0000000000000000000000000000000000000000..e21815064c18d90d4dafcec5abdf71e95a5f2589
--- /dev/null
+++ b/student2019/201421044/Final_Project
@@ -0,0 +1 @@
+Subproject commit e21815064c18d90d4dafcec5abdf71e95a5f2589
diff --git a/student2019/201421109/cg_project b/student2019/201421109/cg_project
new file mode 160000
index 0000000000000000000000000000000000000000..c71eb4c9d1f6781035246a9d47045d4977f63bac
--- /dev/null
+++ b/student2019/201421109/cg_project
@@ -0,0 +1 @@
+Subproject commit c71eb4c9d1f6781035246a9d47045d4977f63bac
diff --git a/student2019/201520510/webgl-tutorial-master/README.md b/student2019/201520510/webgl-tutorial-master/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..28df9f86df8bc4e5448799eca0f3fdc966340845
--- /dev/null
+++ b/student2019/201520510/webgl-tutorial-master/README.md
@@ -0,0 +1,198 @@
+# WebGL Tutorial - Transparent WebGL content on top of other HTML elements
+
+## Objectives
+Users should, at the end of the tutorial, be able to:
+*  Write out the basic skeleton of an HTML page.
+* Write CSS and use it to add styling to a basic page.
+* Render Transparent WebGL content on top of other HTML elements
+
+## Overview
+
+### HTML
+HTML defines the structure and content of information on the page.
+
+All HTML pages have the same basic structure:
+
+```
+  <!DOCTYPE html>
+  <html>
+    <head>
+    <!-- Meta-data goes here. -->
+    </head>
+    <body>
+      <!-- Page content goes here. -->
+    </body>
+  </html>
+```
+HTML tags generally come in matched pairs, with the format `<tag> ... </tag>`.
+
+The first tag is called the opening tag, while the second is called the closing tag.
+
+#### `<head>`
+The ``<head>`` element is a container for all the head elements.
+
+The ``<head>`` element can include a title for the document, scripts, styles, meta information, and more.
+
+
+#### ``<title>``
+*  defines a title in the browser toolbar
+*  provides a title for the page when it is added to favorites
+*  displays a title for the page in search-engine results
+
+
+#### ``<meta>``
+The <meta> tag provides metadata about the HTML document. Metadata will not be displayed on the page, but will be machine parsable.
+
+Meta elements are typically used to specify page description, keywords, author of the document, last modified, and other metadata.
+
+The metadata can be used by browsers (how to display content or reload page), search engines (keywords), or other web services.
+
+#### ``<script>``
+The ``<script>`` tag is used to define a client-side script (JavaScript).
+
+The ``<script>`` element either contains scripting statements, or it points to an external script file through the src attribute.
+
+
+#### ``<link>``
+The ``<link>`` tag defines a link between a document and an external resource.
+
+The ``<link>`` tag is used to link to external style sheets.
+
+#### ``<body>``
+The ``<body>`` tag defines the document's body.
+
+The ``<body>`` element contains all the contents of an HTML document, such as text, hyperlinks, images, tables, lists, etc.
+
+#### ``<h1>`` to ``<h6>``
+The ``<h1>`` to ``<h6>`` tags are used to define HTML headings.
+
+``<h1>`` defines the most important heading. ``<h6>`` defines the least important heading.
+
+#### ``<pre>``
+The ``<pre>`` tag defines preformatted text.
+
+Text in a ``<pre>`` element is displayed in a fixed-width font (usually Courier), and it preserves both spaces and line breaks.
+
+#### ``<canvas>``
+The ``<canvas>`` tag is used to draw graphics, on the fly, via scripting (usually JavaScript).
+
+The ``<canvas>`` tag is only a container for graphics, you must use a script to actually draw the graphics.
+
+
+#### ``<p>``
+The ``<p>`` tag defines a paragraph.
+
+Browsers automatically add some space (margin) before and after each <p> element. The margins can be modified with CSS (with the margin properties).
+
+- - -
+
+### CSS
+CSS is a language that describes the style of an HTML document.
+
+CSS describes how HTML elements should be displayed.
+
+```
+body {
+  background-color: lightblue;
+}
+
+h1 {
+  color: white;
+  text-align: center;
+}
+
+p {
+  font-family: verdana;
+  font-size: 20px;
+}
+```
+
+#### CSS Pading
+The CSS padding properties are used to generate space around an element's content, inside of any defined borders.
+
+With CSS, you have full control over the padding. There are properties for setting the padding for each side of an element (top, right, bottom, and left).
+
+#### CSS Font
+* ###### Font Family
+  The font family of a text is set with the font-family property.
+
+  The font-family property should hold several font names as a "fallback" system. If the browser does not support the first font, it tries the next font, and so on.
+
+  Start with the font you want, and end with a generic family, to let the browser pick a similar font in the generic family, if no other fonts are available.
+ 
+* ###### Font Size
+  The font-size property sets the size of the text.
+
+  Being able to manage the text size is important in web design. However, you should not use font size adjustments to make paragraphs look like headings, or headings look like paragraphs.
+
+  Always use the proper HTML tags, like ``<h1>`` - ``<h6>`` for headings and ``<p>`` for paragraphs.
+
+  The font-size value can be an absolute, or relative size.
+
+* ###### Font Weight
+  The font-weight property specifies the weight of a font
+
+
+#### CSS Position
+The position property specifies the type of positioning method used for an element.
+
+There are five different position values:
+
+* static
+* relative
+* fixed
+* absolute 
+* sticky
+
+##### position: absolute;
+An element with position: absolute; is positioned relative to the nearest positioned ancestor (instead of positioned relative to the viewport, like fixed).
+
+However; if an absolute positioned element has no positioned ancestors, it uses the document body, and moves along with page scrolling.
+
+#### CSS Border - Shorthand Property
+To shorten the code, it is also possible to specify all the individual border properties in one property.
+
+The border property is a shorthand property for the following individual border properties:
+
+* border-width
+* border-style (required)
+* border-color
+
+#### CSS Colors
+Colors are specified using predefined color names, or RGB, HEX, HSL, RGBA, HSLA values.
+
+#### Overlapping Elements
+When elements are positioned, they can overlap other elements.
+
+The z-index property specifies the stack order of an element (which element should be placed in front of, or behind, the others).
+
+An element can have a positive or negative stack order:
+
+```
+img {
+  position: absolute;
+  left: 0px;
+  top: 0px;
+  z-index: -1;
+}
+```
+
+## How to ?
+We clear the canvas. 0, 0, 0, 0 are red, green, blue, alpha respectively so in this case we're making the canvas transparent.
+
+```
+// Clear the canvas
+gl.clearColor(0, 0, 0, 0);
+gl.clear(gl.COLOR_BUFFER_BIT);
+```
+In CSS,
+```
+canvas {
+    z-index: 2;
+	position: absolute;
+    top: 20px;
+    border: 1px solid black;
+}
+```
+## Conference
+[1] https://www.w3schools.com/
\ No newline at end of file
diff --git a/student2019/201520510/webgl-tutorial-master/WebGLHelloAPI.js b/student2019/201520510/webgl-tutorial-master/WebGLHelloAPI.js
new file mode 100644
index 0000000000000000000000000000000000000000..c10fb13daa8a0c1348f4c7d4c28012b1d07f3ba4
--- /dev/null
+++ b/student2019/201520510/webgl-tutorial-master/WebGLHelloAPI.js
@@ -0,0 +1,256 @@
+/*(CC-NC-BY) Yumin Cho 2019 */
+var gl;
+
+function testGLError(functionLastCalled) {
+
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+ // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+
+    return true;
+}
+
+var shaderProgram;
+
+function initialiseBuffer() {
+		
+    var vertexData = [
+		-0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		0.0, 1.0,//3
+        0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		1.0, 1.0,//1
+		0.5, 0.5, -0.5,		1.0, 1.0, 1.0, 0.5,		1.0, 1.0,//2
+				
+		-0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		0.0, 1.0,//3
+		0.5, 0.5, -0.5,		1.0, 1.0, 1.0, 0.5,		1.0, 1.0,//2
+		-0.5, 0.5, -0.5,	1.0, 1.0, 1.0, 0.5,		0.0, 1.0,//4
+		 
+		0.5, 0.5, -0.5,		0.0, 0.0, 0.0, 0.5,		1.0, 1.0,//2
+		0.5, -0.5, -0.5,	0.0, 0.0, 0.0, 0.5,		1.0, 0.0,//6
+		-0.5,-0.5,-0.5,		0.0, 0.0, 0.0, 0.5,		0.0, 0.0,//8
+		   
+		-0.5, 0.5, -0.5,	0.0, 0.0, 0.0, 0.5,		0.0, 1.0,//4
+		0.5, 0.5, -0.5,		0.0, 0.0, 0.0, 0.5,		1.0, 1.0,//2
+		-0.5,-0.5,-0.5,		0.0, 0.0, 0.0, 0.5,		0.0, 0.0,//8
+			
+		0.5, -0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		0.0, 1.0,//5
+		0.5, -0.5, -0.5,	1.0, 0.5, 0.0, 0.5,		0.0, 1.0,//6
+		0.5, 0.5, -0.5,		1.0, 0.5, 0.0, 0.5,		1.0, 1.0,//2
+
+		0.5, -0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		0.0, 1.0,//5
+		0.5, 0.5, -0.5,		1.0, 0.5, 0.0, 0.5,		1.0, 1.0,//2
+		0.5, 0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		1.0, 1.0,//1
+				 
+		-0.5, 0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 1.0,//4
+		-0.5,-0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 0.0,//8
+		-0.5, -0.5, 0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 0.0,//7
+		
+		-0.5, 0.5, 0.5,		1.0, 0.0, 0.0, 0.5,		0.0, 1.0,//3
+		-0.5, 0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 1.0,//4
+		-0.5, -0.5, 0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 0.0,//7
+		
+		-0.5, -0.5, 0.5,	0.0, 0.0, 1.0, 0.5,		0.0, 0.0,//7
+		0.5, -0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		1.0, 0.0,//5
+		0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		1.0, 1.0,//1
+				 
+		-0.5, -0.5, 0.5,	0.0, 0.0, 1.0, 0.5,		0.0, 0.0,//7
+		0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		1.0, 1.0,//1
+		-0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		0.0, 1.0,//3
+		
+		 0.5, -0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		1.0, 0.0,//6
+		 0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		1.0, 0.0,//5
+		-0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		0.0, 0.0,//7
+		
+		-0.5,-0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		0.0, 0.0,//8
+		 0.5, -0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		1.0, 0.0,//6
+		-0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		0.0, 0.0,//7
+    ];
+	
+    // Generate a buffer object
+    gl.vertexBuffer = gl.createBuffer();
+    // Bind buffer as a vertex buffer so we can fill it with data
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying mediump vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = 1.0 * color;\
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    var vertexShaderSource = '\
+			attribute highp vec3 myVertex; \
+			attribute highp vec4 myColor; \
+			attribute highp vec2 myUV; \
+			uniform mediump mat4 Pmatrix; \
+			uniform mediump mat4 Vmatrix; \
+			uniform mediump mat4 Mmatrix; \
+			varying mediump vec4 color; \
+			varying mediump vec2 texCoord;\
+			void main(void)  \
+			{ \
+				gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(myVertex, 1.0);\
+				color = myColor;\
+				texCoord = myUV; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    gl.programObject = gl.createProgram();
+
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+	gl.bindAttribLocation(gl.programObject, 2, "myUV");
+
+    // Link the program
+    gl.linkProgram(gl.programObject);
+
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+
+    return testGLError("initialiseShaders");
+}
+
+// FOV, Aspect Ratio, Near, Far 
+function get_projection(angle, a, zMin, zMax) {
+    var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
+    return [
+    	0.5/ang, 0 , 0, 0,
+        0, 0.5*a/ang, 0, 0,
+        0, 0, -(zMax+zMin)/(zMax-zMin), -1,
+        0, 0, (-2*zMax*zMin)/(zMax-zMin), 0 ];
+}
+			
+var proj_matrix = get_projection(30, 1.0, 1, 5.0);
+var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+// translating z
+
+view_matrix[14] = view_matrix[14]-2;//zoom
+
+function renderScene() {
+
+    //console.log("Frame "+frames+"\n");
+   
+
+    var Pmatrix = gl.getUniformLocation(gl.programObject, "Pmatrix");
+    var Vmatrix = gl.getUniformLocation(gl.programObject, "Vmatrix");
+    var Mmatrix = gl.getUniformLocation(gl.programObject, "Mmatrix");
+
+    gl.uniformMatrix4fv(Pmatrix, false, proj_matrix);
+    gl.uniformMatrix4fv(Vmatrix, false, view_matrix);
+    gl.uniformMatrix4fv(Mmatrix, false, mov_matrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 36, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 36, 12);
+	gl.enableVertexAttribArray(2);
+    gl.vertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 36, 28);
+
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+    
+	gl.enable(gl.BLEND);
+	gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+	gl.blendEquation(gl.FUNC_ADD);
+
+	// Clear the canvas
+    gl.clearColor(0.0, 0.0, 0.0, 0.0);
+    gl.clearDepth(1.0); 
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+	
+	gl.drawArrays(gl.TRIANGLES, 0, 36);
+
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+    console.log("Start");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+    // Render loop
+    requestAnimFrame = (
+	function () {
+        //	return window.requestAnimationFrame || window.webkitRequestAnimationFrame 
+	//	|| window.mozRequestAnimationFrame || 
+	   	return function (callback) {
+			    // console.log("Callback is"+callback); 
+			    window.setTimeout(callback, 10, 10); };
+    })();
+
+    (function renderLoop(param) {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git a/student2019/201520510/webgl-tutorial-master/index.css b/student2019/201520510/webgl-tutorial-master/index.css
new file mode 100644
index 0000000000000000000000000000000000000000..026b3b91303aaa53715ac7be0a5d5ad7b5d2e3ea
--- /dev/null
+++ b/student2019/201520510/webgl-tutorial-master/index.css
@@ -0,0 +1,23 @@
+/*(CC-NC-BY) Yumin Cho 2019 */
+
+/*text settings*/
+pre {
+    padding-left: 2px;
+    font-family: sans-serif;
+    font-size: 30px;
+    font-weight: bold;
+}
+
+/* canvas settings - Set z-index to place transparent WebGL Content on top of other HTML elements */
+/* The z-index property specifies the stack order of an element (which element should be placed in front of, or behind, the others). */
+canvas {
+    z-index: 2;
+	position: absolute;
+    top: 20px;
+    border: 1px solid black;
+}
+
+/* Change color to emphasize specific word */
+c {
+	color: red;
+}
diff --git a/student2019/201520510/webgl-tutorial-master/index.html b/student2019/201520510/webgl-tutorial-master/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..31d04f23482edc41a09e6500b9301f60f356596f
--- /dev/null
+++ b/student2019/201520510/webgl-tutorial-master/index.html
@@ -0,0 +1,31 @@
+<!-- (CC-NC-BY) Yumin Cho 2019 -->
+
+<html>
+<head>
+<title>WebGL Tutorial - Transparent WebGL content on top of other HTML elements</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="WebGLHelloAPI.js">
+</script>
+<link type="text/css" rel="stylesheet" href="index.css">
+
+</head>
+<body onload="main()">
+<H2> WebGL Tutorial - Transparent WebGL content on top of other HTML elements </H2>
+<pre>
+  Computer Programming    Discrete Mathematics    Object-oriented Programming 
+Data Structures    Doamin Analysis and Software Design    Digital Circuits   Compilers  
+    Computer Organization and Architecture   Operating Systems   Computer Networks
+System Programming     Embedded Software     Network Software     Algorithms
+   Design of Mobile Systems   Wireless Communications and Networks   Database
+                                             <c>Computer Graphics</c>
+Design of Distributed Systems  Introduction to Information Security  Data Mining
+   Introduction to Open Source Software    Software Engineering    Computer Vision
+Theory of Computation  Human Computer Interaction  Design of Web Service Systems
+      Software Industry Seminar  Undergraduate Project  Artifical Intelligence
+ Software Capstone Design    SW Business Start-up    Modeling and Simulations
+</pre>	
+	<canvas id="helloapicanvas" style="border: none" width="1260" height="600"></canvas>
+	<p> (CC-NC-BY) 2019 Yumin Cho </p>
+</body>
+</html>
+
diff --git a/student2019/201520868/WebGL.html b/student2019/201520868/WebGL.html
new file mode 100644
index 0000000000000000000000000000000000000000..eb7575cae77adbfb3d3e9f7edebcf0fedbb67b7d
--- /dev/null
+++ b/student2019/201520868/WebGL.html
@@ -0,0 +1,248 @@
+<!-- (CC-NC-BY) Kim Kwangho 2019 -->
+<!-- Reference : https://www.tutorialspoint.com/webgl/webgl_interactive_cube.htm -->
+<html>
+
+<head>
+<title>WebGL Tutorial with mouse and keyboard interaction</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js"></script>
+</head>
+
+<body>
+	<!-- set the canvas -->
+	<canvas style="border: none;" width="500" height="500" id="my_Canvas"></canvas>
+	<br>If you want to rotate the cube, drag the cube.<br>
+	If you want to change color of cube , press c.<br>
+	If you want to move the cube, press m and drag the cube.<br>
+	If you want to zoom the cube, wheel the mouse.<br><br>
+	(CC-NC-BY) Kim Kwangho 2019<br>
+	Reference : https://www.tutorialspoint.com/webgl/webgl_interactive_cube.htm
+
+	<script>
+		/*============= Creating a canvas ======================*/
+		var canvas = document.getElementById('my_Canvas');
+		gl = canvas.getContext('experimental-webgl');
+
+		/*========== Defining and storing the geometry ==========*/
+		//location of vertices.
+		var vertices = [
+		   -1,-1,-1,  1,-1,-1,  1, 1,-1, -1, 1,-1,
+		   -1,-1, 1,  1,-1, 1,  1, 1, 1, -1, 1, 1,
+		   -1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
+		    1,-1,-1,  1, 1,-1,  1, 1, 1,  1,-1, 1,
+		   -1,-1,-1, -1,-1, 1,  1,-1, 1,  1,-1,-1,
+		   -1, 1,-1, -1, 1, 1,  1, 1, 1,  1, 1,-1, 
+		];
+		//color per vertices.
+		var colors = [
+		   1,1,1, 1,1,1, 1,1,1, 1,1,1, 
+		   1,1,1, 1,1,1, 1,1,1, 1,1,1, 
+		   0,0,1, 0,0,1, 0,0,1, 0,0,1,
+		   1,0,0, 1,0,0, 1,0,0, 1,0,0,
+		   1,1,0, 1,1,0, 1,1,0, 1,1,0,
+		   0,1,0, 0,1,0, 0,1,0, 0,1,0 
+		];
+		//direction of vertices.
+		var indices = [
+		      0,1,2,    0,2,3,    4,5,6,    4,6,7,
+		     8,9,10,  8,10,11, 12,13,14, 12,14,15,
+		   16,17,18, 16,18,19, 20,21,22, 20,22,23 
+		];
+
+		// Create and store data into vertex buffer
+		var vertex_buffer = gl.createBuffer ();
+		gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
+		gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+
+		// Create and store data into color buffer
+		var color_buffer = gl.createBuffer ();
+		gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
+		gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
+
+		// Create and store data into index buffer
+		var index_buffer = gl.createBuffer ();
+		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
+		gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
+
+		/*=================== SHADERS =================== */
+
+		var vertCode = 'attribute vec3 position;'+
+		   'uniform mat4 Pmatrix;'+
+		   'uniform mat4 Vmatrix;'+
+		   'uniform mat4 Mmatrix;'+
+		   'attribute vec3 color;'+
+		   'varying vec3 vColor;'+
+		   'void main(void) { '+ 
+			  'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
+			  'vColor = color;'+
+		   '}';
+
+		var fragCode = 'precision highp float;'+
+		   'varying vec3 vColor;'+
+		   'void main(void) {'+
+			  'gl_FragColor = vec4(vColor, 1.);'+
+		   '}';
+		//make vertex shader and compile
+		var vertShader = gl.createShader(gl.VERTEX_SHADER);
+		gl.shaderSource(vertShader, vertCode);
+		gl.compileShader(vertShader);
+
+		//make fragment shader and compile
+		var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+		gl.shaderSource(fragShader, fragCode);
+		gl.compileShader(fragShader);
+
+		//attach these 2 shader to shader program and link.
+		var shaderprogram = gl.createProgram();
+		gl.attachShader(shaderprogram, vertShader);
+		gl.attachShader(shaderprogram, fragShader);
+		gl.linkProgram(shaderprogram);
+
+		/*======== Associating attributes to vertex shader =====*/
+		var _Pmatrix = gl.getUniformLocation(shaderprogram, "Pmatrix"); //these matrices are all used in vertex shader
+		var _Vmatrix = gl.getUniformLocation(shaderprogram, "Vmatrix");
+		var _Mmatrix = gl.getUniformLocation(shaderprogram, "Mmatrix");
+
+		gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
+		var _position = gl.getAttribLocation(shaderprogram, "position");
+		gl.vertexAttribPointer(_position, 3, gl.FLOAT, false,0,0);
+		gl.enableVertexAttribArray(_position);
+
+		gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
+		var _color = gl.getAttribLocation(shaderprogram, "color");
+		gl.vertexAttribPointer(_color, 3, gl.FLOAT, false,0,0) ;
+		gl.enableVertexAttribArray(_color);
+		gl.useProgram(shaderprogram);
+
+		/*==================== MATRIX ====================== */
+		var proj_matrix = glMatrix.mat4.create();
+		glMatrix.mat4.perspective(proj_matrix,40/180*Math.PI,canvas.width/canvas.height,1,100);
+		var mo_matrix = glMatrix.mat4.create();
+		var view_matrix = glMatrix.mat4.create();
+		view_matrix[14] = view_matrix[14]-8;
+
+		/*================= Mouse events ======================*/
+
+		var reduce = 0.98;
+		var drag = false;
+		var old_x, old_y;
+		var dX = 0, dY = 0, mX = 0.0, mY = 0.0;
+		var sv = glMatrix.vec3.create(),old_sv = glMatrix.vec3.create();
+		//when mouse is pressed.
+		var mouseDown = function(e) {
+		   drag = true;
+		   old_x = e.pageX, old_y = e.pageY;
+		   e.preventDefault();
+		   return false;
+		}; 
+		//when mouse is released.
+		var mouseUp = function(e){
+		   drag = false;
+		};
+		//when mouse is moving while mouse is pressed.
+		var move=0; 
+		var mouseMove = function(e) {
+
+			if (!drag) return false;
+		   	if(!move){
+				//when m is not pressed.
+				dX = (e.pageX-old_x)*2*Math.PI/canvas.width,
+				dY = (e.pageY-old_y)*2*Math.PI/canvas.height;
+				RotX+= dX;
+				RotY+=dY;
+				old_x = e.pageX, old_y = e.pageY;
+				e.preventDefault();
+			}
+			else{
+				//when m is pressed.
+				mX = (e.pageX-old_x)/canvas.width*view_matrix[14];
+				mY = (-e.pageY+old_y)/canvas.height*view_matrix[14];
+				view_matrix[12]-=mX;
+				view_matrix[13]-=mY;
+				old_x = e.pageX, old_y = e.pageY;
+				e.preventDefault();
+			}
+		};
+
+		//when mouse wheels.
+		var Wheel = function(e){
+			if(e.deltaY<0){
+				if(view_matrix[14]<-5.1) view_matrix[14] = view_matrix[14]+0.2;
+			}
+			else {
+				if(view_matrix[14]>-20) view_matrix[14] = view_matrix[14]-0.2;
+			}
+		};
+
+		/*================= Keyboard events ======================*/
+		//when any keyboard key is pressed.
+		var onKeyPress = function(e){
+			//when c is pressed. c means change.
+			if(e.key=='c'){// when user pushes c, user can change the color of box
+				for(i in colors){
+					colors[i] = Math.random()+0.3;
+				}
+				gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
+			}
+			//when m is pressed. m means move
+			if(e.key=='m'){
+				move=1;
+		   		return false;
+			}
+		};
+
+		// when all keys are released.
+		var onKeyUp = function(e){
+				move=0;
+		};
+
+		//EventListner has lots of action to trigger the event.
+		canvas.addEventListener("mousedown", mouseDown, false);	//mouse clicked.
+		canvas.addEventListener("mouseup", mouseUp, false);		//mouse released.
+		canvas.addEventListener("mouseout", mouseUp, false);	//mouse cursor is going out of canvas
+		canvas.addEventListener("mousemove", mouseMove, false);	//mouse is moving
+		canvas.addEventListener("wheel",Wheel, false);			//mouse wheels.
+		window.addEventListener("keypress",onKeyPress, false);	//key is pressed.
+		window.addEventListener("keyup",onKeyUp, false);		//key is released.
+		/*=================== Drawing =================== */
+
+		var RotX = 0,	//variable for rotate y-axis
+		RotY = 0;		//variabe for rotate x-axis
+		var time_old = 0;
+
+		var animate = function(time) {
+		   var dt = time-time_old;
+
+		   if (!drag) {
+			  dX *= reduce, dY*=reduce;
+			  RotX+=dX, RotY+=dY;
+		   }
+		   
+		   glMatrix.mat4.identity(mo_matrix);					//before drawing, model matrix is being identity matrix
+		   glMatrix.mat4.rotateY(mo_matrix,mo_matrix,RotX);		
+		   glMatrix.mat4.rotateX(mo_matrix,mo_matrix,RotY);		
+		   time_old = time; 
+		   gl.enable(gl.DEPTH_TEST);//DEPTH_TEST is enabled.
+
+		   gl.clearColor(0.7, 0.7, 0.7, 1.0);
+		   gl.clearDepth(1.0);
+		   gl.viewport(0.0, 0.0, canvas.width, canvas.height);
+		   gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+		   //Uniform Matrices
+		   gl.uniformMatrix4fv(_Pmatrix, false, proj_matrix);
+		   gl.uniformMatrix4fv(_Vmatrix, false, view_matrix);
+		   gl.uniformMatrix4fv(_Mmatrix, false, mo_matrix);
+
+		   gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
+		   gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
+
+		   window.requestAnimationFrame(animate);
+		}
+		animate(0);
+	 </script>
+</body>
+
+</html>
+
+</script>
\ No newline at end of file
diff --git a/student2019/201520868/gl-matrix.js b/student2019/201520868/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..45ac91d38cf1317e802be2fe96fde99e00c68397
--- /dev/null
+++ b/student2019/201520868/gl-matrix.js
@@ -0,0 +1,7546 @@
+
+/*!
+@fileoverview gl-matrix - High performance matrix and vector operations
+@author Brandon Jones
+@author Colin MacKenzie IV
+@version 3.0.0
+
+Copyright (c) 2015-2019, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+  typeof define === 'function' && define.amd ? define(['exports'], factory) :
+  (global = global || self, factory(global.glMatrix = {}));
+}(this, function (exports) { 'use strict';
+
+  /**
+   * Common utilities
+   * @module glMatrix
+   */
+  // Configuration Constants
+  var EPSILON = 0.000001;
+  var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+  var RANDOM = Math.random;
+  /**
+   * Sets the type of array used when creating new vectors and matrices
+   *
+   * @param {Type} type Array type, such as Float32Array or Array
+   */
+
+  function setMatrixArrayType(type) {
+    ARRAY_TYPE = type;
+  }
+  var degree = Math.PI / 180;
+  /**
+   * Convert Degree To Radian
+   *
+   * @param {Number} a Angle in Degrees
+   */
+
+  function toRadian(a) {
+    return a * degree;
+  }
+  /**
+   * Tests whether or not the arguments have approximately the same value, within an absolute
+   * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+   * than or equal to 1.0, and a relative tolerance is used for larger values)
+   *
+   * @param {Number} a The first number to test.
+   * @param {Number} b The second number to test.
+   * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+   */
+
+  function equals(a, b) {
+    return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+  }
+  if (!Math.hypot) Math.hypot = function () {
+    var y = 0,
+        i = arguments.length;
+
+    while (i--) {
+      y += arguments[i] * arguments[i];
+    }
+
+    return Math.sqrt(y);
+  };
+
+  var common = /*#__PURE__*/Object.freeze({
+    EPSILON: EPSILON,
+    get ARRAY_TYPE () { return ARRAY_TYPE; },
+    RANDOM: RANDOM,
+    setMatrixArrayType: setMatrixArrayType,
+    toRadian: toRadian,
+    equals: equals
+  });
+
+  /**
+   * 2x2 Matrix
+   * @module mat2
+   */
+
+  /**
+   * Creates a new identity mat2
+   *
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function create() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2 initialized with values from an existing matrix
+   *
+   * @param {mat2} a matrix to clone
+   * @returns {mat2} a new 2x2 matrix
+   */
+
+  function clone(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2 to another
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function copy(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set a mat2 to the identity matrix
+   *
+   * @param {mat2} out the receiving matrix
+   * @returns {mat2} out
+   */
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Create a new mat2 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out A new 2x2 matrix
+   */
+
+  function fromValues(m00, m01, m10, m11) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Set the components of a mat2 to the given values
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m10 Component in column 1, row 0 position (index 2)
+   * @param {Number} m11 Component in column 1, row 1 position (index 3)
+   * @returns {mat2} out
+   */
+
+  function set(out, m00, m01, m10, m11) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m10;
+    out[3] = m11;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function transpose(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache
+    // some values
+    if (out === a) {
+      var a1 = a[1];
+      out[1] = a[2];
+      out[2] = a1;
+    } else {
+      out[0] = a[0];
+      out[1] = a[2];
+      out[2] = a[1];
+      out[3] = a[3];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function invert(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3]; // Calculate the determinant
+
+    var det = a0 * a3 - a2 * a1;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = a3 * det;
+    out[1] = -a1 * det;
+    out[2] = -a2 * det;
+    out[3] = a0 * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the source matrix
+   * @returns {mat2} out
+   */
+
+  function adjoint(out, a) {
+    // Caching this value is nessecary if out == a
+    var a0 = a[0];
+    out[0] = a[3];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a0;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2
+   *
+   * @param {mat2} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant(a) {
+    return a[0] * a[3] - a[2] * a[1];
+  }
+  /**
+   * Multiplies two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the first operand
+   * @param {mat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function multiply(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    return out;
+  }
+  /**
+   * Rotates a mat2 by the given angle
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function rotate(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    return out;
+  }
+  /**
+   * Scales the mat2 by the dimensions in the given vec2
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the matrix to rotate
+   * @param {vec2} v the vec2 to scale the matrix by
+   * @returns {mat2} out
+   **/
+
+  function scale(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.rotate(dest, dest, rad);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2} out
+   */
+
+  function fromRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2.identity(dest);
+   *     mat2.scale(dest, dest, vec);
+   *
+   * @param {mat2} out mat2 receiving operation result
+   * @param {vec2} v Scaling vector
+   * @returns {mat2} out
+   */
+
+  function fromScaling(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2
+   *
+   * @param {mat2} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str(a) {
+    return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+  }
+  /**
+   * Returns Frobenius norm of a mat2
+   *
+   * @param {mat2} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3]);
+  }
+  /**
+   * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+   * @param {mat2} L the lower triangular matrix
+   * @param {mat2} D the diagonal matrix
+   * @param {mat2} U the upper triangular matrix
+   * @param {mat2} a the input matrix to factorize
+   */
+
+  function LDU(L, D, U, a) {
+    L[2] = a[2] / a[0];
+    U[0] = a[0];
+    U[1] = a[1];
+    U[3] = a[3] - L[2] * U[1];
+    return [L, D, U];
+  }
+  /**
+   * Adds two mat2's
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the first operand
+   * @param {mat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function add(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the first operand
+   * @param {mat2} b the second operand
+   * @returns {mat2} out
+   */
+
+  function subtract(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {mat2} a The first matrix.
+   * @param {mat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {mat2} a The first matrix.
+   * @param {mat2} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$1(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2} out the receiving matrix
+   * @param {mat2} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2} out
+   */
+
+  function multiplyScalar(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2} out the receiving vector
+   * @param {mat2} a the first operand
+   * @param {mat2} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2} out
+   */
+
+  function multiplyScalarAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Alias for {@link mat2.multiply}
+   * @function
+   */
+
+  var mul = multiply;
+  /**
+   * Alias for {@link mat2.subtract}
+   * @function
+   */
+
+  var sub = subtract;
+
+  var mat2 = /*#__PURE__*/Object.freeze({
+    create: create,
+    clone: clone,
+    copy: copy,
+    identity: identity,
+    fromValues: fromValues,
+    set: set,
+    transpose: transpose,
+    invert: invert,
+    adjoint: adjoint,
+    determinant: determinant,
+    multiply: multiply,
+    rotate: rotate,
+    scale: scale,
+    fromRotation: fromRotation,
+    fromScaling: fromScaling,
+    str: str,
+    frob: frob,
+    LDU: LDU,
+    add: add,
+    subtract: subtract,
+    exactEquals: exactEquals,
+    equals: equals$1,
+    multiplyScalar: multiplyScalar,
+    multiplyScalarAndAdd: multiplyScalarAndAdd,
+    mul: mul,
+    sub: sub
+  });
+
+  /**
+   * 2x3 Matrix
+   * @module mat2d
+   *
+   * @description
+   * A mat2d contains six elements defined as:
+   * <pre>
+   * [a, c, tx,
+   *  b, d, ty]
+   * </pre>
+   * This is a short form for the 3x3 matrix:
+   * <pre>
+   * [a, c, tx,
+   *  b, d, ty,
+   *  0, 0, 1]
+   * </pre>
+   * The last row is ignored so the array is shorter and operations are faster.
+   */
+
+  /**
+   * Creates a new identity mat2d
+   *
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function create$1() {
+    var out = new ARRAY_TYPE(6);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[4] = 0;
+      out[5] = 0;
+    }
+
+    out[0] = 1;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat2d initialized with values from an existing matrix
+   *
+   * @param {mat2d} a matrix to clone
+   * @returns {mat2d} a new 2x3 matrix
+   */
+
+  function clone$1(a) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Copy the values from one mat2d to another
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function copy$1(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    return out;
+  }
+  /**
+   * Set a mat2d to the identity matrix
+   *
+   * @param {mat2d} out the receiving matrix
+   * @returns {mat2d} out
+   */
+
+  function identity$1(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Create a new mat2d with the given values
+   *
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} A new mat2d
+   */
+
+  function fromValues$1(a, b, c, d, tx, ty) {
+    var out = new ARRAY_TYPE(6);
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Set the components of a mat2d to the given values
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {Number} a Component A (index 0)
+   * @param {Number} b Component B (index 1)
+   * @param {Number} c Component C (index 2)
+   * @param {Number} d Component D (index 3)
+   * @param {Number} tx Component TX (index 4)
+   * @param {Number} ty Component TY (index 5)
+   * @returns {mat2d} out
+   */
+
+  function set$1(out, a, b, c, d, tx, ty) {
+    out[0] = a;
+    out[1] = b;
+    out[2] = c;
+    out[3] = d;
+    out[4] = tx;
+    out[5] = ty;
+    return out;
+  }
+  /**
+   * Inverts a mat2d
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the source matrix
+   * @returns {mat2d} out
+   */
+
+  function invert$1(out, a) {
+    var aa = a[0],
+        ab = a[1],
+        ac = a[2],
+        ad = a[3];
+    var atx = a[4],
+        aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat2d
+   *
+   * @param {mat2d} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$1(a) {
+    return a[0] * a[3] - a[1] * a[2];
+  }
+  /**
+   * Multiplies two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the first operand
+   * @param {mat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function multiply$1(out, a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    out[0] = a0 * b0 + a2 * b1;
+    out[1] = a1 * b0 + a3 * b1;
+    out[2] = a0 * b2 + a2 * b3;
+    out[3] = a1 * b2 + a3 * b3;
+    out[4] = a0 * b4 + a2 * b5 + a4;
+    out[5] = a1 * b4 + a3 * b5 + a5;
+    return out;
+  }
+  /**
+   * Rotates a mat2d by the given angle
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function rotate$1(out, a, rad) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    out[0] = a0 * c + a2 * s;
+    out[1] = a1 * c + a3 * s;
+    out[2] = a0 * -s + a2 * c;
+    out[3] = a1 * -s + a3 * c;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Scales the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the matrix to translate
+   * @param {vec2} v the vec2 to scale the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function scale$1(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0 * v0;
+    out[1] = a1 * v0;
+    out[2] = a2 * v1;
+    out[3] = a3 * v1;
+    out[4] = a4;
+    out[5] = a5;
+    return out;
+  }
+  /**
+   * Translates the mat2d by the dimensions in the given vec2
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the matrix to translate
+   * @param {vec2} v the vec2 to translate the matrix by
+   * @returns {mat2d} out
+   **/
+
+  function translate(out, a, v) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var v0 = v[0],
+        v1 = v[1];
+    out[0] = a0;
+    out[1] = a1;
+    out[2] = a2;
+    out[3] = a3;
+    out[4] = a0 * v0 + a2 * v1 + a4;
+    out[5] = a1 * v0 + a3 * v1 + a5;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.rotate(dest, dest, rad);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat2d} out
+   */
+
+  function fromRotation$1(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = -s;
+    out[3] = c;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.scale(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {vec2} v Scaling vector
+   * @returns {mat2d} out
+   */
+
+  function fromScaling$1(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = v[1];
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat2d.identity(dest);
+   *     mat2d.translate(dest, dest, vec);
+   *
+   * @param {mat2d} out mat2d receiving operation result
+   * @param {vec2} v Translation vector
+   * @returns {mat2d} out
+   */
+
+  function fromTranslation(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = v[0];
+    out[5] = v[1];
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat2d
+   *
+   * @param {mat2d} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$1(a) {
+    return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+  }
+  /**
+   * Returns Frobenius norm of a mat2d
+   *
+   * @param {mat2d} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$1(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1);
+  }
+  /**
+   * Adds two mat2d's
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the first operand
+   * @param {mat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function add$1(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the first operand
+   * @param {mat2d} b the second operand
+   * @returns {mat2d} out
+   */
+
+  function subtract$1(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat2d} out the receiving matrix
+   * @param {mat2d} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalar$1(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    return out;
+  }
+  /**
+   * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat2d} out the receiving vector
+   * @param {mat2d} a the first operand
+   * @param {mat2d} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat2d} out
+   */
+
+  function multiplyScalarAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {mat2d} a The first matrix.
+   * @param {mat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$1(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {mat2d} a The first matrix.
+   * @param {mat2d} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$2(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+  }
+  /**
+   * Alias for {@link mat2d.multiply}
+   * @function
+   */
+
+  var mul$1 = multiply$1;
+  /**
+   * Alias for {@link mat2d.subtract}
+   * @function
+   */
+
+  var sub$1 = subtract$1;
+
+  var mat2d = /*#__PURE__*/Object.freeze({
+    create: create$1,
+    clone: clone$1,
+    copy: copy$1,
+    identity: identity$1,
+    fromValues: fromValues$1,
+    set: set$1,
+    invert: invert$1,
+    determinant: determinant$1,
+    multiply: multiply$1,
+    rotate: rotate$1,
+    scale: scale$1,
+    translate: translate,
+    fromRotation: fromRotation$1,
+    fromScaling: fromScaling$1,
+    fromTranslation: fromTranslation,
+    str: str$1,
+    frob: frob$1,
+    add: add$1,
+    subtract: subtract$1,
+    multiplyScalar: multiplyScalar$1,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$1,
+    exactEquals: exactEquals$1,
+    equals: equals$2,
+    mul: mul$1,
+    sub: sub$1
+  });
+
+  /**
+   * 3x3 Matrix
+   * @module mat3
+   */
+
+  /**
+   * Creates a new identity mat3
+   *
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function create$2() {
+    var out = new ARRAY_TYPE(9);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[5] = 0;
+      out[6] = 0;
+      out[7] = 0;
+    }
+
+    out[0] = 1;
+    out[4] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the upper-left 3x3 values into the given mat3.
+   *
+   * @param {mat3} out the receiving 3x3 matrix
+   * @param {mat4} a   the source 4x4 matrix
+   * @returns {mat3} out
+   */
+
+  function fromMat4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[4];
+    out[4] = a[5];
+    out[5] = a[6];
+    out[6] = a[8];
+    out[7] = a[9];
+    out[8] = a[10];
+    return out;
+  }
+  /**
+   * Creates a new mat3 initialized with values from an existing matrix
+   *
+   * @param {mat3} a matrix to clone
+   * @returns {mat3} a new 3x3 matrix
+   */
+
+  function clone$2(a) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Copy the values from one mat3 to another
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function copy$2(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Create a new mat3 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} A new mat3
+   */
+
+  function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    var out = new ARRAY_TYPE(9);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set the components of a mat3 to the given values
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m10 Component in column 1, row 0 position (index 3)
+   * @param {Number} m11 Component in column 1, row 1 position (index 4)
+   * @param {Number} m12 Component in column 1, row 2 position (index 5)
+   * @param {Number} m20 Component in column 2, row 0 position (index 6)
+   * @param {Number} m21 Component in column 2, row 1 position (index 7)
+   * @param {Number} m22 Component in column 2, row 2 position (index 8)
+   * @returns {mat3} out
+   */
+
+  function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m10;
+    out[4] = m11;
+    out[5] = m12;
+    out[6] = m20;
+    out[7] = m21;
+    out[8] = m22;
+    return out;
+  }
+  /**
+   * Set a mat3 to the identity matrix
+   *
+   * @param {mat3} out the receiving matrix
+   * @returns {mat3} out
+   */
+
+  function identity$2(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function transpose$1(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a12 = a[5];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a01;
+      out[5] = a[7];
+      out[6] = a02;
+      out[7] = a12;
+    } else {
+      out[0] = a[0];
+      out[1] = a[3];
+      out[2] = a[6];
+      out[3] = a[1];
+      out[4] = a[4];
+      out[5] = a[7];
+      out[6] = a[2];
+      out[7] = a[5];
+      out[8] = a[8];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function invert$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b01 = a22 * a11 - a12 * a21;
+    var b11 = -a22 * a10 + a12 * a20;
+    var b21 = a21 * a10 - a11 * a20; // Calculate the determinant
+
+    var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = b01 * det;
+    out[1] = (-a22 * a01 + a02 * a21) * det;
+    out[2] = (a12 * a01 - a02 * a11) * det;
+    out[3] = b11 * det;
+    out[4] = (a22 * a00 - a02 * a20) * det;
+    out[5] = (-a12 * a00 + a02 * a10) * det;
+    out[6] = b21 * det;
+    out[7] = (-a21 * a00 + a01 * a20) * det;
+    out[8] = (a11 * a00 - a01 * a10) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the source matrix
+   * @returns {mat3} out
+   */
+
+  function adjoint$1(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    out[0] = a11 * a22 - a12 * a21;
+    out[1] = a02 * a21 - a01 * a22;
+    out[2] = a01 * a12 - a02 * a11;
+    out[3] = a12 * a20 - a10 * a22;
+    out[4] = a00 * a22 - a02 * a20;
+    out[5] = a02 * a10 - a00 * a12;
+    out[6] = a10 * a21 - a11 * a20;
+    out[7] = a01 * a20 - a00 * a21;
+    out[8] = a00 * a11 - a01 * a10;
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat3
+   *
+   * @param {mat3} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$2(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+  }
+  /**
+   * Multiplies two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the first operand
+   * @param {mat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function multiply$2(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2];
+    var a10 = a[3],
+        a11 = a[4],
+        a12 = a[5];
+    var a20 = a[6],
+        a21 = a[7],
+        a22 = a[8];
+    var b00 = b[0],
+        b01 = b[1],
+        b02 = b[2];
+    var b10 = b[3],
+        b11 = b[4],
+        b12 = b[5];
+    var b20 = b[6],
+        b21 = b[7],
+        b22 = b[8];
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+    return out;
+  }
+  /**
+   * Translate a mat3 by the given vector
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the matrix to translate
+   * @param {vec2} v vector to translate by
+   * @returns {mat3} out
+   */
+
+  function translate$1(out, a, v) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        x = v[0],
+        y = v[1];
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+  }
+  /**
+   * Rotates a mat3 by the given angle
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function rotate$2(out, a, rad) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a10 = a[3],
+        a11 = a[4],
+        a12 = a[5],
+        a20 = a[6],
+        a21 = a[7],
+        a22 = a[8],
+        s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
+  }
+  /**
+   * Scales the mat3 by the dimensions in the given vec2
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the matrix to rotate
+   * @param {vec2} v the vec2 to scale the matrix by
+   * @returns {mat3} out
+   **/
+
+  function scale$2(out, a, v) {
+    var x = v[0],
+        y = v[1];
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.translate(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {vec2} v Translation vector
+   * @returns {mat3} out
+   */
+
+  function fromTranslation$1(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 1;
+    out[5] = 0;
+    out[6] = v[0];
+    out[7] = v[1];
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.rotate(dest, dest, rad);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat3} out
+   */
+
+  function fromRotation$2(out, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad);
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = -s;
+    out[4] = c;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat3.identity(dest);
+   *     mat3.scale(dest, dest, vec);
+   *
+   * @param {mat3} out mat3 receiving operation result
+   * @param {vec2} v Scaling vector
+   * @returns {mat3} out
+   */
+
+  function fromScaling$2(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = v[1];
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Copies the values from a mat2d into a mat3
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat2d} a the matrix to copy
+   * @returns {mat3} out
+   **/
+
+  function fromMat2d(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = 0;
+    out[3] = a[2];
+    out[4] = a[3];
+    out[5] = 0;
+    out[6] = a[4];
+    out[7] = a[5];
+    out[8] = 1;
+    return out;
+  }
+  /**
+  * Calculates a 3x3 matrix from the given quaternion
+  *
+  * @param {mat3} out mat3 receiving operation result
+  * @param {quat} q Quaternion to create matrix from
+  *
+  * @returns {mat3} out
+  */
+
+  function fromQuat(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[3] = yx - wz;
+    out[6] = zx + wy;
+    out[1] = yx + wz;
+    out[4] = 1 - xx - zz;
+    out[7] = zy - wx;
+    out[2] = zx - wy;
+    out[5] = zy + wx;
+    out[8] = 1 - xx - yy;
+    return out;
+  }
+  /**
+  * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+  *
+  * @param {mat3} out mat3 receiving operation result
+  * @param {mat4} a Mat4 to derive the normal matrix from
+  *
+  * @returns {mat3} out
+  */
+
+  function normalFromMat4(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    return out;
+  }
+  /**
+   * Generates a 2D projection matrix with the given bounds
+   *
+   * @param {mat3} out mat3 frustum matrix will be written into
+   * @param {number} width Width of your gl context
+   * @param {number} height Height of gl context
+   * @returns {mat3} out
+   */
+
+  function projection(out, width, height) {
+    out[0] = 2 / width;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -2 / height;
+    out[5] = 0;
+    out[6] = -1;
+    out[7] = 1;
+    out[8] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat3
+   *
+   * @param {mat3} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$2(a) {
+    return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+  }
+  /**
+   * Returns Frobenius norm of a mat3
+   *
+   * @param {mat3} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$2(a) {
+    return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+  }
+  /**
+   * Adds two mat3's
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the first operand
+   * @param {mat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function add$2(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the first operand
+   * @param {mat3} b the second operand
+   * @returns {mat3} out
+   */
+
+  function subtract$2(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat3} out the receiving matrix
+   * @param {mat3} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat3} out
+   */
+
+  function multiplyScalar$2(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    return out;
+  }
+  /**
+   * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat3} out the receiving vector
+   * @param {mat3} a the first operand
+   * @param {mat3} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat3} out
+   */
+
+  function multiplyScalarAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {mat3} a The first matrix.
+   * @param {mat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$2(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {mat3} a The first matrix.
+   * @param {mat3} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$3(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7],
+        a8 = a[8];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7],
+        b8 = b[8];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+  }
+  /**
+   * Alias for {@link mat3.multiply}
+   * @function
+   */
+
+  var mul$2 = multiply$2;
+  /**
+   * Alias for {@link mat3.subtract}
+   * @function
+   */
+
+  var sub$2 = subtract$2;
+
+  var mat3 = /*#__PURE__*/Object.freeze({
+    create: create$2,
+    fromMat4: fromMat4,
+    clone: clone$2,
+    copy: copy$2,
+    fromValues: fromValues$2,
+    set: set$2,
+    identity: identity$2,
+    transpose: transpose$1,
+    invert: invert$2,
+    adjoint: adjoint$1,
+    determinant: determinant$2,
+    multiply: multiply$2,
+    translate: translate$1,
+    rotate: rotate$2,
+    scale: scale$2,
+    fromTranslation: fromTranslation$1,
+    fromRotation: fromRotation$2,
+    fromScaling: fromScaling$2,
+    fromMat2d: fromMat2d,
+    fromQuat: fromQuat,
+    normalFromMat4: normalFromMat4,
+    projection: projection,
+    str: str$2,
+    frob: frob$2,
+    add: add$2,
+    subtract: subtract$2,
+    multiplyScalar: multiplyScalar$2,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$2,
+    exactEquals: exactEquals$2,
+    equals: equals$3,
+    mul: mul$2,
+    sub: sub$2
+  });
+
+  /**
+   * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.
+   * @module mat4
+   */
+
+  /**
+   * Creates a new identity mat4
+   *
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function create$3() {
+    var out = new ARRAY_TYPE(16);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+      out[4] = 0;
+      out[6] = 0;
+      out[7] = 0;
+      out[8] = 0;
+      out[9] = 0;
+      out[11] = 0;
+      out[12] = 0;
+      out[13] = 0;
+      out[14] = 0;
+    }
+
+    out[0] = 1;
+    out[5] = 1;
+    out[10] = 1;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 initialized with values from an existing matrix
+   *
+   * @param {mat4} a matrix to clone
+   * @returns {mat4} a new 4x4 matrix
+   */
+
+  function clone$3(a) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Copy the values from one mat4 to another
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function copy$3(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Create a new mat4 with the given values
+   *
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} A new mat4
+   */
+
+  function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    var out = new ARRAY_TYPE(16);
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set the components of a mat4 to the given values
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {Number} m00 Component in column 0, row 0 position (index 0)
+   * @param {Number} m01 Component in column 0, row 1 position (index 1)
+   * @param {Number} m02 Component in column 0, row 2 position (index 2)
+   * @param {Number} m03 Component in column 0, row 3 position (index 3)
+   * @param {Number} m10 Component in column 1, row 0 position (index 4)
+   * @param {Number} m11 Component in column 1, row 1 position (index 5)
+   * @param {Number} m12 Component in column 1, row 2 position (index 6)
+   * @param {Number} m13 Component in column 1, row 3 position (index 7)
+   * @param {Number} m20 Component in column 2, row 0 position (index 8)
+   * @param {Number} m21 Component in column 2, row 1 position (index 9)
+   * @param {Number} m22 Component in column 2, row 2 position (index 10)
+   * @param {Number} m23 Component in column 2, row 3 position (index 11)
+   * @param {Number} m30 Component in column 3, row 0 position (index 12)
+   * @param {Number} m31 Component in column 3, row 1 position (index 13)
+   * @param {Number} m32 Component in column 3, row 2 position (index 14)
+   * @param {Number} m33 Component in column 3, row 3 position (index 15)
+   * @returns {mat4} out
+   */
+
+  function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+    out[0] = m00;
+    out[1] = m01;
+    out[2] = m02;
+    out[3] = m03;
+    out[4] = m10;
+    out[5] = m11;
+    out[6] = m12;
+    out[7] = m13;
+    out[8] = m20;
+    out[9] = m21;
+    out[10] = m22;
+    out[11] = m23;
+    out[12] = m30;
+    out[13] = m31;
+    out[14] = m32;
+    out[15] = m33;
+    return out;
+  }
+  /**
+   * Set a mat4 to the identity matrix
+   *
+   * @param {mat4} out the receiving matrix
+   * @returns {mat4} out
+   */
+
+  function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Transpose the values of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function transpose$2(out, a) {
+    // If we are transposing ourselves we can skip a few steps but have to cache some values
+    if (out === a) {
+      var a01 = a[1],
+          a02 = a[2],
+          a03 = a[3];
+      var a12 = a[6],
+          a13 = a[7];
+      var a23 = a[11];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a01;
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a02;
+      out[9] = a12;
+      out[11] = a[14];
+      out[12] = a03;
+      out[13] = a13;
+      out[14] = a23;
+    } else {
+      out[0] = a[0];
+      out[1] = a[4];
+      out[2] = a[8];
+      out[3] = a[12];
+      out[4] = a[1];
+      out[5] = a[5];
+      out[6] = a[9];
+      out[7] = a[13];
+      out[8] = a[2];
+      out[9] = a[6];
+      out[10] = a[10];
+      out[11] = a[14];
+      out[12] = a[3];
+      out[13] = a[7];
+      out[14] = a[11];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Inverts a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function invert$3(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+    return out;
+  }
+  /**
+   * Calculates the adjugate of a mat4
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the source matrix
+   * @returns {mat4} out
+   */
+
+  function adjoint$2(out, a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+    return out;
+  }
+  /**
+   * Calculates the determinant of a mat4
+   *
+   * @param {mat4} a the source matrix
+   * @returns {Number} determinant of a
+   */
+
+  function determinant$3(a) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15];
+    var b00 = a00 * a11 - a01 * a10;
+    var b01 = a00 * a12 - a02 * a10;
+    var b02 = a00 * a13 - a03 * a10;
+    var b03 = a01 * a12 - a02 * a11;
+    var b04 = a01 * a13 - a03 * a11;
+    var b05 = a02 * a13 - a03 * a12;
+    var b06 = a20 * a31 - a21 * a30;
+    var b07 = a20 * a32 - a22 * a30;
+    var b08 = a20 * a33 - a23 * a30;
+    var b09 = a21 * a32 - a22 * a31;
+    var b10 = a21 * a33 - a23 * a31;
+    var b11 = a22 * a33 - a23 * a32; // Calculate the determinant
+
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+  }
+  /**
+   * Multiplies two mat4s
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the first operand
+   * @param {mat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+  }
+  /**
+   * Translate a mat4 by the given vector
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to translate
+   * @param {vec3} v vector to translate by
+   * @returns {mat4} out
+   */
+
+  function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+      out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+      out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+      out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+      out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+      a00 = a[0];
+      a01 = a[1];
+      a02 = a[2];
+      a03 = a[3];
+      a10 = a[4];
+      a11 = a[5];
+      a12 = a[6];
+      a13 = a[7];
+      a20 = a[8];
+      a21 = a[9];
+      a22 = a[10];
+      a23 = a[11];
+      out[0] = a00;
+      out[1] = a01;
+      out[2] = a02;
+      out[3] = a03;
+      out[4] = a10;
+      out[5] = a11;
+      out[6] = a12;
+      out[7] = a13;
+      out[8] = a20;
+      out[9] = a21;
+      out[10] = a22;
+      out[11] = a23;
+      out[12] = a00 * x + a10 * y + a20 * z + a[12];
+      out[13] = a01 * x + a11 * y + a21 * z + a[13];
+      out[14] = a02 * x + a12 * y + a22 * z + a[14];
+      out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to scale
+   * @param {vec3} v the vec3 to scale the matrix by
+   * @returns {mat4} out
+   **/
+
+  function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+  }
+  /**
+   * Rotates a mat4 by the given angle around the given axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {vec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function rotate$3(out, a, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+    var b00, b01, b02;
+    var b10, b11, b12;
+    var b20, b21, b22;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
+    a00 = a[0];
+    a01 = a[1];
+    a02 = a[2];
+    a03 = a[3];
+    a10 = a[4];
+    a11 = a[5];
+    a12 = a[6];
+    a13 = a[7];
+    a20 = a[8];
+    a21 = a[9];
+    a22 = a[10];
+    a23 = a[11]; // Construct the elements of the rotation matrix
+
+    b00 = x * x * t + c;
+    b01 = y * x * t + z * s;
+    b02 = z * x * t - y * s;
+    b10 = x * y * t - z * s;
+    b11 = y * y * t + c;
+    b12 = z * y * t + x * s;
+    b20 = x * z * t + y * s;
+    b21 = y * z * t - x * s;
+    b22 = z * z * t + c; // Perform rotation-specific matrix multiplication
+
+    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    }
+
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the X axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[0] = a[0];
+      out[1] = a[1];
+      out[2] = a[2];
+      out[3] = a[3];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Y axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged rows
+      out[4] = a[4];
+      out[5] = a[5];
+      out[6] = a[6];
+      out[7] = a[7];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+  }
+  /**
+   * Rotates a matrix by the given angle around the Z axis
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to rotate
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+      // If the source and destination differ, copy the unchanged last row
+      out[8] = a[8];
+      out[9] = a[9];
+      out[10] = a[10];
+      out[11] = a[11];
+      out[12] = a[12];
+      out[13] = a[13];
+      out[14] = a[14];
+      out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {vec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromTranslation$2(out, v) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a vector scaling
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.scale(dest, dest, vec);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {vec3} v Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromScaling$3(out, v) {
+    out[0] = v[0];
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = v[1];
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = v[2];
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a given angle around a given axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotate(dest, dest, rad, axis);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @param {vec3} axis the axis to rotate around
+   * @returns {mat4} out
+   */
+
+  function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the X axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateX(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromXRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = c;
+    out[6] = s;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = -s;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Y axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateY(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromYRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = 0;
+    out[2] = -s;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = s;
+    out[9] = 0;
+    out[10] = c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from the given angle around the Z axis
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.rotateZ(dest, dest, rad);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {Number} rad the angle to rotate the matrix by
+   * @returns {mat4} out
+   */
+
+  function fromZRotation(out, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+
+    out[0] = c;
+    out[1] = s;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = -s;
+    out[5] = c;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation and vector translation
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {vec3} v Translation vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslation(out, q, v) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - (yy + zz);
+    out[1] = xy + wz;
+    out[2] = xz - wy;
+    out[3] = 0;
+    out[4] = xy - wz;
+    out[5] = 1 - (xx + zz);
+    out[6] = yz + wx;
+    out[7] = 0;
+    out[8] = xz + wy;
+    out[9] = yz - wx;
+    out[10] = 1 - (xx + yy);
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a new mat4 from a dual quat.
+   *
+   * @param {mat4} out Matrix
+   * @param {quat2} a Dual Quaternion
+   * @returns {mat4} mat4 receiving operation result
+   */
+
+  function fromQuat2(out, a) {
+    var translation = new ARRAY_TYPE(3);
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense
+
+    if (magnitude > 0) {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
+    } else {
+      translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+      translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+      translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    }
+
+    fromRotationTranslation(out, a, translation);
+    return out;
+  }
+  /**
+   * Returns the translation vector component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslation,
+   *  the returned vector will be the same as the translation vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive translation component
+   * @param  {mat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getTranslation(out, mat) {
+    out[0] = mat[12];
+    out[1] = mat[13];
+    out[2] = mat[14];
+    return out;
+  }
+  /**
+   * Returns the scaling factor component of a transformation
+   *  matrix. If a matrix is built with fromRotationTranslationScale
+   *  with a normalized Quaternion paramter, the returned vector will be
+   *  the same as the scaling vector
+   *  originally supplied.
+   * @param  {vec3} out Vector to receive scaling factor component
+   * @param  {mat4} mat Matrix to be decomposed (input)
+   * @return {vec3} out
+   */
+
+  function getScaling(out, mat) {
+    var m11 = mat[0];
+    var m12 = mat[1];
+    var m13 = mat[2];
+    var m21 = mat[4];
+    var m22 = mat[5];
+    var m23 = mat[6];
+    var m31 = mat[8];
+    var m32 = mat[9];
+    var m33 = mat[10];
+    out[0] = Math.hypot(m11, m12, m13);
+    out[1] = Math.hypot(m21, m22, m23);
+    out[2] = Math.hypot(m31, m32, m33);
+    return out;
+  }
+  /**
+   * Returns a quaternion representing the rotational component
+   *  of a transformation matrix. If a matrix is built with
+   *  fromRotationTranslation, the returned quaternion will be the
+   *  same as the quaternion originally supplied.
+   * @param {quat} out Quaternion to receive the rotation component
+   * @param {mat4} mat Matrix to be decomposed (input)
+   * @return {quat} out
+   */
+
+  function getRotation(out, mat) {
+    var scaling = new ARRAY_TYPE(3);
+    getScaling(scaling, mat);
+    var is1 = 1 / scaling[0];
+    var is2 = 1 / scaling[1];
+    var is3 = 1 / scaling[2];
+    var sm11 = mat[0] * is1;
+    var sm12 = mat[1] * is2;
+    var sm13 = mat[2] * is3;
+    var sm21 = mat[4] * is1;
+    var sm22 = mat[5] * is2;
+    var sm23 = mat[6] * is3;
+    var sm31 = mat[8] * is1;
+    var sm32 = mat[9] * is2;
+    var sm33 = mat[10] * is3;
+    var trace = sm11 + sm22 + sm33;
+    var S = 0;
+
+    if (trace > 0) {
+      S = Math.sqrt(trace + 1.0) * 2;
+      out[3] = 0.25 * S;
+      out[0] = (sm23 - sm32) / S;
+      out[1] = (sm31 - sm13) / S;
+      out[2] = (sm12 - sm21) / S;
+    } else if (sm11 > sm22 && sm11 > sm33) {
+      S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2;
+      out[3] = (sm23 - sm32) / S;
+      out[0] = 0.25 * S;
+      out[1] = (sm12 + sm21) / S;
+      out[2] = (sm31 + sm13) / S;
+    } else if (sm22 > sm33) {
+      S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2;
+      out[3] = (sm31 - sm13) / S;
+      out[0] = (sm12 + sm21) / S;
+      out[1] = 0.25 * S;
+      out[2] = (sm23 + sm32) / S;
+    } else {
+      S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2;
+      out[3] = (sm12 - sm21) / S;
+      out[0] = (sm31 + sm13) / S;
+      out[1] = (sm23 + sm32) / S;
+      out[2] = 0.25 * S;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {vec3} v Translation vector
+   * @param {vec3} s Scaling vector
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScale(out, q, v, s) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    out[0] = (1 - (yy + zz)) * sx;
+    out[1] = (xy + wz) * sx;
+    out[2] = (xz - wy) * sx;
+    out[3] = 0;
+    out[4] = (xy - wz) * sy;
+    out[5] = (1 - (xx + zz)) * sy;
+    out[6] = (yz + wx) * sy;
+    out[7] = 0;
+    out[8] = (xz + wy) * sz;
+    out[9] = (yz - wx) * sz;
+    out[10] = (1 - (xx + yy)) * sz;
+    out[11] = 0;
+    out[12] = v[0];
+    out[13] = v[1];
+    out[14] = v[2];
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+   * This is equivalent to (but much faster than):
+   *
+   *     mat4.identity(dest);
+   *     mat4.translate(dest, vec);
+   *     mat4.translate(dest, origin);
+   *     let quatMat = mat4.create();
+   *     quat4.toMat4(quat, quatMat);
+   *     mat4.multiply(dest, quatMat);
+   *     mat4.scale(dest, scale)
+   *     mat4.translate(dest, negativeOrigin);
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat4} q Rotation quaternion
+   * @param {vec3} v Translation vector
+   * @param {vec3} s Scaling vector
+   * @param {vec3} o The origin vector around which to scale and rotate
+   * @returns {mat4} out
+   */
+
+  function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+    // Quaternion math
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var xy = x * y2;
+    var xz = x * z2;
+    var yy = y * y2;
+    var yz = y * z2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    var sx = s[0];
+    var sy = s[1];
+    var sz = s[2];
+    var ox = o[0];
+    var oy = o[1];
+    var oz = o[2];
+    var out0 = (1 - (yy + zz)) * sx;
+    var out1 = (xy + wz) * sx;
+    var out2 = (xz - wy) * sx;
+    var out4 = (xy - wz) * sy;
+    var out5 = (1 - (xx + zz)) * sy;
+    var out6 = (yz + wx) * sy;
+    var out8 = (xz + wy) * sz;
+    var out9 = (yz - wx) * sz;
+    var out10 = (1 - (xx + yy)) * sz;
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = 0;
+    out[4] = out4;
+    out[5] = out5;
+    out[6] = out6;
+    out[7] = 0;
+    out[8] = out8;
+    out[9] = out9;
+    out[10] = out10;
+    out[11] = 0;
+    out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
+    out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
+    out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Calculates a 4x4 matrix from the given quaternion
+   *
+   * @param {mat4} out mat4 receiving operation result
+   * @param {quat} q Quaternion to create matrix from
+   *
+   * @returns {mat4} out
+   */
+
+  function fromQuat$1(out, q) {
+    var x = q[0],
+        y = q[1],
+        z = q[2],
+        w = q[3];
+    var x2 = x + x;
+    var y2 = y + y;
+    var z2 = z + z;
+    var xx = x * x2;
+    var yx = y * x2;
+    var yy = y * y2;
+    var zx = z * x2;
+    var zy = z * y2;
+    var zz = z * z2;
+    var wx = w * x2;
+    var wy = w * y2;
+    var wz = w * z2;
+    out[0] = 1 - yy - zz;
+    out[1] = yx + wz;
+    out[2] = zx - wy;
+    out[3] = 0;
+    out[4] = yx - wz;
+    out[5] = 1 - xx - zz;
+    out[6] = zy + wx;
+    out[7] = 0;
+    out[8] = zx + wy;
+    out[9] = zy - wx;
+    out[10] = 1 - xx - yy;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a frustum matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Number} left Left bound of the frustum
+   * @param {Number} right Right bound of the frustum
+   * @param {Number} bottom Bottom bound of the frustum
+   * @param {Number} top Top bound of the frustum
+   * @param {Number} near Near bound of the frustum
+   * @param {Number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function frustum(out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left);
+    var tb = 1 / (top - bottom);
+    var nf = 1 / (near - far);
+    out[0] = near * 2 * rl;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = near * 2 * tb;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = (right + left) * rl;
+    out[9] = (top + bottom) * tb;
+    out[10] = (far + near) * nf;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = far * near * 2 * nf;
+    out[15] = 0;
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given bounds.
+   * Passing null/undefined/no value for far will generate infinite projection matrix.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} fovy Vertical field of view in radians
+   * @param {number} aspect Aspect ratio. typically viewport width/height
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum, can be null or Infinity
+   * @returns {mat4} out
+   */
+
+  function perspective(out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        nf;
+    out[0] = f / aspect;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = f;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[11] = -1;
+    out[12] = 0;
+    out[13] = 0;
+    out[15] = 0;
+
+    if (far != null && far !== Infinity) {
+      nf = 1 / (near - far);
+      out[10] = (far + near) * nf;
+      out[14] = 2 * far * near * nf;
+    } else {
+      out[10] = -1;
+      out[14] = -2 * near;
+    }
+
+    return out;
+  }
+  /**
+   * Generates a perspective projection matrix with the given field of view.
+   * This is primarily useful for generating projection matrices to be used
+   * with the still experiemental WebVR API.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function perspectiveFromFieldOfView(out, fov, near, far) {
+    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+    var xScale = 2.0 / (leftTan + rightTan);
+    var yScale = 2.0 / (upTan + downTan);
+    out[0] = xScale;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    out[4] = 0.0;
+    out[5] = yScale;
+    out[6] = 0.0;
+    out[7] = 0.0;
+    out[8] = -((leftTan - rightTan) * xScale * 0.5);
+    out[9] = (upTan - downTan) * yScale * 0.5;
+    out[10] = far / (near - far);
+    out[11] = -1.0;
+    out[12] = 0.0;
+    out[13] = 0.0;
+    out[14] = far * near / (near - far);
+    out[15] = 0.0;
+    return out;
+  }
+  /**
+   * Generates a orthogonal projection matrix with the given bounds
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {number} left Left bound of the frustum
+   * @param {number} right Right bound of the frustum
+   * @param {number} bottom Bottom bound of the frustum
+   * @param {number} top Top bound of the frustum
+   * @param {number} near Near bound of the frustum
+   * @param {number} far Far bound of the frustum
+   * @returns {mat4} out
+   */
+
+  function ortho(out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right);
+    var bt = 1 / (bottom - top);
+    var nf = 1 / (near - far);
+    out[0] = -2 * lr;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = -2 * bt;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 2 * nf;
+    out[11] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a look-at matrix with the given eye position, focal point, and up axis.
+   * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {vec3} eye Position of the viewer
+   * @param {vec3} center Point the viewer is looking at
+   * @param {vec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function lookAt(out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
+    var eyex = eye[0];
+    var eyey = eye[1];
+    var eyez = eye[2];
+    var upx = up[0];
+    var upy = up[1];
+    var upz = up[2];
+    var centerx = center[0];
+    var centery = center[1];
+    var centerz = center[2];
+
+    if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
+      return identity$3(out);
+    }
+
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
+    len = 1 / Math.hypot(z0, z1, z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+    x0 = upy * z2 - upz * z1;
+    x1 = upz * z0 - upx * z2;
+    x2 = upx * z1 - upy * z0;
+    len = Math.hypot(x0, x1, x2);
+
+    if (!len) {
+      x0 = 0;
+      x1 = 0;
+      x2 = 0;
+    } else {
+      len = 1 / len;
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
+    len = Math.hypot(y0, y1, y2);
+
+    if (!len) {
+      y0 = 0;
+      y1 = 0;
+      y2 = 0;
+    } else {
+      len = 1 / len;
+      y0 *= len;
+      y1 *= len;
+      y2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = y0;
+    out[2] = z0;
+    out[3] = 0;
+    out[4] = x1;
+    out[5] = y1;
+    out[6] = z1;
+    out[7] = 0;
+    out[8] = x2;
+    out[9] = y2;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Generates a matrix that makes something look at something else.
+   *
+   * @param {mat4} out mat4 frustum matrix will be written into
+   * @param {vec3} eye Position of the viewer
+   * @param {vec3} center Point the viewer is looking at
+   * @param {vec3} up vec3 pointing up
+   * @returns {mat4} out
+   */
+
+  function targetTo(out, eye, target, up) {
+    var eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2];
+    var z0 = eyex - target[0],
+        z1 = eyey - target[1],
+        z2 = eyez - target[2];
+    var len = z0 * z0 + z1 * z1 + z2 * z2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      z0 *= len;
+      z1 *= len;
+      z2 *= len;
+    }
+
+    var x0 = upy * z2 - upz * z1,
+        x1 = upz * z0 - upx * z2,
+        x2 = upx * z1 - upy * z0;
+    len = x0 * x0 + x1 * x1 + x2 * x2;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+      x0 *= len;
+      x1 *= len;
+      x2 *= len;
+    }
+
+    out[0] = x0;
+    out[1] = x1;
+    out[2] = x2;
+    out[3] = 0;
+    out[4] = z1 * x2 - z2 * x1;
+    out[5] = z2 * x0 - z0 * x2;
+    out[6] = z0 * x1 - z1 * x0;
+    out[7] = 0;
+    out[8] = z0;
+    out[9] = z1;
+    out[10] = z2;
+    out[11] = 0;
+    out[12] = eyex;
+    out[13] = eyey;
+    out[14] = eyez;
+    out[15] = 1;
+    return out;
+  }
+  /**
+   * Returns a string representation of a mat4
+   *
+   * @param {mat4} a matrix to represent as a string
+   * @returns {String} string representation of the matrix
+   */
+
+  function str$3(a) {
+    return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+  }
+  /**
+   * Returns Frobenius norm of a mat4
+   *
+   * @param {mat4} a the matrix to calculate Frobenius norm of
+   * @returns {Number} Frobenius norm
+   */
+
+  function frob$3(a) {
+    return Math.hypot(a[0], a[1], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
+  }
+  /**
+   * Adds two mat4's
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the first operand
+   * @param {mat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function add$3(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    out[8] = a[8] + b[8];
+    out[9] = a[9] + b[9];
+    out[10] = a[10] + b[10];
+    out[11] = a[11] + b[11];
+    out[12] = a[12] + b[12];
+    out[13] = a[13] + b[13];
+    out[14] = a[14] + b[14];
+    out[15] = a[15] + b[15];
+    return out;
+  }
+  /**
+   * Subtracts matrix b from matrix a
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the first operand
+   * @param {mat4} b the second operand
+   * @returns {mat4} out
+   */
+
+  function subtract$3(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    out[4] = a[4] - b[4];
+    out[5] = a[5] - b[5];
+    out[6] = a[6] - b[6];
+    out[7] = a[7] - b[7];
+    out[8] = a[8] - b[8];
+    out[9] = a[9] - b[9];
+    out[10] = a[10] - b[10];
+    out[11] = a[11] - b[11];
+    out[12] = a[12] - b[12];
+    out[13] = a[13] - b[13];
+    out[14] = a[14] - b[14];
+    out[15] = a[15] - b[15];
+    return out;
+  }
+  /**
+   * Multiply each element of the matrix by a scalar.
+   *
+   * @param {mat4} out the receiving matrix
+   * @param {mat4} a the matrix to scale
+   * @param {Number} b amount to scale the matrix's elements by
+   * @returns {mat4} out
+   */
+
+  function multiplyScalar$3(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    out[8] = a[8] * b;
+    out[9] = a[9] * b;
+    out[10] = a[10] * b;
+    out[11] = a[11] * b;
+    out[12] = a[12] * b;
+    out[13] = a[13] * b;
+    out[14] = a[14] * b;
+    out[15] = a[15] * b;
+    return out;
+  }
+  /**
+   * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+   *
+   * @param {mat4} out the receiving vector
+   * @param {mat4} a the first operand
+   * @param {mat4} b the second operand
+   * @param {Number} scale the amount to scale b's elements by before adding
+   * @returns {mat4} out
+   */
+
+  function multiplyScalarAndAdd$3(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    out[4] = a[4] + b[4] * scale;
+    out[5] = a[5] + b[5] * scale;
+    out[6] = a[6] + b[6] * scale;
+    out[7] = a[7] + b[7] * scale;
+    out[8] = a[8] + b[8] * scale;
+    out[9] = a[9] + b[9] * scale;
+    out[10] = a[10] + b[10] * scale;
+    out[11] = a[11] + b[11] * scale;
+    out[12] = a[12] + b[12] * scale;
+    out[13] = a[13] + b[13] * scale;
+    out[14] = a[14] + b[14] * scale;
+    out[15] = a[15] + b[15] * scale;
+    return out;
+  }
+  /**
+   * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {mat4} a The first matrix.
+   * @param {mat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function exactEquals$3(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+  }
+  /**
+   * Returns whether or not the matrices have approximately the same elements in the same position.
+   *
+   * @param {mat4} a The first matrix.
+   * @param {mat4} b The second matrix.
+   * @returns {Boolean} True if the matrices are equal, false otherwise.
+   */
+
+  function equals$4(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var a8 = a[8],
+        a9 = a[9],
+        a10 = a[10],
+        a11 = a[11];
+    var a12 = a[12],
+        a13 = a[13],
+        a14 = a[14],
+        a15 = a[15];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    var b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    var b8 = b[8],
+        b9 = b[9],
+        b10 = b[10],
+        b11 = b[11];
+    var b12 = b[12],
+        b13 = b[13],
+        b14 = b[14],
+        b15 = b[15];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+  }
+  /**
+   * Alias for {@link mat4.multiply}
+   * @function
+   */
+
+  var mul$3 = multiply$3;
+  /**
+   * Alias for {@link mat4.subtract}
+   * @function
+   */
+
+  var sub$3 = subtract$3;
+
+  var mat4 = /*#__PURE__*/Object.freeze({
+    create: create$3,
+    clone: clone$3,
+    copy: copy$3,
+    fromValues: fromValues$3,
+    set: set$3,
+    identity: identity$3,
+    transpose: transpose$2,
+    invert: invert$3,
+    adjoint: adjoint$2,
+    determinant: determinant$3,
+    multiply: multiply$3,
+    translate: translate$2,
+    scale: scale$3,
+    rotate: rotate$3,
+    rotateX: rotateX,
+    rotateY: rotateY,
+    rotateZ: rotateZ,
+    fromTranslation: fromTranslation$2,
+    fromScaling: fromScaling$3,
+    fromRotation: fromRotation$3,
+    fromXRotation: fromXRotation,
+    fromYRotation: fromYRotation,
+    fromZRotation: fromZRotation,
+    fromRotationTranslation: fromRotationTranslation,
+    fromQuat2: fromQuat2,
+    getTranslation: getTranslation,
+    getScaling: getScaling,
+    getRotation: getRotation,
+    fromRotationTranslationScale: fromRotationTranslationScale,
+    fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin,
+    fromQuat: fromQuat$1,
+    frustum: frustum,
+    perspective: perspective,
+    perspectiveFromFieldOfView: perspectiveFromFieldOfView,
+    ortho: ortho,
+    lookAt: lookAt,
+    targetTo: targetTo,
+    str: str$3,
+    frob: frob$3,
+    add: add$3,
+    subtract: subtract$3,
+    multiplyScalar: multiplyScalar$3,
+    multiplyScalarAndAdd: multiplyScalarAndAdd$3,
+    exactEquals: exactEquals$3,
+    equals: equals$4,
+    mul: mul$3,
+    sub: sub$3
+  });
+
+  /**
+   * 3 Dimensional Vector
+   * @module vec3
+   */
+
+  /**
+   * Creates a new, empty vec3
+   *
+   * @returns {vec3} a new 3D vector
+   */
+
+  function create$4() {
+    var out = new ARRAY_TYPE(3);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec3 initialized with values from an existing vector
+   *
+   * @param {vec3} a vector to clone
+   * @returns {vec3} a new 3D vector
+   */
+
+  function clone$4(a) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Calculates the length of a vec3
+   *
+   * @param {vec3} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Creates a new vec3 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} a new 3D vector
+   */
+
+  function fromValues$4(x, y, z) {
+    var out = new ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Copy the values from one vec3 to another
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the source vector
+   * @returns {vec3} out
+   */
+
+  function copy$4(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+  }
+  /**
+   * Set the components of a vec3 to the given values
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @returns {vec3} out
+   */
+
+  function set$4(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Adds two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function add$4(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function subtract$4(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+  }
+  /**
+   * Multiplies two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function multiply$4(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+  }
+  /**
+   * Divides two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function divide(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to ceil
+   * @returns {vec3} out
+   */
+
+  function ceil(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to floor
+   * @returns {vec3} out
+   */
+
+  function floor(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function min(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function max(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to round
+   * @returns {vec3} out
+   */
+
+  function round(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    return out;
+  }
+  /**
+   * Scales a vec3 by a scalar number
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec3} out
+   */
+
+  function scale$4(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+  }
+  /**
+   * Adds two vec3's after scaling the second operand by a scalar value
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec3} out
+   */
+
+  function scaleAndAdd(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec3's
+   *
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return Math.hypot(x, y, z);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec3's
+   *
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Calculates the squared length of a vec3
+   *
+   * @param {vec3} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    return x * x + y * y + z * z;
+  }
+  /**
+   * Negates the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to negate
+   * @returns {vec3} out
+   */
+
+  function negate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to invert
+   * @returns {vec3} out
+   */
+
+  function inverse(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    return out;
+  }
+  /**
+   * Normalize a vec3
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a vector to normalize
+   * @returns {vec3} out
+   */
+
+  function normalize(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var len = x * x + y * y + z * z;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec3's
+   *
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  /**
+   * Computes the cross product of two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2];
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec3's
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function lerp(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    return out;
+  }
+  /**
+   * Performs a hermite interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @param {vec3} c the third operand
+   * @param {vec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function hermite(out, a, b, c, d, t) {
+    var factorTimes2 = t * t;
+    var factor1 = factorTimes2 * (2 * t - 3) + 1;
+    var factor2 = factorTimes2 * (t - 2) + t;
+    var factor3 = factorTimes2 * (t - 1);
+    var factor4 = factorTimes2 * (3 - 2 * t);
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Performs a bezier interpolation with two control points
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the first operand
+   * @param {vec3} b the second operand
+   * @param {vec3} c the third operand
+   * @param {vec3} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec3} out
+   */
+
+  function bezier(out, a, b, c, d, t) {
+    var inverseFactor = 1 - t;
+    var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+    var factorTimes2 = t * t;
+    var factor1 = inverseFactorTimesTwo * inverseFactor;
+    var factor2 = 3 * t * inverseFactorTimesTwo;
+    var factor3 = 3 * factorTimes2 * inverseFactor;
+    var factor4 = factorTimes2 * t;
+    out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+    out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+    out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec3} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec3} out
+   */
+
+  function random(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    var z = RANDOM() * 2.0 - 1.0;
+    var zScale = Math.sqrt(1.0 - z * z) * scale;
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat4.
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the vector to transform
+   * @param {mat4} m matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat4(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+    w = w || 1.0;
+    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a mat3.
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the vector to transform
+   * @param {mat3} m the 3x3 matrix to transform with
+   * @returns {vec3} out
+   */
+
+  function transformMat3(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x * m[0] + y * m[3] + z * m[6];
+    out[1] = x * m[1] + y * m[4] + z * m[7];
+    out[2] = x * m[2] + y * m[5] + z * m[8];
+    return out;
+  }
+  /**
+   * Transforms the vec3 with a quat
+   * Can also be used for dual quaternions. (Multiply it with the real part)
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec3} a the vector to transform
+   * @param {quat} q quaternion to transform with
+   * @returns {vec3} out
+   */
+
+  function transformQuat(out, a, q) {
+    // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3];
+    var x = a[0],
+        y = a[1],
+        z = a[2]; // var qvec = [qx, qy, qz];
+    // var uv = vec3.cross([], qvec, a);
+
+    var uvx = qy * z - qz * y,
+        uvy = qz * x - qx * z,
+        uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv);
+
+    var uuvx = qy * uvz - qz * uvy,
+        uuvy = qz * uvx - qx * uvz,
+        uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w);
+
+    var w2 = qw * 2;
+    uvx *= w2;
+    uvy *= w2;
+    uvz *= w2; // vec3.scale(uuv, uuv, 2);
+
+    uuvx *= 2;
+    uuvy *= 2;
+    uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv));
+
+    out[0] = x + uvx + uuvx;
+    out[1] = y + uvy + uuvy;
+    out[2] = z + uvz + uuvz;
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the x-axis
+   * @param {vec3} out The receiving vec3
+   * @param {vec3} a The vec3 point to rotate
+   * @param {vec3} b The origin of the rotation
+   * @param {Number} c The angle of rotation
+   * @returns {vec3} out
+   */
+
+  function rotateX$1(out, a, b, c) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0];
+    r[1] = p[1] * Math.cos(c) - p[2] * Math.sin(c);
+    r[2] = p[1] * Math.sin(c) + p[2] * Math.cos(c); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the y-axis
+   * @param {vec3} out The receiving vec3
+   * @param {vec3} a The vec3 point to rotate
+   * @param {vec3} b The origin of the rotation
+   * @param {Number} c The angle of rotation
+   * @returns {vec3} out
+   */
+
+  function rotateY$1(out, a, b, c) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[2] * Math.sin(c) + p[0] * Math.cos(c);
+    r[1] = p[1];
+    r[2] = p[2] * Math.cos(c) - p[0] * Math.sin(c); //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Rotate a 3D vector around the z-axis
+   * @param {vec3} out The receiving vec3
+   * @param {vec3} a The vec3 point to rotate
+   * @param {vec3} b The origin of the rotation
+   * @param {Number} c The angle of rotation
+   * @returns {vec3} out
+   */
+
+  function rotateZ$1(out, a, b, c) {
+    var p = [],
+        r = []; //Translate point to the origin
+
+    p[0] = a[0] - b[0];
+    p[1] = a[1] - b[1];
+    p[2] = a[2] - b[2]; //perform rotation
+
+    r[0] = p[0] * Math.cos(c) - p[1] * Math.sin(c);
+    r[1] = p[0] * Math.sin(c) + p[1] * Math.cos(c);
+    r[2] = p[2]; //translate to correct position
+
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
+    return out;
+  }
+  /**
+   * Get the angle between two 3D vectors
+   * @param {vec3} a The first operand
+   * @param {vec3} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle(a, b) {
+    var tempA = fromValues$4(a[0], a[1], a[2]);
+    var tempB = fromValues$4(b[0], b[1], b[2]);
+    normalize(tempA, tempA);
+    normalize(tempB, tempB);
+    var cosine = dot(tempA, tempB);
+
+    if (cosine > 1.0) {
+      return 0;
+    } else if (cosine < -1.0) {
+      return Math.PI;
+    } else {
+      return Math.acos(cosine);
+    }
+  }
+  /**
+   * Set the components of a vec3 to zero
+   *
+   * @param {vec3} out the receiving vector
+   * @returns {vec3} out
+   */
+
+  function zero(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {vec3} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$4(a) {
+    return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {vec3} a The first vector.
+   * @param {vec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$4(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {vec3} a The first vector.
+   * @param {vec3} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$5(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+  }
+  /**
+   * Alias for {@link vec3.subtract}
+   * @function
+   */
+
+  var sub$4 = subtract$4;
+  /**
+   * Alias for {@link vec3.multiply}
+   * @function
+   */
+
+  var mul$4 = multiply$4;
+  /**
+   * Alias for {@link vec3.divide}
+   * @function
+   */
+
+  var div = divide;
+  /**
+   * Alias for {@link vec3.distance}
+   * @function
+   */
+
+  var dist = distance;
+  /**
+   * Alias for {@link vec3.squaredDistance}
+   * @function
+   */
+
+  var sqrDist = squaredDistance;
+  /**
+   * Alias for {@link vec3.length}
+   * @function
+   */
+
+  var len = length;
+  /**
+   * Alias for {@link vec3.squaredLength}
+   * @function
+   */
+
+  var sqrLen = squaredLength;
+  /**
+   * Perform some operation over an array of vec3s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach = function () {
+    var vec = create$4();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 3;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec3 = /*#__PURE__*/Object.freeze({
+    create: create$4,
+    clone: clone$4,
+    length: length,
+    fromValues: fromValues$4,
+    copy: copy$4,
+    set: set$4,
+    add: add$4,
+    subtract: subtract$4,
+    multiply: multiply$4,
+    divide: divide,
+    ceil: ceil,
+    floor: floor,
+    min: min,
+    max: max,
+    round: round,
+    scale: scale$4,
+    scaleAndAdd: scaleAndAdd,
+    distance: distance,
+    squaredDistance: squaredDistance,
+    squaredLength: squaredLength,
+    negate: negate,
+    inverse: inverse,
+    normalize: normalize,
+    dot: dot,
+    cross: cross,
+    lerp: lerp,
+    hermite: hermite,
+    bezier: bezier,
+    random: random,
+    transformMat4: transformMat4,
+    transformMat3: transformMat3,
+    transformQuat: transformQuat,
+    rotateX: rotateX$1,
+    rotateY: rotateY$1,
+    rotateZ: rotateZ$1,
+    angle: angle,
+    zero: zero,
+    str: str$4,
+    exactEquals: exactEquals$4,
+    equals: equals$5,
+    sub: sub$4,
+    mul: mul$4,
+    div: div,
+    dist: dist,
+    sqrDist: sqrDist,
+    len: len,
+    sqrLen: sqrLen,
+    forEach: forEach
+  });
+
+  /**
+   * 4 Dimensional Vector
+   * @module vec4
+   */
+
+  /**
+   * Creates a new, empty vec4
+   *
+   * @returns {vec4} a new 4D vector
+   */
+
+  function create$5() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with values from an existing vector
+   *
+   * @param {vec4} a vector to clone
+   * @returns {vec4} a new 4D vector
+   */
+
+  function clone$5(a) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a new vec4 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} a new 4D vector
+   */
+
+  function fromValues$5(x, y, z, w) {
+    var out = new ARRAY_TYPE(4);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Copy the values from one vec4 to another
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the source vector
+   * @returns {vec4} out
+   */
+
+  function copy$5(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to the given values
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {vec4} out
+   */
+
+  function set$5(out, x, y, z, w) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = w;
+    return out;
+  }
+  /**
+   * Adds two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function add$5(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function subtract$5(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    out[3] = a[3] - b[3];
+    return out;
+  }
+  /**
+   * Multiplies two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function multiply$5(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    out[3] = a[3] * b[3];
+    return out;
+  }
+  /**
+   * Divides two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function divide$1(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    out[3] = a[3] / b[3];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to ceil
+   * @returns {vec4} out
+   */
+
+  function ceil$1(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    out[2] = Math.ceil(a[2]);
+    out[3] = Math.ceil(a[3]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to floor
+   * @returns {vec4} out
+   */
+
+  function floor$1(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    out[2] = Math.floor(a[2]);
+    out[3] = Math.floor(a[3]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function min$1(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    out[2] = Math.min(a[2], b[2]);
+    out[3] = Math.min(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {vec4} out
+   */
+
+  function max$1(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    out[2] = Math.max(a[2], b[2]);
+    out[3] = Math.max(a[3], b[3]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to round
+   * @returns {vec4} out
+   */
+
+  function round$1(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    out[2] = Math.round(a[2]);
+    out[3] = Math.round(a[3]);
+    return out;
+  }
+  /**
+   * Scales a vec4 by a scalar number
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec4} out
+   */
+
+  function scale$5(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    return out;
+  }
+  /**
+   * Adds two vec4's after scaling the second operand by a scalar value
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec4} out
+   */
+
+  function scaleAndAdd$1(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    out[2] = a[2] + b[2] * scale;
+    out[3] = a[3] + b[3] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec4's
+   *
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec4's
+   *
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$1(a, b) {
+    var x = b[0] - a[0];
+    var y = b[1] - a[1];
+    var z = b[2] - a[2];
+    var w = b[3] - a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Calculates the length of a vec4
+   *
+   * @param {vec4} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return Math.hypot(x, y, z, w);
+  }
+  /**
+   * Calculates the squared length of a vec4
+   *
+   * @param {vec4} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$1(a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    return x * x + y * y + z * z + w * w;
+  }
+  /**
+   * Negates the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to negate
+   * @returns {vec4} out
+   */
+
+  function negate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = -a[3];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to invert
+   * @returns {vec4} out
+   */
+
+  function inverse$1(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    out[2] = 1.0 / a[2];
+    out[3] = 1.0 / a[3];
+    return out;
+  }
+  /**
+   * Normalize a vec4
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a vector to normalize
+   * @returns {vec4} out
+   */
+
+  function normalize$1(out, a) {
+    var x = a[0];
+    var y = a[1];
+    var z = a[2];
+    var w = a[3];
+    var len = x * x + y * y + z * z + w * w;
+
+    if (len > 0) {
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec4's
+   *
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$1(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  /**
+   * Returns the cross-product of three vectors in a 4-dimensional space
+   *
+   * @param {vec4} result the receiving vector
+   * @param {vec4} U the first vector
+   * @param {vec4} V the second vector
+   * @param {vec4} W the third vector
+   * @returns {vec4} result
+   */
+
+  function cross$1(out, u, v, w) {
+    var A = v[0] * w[1] - v[1] * w[0],
+        B = v[0] * w[2] - v[2] * w[0],
+        C = v[0] * w[3] - v[3] * w[0],
+        D = v[1] * w[2] - v[2] * w[1],
+        E = v[1] * w[3] - v[3] * w[1],
+        F = v[2] * w[3] - v[3] * w[2];
+    var G = u[0];
+    var H = u[1];
+    var I = u[2];
+    var J = u[3];
+    out[0] = H * F - I * E + J * D;
+    out[1] = -(G * F) + I * C - J * B;
+    out[2] = G * E - H * C + J * A;
+    out[3] = -(G * D) + H * B - I * A;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec4's
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the first operand
+   * @param {vec4} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec4} out
+   */
+
+  function lerp$1(out, a, b, t) {
+    var ax = a[0];
+    var ay = a[1];
+    var az = a[2];
+    var aw = a[3];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    out[2] = az + t * (b[2] - az);
+    out[3] = aw + t * (b[3] - aw);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec4} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec4} out
+   */
+
+  function random$1(out, scale) {
+    scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a
+    // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.
+    // http://projecteuclid.org/euclid.aoms/1177692644;
+
+    var v1, v2, v3, v4;
+    var s1, s2;
+
+    do {
+      v1 = RANDOM() * 2 - 1;
+      v2 = RANDOM() * 2 - 1;
+      s1 = v1 * v1 + v2 * v2;
+    } while (s1 >= 1);
+
+    do {
+      v3 = RANDOM() * 2 - 1;
+      v4 = RANDOM() * 2 - 1;
+      s2 = v3 * v3 + v4 * v4;
+    } while (s2 >= 1);
+
+    var d = Math.sqrt((1 - s1) / s2);
+    out[0] = scale * v1;
+    out[1] = scale * v2;
+    out[2] = scale * v3 * d;
+    out[3] = scale * v4 * d;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a mat4.
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the vector to transform
+   * @param {mat4} m matrix to transform with
+   * @returns {vec4} out
+   */
+
+  function transformMat4$1(out, a, m) {
+    var x = a[0],
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+    return out;
+  }
+  /**
+   * Transforms the vec4 with a quat
+   *
+   * @param {vec4} out the receiving vector
+   * @param {vec4} a the vector to transform
+   * @param {quat} q quaternion to transform with
+   * @returns {vec4} out
+   */
+
+  function transformQuat$1(out, a, q) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3]; // calculate quat * vec
+
+    var ix = qw * x + qy * z - qz * y;
+    var iy = qw * y + qz * x - qx * z;
+    var iz = qw * z + qx * y - qy * x;
+    var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
+
+    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Set the components of a vec4 to zero
+   *
+   * @param {vec4} out the receiving vector
+   * @returns {vec4} out
+   */
+
+  function zero$1(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    out[2] = 0.0;
+    out[3] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {vec4} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$5(a) {
+    return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+  }
+  /**
+   * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {vec4} a The first vector.
+   * @param {vec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$5(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {vec4} a The first vector.
+   * @param {vec4} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$6(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+  }
+  /**
+   * Alias for {@link vec4.subtract}
+   * @function
+   */
+
+  var sub$5 = subtract$5;
+  /**
+   * Alias for {@link vec4.multiply}
+   * @function
+   */
+
+  var mul$5 = multiply$5;
+  /**
+   * Alias for {@link vec4.divide}
+   * @function
+   */
+
+  var div$1 = divide$1;
+  /**
+   * Alias for {@link vec4.distance}
+   * @function
+   */
+
+  var dist$1 = distance$1;
+  /**
+   * Alias for {@link vec4.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$1 = squaredDistance$1;
+  /**
+   * Alias for {@link vec4.length}
+   * @function
+   */
+
+  var len$1 = length$1;
+  /**
+   * Alias for {@link vec4.squaredLength}
+   * @function
+   */
+
+  var sqrLen$1 = squaredLength$1;
+  /**
+   * Perform some operation over an array of vec4s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$1 = function () {
+    var vec = create$5();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 4;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        vec[2] = a[i + 2];
+        vec[3] = a[i + 3];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+        a[i + 2] = vec[2];
+        a[i + 3] = vec[3];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec4 = /*#__PURE__*/Object.freeze({
+    create: create$5,
+    clone: clone$5,
+    fromValues: fromValues$5,
+    copy: copy$5,
+    set: set$5,
+    add: add$5,
+    subtract: subtract$5,
+    multiply: multiply$5,
+    divide: divide$1,
+    ceil: ceil$1,
+    floor: floor$1,
+    min: min$1,
+    max: max$1,
+    round: round$1,
+    scale: scale$5,
+    scaleAndAdd: scaleAndAdd$1,
+    distance: distance$1,
+    squaredDistance: squaredDistance$1,
+    length: length$1,
+    squaredLength: squaredLength$1,
+    negate: negate$1,
+    inverse: inverse$1,
+    normalize: normalize$1,
+    dot: dot$1,
+    cross: cross$1,
+    lerp: lerp$1,
+    random: random$1,
+    transformMat4: transformMat4$1,
+    transformQuat: transformQuat$1,
+    zero: zero$1,
+    str: str$5,
+    exactEquals: exactEquals$5,
+    equals: equals$6,
+    sub: sub$5,
+    mul: mul$5,
+    div: div$1,
+    dist: dist$1,
+    sqrDist: sqrDist$1,
+    len: len$1,
+    sqrLen: sqrLen$1,
+    forEach: forEach$1
+  });
+
+  /**
+   * Quaternion
+   * @module quat
+   */
+
+  /**
+   * Creates a new identity quat
+   *
+   * @returns {quat} a new quaternion
+   */
+
+  function create$6() {
+    var out = new ARRAY_TYPE(4);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+    }
+
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Set a quat to the identity quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function identity$4(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    return out;
+  }
+  /**
+   * Sets a quat from the given angle and rotation axis,
+   * then returns it.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {vec3} axis the axis around which to rotate
+   * @param {Number} rad the angle in radians
+   * @returns {quat} out
+   **/
+
+  function setAxisAngle(out, axis, rad) {
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    out[0] = s * axis[0];
+    out[1] = s * axis[1];
+    out[2] = s * axis[2];
+    out[3] = Math.cos(rad);
+    return out;
+  }
+  /**
+   * Gets the rotation axis and angle for a given
+   *  quaternion. If a quaternion is created with
+   *  setAxisAngle, this method will return the same
+   *  values as providied in the original parameter list
+   *  OR functionally equivalent values.
+   * Example: The quaternion formed by axis [0, 0, 1] and
+   *  angle -90 is the same as the quaternion formed by
+   *  [0, 0, 1] and 270. This method favors the latter.
+   * @param  {vec3} out_axis  Vector receiving the axis of rotation
+   * @param  {quat} q     Quaternion to be decomposed
+   * @return {Number}     Angle, in radians, of the rotation
+   */
+
+  function getAxisAngle(out_axis, q) {
+    var rad = Math.acos(q[3]) * 2.0;
+    var s = Math.sin(rad / 2.0);
+
+    if (s > EPSILON) {
+      out_axis[0] = q[0] / s;
+      out_axis[1] = q[1] / s;
+      out_axis[2] = q[2] / s;
+    } else {
+      // If s is zero, return any axis (no rotation - axis does not matter)
+      out_axis[0] = 1;
+      out_axis[1] = 0;
+      out_axis[2] = 0;
+    }
+
+    return rad;
+  }
+  /**
+   * Multiplies two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @returns {quat} out
+   */
+
+  function multiply$6(out, a, b) {
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    out[0] = ax * bw + aw * bx + ay * bz - az * by;
+    out[1] = ay * bw + aw * by + az * bx - ax * bz;
+    out[2] = az * bw + aw * bz + ax * by - ay * bx;
+    out[3] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the X axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {quat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateX$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + aw * bx;
+    out[1] = ay * bw + az * bx;
+    out[2] = az * bw - ay * bx;
+    out[3] = aw * bw - ax * bx;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Y axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {quat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateY$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var by = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw - az * by;
+    out[1] = ay * bw + aw * by;
+    out[2] = az * bw + ax * by;
+    out[3] = aw * bw - ay * by;
+    return out;
+  }
+  /**
+   * Rotates a quaternion by the given angle about the Z axis
+   *
+   * @param {quat} out quat receiving operation result
+   * @param {quat} a quat to rotate
+   * @param {number} rad angle (in radians) to rotate
+   * @returns {quat} out
+   */
+
+  function rotateZ$2(out, a, rad) {
+    rad *= 0.5;
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bz = Math.sin(rad),
+        bw = Math.cos(rad);
+    out[0] = ax * bw + ay * bz;
+    out[1] = ay * bw - ax * bz;
+    out[2] = az * bw + aw * bz;
+    out[3] = aw * bw - az * bz;
+    return out;
+  }
+  /**
+   * Calculates the W component of a quat from the X, Y, and Z components.
+   * Assumes that quaternion is 1 unit in length.
+   * Any existing W component will be ignored.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a quat to calculate W component of
+   * @returns {quat} out
+   */
+
+  function calculateW(out, a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+    return out;
+  }
+  /**
+   * Performs a spherical linear interpolation between two quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  function slerp(out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+    var ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    var bx = b[0],
+        by = b[1],
+        bz = b[2],
+        bw = b[3];
+    var omega, cosom, sinom, scale0, scale1; // calc cosine
+
+    cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary)
+
+    if (cosom < 0.0) {
+      cosom = -cosom;
+      bx = -bx;
+      by = -by;
+      bz = -bz;
+      bw = -bw;
+    } // calculate coefficients
+
+
+    if (1.0 - cosom > EPSILON) {
+      // standard case (slerp)
+      omega = Math.acos(cosom);
+      sinom = Math.sin(omega);
+      scale0 = Math.sin((1.0 - t) * omega) / sinom;
+      scale1 = Math.sin(t * omega) / sinom;
+    } else {
+      // "from" and "to" quaternions are very close
+      //  ... so we can do a linear interpolation
+      scale0 = 1.0 - t;
+      scale1 = t;
+    } // calculate final values
+
+
+    out[0] = scale0 * ax + scale1 * bx;
+    out[1] = scale0 * ay + scale1 * by;
+    out[2] = scale0 * az + scale1 * bz;
+    out[3] = scale0 * aw + scale1 * bw;
+    return out;
+  }
+  /**
+   * Generates a random quaternion
+   *
+   * @param {quat} out the receiving quaternion
+   * @returns {quat} out
+   */
+
+  function random$2(out) {
+    // Implementation of http://planning.cs.uiuc.edu/node198.html
+    // TODO: Calling random 3 times is probably not the fastest solution
+    var u1 = RANDOM();
+    var u2 = RANDOM();
+    var u3 = RANDOM();
+    var sqrt1MinusU1 = Math.sqrt(1 - u1);
+    var sqrtU1 = Math.sqrt(u1);
+    out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);
+    out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);
+    out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);
+    out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);
+    return out;
+  }
+  /**
+   * Calculates the inverse of a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a quat to calculate inverse of
+   * @returns {quat} out
+   */
+
+  function invert$4(out, a) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3];
+    var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+    var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+    out[0] = -a0 * invDot;
+    out[1] = -a1 * invDot;
+    out[2] = -a2 * invDot;
+    out[3] = a3 * invDot;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a quat
+   * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a quat to calculate conjugate of
+   * @returns {quat} out
+   */
+
+  function conjugate(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given 3x3 rotation matrix.
+   *
+   * NOTE: The resultant quaternion is not normalized, so you should be sure
+   * to renormalize the quaternion yourself where necessary.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {mat3} m rotation matrix
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromMat3(out, m) {
+    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+    // article "Quaternion Calculus and Fast Animation".
+    var fTrace = m[0] + m[4] + m[8];
+    var fRoot;
+
+    if (fTrace > 0.0) {
+      // |w| > 1/2, may as well choose w > 1/2
+      fRoot = Math.sqrt(fTrace + 1.0); // 2w
+
+      out[3] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot; // 1/(4w)
+
+      out[0] = (m[5] - m[7]) * fRoot;
+      out[1] = (m[6] - m[2]) * fRoot;
+      out[2] = (m[1] - m[3]) * fRoot;
+    } else {
+      // |w| <= 1/2
+      var i = 0;
+      if (m[4] > m[0]) i = 1;
+      if (m[8] > m[i * 3 + i]) i = 2;
+      var j = (i + 1) % 3;
+      var k = (i + 2) % 3;
+      fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+      out[i] = 0.5 * fRoot;
+      fRoot = 0.5 / fRoot;
+      out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+      out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+      out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a quaternion from the given euler angle x, y, z.
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {x} Angle to rotate around X axis in degrees.
+   * @param {y} Angle to rotate around Y axis in degrees.
+   * @param {z} Angle to rotate around Z axis in degrees.
+   * @returns {quat} out
+   * @function
+   */
+
+  function fromEuler(out, x, y, z) {
+    var halfToRad = 0.5 * Math.PI / 180.0;
+    x *= halfToRad;
+    y *= halfToRad;
+    z *= halfToRad;
+    var sx = Math.sin(x);
+    var cx = Math.cos(x);
+    var sy = Math.sin(y);
+    var cy = Math.cos(y);
+    var sz = Math.sin(z);
+    var cz = Math.cos(z);
+    out[0] = sx * cy * cz - cx * sy * sz;
+    out[1] = cx * sy * cz + sx * cy * sz;
+    out[2] = cx * cy * sz - sx * sy * cz;
+    out[3] = cx * cy * cz + sx * sy * sz;
+    return out;
+  }
+  /**
+   * Returns a string representation of a quatenion
+   *
+   * @param {quat} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$6(a) {
+    return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {quat} a quaternion to clone
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var clone$6 = clone$5;
+  /**
+   * Creates a new quat initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} a new quaternion
+   * @function
+   */
+
+  var fromValues$6 = fromValues$5;
+  /**
+   * Copy the values from one quat to another
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the source quaternion
+   * @returns {quat} out
+   * @function
+   */
+
+  var copy$6 = copy$5;
+  /**
+   * Set the components of a quat to the given values
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @param {Number} z Z component
+   * @param {Number} w W component
+   * @returns {quat} out
+   * @function
+   */
+
+  var set$6 = set$5;
+  /**
+   * Adds two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @returns {quat} out
+   * @function
+   */
+
+  var add$6 = add$5;
+  /**
+   * Alias for {@link quat.multiply}
+   * @function
+   */
+
+  var mul$6 = multiply$6;
+  /**
+   * Scales a quat by a scalar number
+   *
+   * @param {quat} out the receiving vector
+   * @param {quat} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {quat} out
+   * @function
+   */
+
+  var scale$6 = scale$5;
+  /**
+   * Calculates the dot product of two quat's
+   *
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$2 = dot$1;
+  /**
+   * Performs a linear interpolation between two quat's
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   * @function
+   */
+
+  var lerp$2 = lerp$1;
+  /**
+   * Calculates the length of a quat
+   *
+   * @param {quat} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  var length$2 = length$1;
+  /**
+   * Alias for {@link quat.length}
+   * @function
+   */
+
+  var len$2 = length$2;
+  /**
+   * Calculates the squared length of a quat
+   *
+   * @param {quat} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$2 = squaredLength$1;
+  /**
+   * Alias for {@link quat.squaredLength}
+   * @function
+   */
+
+  var sqrLen$2 = squaredLength$2;
+  /**
+   * Normalize a quat
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a quaternion to normalize
+   * @returns {quat} out
+   * @function
+   */
+
+  var normalize$2 = normalize$1;
+  /**
+   * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {quat} a The first quaternion.
+   * @param {quat} b The second quaternion.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var exactEquals$6 = exactEquals$5;
+  /**
+   * Returns whether or not the quaternions have approximately the same elements in the same position.
+   *
+   * @param {quat} a The first vector.
+   * @param {quat} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  var equals$7 = equals$6;
+  /**
+   * Sets a quaternion to represent the shortest rotation from one
+   * vector to another.
+   *
+   * Both vectors are assumed to be unit length.
+   *
+   * @param {quat} out the receiving quaternion.
+   * @param {vec3} a the initial vector
+   * @param {vec3} b the destination vector
+   * @returns {quat} out
+   */
+
+  var rotationTo = function () {
+    var tmpvec3 = create$4();
+    var xUnitVec3 = fromValues$4(1, 0, 0);
+    var yUnitVec3 = fromValues$4(0, 1, 0);
+    return function (out, a, b) {
+      var dot$1 = dot(a, b);
+
+      if (dot$1 < -0.999999) {
+        cross(tmpvec3, xUnitVec3, a);
+        if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+        normalize(tmpvec3, tmpvec3);
+        setAxisAngle(out, tmpvec3, Math.PI);
+        return out;
+      } else if (dot$1 > 0.999999) {
+        out[0] = 0;
+        out[1] = 0;
+        out[2] = 0;
+        out[3] = 1;
+        return out;
+      } else {
+        cross(tmpvec3, a, b);
+        out[0] = tmpvec3[0];
+        out[1] = tmpvec3[1];
+        out[2] = tmpvec3[2];
+        out[3] = 1 + dot$1;
+        return normalize$2(out, out);
+      }
+    };
+  }();
+  /**
+   * Performs a spherical linear interpolation with two control points
+   *
+   * @param {quat} out the receiving quaternion
+   * @param {quat} a the first operand
+   * @param {quat} b the second operand
+   * @param {quat} c the third operand
+   * @param {quat} d the fourth operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat} out
+   */
+
+  var sqlerp = function () {
+    var temp1 = create$6();
+    var temp2 = create$6();
+    return function (out, a, b, c, d, t) {
+      slerp(temp1, a, d, t);
+      slerp(temp2, b, c, t);
+      slerp(out, temp1, temp2, 2 * t * (1 - t));
+      return out;
+    };
+  }();
+  /**
+   * Sets the specified quaternion with values corresponding to the given
+   * axes. Each axis is a vec3 and is expected to be unit length and
+   * perpendicular to all other specified axes.
+   *
+   * @param {vec3} view  the vector representing the viewing direction
+   * @param {vec3} right the vector representing the local "right" direction
+   * @param {vec3} up    the vector representing the local "up" direction
+   * @returns {quat} out
+   */
+
+  var setAxes = function () {
+    var matr = create$2();
+    return function (out, view, right, up) {
+      matr[0] = right[0];
+      matr[3] = right[1];
+      matr[6] = right[2];
+      matr[1] = up[0];
+      matr[4] = up[1];
+      matr[7] = up[2];
+      matr[2] = -view[0];
+      matr[5] = -view[1];
+      matr[8] = -view[2];
+      return normalize$2(out, fromMat3(out, matr));
+    };
+  }();
+
+  var quat = /*#__PURE__*/Object.freeze({
+    create: create$6,
+    identity: identity$4,
+    setAxisAngle: setAxisAngle,
+    getAxisAngle: getAxisAngle,
+    multiply: multiply$6,
+    rotateX: rotateX$2,
+    rotateY: rotateY$2,
+    rotateZ: rotateZ$2,
+    calculateW: calculateW,
+    slerp: slerp,
+    random: random$2,
+    invert: invert$4,
+    conjugate: conjugate,
+    fromMat3: fromMat3,
+    fromEuler: fromEuler,
+    str: str$6,
+    clone: clone$6,
+    fromValues: fromValues$6,
+    copy: copy$6,
+    set: set$6,
+    add: add$6,
+    mul: mul$6,
+    scale: scale$6,
+    dot: dot$2,
+    lerp: lerp$2,
+    length: length$2,
+    len: len$2,
+    squaredLength: squaredLength$2,
+    sqrLen: sqrLen$2,
+    normalize: normalize$2,
+    exactEquals: exactEquals$6,
+    equals: equals$7,
+    rotationTo: rotationTo,
+    sqlerp: sqlerp,
+    setAxes: setAxes
+  });
+
+  /**
+   * Dual Quaternion<br>
+   * Format: [real, dual]<br>
+   * Quaternion format: XYZW<br>
+   * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>
+   * @module quat2
+   */
+
+  /**
+   * Creates a new identity dual quat
+   *
+   * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]
+   */
+
+  function create$7() {
+    var dq = new ARRAY_TYPE(8);
+
+    if (ARRAY_TYPE != Float32Array) {
+      dq[0] = 0;
+      dq[1] = 0;
+      dq[2] = 0;
+      dq[4] = 0;
+      dq[5] = 0;
+      dq[6] = 0;
+      dq[7] = 0;
+    }
+
+    dq[3] = 1;
+    return dq;
+  }
+  /**
+   * Creates a new quat initialized with values from an existing quaternion
+   *
+   * @param {quat2} a dual quaternion to clone
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function clone$7(a) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = a[0];
+    dq[1] = a[1];
+    dq[2] = a[2];
+    dq[3] = a[3];
+    dq[4] = a[4];
+    dq[5] = a[5];
+    dq[6] = a[6];
+    dq[7] = a[7];
+    return dq;
+  }
+  /**
+   * Creates a new dual quat initialized with the given values
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    dq[4] = x2;
+    dq[5] = y2;
+    dq[6] = z2;
+    dq[7] = w2;
+    return dq;
+  }
+  /**
+   * Creates a new dual quat from the given values (quat and translation)
+   *
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component (translation)
+   * @param {Number} y2 Y component (translation)
+   * @param {Number} z2 Z component (translation)
+   * @returns {quat2} new dual quaternion
+   * @function
+   */
+
+  function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {
+    var dq = new ARRAY_TYPE(8);
+    dq[0] = x1;
+    dq[1] = y1;
+    dq[2] = z1;
+    dq[3] = w1;
+    var ax = x2 * 0.5,
+        ay = y2 * 0.5,
+        az = z2 * 0.5;
+    dq[4] = ax * w1 + ay * z1 - az * y1;
+    dq[5] = ay * w1 + az * x1 - ax * z1;
+    dq[6] = az * w1 + ax * y1 - ay * x1;
+    dq[7] = -ax * x1 - ay * y1 - az * z1;
+    return dq;
+  }
+  /**
+   * Creates a dual quat from a quaternion and a translation
+   *
+   * @param {quat2} dual quaternion receiving operation result
+   * @param {quat} q a normalized quaternion
+   * @param {vec3} t tranlation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotationTranslation$1(out, q, t) {
+    var ax = t[0] * 0.5,
+        ay = t[1] * 0.5,
+        az = t[2] * 0.5,
+        bx = q[0],
+        by = q[1],
+        bz = q[2],
+        bw = q[3];
+    out[0] = bx;
+    out[1] = by;
+    out[2] = bz;
+    out[3] = bw;
+    out[4] = ax * bw + ay * bz - az * by;
+    out[5] = ay * bw + az * bx - ax * bz;
+    out[6] = az * bw + ax * by - ay * bx;
+    out[7] = -ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a translation
+   *
+   * @param {quat2} dual quaternion receiving operation result
+   * @param {vec3} t translation vector
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromTranslation$3(out, t) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = t[0] * 0.5;
+    out[5] = t[1] * 0.5;
+    out[6] = t[2] * 0.5;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a dual quat from a quaternion
+   *
+   * @param {quat2} dual quaternion receiving operation result
+   * @param {quat} q the quaternion
+   * @returns {quat2} dual quaternion receiving operation result
+   * @function
+   */
+
+  function fromRotation$4(out, q) {
+    out[0] = q[0];
+    out[1] = q[1];
+    out[2] = q[2];
+    out[3] = q[3];
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Creates a new dual quat from a matrix (4x4)
+   *
+   * @param {quat2} out the dual quaternion
+   * @param {mat4} a the matrix
+   * @returns {quat2} dual quat receiving operation result
+   * @function
+   */
+
+  function fromMat4$1(out, a) {
+    //TODO Optimize this
+    var outer = create$6();
+    getRotation(outer, a);
+    var t = new ARRAY_TYPE(3);
+    getTranslation(t, a);
+    fromRotationTranslation$1(out, outer, t);
+    return out;
+  }
+  /**
+   * Copy the values from one dual quat to another
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the source dual quaternion
+   * @returns {quat2} out
+   * @function
+   */
+
+  function copy$7(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Set a dual quat to the identity dual quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @returns {quat2} out
+   */
+
+  function identity$5(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    out[6] = 0;
+    out[7] = 0;
+    return out;
+  }
+  /**
+   * Set the components of a dual quat to the given values
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {Number} x1 X component
+   * @param {Number} y1 Y component
+   * @param {Number} z1 Z component
+   * @param {Number} w1 W component
+   * @param {Number} x2 X component
+   * @param {Number} y2 Y component
+   * @param {Number} z2 Z component
+   * @param {Number} w2 W component
+   * @returns {quat2} out
+   * @function
+   */
+
+  function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) {
+    out[0] = x1;
+    out[1] = y1;
+    out[2] = z1;
+    out[3] = w1;
+    out[4] = x2;
+    out[5] = y2;
+    out[6] = z2;
+    out[7] = w2;
+    return out;
+  }
+  /**
+   * Gets the real part of a dual quat
+   * @param  {quat} out real part
+   * @param  {quat2} a Dual Quaternion
+   * @return {quat} real part
+   */
+
+  var getReal = copy$6;
+  /**
+   * Gets the dual part of a dual quat
+   * @param  {quat} out dual part
+   * @param  {quat2} a Dual Quaternion
+   * @return {quat} dual part
+   */
+
+  function getDual(out, a) {
+    out[0] = a[4];
+    out[1] = a[5];
+    out[2] = a[6];
+    out[3] = a[7];
+    return out;
+  }
+  /**
+   * Set the real component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {quat} q a quaternion representing the real part
+   * @returns {quat2} out
+   * @function
+   */
+
+  var setReal = copy$6;
+  /**
+   * Set the dual component of a dual quat to the given quaternion
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {quat} q a quaternion representing the dual part
+   * @returns {quat2} out
+   * @function
+   */
+
+  function setDual(out, q) {
+    out[4] = q[0];
+    out[5] = q[1];
+    out[6] = q[2];
+    out[7] = q[3];
+    return out;
+  }
+  /**
+   * Gets the translation of a normalized dual quat
+   * @param  {vec3} out translation
+   * @param  {quat2} a Dual Quaternion to be decomposed
+   * @return {vec3} translation
+   */
+
+  function getTranslation$1(out, a) {
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3];
+    out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
+    out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
+    out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
+    return out;
+  }
+  /**
+   * Translates a dual quat by the given vector
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to translate
+   * @param {vec3} v vector to translate by
+   * @returns {quat2} out
+   */
+
+  function translate$3(out, a, v) {
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3],
+        bx1 = v[0] * 0.5,
+        by1 = v[1] * 0.5,
+        bz1 = v[2] * 0.5,
+        ax2 = a[4],
+        ay2 = a[5],
+        az2 = a[6],
+        aw2 = a[7];
+    out[0] = ax1;
+    out[1] = ay1;
+    out[2] = az1;
+    out[3] = aw1;
+    out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;
+    out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;
+    out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;
+    out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the X axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateX$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateX$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Y axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateY$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateY$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around the Z axis
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {number} rad how far should the rotation be
+   * @returns {quat2} out
+   */
+
+  function rotateZ$3(out, a, rad) {
+    var bx = -a[0],
+        by = -a[1],
+        bz = -a[2],
+        bw = a[3],
+        ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7],
+        ax1 = ax * bw + aw * bx + ay * bz - az * by,
+        ay1 = ay * bw + aw * by + az * bx - ax * bz,
+        az1 = az * bw + aw * bz + ax * by - ay * bx,
+        aw1 = aw * bw - ax * bx - ay * by - az * bz;
+    rotateZ$2(out, a, rad);
+    bx = out[0];
+    by = out[1];
+    bz = out[2];
+    bw = out[3];
+    out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (a * q)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {quat} q quaternion to rotate by
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatAppend(out, a, q) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        ax = a[0],
+        ay = a[1],
+        az = a[2],
+        aw = a[3];
+    out[0] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[1] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[2] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[3] = aw * qw - ax * qx - ay * qy - az * qz;
+    ax = a[4];
+    ay = a[5];
+    az = a[6];
+    aw = a[7];
+    out[4] = ax * qw + aw * qx + ay * qz - az * qy;
+    out[5] = ay * qw + aw * qy + az * qx - ax * qz;
+    out[6] = az * qw + aw * qz + ax * qy - ay * qx;
+    out[7] = aw * qw - ax * qx - ay * qy - az * qz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat by a given quaternion (q * a)
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat} q quaternion to rotate by
+   * @param {quat2} a the dual quaternion to rotate
+   * @returns {quat2} out
+   */
+
+  function rotateByQuatPrepend(out, q, a) {
+    var qx = q[0],
+        qy = q[1],
+        qz = q[2],
+        qw = q[3],
+        bx = a[0],
+        by = a[1],
+        bz = a[2],
+        bw = a[3];
+    out[0] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[1] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[2] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[3] = qw * bw - qx * bx - qy * by - qz * bz;
+    bx = a[4];
+    by = a[5];
+    bz = a[6];
+    bw = a[7];
+    out[4] = qx * bw + qw * bx + qy * bz - qz * by;
+    out[5] = qy * bw + qw * by + qz * bx - qx * bz;
+    out[6] = qz * bw + qw * bz + qx * by - qy * bx;
+    out[7] = qw * bw - qx * bx - qy * by - qz * bz;
+    return out;
+  }
+  /**
+   * Rotates a dual quat around a given axis. Does the normalisation automatically
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the dual quaternion to rotate
+   * @param {vec3} axis the axis to rotate around
+   * @param {Number} rad how far the rotation should be
+   * @returns {quat2} out
+   */
+
+  function rotateAroundAxis(out, a, axis, rad) {
+    //Special case for rad = 0
+    if (Math.abs(rad) < EPSILON) {
+      return copy$7(out, a);
+    }
+
+    var axisLength = Math.hypot(axis[0], axis[1], axis[2]);
+    rad = rad * 0.5;
+    var s = Math.sin(rad);
+    var bx = s * axis[0] / axisLength;
+    var by = s * axis[1] / axisLength;
+    var bz = s * axis[2] / axisLength;
+    var bw = Math.cos(rad);
+    var ax1 = a[0],
+        ay1 = a[1],
+        az1 = a[2],
+        aw1 = a[3];
+    out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;
+    out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;
+    out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;
+    out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;
+    var ax = a[4],
+        ay = a[5],
+        az = a[6],
+        aw = a[7];
+    out[4] = ax * bw + aw * bx + ay * bz - az * by;
+    out[5] = ay * bw + aw * by + az * bx - ax * bz;
+    out[6] = az * bw + aw * bz + ax * by - ay * bx;
+    out[7] = aw * bw - ax * bx - ay * by - az * bz;
+    return out;
+  }
+  /**
+   * Adds two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the first operand
+   * @param {quat2} b the second operand
+   * @returns {quat2} out
+   * @function
+   */
+
+  function add$7(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    out[3] = a[3] + b[3];
+    out[4] = a[4] + b[4];
+    out[5] = a[5] + b[5];
+    out[6] = a[6] + b[6];
+    out[7] = a[7] + b[7];
+    return out;
+  }
+  /**
+   * Multiplies two dual quat's
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a the first operand
+   * @param {quat2} b the second operand
+   * @returns {quat2} out
+   */
+
+  function multiply$7(out, a, b) {
+    var ax0 = a[0],
+        ay0 = a[1],
+        az0 = a[2],
+        aw0 = a[3],
+        bx1 = b[4],
+        by1 = b[5],
+        bz1 = b[6],
+        bw1 = b[7],
+        ax1 = a[4],
+        ay1 = a[5],
+        az1 = a[6],
+        aw1 = a[7],
+        bx0 = b[0],
+        by0 = b[1],
+        bz0 = b[2],
+        bw0 = b[3];
+    out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;
+    out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;
+    out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;
+    out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;
+    out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;
+    out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;
+    out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;
+    out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;
+    return out;
+  }
+  /**
+   * Alias for {@link quat2.multiply}
+   * @function
+   */
+
+  var mul$7 = multiply$7;
+  /**
+   * Scales a dual quat by a scalar number
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {quat2} a the dual quat to scale
+   * @param {Number} b amount to scale the dual quat by
+   * @returns {quat2} out
+   * @function
+   */
+
+  function scale$7(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    out[3] = a[3] * b;
+    out[4] = a[4] * b;
+    out[5] = a[5] * b;
+    out[6] = a[6] * b;
+    out[7] = a[7] * b;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two dual quat's (The dot product of the real parts)
+   *
+   * @param {quat2} a the first operand
+   * @param {quat2} b the second operand
+   * @returns {Number} dot product of a and b
+   * @function
+   */
+
+  var dot$3 = dot$2;
+  /**
+   * Performs a linear interpolation between two dual quats's
+   * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)
+   *
+   * @param {quat2} out the receiving dual quat
+   * @param {quat2} a the first operand
+   * @param {quat2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {quat2} out
+   */
+
+  function lerp$3(out, a, b, t) {
+    var mt = 1 - t;
+    if (dot$3(a, b) < 0) t = -t;
+    out[0] = a[0] * mt + b[0] * t;
+    out[1] = a[1] * mt + b[1] * t;
+    out[2] = a[2] * mt + b[2] * t;
+    out[3] = a[3] * mt + b[3] * t;
+    out[4] = a[4] * mt + b[4] * t;
+    out[5] = a[5] * mt + b[5] * t;
+    out[6] = a[6] * mt + b[6] * t;
+    out[7] = a[7] * mt + b[7] * t;
+    return out;
+  }
+  /**
+   * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a dual quat to calculate inverse of
+   * @returns {quat2} out
+   */
+
+  function invert$5(out, a) {
+    var sqlen = squaredLength$3(a);
+    out[0] = -a[0] / sqlen;
+    out[1] = -a[1] / sqlen;
+    out[2] = -a[2] / sqlen;
+    out[3] = a[3] / sqlen;
+    out[4] = -a[4] / sqlen;
+    out[5] = -a[5] / sqlen;
+    out[6] = -a[6] / sqlen;
+    out[7] = a[7] / sqlen;
+    return out;
+  }
+  /**
+   * Calculates the conjugate of a dual quat
+   * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.
+   *
+   * @param {quat2} out the receiving quaternion
+   * @param {quat2} a quat to calculate conjugate of
+   * @returns {quat2} out
+   */
+
+  function conjugate$1(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
+    out[4] = -a[4];
+    out[5] = -a[5];
+    out[6] = -a[6];
+    out[7] = a[7];
+    return out;
+  }
+  /**
+   * Calculates the length of a dual quat
+   *
+   * @param {quat2} a dual quat to calculate length of
+   * @returns {Number} length of a
+   * @function
+   */
+
+  var length$3 = length$2;
+  /**
+   * Alias for {@link quat2.length}
+   * @function
+   */
+
+  var len$3 = length$3;
+  /**
+   * Calculates the squared length of a dual quat
+   *
+   * @param {quat2} a dual quat to calculate squared length of
+   * @returns {Number} squared length of a
+   * @function
+   */
+
+  var squaredLength$3 = squaredLength$2;
+  /**
+   * Alias for {@link quat2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$3 = squaredLength$3;
+  /**
+   * Normalize a dual quat
+   *
+   * @param {quat2} out the receiving dual quaternion
+   * @param {quat2} a dual quaternion to normalize
+   * @returns {quat2} out
+   * @function
+   */
+
+  function normalize$3(out, a) {
+    var magnitude = squaredLength$3(a);
+
+    if (magnitude > 0) {
+      magnitude = Math.sqrt(magnitude);
+      var a0 = a[0] / magnitude;
+      var a1 = a[1] / magnitude;
+      var a2 = a[2] / magnitude;
+      var a3 = a[3] / magnitude;
+      var b0 = a[4];
+      var b1 = a[5];
+      var b2 = a[6];
+      var b3 = a[7];
+      var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3;
+      out[0] = a0;
+      out[1] = a1;
+      out[2] = a2;
+      out[3] = a3;
+      out[4] = (b0 - a0 * a_dot_b) / magnitude;
+      out[5] = (b1 - a1 * a_dot_b) / magnitude;
+      out[6] = (b2 - a2 * a_dot_b) / magnitude;
+      out[7] = (b3 - a3 * a_dot_b) / magnitude;
+    }
+
+    return out;
+  }
+  /**
+   * Returns a string representation of a dual quatenion
+   *
+   * @param {quat2} a dual quaternion to represent as a string
+   * @returns {String} string representation of the dual quat
+   */
+
+  function str$7(a) {
+    return 'quat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ')';
+  }
+  /**
+   * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)
+   *
+   * @param {quat2} a the first dual quaternion.
+   * @param {quat2} b the second dual quaternion.
+   * @returns {Boolean} true if the dual quaternions are equal, false otherwise.
+   */
+
+  function exactEquals$7(a, b) {
+    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
+  }
+  /**
+   * Returns whether or not the dual quaternions have approximately the same elements in the same position.
+   *
+   * @param {quat2} a the first dual quat.
+   * @param {quat2} b the second dual quat.
+   * @returns {Boolean} true if the dual quats are equal, false otherwise.
+   */
+
+  function equals$8(a, b) {
+    var a0 = a[0],
+        a1 = a[1],
+        a2 = a[2],
+        a3 = a[3],
+        a4 = a[4],
+        a5 = a[5],
+        a6 = a[6],
+        a7 = a[7];
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3],
+        b4 = b[4],
+        b5 = b[5],
+        b6 = b[6],
+        b7 = b[7];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7));
+  }
+
+  var quat2 = /*#__PURE__*/Object.freeze({
+    create: create$7,
+    clone: clone$7,
+    fromValues: fromValues$7,
+    fromRotationTranslationValues: fromRotationTranslationValues,
+    fromRotationTranslation: fromRotationTranslation$1,
+    fromTranslation: fromTranslation$3,
+    fromRotation: fromRotation$4,
+    fromMat4: fromMat4$1,
+    copy: copy$7,
+    identity: identity$5,
+    set: set$7,
+    getReal: getReal,
+    getDual: getDual,
+    setReal: setReal,
+    setDual: setDual,
+    getTranslation: getTranslation$1,
+    translate: translate$3,
+    rotateX: rotateX$3,
+    rotateY: rotateY$3,
+    rotateZ: rotateZ$3,
+    rotateByQuatAppend: rotateByQuatAppend,
+    rotateByQuatPrepend: rotateByQuatPrepend,
+    rotateAroundAxis: rotateAroundAxis,
+    add: add$7,
+    multiply: multiply$7,
+    mul: mul$7,
+    scale: scale$7,
+    dot: dot$3,
+    lerp: lerp$3,
+    invert: invert$5,
+    conjugate: conjugate$1,
+    length: length$3,
+    len: len$3,
+    squaredLength: squaredLength$3,
+    sqrLen: sqrLen$3,
+    normalize: normalize$3,
+    str: str$7,
+    exactEquals: exactEquals$7,
+    equals: equals$8
+  });
+
+  /**
+   * 2 Dimensional Vector
+   * @module vec2
+   */
+
+  /**
+   * Creates a new, empty vec2
+   *
+   * @returns {vec2} a new 2D vector
+   */
+
+  function create$8() {
+    var out = new ARRAY_TYPE(2);
+
+    if (ARRAY_TYPE != Float32Array) {
+      out[0] = 0;
+      out[1] = 0;
+    }
+
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with values from an existing vector
+   *
+   * @param {vec2} a vector to clone
+   * @returns {vec2} a new 2D vector
+   */
+
+  function clone$8(a) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Creates a new vec2 initialized with the given values
+   *
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} a new 2D vector
+   */
+
+  function fromValues$8(x, y) {
+    var out = new ARRAY_TYPE(2);
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Copy the values from one vec2 to another
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the source vector
+   * @returns {vec2} out
+   */
+
+  function copy$8(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    return out;
+  }
+  /**
+   * Set the components of a vec2 to the given values
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} x X component
+   * @param {Number} y Y component
+   * @returns {vec2} out
+   */
+
+  function set$8(out, x, y) {
+    out[0] = x;
+    out[1] = y;
+    return out;
+  }
+  /**
+   * Adds two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function add$8(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    return out;
+  }
+  /**
+   * Subtracts vector b from vector a
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function subtract$6(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    return out;
+  }
+  /**
+   * Multiplies two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function multiply$8(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    return out;
+  }
+  /**
+   * Divides two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function divide$2(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    return out;
+  }
+  /**
+   * Math.ceil the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to ceil
+   * @returns {vec2} out
+   */
+
+  function ceil$2(out, a) {
+    out[0] = Math.ceil(a[0]);
+    out[1] = Math.ceil(a[1]);
+    return out;
+  }
+  /**
+   * Math.floor the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to floor
+   * @returns {vec2} out
+   */
+
+  function floor$2(out, a) {
+    out[0] = Math.floor(a[0]);
+    out[1] = Math.floor(a[1]);
+    return out;
+  }
+  /**
+   * Returns the minimum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function min$2(out, a, b) {
+    out[0] = Math.min(a[0], b[0]);
+    out[1] = Math.min(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Returns the maximum of two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec2} out
+   */
+
+  function max$2(out, a, b) {
+    out[0] = Math.max(a[0], b[0]);
+    out[1] = Math.max(a[1], b[1]);
+    return out;
+  }
+  /**
+   * Math.round the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to round
+   * @returns {vec2} out
+   */
+
+  function round$2(out, a) {
+    out[0] = Math.round(a[0]);
+    out[1] = Math.round(a[1]);
+    return out;
+  }
+  /**
+   * Scales a vec2 by a scalar number
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to scale
+   * @param {Number} b amount to scale the vector by
+   * @returns {vec2} out
+   */
+
+  function scale$8(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    return out;
+  }
+  /**
+   * Adds two vec2's after scaling the second operand by a scalar value
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @param {Number} scale the amount to scale b by before adding
+   * @returns {vec2} out
+   */
+
+  function scaleAndAdd$2(out, a, b, scale) {
+    out[0] = a[0] + b[0] * scale;
+    out[1] = a[1] + b[1] * scale;
+    return out;
+  }
+  /**
+   * Calculates the euclidian distance between two vec2's
+   *
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {Number} distance between a and b
+   */
+
+  function distance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared euclidian distance between two vec2's
+   *
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {Number} squared distance between a and b
+   */
+
+  function squaredDistance$2(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Calculates the length of a vec2
+   *
+   * @param {vec2} a vector to calculate length of
+   * @returns {Number} length of a
+   */
+
+  function length$4(a) {
+    var x = a[0],
+        y = a[1];
+    return Math.hypot(x, y);
+  }
+  /**
+   * Calculates the squared length of a vec2
+   *
+   * @param {vec2} a vector to calculate squared length of
+   * @returns {Number} squared length of a
+   */
+
+  function squaredLength$4(a) {
+    var x = a[0],
+        y = a[1];
+    return x * x + y * y;
+  }
+  /**
+   * Negates the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to negate
+   * @returns {vec2} out
+   */
+
+  function negate$2(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    return out;
+  }
+  /**
+   * Returns the inverse of the components of a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to invert
+   * @returns {vec2} out
+   */
+
+  function inverse$2(out, a) {
+    out[0] = 1.0 / a[0];
+    out[1] = 1.0 / a[1];
+    return out;
+  }
+  /**
+   * Normalize a vec2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a vector to normalize
+   * @returns {vec2} out
+   */
+
+  function normalize$4(out, a) {
+    var x = a[0],
+        y = a[1];
+    var len = x * x + y * y;
+
+    if (len > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len = 1 / Math.sqrt(len);
+    }
+
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    return out;
+  }
+  /**
+   * Calculates the dot product of two vec2's
+   *
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {Number} dot product of a and b
+   */
+
+  function dot$4(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  /**
+   * Computes the cross product of two vec2's
+   * Note that the cross product must by definition produce a 3D vector
+   *
+   * @param {vec3} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @returns {vec3} out
+   */
+
+  function cross$2(out, a, b) {
+    var z = a[0] * b[1] - a[1] * b[0];
+    out[0] = out[1] = 0;
+    out[2] = z;
+    return out;
+  }
+  /**
+   * Performs a linear interpolation between two vec2's
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the first operand
+   * @param {vec2} b the second operand
+   * @param {Number} t interpolation amount, in the range [0-1], between the two inputs
+   * @returns {vec2} out
+   */
+
+  function lerp$4(out, a, b, t) {
+    var ax = a[0],
+        ay = a[1];
+    out[0] = ax + t * (b[0] - ax);
+    out[1] = ay + t * (b[1] - ay);
+    return out;
+  }
+  /**
+   * Generates a random vector with the given scale
+   *
+   * @param {vec2} out the receiving vector
+   * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+   * @returns {vec2} out
+   */
+
+  function random$3(out, scale) {
+    scale = scale || 1.0;
+    var r = RANDOM() * 2.0 * Math.PI;
+    out[0] = Math.cos(r) * scale;
+    out[1] = Math.sin(r) * scale;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to transform
+   * @param {mat2} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y;
+    out[1] = m[1] * x + m[3] * y;
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat2d
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to transform
+   * @param {mat2d} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat2d(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat3
+   * 3rd vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to transform
+   * @param {mat3} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat3$1(out, a, m) {
+    var x = a[0],
+        y = a[1];
+    out[0] = m[0] * x + m[3] * y + m[6];
+    out[1] = m[1] * x + m[4] * y + m[7];
+    return out;
+  }
+  /**
+   * Transforms the vec2 with a mat4
+   * 3rd vector component is implicitly '0'
+   * 4th vector component is implicitly '1'
+   *
+   * @param {vec2} out the receiving vector
+   * @param {vec2} a the vector to transform
+   * @param {mat4} m matrix to transform with
+   * @returns {vec2} out
+   */
+
+  function transformMat4$2(out, a, m) {
+    var x = a[0];
+    var y = a[1];
+    out[0] = m[0] * x + m[4] * y + m[12];
+    out[1] = m[1] * x + m[5] * y + m[13];
+    return out;
+  }
+  /**
+   * Rotate a 2D vector
+   * @param {vec2} out The receiving vec2
+   * @param {vec2} a The vec2 point to rotate
+   * @param {vec2} b The origin of the rotation
+   * @param {Number} c The angle of rotation
+   * @returns {vec2} out
+   */
+
+  function rotate$4(out, a, b, c) {
+    //Translate point to the origin
+    var p0 = a[0] - b[0],
+        p1 = a[1] - b[1],
+        sinC = Math.sin(c),
+        cosC = Math.cos(c); //perform rotation and translate to correct position
+
+    out[0] = p0 * cosC - p1 * sinC + b[0];
+    out[1] = p0 * sinC + p1 * cosC + b[1];
+    return out;
+  }
+  /**
+   * Get the angle between two 2D vectors
+   * @param {vec2} a The first operand
+   * @param {vec2} b The second operand
+   * @returns {Number} The angle in radians
+   */
+
+  function angle$1(a, b) {
+    var x1 = a[0],
+        y1 = a[1],
+        x2 = b[0],
+        y2 = b[1];
+    var len1 = x1 * x1 + y1 * y1;
+
+    if (len1 > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len1 = 1 / Math.sqrt(len1);
+    }
+
+    var len2 = x2 * x2 + y2 * y2;
+
+    if (len2 > 0) {
+      //TODO: evaluate use of glm_invsqrt here?
+      len2 = 1 / Math.sqrt(len2);
+    }
+
+    var cosine = (x1 * x2 + y1 * y2) * len1 * len2;
+
+    if (cosine > 1.0) {
+      return 0;
+    } else if (cosine < -1.0) {
+      return Math.PI;
+    } else {
+      return Math.acos(cosine);
+    }
+  }
+  /**
+   * Set the components of a vec2 to zero
+   *
+   * @param {vec2} out the receiving vector
+   * @returns {vec2} out
+   */
+
+  function zero$2(out) {
+    out[0] = 0.0;
+    out[1] = 0.0;
+    return out;
+  }
+  /**
+   * Returns a string representation of a vector
+   *
+   * @param {vec2} a vector to represent as a string
+   * @returns {String} string representation of the vector
+   */
+
+  function str$8(a) {
+    return 'vec2(' + a[0] + ', ' + a[1] + ')';
+  }
+  /**
+   * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+   *
+   * @param {vec2} a The first vector.
+   * @param {vec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function exactEquals$8(a, b) {
+    return a[0] === b[0] && a[1] === b[1];
+  }
+  /**
+   * Returns whether or not the vectors have approximately the same elements in the same position.
+   *
+   * @param {vec2} a The first vector.
+   * @param {vec2} b The second vector.
+   * @returns {Boolean} True if the vectors are equal, false otherwise.
+   */
+
+  function equals$9(a, b) {
+    var a0 = a[0],
+        a1 = a[1];
+    var b0 = b[0],
+        b1 = b[1];
+    return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+  }
+  /**
+   * Alias for {@link vec2.length}
+   * @function
+   */
+
+  var len$4 = length$4;
+  /**
+   * Alias for {@link vec2.subtract}
+   * @function
+   */
+
+  var sub$6 = subtract$6;
+  /**
+   * Alias for {@link vec2.multiply}
+   * @function
+   */
+
+  var mul$8 = multiply$8;
+  /**
+   * Alias for {@link vec2.divide}
+   * @function
+   */
+
+  var div$2 = divide$2;
+  /**
+   * Alias for {@link vec2.distance}
+   * @function
+   */
+
+  var dist$2 = distance$2;
+  /**
+   * Alias for {@link vec2.squaredDistance}
+   * @function
+   */
+
+  var sqrDist$2 = squaredDistance$2;
+  /**
+   * Alias for {@link vec2.squaredLength}
+   * @function
+   */
+
+  var sqrLen$4 = squaredLength$4;
+  /**
+   * Perform some operation over an array of vec2s.
+   *
+   * @param {Array} a the array of vectors to iterate over
+   * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+   * @param {Number} offset Number of elements to skip at the beginning of the array
+   * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+   * @param {Function} fn Function to call for each vector in the array
+   * @param {Object} [arg] additional argument to pass to fn
+   * @returns {Array} a
+   * @function
+   */
+
+  var forEach$2 = function () {
+    var vec = create$8();
+    return function (a, stride, offset, count, fn, arg) {
+      var i, l;
+
+      if (!stride) {
+        stride = 2;
+      }
+
+      if (!offset) {
+        offset = 0;
+      }
+
+      if (count) {
+        l = Math.min(count * stride + offset, a.length);
+      } else {
+        l = a.length;
+      }
+
+      for (i = offset; i < l; i += stride) {
+        vec[0] = a[i];
+        vec[1] = a[i + 1];
+        fn(vec, vec, arg);
+        a[i] = vec[0];
+        a[i + 1] = vec[1];
+      }
+
+      return a;
+    };
+  }();
+
+  var vec2 = /*#__PURE__*/Object.freeze({
+    create: create$8,
+    clone: clone$8,
+    fromValues: fromValues$8,
+    copy: copy$8,
+    set: set$8,
+    add: add$8,
+    subtract: subtract$6,
+    multiply: multiply$8,
+    divide: divide$2,
+    ceil: ceil$2,
+    floor: floor$2,
+    min: min$2,
+    max: max$2,
+    round: round$2,
+    scale: scale$8,
+    scaleAndAdd: scaleAndAdd$2,
+    distance: distance$2,
+    squaredDistance: squaredDistance$2,
+    length: length$4,
+    squaredLength: squaredLength$4,
+    negate: negate$2,
+    inverse: inverse$2,
+    normalize: normalize$4,
+    dot: dot$4,
+    cross: cross$2,
+    lerp: lerp$4,
+    random: random$3,
+    transformMat2: transformMat2,
+    transformMat2d: transformMat2d,
+    transformMat3: transformMat3$1,
+    transformMat4: transformMat4$2,
+    rotate: rotate$4,
+    angle: angle$1,
+    zero: zero$2,
+    str: str$8,
+    exactEquals: exactEquals$8,
+    equals: equals$9,
+    len: len$4,
+    sub: sub$6,
+    mul: mul$8,
+    div: div$2,
+    dist: dist$2,
+    sqrDist: sqrDist$2,
+    sqrLen: sqrLen$4,
+    forEach: forEach$2
+  });
+
+  exports.glMatrix = common;
+  exports.mat2 = mat2;
+  exports.mat2d = mat2d;
+  exports.mat3 = mat3;
+  exports.mat4 = mat4;
+  exports.quat = quat;
+  exports.quat2 = quat2;
+  exports.vec2 = vec2;
+  exports.vec3 = vec3;
+  exports.vec4 = vec4;
+
+  Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
diff --git a/student2019/201520868/readme.md b/student2019/201520868/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..d776d751ad01fbb50c91ab7f2b57c9dbf310241a
--- /dev/null
+++ b/student2019/201520868/readme.md
@@ -0,0 +1,139 @@
+# WebGL Tutorial with Mouse and Keyboard Interaction 
+
+## File Manifest
+- WebGL.html
+- gl-matrix.js
+
+## Basic
+- Canvas size is 500 x 500
+- Vertex Shader code
+ 
+```c
+attribute vec3 position;
+uniform mat4 Pmatrix;
+uniform mat4 Vmatrix;
+uniform mat4 Mmatrix;
+attribute vec3 color;
+varying vec3 vColor;
+void main(void) {  
+    gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);
+    vColor = color;
+}
+```
+Model, View, Projective Matrices are Uniform.<br>
+Position and color Matrices are attribute<br>
+Return color vColor is varying to return to Fragment Shader.
+
+- Fragment Shader code
+```c
+precision mediump float;
+varying vec3 vColor;
+void main(void) {
+    gl_FragColor = vec4(vColor, 1.);
+}
+```
+vColor is returned from Vertex Shader.
+
+- Perspective Matrix 
+```c
+glMatrix.mat4.perspective(proj_matrix,40/180*Math.PI,canvas.width/canvas.height,1,100);
+```
+Perspective matrix has 5 parameters.
+1. out      - Frustrum matrix will be written to.
+2. fovy     - Vertical field of view in radians. if has angle, convert to radians using angle/180*Math.PI
+3. aspect   - Aspect ratio of canvas typically viewport width/height
+4. near     - Near bound of the frustrum
+5. far      - Far bound of the frustrum. can be null or Infinity
+
+
+## Events
+HTML has addEventListner function that sets up a function that will be called whenever the specified event is delivered to the targer.<br>
+I used this function to implement interation WebGL Program.
+
+### Mouse Event
+- mouseDown
+
+this function is called when mouse is clicked.
+```c
+drag = true;
+old_x = e.pageX, old_y = e.pageY;
+e.preventDefault();
+return false;
+```
+                
+- mouseUp
+
+this function is called when mouse is released.
+```c
+drag = false;
+```
+
+- mouseMove
+this function has 2 ways. it collaborates with Keyboard Event.<br>
+when mouse is not clicked, it ignores the function.<br>
+when m(move) is pressed. mousemove is working as translator, else working as rotator.
+```c
+if (!drag) return false;
+if(!move){
+	dX = (e.pageX-old_x)*2*Math.PI/canvas.width,
+	dY = (e.pageY-old_y)*2*Math.PI/canvas.height;
+	THETA+= dX;
+	PHI+=dY;
+	old_x = e.pageX, old_y = e.pageY;
+	e.preventDefault();
+}
+else{
+	mX = (e.pageX-old_x)/canvas.width*view_matrix[14];
+	mY = (-e.pageY+old_y)/canvas.height*view_matrix[14];
+	view_matrix[12]-=mX;
+	view_matrix[13]-=mY;
+	old_x = e.pageX, old_y = e.pageY;
+	e.preventDefault();
+}
+```
+
+- Wheel
+
+Wheel has 2 directions. When up, e.deltaY will be negative. when down, it will be positive.<br>
+per 1 click, Zoom +-0.2 and view_matrix[14]is limited from -20 to -5.
+```c
+if(e.deltaY<0){
+	if(view_matrix[14]<-5.1) view_matrix[14] = view_matrix[14]+0.2;
+}
+else {
+	if(view_matrix[14]>-20) view_matrix[14] = view_matrix[14]-0.2;
+}
+```
+
+### Keyboard Event
+- onKeyPress
+
+as I told above, mouseMove action collaborates with onKeyPress action.<br>
+when m is pressed, variable move become 1. now mouseMove action will working as translator.<br>
+when c is pressed, this action will change the color of cube. color will be randomly chosen.
+
+```c
+if(e.key=='c'){
+    for(i in colors){
+        colors[i] = Math.random()+0.3;
+    }
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
+}
+if(e.key=='m'){
+    move=1;
+    return false;
+}
+```
+ 
+- onKeyUp
+```c
+move=0;
+```
+
+
+## Copyright
+(CC-NC-BY) Kim Kwangho 2019
+
+## References
+- https://www.tutorialspoint.com/webgl/webgl_interactive_cube.htm
+- http://glmatrix.net/
\ No newline at end of file
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._.DS_Store b/student2019/201520889/__MACOSX/webglfinalproject/._.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..a5b28df1cbc6e15bd0d35cdadd0c2e65d5131c7d
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._.DS_Store differ
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._assembly.png b/student2019/201520889/__MACOSX/webglfinalproject/._assembly.png
new file mode 100644
index 0000000000000000000000000000000000000000..5418d02ffa7c45aacd329500766421145db4166f
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._assembly.png differ
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._bayesian.png b/student2019/201520889/__MACOSX/webglfinalproject/._bayesian.png
new file mode 100644
index 0000000000000000000000000000000000000000..79bb31ab5ed1da50315aa30ff44e588a04ce0caa
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._bayesian.png differ
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._img0.png b/student2019/201520889/__MACOSX/webglfinalproject/._img0.png
new file mode 100644
index 0000000000000000000000000000000000000000..bea7af2af8a3e090a90af11c3d37045eed6c9605
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._img0.png differ
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._img1.png b/student2019/201520889/__MACOSX/webglfinalproject/._img1.png
new file mode 100644
index 0000000000000000000000000000000000000000..91bf2a9532f6427ee23252f9fc2ecc2f68ecc909
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._img1.png differ
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._img2.png b/student2019/201520889/__MACOSX/webglfinalproject/._img2.png
new file mode 100644
index 0000000000000000000000000000000000000000..c3e6142c16a3c442ab239cd3157085180caae682
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._img2.png differ
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._img3.png b/student2019/201520889/__MACOSX/webglfinalproject/._img3.png
new file mode 100644
index 0000000000000000000000000000000000000000..714fb1eaf4e87a81a82669c8e42f08afd8bc2ffd
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._img3.png differ
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._img4.png b/student2019/201520889/__MACOSX/webglfinalproject/._img4.png
new file mode 100644
index 0000000000000000000000000000000000000000..22889ede441a331ba1332fe2ee458232562c53e7
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._img4.png differ
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._img5.png b/student2019/201520889/__MACOSX/webglfinalproject/._img5.png
new file mode 100644
index 0000000000000000000000000000000000000000..c8532488e3a93ad9e473ab66f5b4ac226a915fbd
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._img5.png differ
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._img6.png b/student2019/201520889/__MACOSX/webglfinalproject/._img6.png
new file mode 100644
index 0000000000000000000000000000000000000000..6426d044751aa11d46ae4e890d7a4198b4024141
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._img6.png differ
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._img7.png b/student2019/201520889/__MACOSX/webglfinalproject/._img7.png
new file mode 100644
index 0000000000000000000000000000000000000000..acac891d2df548214acca1dd311ff5e2568726af
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._img7.png differ
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._tutorial0.png b/student2019/201520889/__MACOSX/webglfinalproject/._tutorial0.png
new file mode 100644
index 0000000000000000000000000000000000000000..da1ed4da67322faf69ce9a00c26adcfe73a6ecf9
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._tutorial0.png differ
diff --git a/student2019/201520889/__MACOSX/webglfinalproject/._tutorial1.png b/student2019/201520889/__MACOSX/webglfinalproject/._tutorial1.png
new file mode 100644
index 0000000000000000000000000000000000000000..a49f5af3c8199e2da683f67f0dc446c70a5d6cb7
Binary files /dev/null and b/student2019/201520889/__MACOSX/webglfinalproject/._tutorial1.png differ
diff --git a/student2019/201520889/webglfinalproject b/student2019/201520889/webglfinalproject
new file mode 160000
index 0000000000000000000000000000000000000000..5904e223bb6f33849f1bc3d2702f5a1d1fa95b7c
--- /dev/null
+++ b/student2019/201520889/webglfinalproject
@@ -0,0 +1 @@
+Subproject commit 5904e223bb6f33849f1bc3d2702f5a1d1fa95b7c
diff --git "a/student2019/201520987/WebGL \353\263\264\352\263\240\354\204\234 - 201520987 \355\225\234\354\240\225\354\232\260.docx" "b/student2019/201520987/WebGL \353\263\264\352\263\240\354\204\234 - 201520987 \355\225\234\354\240\225\354\232\260.docx"
new file mode 100644
index 0000000000000000000000000000000000000000..8ac6d7b311a4597e17561f6cc5939c63408fe1d6
Binary files /dev/null and "b/student2019/201520987/WebGL \353\263\264\352\263\240\354\204\234 - 201520987 \355\225\234\354\240\225\354\232\260.docx" differ
diff --git a/student2019/201520987/final_project.html b/student2019/201520987/final_project.html
new file mode 100644
index 0000000000000000000000000000000000000000..017386702777a4a510adcc80c8cfb8b6faed46ec
--- /dev/null
+++ b/student2019/201520987/final_project.html
@@ -0,0 +1,80 @@
+<html>
+
+<head>
+	<title>Welcome to WebGL</title>
+	<h1>WebGL Study Program - Basic WebGL & Bezier Curve</h1>
+	<p> (CC-NC-BY) Jung Woo Han 2019 </p>
+	<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+
+	<script type="text/javascript" src="final_project.js">
+	</script>
+
+</head>
+
+<body onload="main()">
+	<canvas id="helloapicanvas" style="border: none;" width="350" height="350"></canvas>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+	<textarea rows="22" cols="50" id="information" readonly></textarea>
+	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+	<canvas id="beziercurve" width="350" height="350" style="border:solid 2px green"></canvas>
+
+	<p> &emsp;&emsp;&emsp; Translate Num & Speed
+		&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
+		&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
+		&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
+		&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
+		&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+		Bezier Curve</p>
+	&nbsp;<input type="text" id="inputX" style="text-align:center; width:70px; height:30px;">&emsp;
+	<input type="text" id="inputY" style="text-align:center; width:70px; height:30px;">&emsp;&nbsp;
+	<input type="text" id="inputZ" style="text-align:center; width:70px; height:30px;">&emsp;&emsp;&nbsp;
+	<input type="text" id="inputMoonX"
+		style="text-align:center; width:70px; height:30px;">&emsp;&emsp;&emsp;&nbsp;&nbsp;
+	<input type="text" id="inputMoonY"
+		style="text-align:center; width:70px; height:30px;">&emsp;&emsp;&emsp;&nbsp;&nbsp;
+	<input type="text" id="inputMoonZ"
+		style="text-align:center; width:70px; height:30px;">&emsp;&nbsp;&nbsp;&nbsp;&nbsp;
+	<input type="text" id="speed"
+		style="text-align:center; width:70px; height:30px;">&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
+	<input type="text" id="startX" style="text-align:center; width:30px; height:30px;">&emsp;&emsp;
+	<input type="text" id="startY" style="text-align:center; width:30px; height:30px;">&emsp;&emsp;
+	<input type="text" id="endX" style="text-align:center; width:30px; height:30px;">&emsp;&nbsp;&nbsp;
+	<input type="text" id="endY" style="text-align:center; width:30px; height:30px;">
+	<p style="font-size: 15px"> (Translate X)&nbsp;(Translate Y)&nbsp;(Translate Z)&nbsp;&nbsp;&nbsp;
+		(Translate Moon X)&nbsp;(Translate Moon X)&nbsp;(Translate Moon X)&nbsp;&nbsp;&nbsp;(Speed)
+		&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&nbsp;(StartX)&emsp;&nbsp;(StartY)&emsp;&nbsp;(EndX)&emsp;&nbsp;(EndY) </p>
+	<button onclick="initialize()">To the Start</button>&nbsp;&nbsp;&nbsp;
+	<button onclick="zoomIn()">Zoom in</button>&nbsp;&nbsp;&nbsp;
+	<button onclick="zoomOut()">Zoom out</button>&nbsp;&nbsp;&nbsp;
+	<button onclick="pivot()">Pivot</button>&nbsp;&nbsp;&nbsp;
+	<button onclick="pivotRotate()">Pivot Rotate</button>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
+	&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&nbsp;
+	<input type="text" id="controlX" style="text-align:center; width:30px; height:30px;">&emsp;&emsp;&emsp;
+	<input type="text" id="controlY"
+		style="text-align:center; width:30px; height:30px;">&emsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+	<input type="text" id="controlX1"
+		style="text-align:center; width:30px; height:30px;">&emsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+	<input type="text" id="controlY1" style="text-align:center; width:30px; height:30px;"><br>
+	<p style="font-size: 15px">
+		<button onclick="trXinc()">Translate X</button>
+		<button onclick="trYinc()">Translate Y</button>
+		<button onclick="trZinc()">Translate Z</button>
+		<button onclick="moontrXinc()">Translate Moon X</button>
+		<button onclick="moontrYinc()">Translate Moon Y</button>
+		<button onclick="moontrZinc()">Translate Moon Z</button>
+		&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&nbsp;&nbsp;
+		(ControlX1)&nbsp;(ControlY1)&nbsp;(ControlX2)&nbsp;(ControlY2)</p>
+	<button onclick="animRotateAll()">All Animation Rotate</button>
+	<button onclick="animRotate()">Animation Rotate</button>
+	<button onclick="animPauseAll()">All Animation Pause</button>
+	<button onclick="animPause()">Animation Pause</button>
+	<button onclick="moonRotate()">Moon Rotate</button>
+	<button onclick="moonPause()">Moon Pause</button>
+	&emsp;&emsp;&emsp;&nbsp;&nbsp;
+	<button onclick="quadraticBezierCurve()">Quadratic Bezier Curve</button>&emsp;
+	<button onclick="cubicBezierCurve()">Cubic Bezier Curve</button>&emsp;
+	<button onclick="bezierCurveErase()">Erase</button><br>
+
+</body>
+
+</html>
\ No newline at end of file
diff --git a/student2019/201520987/final_project.js b/student2019/201520987/final_project.js
new file mode 100644
index 0000000000000000000000000000000000000000..58b26c4793406280fc4e65cadb82de9971eb972d
--- /dev/null
+++ b/student2019/201520987/final_project.js
@@ -0,0 +1,851 @@
+//WebGL Study Program - Basic WebGL & Bezier Curve
+//(CC-NC-BY) Jung Woo Han 2019
+var gl;
+
+function testGLError(functionLastCalled) {
+
+	var lastError = gl.getError();
+
+	if (lastError != gl.NO_ERROR) {
+		alert(functionLastCalled + " failed (" + lastError + ")");
+		return false;
+	}
+
+	return true;
+}
+
+//Initialize canvas
+function initialiseGL(canvas) {
+	try {
+		// Try to grab the standard context. If it fails, fallback to experimental
+		gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+		gl.viewport(0, 0, canvas.width, canvas.height);
+	}
+	catch (e) {
+	}
+
+	if (!gl) {
+		alert("Unable to initialise WebGL. Your browser may not support it");
+		return false;
+	}
+
+	return true;
+}
+
+var shaderProgram;
+
+//Initialize buffer
+function initialiseBuffer() {
+
+	var vertexData = [
+		-0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 0.5, 0.0, 1.0,//3
+		0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0,//1
+		0.5, 0.5, -0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0,//2
+
+		-0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 0.5, 0.0, 1.0,//3
+		0.5, 0.5, -0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0,//2
+		-0.5, 0.5, -0.5, 1.0, 1.0, 1.0, 0.5, 0.0, 1.0,//4
+
+		0.5, 0.5, -0.5, 0.0, 0.0, 0.0, 0.5, 1.0, 1.0,//2
+		0.5, -0.5, -0.5, 0.0, 0.0, 0.0, 0.5, 1.0, 0.0,//6
+		-0.5, -0.5, -0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0,//8
+
+		-0.5, 0.5, -0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 1.0,//4
+		0.5, 0.5, -0.5, 0.0, 0.0, 0.0, 0.5, 1.0, 1.0,//2
+		-0.5, -0.5, -0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0,//8
+
+		0.5, -0.5, 0.5, 1.0, 0.5, 0.0, 0.5, 0.0, 1.0,//5
+		0.5, -0.5, -0.5, 1.0, 0.5, 0.0, 0.5, 0.0, 1.0,//6
+		0.5, 0.5, -0.5, 1.0, 0.5, 0.0, 0.5, 1.0, 1.0,//2
+
+		0.5, -0.5, 0.5, 1.0, 0.5, 0.0, 0.5, 0.0, 1.0,//5
+		0.5, 0.5, -0.5, 1.0, 0.5, 0.0, 0.5, 1.0, 1.0,//2
+		0.5, 0.5, 0.5, 1.0, 0.5, 0.0, 0.5, 1.0, 1.0,//1
+
+		-0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 0.5, 0.0, 1.0,//4
+		-0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 0.5, 0.0, 0.0,//8
+		-0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 0.5, 0.0, 0.0,//7
+
+		-0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 0.5, 0.0, 1.0,//3
+		-0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 0.5, 0.0, 1.0,//4
+		-0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 0.5, 0.0, 0.0,//7
+
+		-0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 0.5, 0.0, 0.0,//7
+		0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 0.5, 1.0, 0.0,//5
+		0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 0.5, 1.0, 1.0,//1
+
+		-0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 0.5, 0.0, 0.0,//7
+		0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 0.5, 1.0, 1.0,//1
+		-0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 0.5, 0.0, 1.0,//3
+
+		0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 0.5, 1.0, 0.0,//6
+		0.5, -0.5, 0.5, 0.0, 1.0, 0.0, 0.5, 1.0, 0.0,//5
+		-0.5, -0.5, 0.5, 0.0, 1.0, 0.0, 0.5, 0.0, 0.0,//7
+
+		-0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 0.5, 0.0, 0.0,//8
+		0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 0.5, 1.0, 0.0,//6
+		-0.5, -0.5, 0.5, 0.0, 1.0, 0.0, 0.5, 0.0, 0.0,//7
+	];
+
+	// Generate a buffer object
+	gl.vertexBuffer = gl.createBuffer();
+	// Bind buffer as a vertex buffer so we can fill it with data
+	gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+	return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+	var fragmentShaderSource = '\
+			varying mediump vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = 1.0 * color;\
+			}';
+
+	gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+	gl.shaderSource(gl.fragShader, fragmentShaderSource);
+	gl.compileShader(gl.fragShader);
+	if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+		alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+		return false;
+	}
+
+	var vertexShaderSource = '\
+			attribute highp vec3 myVertex; \
+			attribute highp vec4 myColor; \
+			attribute highp vec2 myUV; \
+			uniform mediump mat4 Pmatrix; \
+			uniform mediump mat4 Vmatrix; \
+			uniform mediump mat4 Mmatrix; \
+			varying mediump vec4 color; \
+			varying mediump vec2 texCoord;\
+			void main(void)  \
+			{ \
+				gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(myVertex, 1.0);\
+				color = myColor;\
+				texCoord = myUV; \
+			}';
+
+	gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+	gl.shaderSource(gl.vertexShader, vertexShaderSource);
+	gl.compileShader(gl.vertexShader);
+	if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+		alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+		return false;
+	}
+
+	gl.programObject = gl.createProgram();
+
+	// Attach the fragment and vertex shaders to it
+	gl.attachShader(gl.programObject, gl.fragShader);
+	gl.attachShader(gl.programObject, gl.vertexShader);
+
+	// Bind the custom vertex attribute "myVertex" to location 0
+	gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+	gl.bindAttribLocation(gl.programObject, 1, "myColor");
+	gl.bindAttribLocation(gl.programObject, 2, "myUV");
+
+	// Link the program
+	gl.linkProgram(gl.programObject);
+
+	if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+		alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+		return false;
+	}
+
+	gl.useProgram(gl.programObject);
+
+	return testGLError("initialiseShaders");
+}
+
+// Projection 
+function get_projection(angle, a, zMin, zMax) {
+	var ang = Math.tan((angle * .5) * Math.PI / 180);//angle*.5
+	return [
+		0.5 / ang, 0, 0, 0,
+		0, 0.5 * a / ang, 0, 0,
+		0, 0, -(zMax + zMin) / (zMax - zMin), -1,
+		0, 0, (-2 * zMax * zMin) / (zMax - zMin), 0];
+}
+
+var proj_matrix = get_projection(30, 1.0, 1, 10.0);
+var mov_matrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
+var view_matrix = [0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 1];
+// translating z
+
+view_matrix[14] = view_matrix[14] - 3;//zoom
+
+//Initialize the matrix
+function identity(out) {
+	out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 1;
+	out[4] = 0; out[5] = 1; out[6] = 0; out[7] = 0;
+	out[8] = 0; out[9] = 0; out[10] = 1; out[11] = 0;
+	out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1;
+	return out;
+}
+
+//Multiplying 2 matrices
+function multiply$2(r, m, k) {
+	m0 = m[0]; m1 = m[1]; m2 = m[2]; m3 = m[3]; m4 = m[4]; m5 = m[5]; m6 = m[6]; m7 = m[7];
+	m8 = m[8]; m9 = m[9]; m10 = m[10]; m11 = m[11]; m12 = m[12]; m13 = m[13]; m14 = m[14]; m15 = m[15];
+	k0 = k[0]; k1 = k[1]; k2 = k[2]; k3 = k[3]; k4 = k[4]; k5 = k[5]; k6 = k[6]; k7 = k[7];
+	k8 = k[8]; k9 = k[9]; k10 = k[10]; k11 = k[11]; k12 = k[12]; k13 = k[13]; k14 = k[14]; k15 = k[15];
+
+	a0 = k0 * m0 + k3 * m12 + k1 * m4 + k2 * m8;
+	a4 = k4 * m0 + k7 * m12 + k5 * m4 + k6 * m8;
+	a8 = k8 * m0 + k11 * m12 + k9 * m4 + k10 * m8;
+	a12 = k12 * m0 + k15 * m12 + k13 * m4 + k14 * m8;
+
+	a1 = k0 * m1 + k3 * m13 + k1 * m5 + k2 * m9;
+	a5 = k4 * m1 + k7 * m13 + k5 * m5 + k6 * m9;
+	a9 = k8 * m1 + k11 * m13 + k9 * m5 + k10 * m9;
+	a13 = k12 * m1 + k15 * m13 + k13 * m5 + k14 * m9;
+
+	a2 = k2 * m10 + k3 * m14 + k0 * m2 + k1 * m6;
+	a6 = k6 * m10 + k7 * m14 + k4 * m2 + k5 * m6;
+	a10 = k10 * m10 + k11 * m14 + k8 * m2 + k9 * m6;
+	a14 = k14 * m10 + k15 * m14 + k12 * m2 + k13 * m6;
+
+	a3 = k2 * m11 + k3 * m15 + k0 * m3 + k1 * m7;
+	a7 = k6 * m11 + k7 * m15 + k4 * m3 + k5 * m7;
+	a11 = k10 * m11 + k11 * m15 + k8 * m3 + k9 * m7;
+	a15 = k14 * m11 + k15 * m15 + k12 * m3 + k13 * m7;
+
+	r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7;
+	r[8] = a8; r[9] = a9; r[10] = a10; r[11] = a11; r[12] = a12; r[13] = a13; r[14] = a14; r[15] = a15;
+}
+
+//Multiplying 2 matrices
+function multiply$2Matrix(m, k) {
+	multiply$2(m, m, k);
+}
+
+//Translate transformation
+function translate(out, v) {
+	out[0] = 1;
+	out[1] = 0;
+	out[2] = 0;
+	out[3] = 0;
+	out[4] = 0;
+	out[5] = 1;
+	out[6] = 0;
+	out[7] = 0;
+	out[8] = 0;
+	out[9] = 0;
+	out[10] = 1;
+	out[11] = 0;
+	out[12] = v[0];
+	out[13] = v[1];
+	out[14] = v[2];
+	out[15] = 1;
+
+	return out;
+}
+
+//Scale transformation
+function scale$1(out, a, v) {
+	var v1 = v[0];
+	var v2 = v[1];
+	var v3 = v[2];
+
+	var t = [v1, 0, 0, 0, 0, v2, 0, 0, 0, 0, v3, 0, 0, 0, 0, 1];
+
+	multiply$2Matrix(out, t);
+}
+
+//Rotate based on x-axis
+function fromXRotation(out, rad) {
+	var s = Math.sin(rad);
+	var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+	var out1 = [];
+
+	out1[0] = 1;
+	out1[1] = 0;
+	out1[2] = 0;
+	out1[3] = 0;
+	out1[4] = 0;
+	out1[5] = c;
+	out1[6] = s;
+	out1[7] = 0;
+	out1[8] = 0;
+	out1[9] = -s;
+	out1[10] = c;
+	out1[11] = 0;
+	out1[12] = 0;
+	out1[13] = 0;
+	out1[14] = 0;
+	out1[15] = 1;
+
+	return multiply$2Matrix(out, out1);
+}
+
+//Rotate based on y-axis
+function fromYRotation(out, rad) {
+	var s = Math.sin(rad);
+	var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+	var out1 = [];
+
+	out1[0] = c;
+	out1[1] = 0;
+	out1[2] = -s;
+	out1[3] = 0;
+	out1[4] = 0;
+	out1[5] = 1;
+	out1[6] = 0;
+	out1[7] = 0;
+	out1[8] = s;
+	out1[9] = 0;
+	out1[10] = c;
+	out1[11] = 0;
+	out1[12] = 0;
+	out1[13] = 0;
+	out1[14] = 0;
+	out1[15] = 1;
+
+	return multiply$2Matrix(out, out1);
+}
+
+//Rotate based on z-axis
+function fromZRotation(out, rad) {
+	var s = Math.sin(rad);
+	var c = Math.cos(rad); // Perform axis-specific matrix multiplication
+	var out1 = [];
+
+	out1[0] = c;
+	out1[1] = s;
+	out1[2] = 0;
+	out1[3] = 0;
+	out1[4] = -s;
+	out1[5] = c;
+	out1[6] = 0;
+	out1[7] = 0;
+	out1[8] = 0;
+	out1[9] = 0;
+	out1[10] = 1;
+	out1[11] = 0;
+	out1[12] = 0;
+	out1[13] = 0;
+	out1[14] = 0;
+	out1[15] = 1;
+
+	return multiply$2Matrix(out, out1);
+}
+
+//Normalizing function
+function normalize(out, a) {
+	len = a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
+	len = Math.sqrt(len);
+	if (len < 0.000001) // Too Small
+		return -1;
+	a[0] /= len;
+	a[1] /= len;
+	a[2] /= len;
+}
+
+//Rotate Transformation
+function rotate$2(m, angle, axis) {
+	var axis_rot = [0, 0, 0];
+	var ux, uy, uz;
+	var rm = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
+	var c = Math.cos(angle);
+	var c1 = 1.0 - c;
+	var s = Math.sin(angle);
+	axis_rot[0] = axis[0];
+	axis_rot[1] = axis[1];
+	axis_rot[2] = axis[2];
+	if (normalize(1, axis_rot) == -1)
+		return -1;
+	ux = axis_rot[0]; uy = axis_rot[1]; uz = axis_rot[2];
+	console.log("Log", angle);
+	rm[0] = c + ux * ux * c1;
+	rm[1] = uy * ux * c1 + uz * s;
+	rm[2] = uz * ux * c1 - uy * s;
+	rm[3] = 0;
+
+	rm[4] = ux * uy * c1 - uz * s;
+	rm[5] = c + uy * uy * c1;
+	rm[6] = uz * uy * c1 + ux * s;
+	rm[7] = 0;
+
+	rm[8] = ux * uz * c1 + uy * s;
+	rm[9] = uy * uz * c1 - ux * s;
+	rm[10] = c + uz * uz * c1;
+	rm[11] = 0;
+
+	rm[12] = 0;
+	rm[13] = 0;
+	rm[14] = 0;
+	rm[15] = 1;
+
+	multiply$2Matrix(m, rm);
+}
+
+//Initializing the value
+rotValue = 0.0;
+rotValue1 = 0.0;
+animRotValue = 0.0;
+moonRotValue = 0.0;
+
+transX = 0.0;
+transY = 0.0;
+transZ = 0.0;
+moontransX = 0.0;
+moontransY = 0.0;
+moontransZ = 0.0;
+
+frames = 1;
+tmpX = 0.0;
+tmpY = 0.0;
+tmpZ = 0.0;
+tmpX1 = 0.0;
+tmpY1 = 0.0;
+tmpZ1 = 0.0;
+rotateSpeed = 0.0;
+
+//Input the translate value based on x-axis
+function inputX() {
+	var inputX = document.getElementById("inputX").value;
+	if (inputX == 0) {
+		tmpX = 0.0;
+	}
+	else {
+		tmpX = parseFloat(inputX);
+	}
+}
+
+//Input the translate value based on y-axis
+function inputY() {
+	var inputY = document.getElementById("inputY").value;
+	if (inputY == 0) {
+		tmpY = 0.0;
+	}
+	else {
+		tmpY = parseFloat(inputY);
+	}
+}
+
+//Input the translate value based on z-axis
+function inputZ() {
+	var inputZ = document.getElementById("inputZ").value;
+	if (inputZ == 0) {
+		tmpZ = 0.0;
+	}
+	else {
+		tmpZ = parseFloat(inputZ);
+	}
+}
+
+//Input the translate value based on x-axis
+function inputMoonX() {
+	var inputMoonX = document.getElementById("inputMoonX").value;
+	if (inputMoonX == 0) {
+		tmpX1 = 0.0;
+	}
+	else {
+		tmpX1 = parseFloat(inputMoonX);
+	}
+}
+
+//Input the translate value based on x-axis
+function inputMoonY() {
+	var inputMoonY = document.getElementById("inputMoonY").value;
+	if (inputMoonY == 0) {
+		tmpY1 = 0.0;
+	}
+	else {
+		tmpY1 = parseFloat(inputMoonY);
+	}
+}
+
+//Input the translate value based on x-axis
+function inputMoonZ() {
+	var inputMoonZ = document.getElementById("inputMoonZ").value;
+	if (inputMoonZ == 0) {
+		tmpZ1 = 0.0;
+	}
+	else {
+		tmpZ1 = parseFloat(inputMoonZ);
+	}
+}
+
+//Input speed value, how fast it rotates
+function speed() {
+	var speed = document.getElementById("speed").value;
+
+	if (speed == 0) {
+		rotateSpeed = 0.0;
+	}
+
+	else {
+		rotateSpeed = parseFloat(speed);
+	}
+}
+
+//Initialize the value
+function initialize() {
+	transX = 0.0;
+	transY = 0.0;
+	transZ = 0.0;
+	moontransX = 0.0;
+	moontransY = 0.0;
+	moontransZ = 0.0;
+	rotValue = 0.0;
+	rotValue1 = 0.0;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button is initializing the whole values of the cube. If you click this button it will change to the first state.";
+}
+
+//Zoom In the camera
+function zoomIn() {
+	transZ += 0.1;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button is zoom in function. If you click this button, you can see the cube more close. z-coordinate has changed.";
+}
+
+//Zoom out the camera
+function zoomOut() {
+	transZ -= 0.1;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button is zoom out function. If you click this button, you can see the cube in the far distance. z-coordinate has changed.";
+}
+
+//All cubes rotate
+function animRotateAll() {
+	speed();
+	animRotValue += rotateSpeed;
+	moonRotValue += rotateSpeed;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button is rotating all of the cubes. You can see the code.\n\n<Code>\nanimRotValue += rotateSpeed;\nmoonRotValue += rotateSpeed;";
+}
+
+//Only the main cube rotates
+function animRotate() {
+	speed();
+	animRotValue += rotateSpeed;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button is rotating only the main cube. You can see the code.\n\n<Code>\nanimRotValue += rotateSpeed;"
+}
+
+//All cubes stop rotating
+function animPauseAll() {
+	animRotValue = 0.0;
+	moonRotValue = 0.0;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button stops the whole cubes. You can see the code.\n\n<Code>\nanimRotValue = 0.0;\nmoonRotValue = 0.0;"
+}
+
+//Only the main cube stops
+function animPause() {
+	animRotValue = 0.0;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button stops only the main cube. You can see the code.\n\n<Code>\nanimRotValue = 0.0;"
+}
+
+//Increase the translate value based on x-axis
+function trXinc() {
+	inputX();
+	transX += tmpX;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button is translating base on x-axis. You can see the code.\n\n<Code>\ntransX += tmpX;"
+}
+
+//Increase the translate value based on y-axis
+function trYinc() {
+	inputY();
+	transY += tmpY;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button is translating base on y-axis. You can see the code.\n\n<Code>\ntransY += tmpY;"
+}
+
+//Increase the translate value based on z-axis
+function trZinc() {
+	inputZ();
+	transZ += tmpZ;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button is translating base on z-axis. You can see the code.\n\n<Code>\ntransZ += tmpZ;"
+}
+
+//Moon rotates
+function moonRotate() {
+	speed();
+	moonRotValue += rotateSpeed;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button is rotating the moon cube. You can see the code.\n\n<Code>\nmoonRotValue += rotateSpeed;"
+}
+
+//Moon stop rotating
+function moonPause() {
+	moonRotValue = 0.0;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button stops the moon cube. You can see the code.\n\n<Code>\nmoonRotValue = 0.0;"
+}
+
+//Moon translate based on x-axis
+function moontrXinc() {
+	inputMoonX();
+	moontransX += tmpX1;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button translating the moon cube base on x-axis. You can see the code.\n\n<Code>\nmoontransX += tmpX1;"
+}
+
+//Moon translate based on y-axis
+function moontrYinc() {
+	inputMoonY();
+	moontransY += tmpY1;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button translating the moon cube base on y-axis. You can see the code.\n\n<Code>\nmoontransY += tmpY1;"
+}
+
+//Moon translate based on z-axis
+function moontrZinc() {
+	inputMoonZ();
+	moontransZ += tmpZ1;
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button translating the moon cube base on z-axis. You can see the code.\n\n<Code>\nmoontransZ += tmpZ1;"
+}
+
+function pivot() {
+	inputMoonX();
+	inputMoonY();
+	inputMoonZ();
+
+	moontransX += tmpX1;
+	moontransY += tmpY1;
+	moontransZ += tmpZ1;
+
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button is translating the cube to the position you chose.\nThe cube will translate to the pivot position.\nYou can see the code.\n\n<Code>\nmoontransX += tmpX1;\nmoontransY += tmpY1;\nmoontransZ += tmpZ1;"
+}
+
+function pivotRotate() {
+	inputMoonX();
+	inputMoonY();
+	inputMoonZ();
+	speed();
+
+	moontransX += tmpX1;
+	moontransY += tmpY1;
+	moontransZ += tmpZ1;
+	moonRotValue += rotateSpeed;
+
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This button is translating the cube to the position you chose and the cube translates in that pivot position.\nYou can see the code.\n\n<Code>\nmoontransX += tmpX1;\nmoontransY += tmpY1;\nmoontransZ += tmpZ1;\nmoonRotValue += rotateSpeed;"
+}
+
+function quadraticBezierCurve() {
+	//Initialize the canvas
+	var c = document.getElementById("beziercurve");
+	var context = c.getContext("2d");
+
+	//Initialize the value of the coordinates
+	var startX = document.getElementById("startX").value;
+	startX = parseFloat(startX);
+	var startY = document.getElementById("startY").value;
+	startY = parseFloat(startY);
+	var controlX = document.getElementById("controlX").value;
+	controlX = parseFloat(controlX);
+	var controlY = document.getElementById("controlY").value;
+	controlY = parseFloat(controlY);
+	var endX = document.getElementById("endX").value;
+	endX = parseFloat(endX);
+	var endY = document.getElementById("endY").value;
+	endY = parseFloat(endY);
+
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This is the bezier curve. There are two types of bezier curve in this program. They are Quadratic Bezier Curve and Cubic Bezier Curve. This is Quadratic Bezier Curve. First you have to input the starting point, control point and the end point. Control Point is the center of the curve and it is very important in the bezier curve.\n\n<Code>\ncontext.beginPath();\ncontext.lineWidth = 3;\ncontext.moveTo(startX, startY);\ncontext.quadraticCurveTo(controlX, controlY, endX, endY);\ncontext.stroke();"
+
+	//Start new path
+	context.beginPath();
+	context.lineWidth = 3;
+
+	//Representing control point
+	context.strokeText(".", controlX, controlY);
+
+	//Starting point of the curve
+	context.moveTo(startX, startY);
+	context.quadraticCurveTo(controlX, controlY, endX, endY);
+
+	//Drawing line on the canvas
+	context.stroke();
+}
+
+function cubicBezierCurve() {
+	//Initialize the canvas
+	var c = document.getElementById("beziercurve");
+	var context = c.getContext("2d");
+
+	//Initialize the value of the coordinates
+	var startX = document.getElementById("startX").value;
+	startX = parseFloat(startX);
+	var startY = document.getElementById("startY").value;
+	startY = parseFloat(startY);
+	var controlX = document.getElementById("controlX").value;
+	controlX = parseFloat(controlX);
+	var controlY = document.getElementById("controlY").value;
+	controlY = parseFloat(controlY);
+	var controlX1 = document.getElementById("controlX1").value;
+	controlX1 = parseFloat(controlX1);
+	var controlY1 = document.getElementById("controlY1").value;
+	controlY1 = parseFloat(controlY1);
+	var endX = document.getElementById("endX").value;
+	endX = parseFloat(endX);
+	var endY = document.getElementById("endY").value;
+	endY = parseFloat(endY);
+
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This is the bezier curve. There are two types of bezier curve in this program. They are Quadratic Bezier Curve and Cubic Bezier Curve. This is Cubic Bezier Curve. First you have to input the starting point, control point and the end point. Control Point is the center of the curve and it is very important in the bezier curve. In the Cubic Bezier Curve, we need 2 control points, because it is cubic.\n\n<Code>\ncontext.beginPath();\ncontext.lineWidth = 3;\ncontext.moveTo(startX, startY);\ncontext.bezierCurveTo(controlX, controlY, controlX1, controlY1, endX, endY);\ncontext.stroke();"
+
+	//Start new path
+	context.beginPath();
+	context.lineWidth = 3;
+
+	//Representing first control point
+	context.strokeText(".", controlX, controlY);
+
+	//Representing second control point
+	context.strokeText(".", controlX1, controlY1);
+
+	//Starting point of the curve
+	context.moveTo(startX, startY);
+	context.bezierCurveTo(controlX, controlY, controlX1, controlY1, endX, endY);
+
+	//Drawing line on the canvas  
+	context.stroke();
+}
+
+function bezierCurveErase() {
+	var c = document.getElementById("beziercurve");
+	var context = c.getContext("2d");
+
+	context.clearRect(0, 0, c.width, c.height);
+
+	document.getElementById("information").style.fontWeight = 'bold';
+	document.getElementById("information").value =
+		"This erases the curve drawn in the canvas.You can see the code.\n\n<Code>\ncontext.clearRect(0, 0, c.width, c.height);"
+}
+
+function renderScene() {
+	//console.log("Frame "+frames+"\n");
+	frames += 1;
+	rotAxis = [1, 1, 0];
+
+	var locPmatrix = gl.getUniformLocation(gl.programObject, "Pmatrix");
+	var locVmatrix = gl.getUniformLocation(gl.programObject, "Vmatrix");
+	var locMmatrix = gl.getUniformLocation(gl.programObject, "Mmatrix");
+
+	gl.uniformMatrix4fv(locPmatrix, false, proj_matrix);
+	gl.uniformMatrix4fv(locVmatrix, false, view_matrix);
+
+	if (!testGLError("gl.uniformMatrix4fv")) {
+		return false;
+	}
+
+	gl.enableVertexAttribArray(0);
+	gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 36, 0);
+	gl.enableVertexAttribArray(1);
+	gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 36, 12);
+
+
+	if (!testGLError("gl.vertexAttribPointer")) {
+		return false;
+	}
+	// gl.enable(gl.DEPTH_TEST);
+	// gl.depthFunc(gl.LEQUAL); 
+	// gl.enable(gl.CULL_FACE);
+	gl.enable(gl.BLEND);
+	gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+	gl.blendEquation(gl.FUNC_ADD);
+
+	gl.clearColor(0.6, 0.8, 1.0, 1.0);
+	gl.clearDepth(1.0);
+	gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+	var t = [];
+	var s = [];
+
+	//Create and initialize the main cube
+	identity(mov_matrix);
+	t = [transX, transY, transZ];
+	translate(mov_matrix, t);
+	rotate$2(mov_matrix, rotValue, rotAxis);
+	rotValue += animRotValue;
+	gl.uniformMatrix4fv(locMmatrix, false, mov_matrix);
+	gl.drawArrays(gl.TRIANGLES, 0, 36);
+
+	//Create and initialize the moon cube
+	var mov_matrix_child = mov_matrix.slice();
+	s = [0.25, 0.25, 0.25];
+	t = [moontransX + 0.75, moontransY + 0.75, moontransZ + 0.75];
+	//Scale 0.25 of the main cube 
+	//Translate 0.75 based on x-axis, y-axis, z-axis
+	translate(mov_matrix, t);
+	fromYRotation(mov_matrix, rotValue1 * 5);
+	rotValue1 += moonRotValue;
+	scale$1(mov_matrix, mov_matrix, s);
+	gl.uniformMatrix4fv(locMmatrix, false, mov_matrix);
+	gl.drawArrays(gl.TRIANGLES, 0, 36);
+
+	if (!testGLError("gl.drawArrays")) {
+		return false;
+	}
+
+	return true;
+}
+
+//main() function
+function main() {
+	var canvas = document.getElementById("helloapicanvas");
+	console.log("Start");
+
+	if (!initialiseGL(canvas)) {
+		return;
+	}
+
+	if (!initialiseBuffer()) {
+		return;
+	}
+
+	if (!initialiseShaders()) {
+		return;
+	}
+
+	// Render loop
+	requestAnimFrame = (
+		function () {
+			//	return window.requestAnimationFrame || window.webkitRequestAnimationFrame 
+			//	|| window.mozRequestAnimationFrame || 
+			return function (callback) {
+				// console.log("Callback is"+callback); 
+				window.setTimeout(callback, 10, 10);
+			};
+		})();
+
+	(function renderLoop(param) {
+		if (renderScene()) {
+			// Everything was successful, request that we redraw our scene again in the future
+			requestAnimFrame(renderLoop);
+		}
+	})();
+}
+
diff --git "a/student2019/201521046/\354\273\264\355\223\250\355\204\260\352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274/Project Code/picsea.png" "b/student2019/201521046/\354\273\264\355\223\250\355\204\260\352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274/Project Code/picsea.png"
new file mode 100644
index 0000000000000000000000000000000000000000..fb2774e3a0dcc067d35ad0ac6105d44e1e407810
Binary files /dev/null and "b/student2019/201521046/\354\273\264\355\223\250\355\204\260\352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274/Project Code/picsea.png" differ
diff --git "a/student2019/201521046/\354\273\264\355\223\250\355\204\260\352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274/Project Code/trCube.html" "b/student2019/201521046/\354\273\264\355\223\250\355\204\260\352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274/Project Code/trCube.html"
new file mode 100644
index 0000000000000000000000000000000000000000..1c5517b60262343f13b55a1eb63542346c37eb9e
--- /dev/null
+++ "b/student2019/201521046/\354\273\264\355\223\250\355\204\260\352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274/Project Code/trCube.html"	
@@ -0,0 +1,72 @@
+<!--(CC-NC-BY) 천혜림 2019-->
+<!--소프트웨어학과 201521046 천혜림 컴퓨터그래픽스 기말 프로젝트 과제 20190622-->
+<html>
+<head>
+    <title>WebGLHelloAPI</title>
+    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+    <script type="text/javascript" src="trCube
+.js">
+    </script>
+
+</head>
+<body onload="main()">
+    <h2>WebGL Tutorial - Project - Ajou university - Computer Graphicss</h2>
+
+    <!--1. 캔버스 색깔 조정 버튼-->
+    <h4>Change Canvas Color</h4>
+    <button onclick="changeR()">Color R</button>
+    <button onclick="changeRmin()">Minus Color R</button>
+    <button onclick="changeG()">Color G</button>
+    <button onclick="changeGmin()">Minus Color G</button>
+    <button onclick="changeB()">Color B</button>
+    <button onclick="changeBmin()">Minus Color B</button>
+    <p> </p>
+
+    <!--캔버스 생성-->
+    <canvas id="helloapicanvas" style="border: none;" width="400" height="400"></canvas>
+
+    <!--2.큐브 돌아가는 속도 조정 / 회전 멈춤 / 회전 축 변경-->
+    <h3>1. Animation Rotate Test & Stop Rotate & Rotate Mode Change </h3>
+    <p>
+        <button onclick="animRotate()">Animation Rotate + 0.01</button>
+        <button onclick="stopRotate()">Stop Rotate</button>
+        <button onclick="romode()">Rotate mode</button>
+    </p>
+
+    <!--3->2.큐브 돌아가는 속도 조정 / 회전 멈춤 / 회전 축 변경-->
+    <h3>2. Z-buffer (Depth Test) ON/OFF Test</h3>
+    <p> <button onclick="Zbuffer()" id="butZbuffer"> Depth Test </button> </p>
+    <p id="idZbuffer"> Depth Test ON </p>
+
+    <!--4. 큐브 primitive 표현법 점, 선, 삼각형 확인버튼-->
+    <h3>3. Primitive Assembly - Point/Line/Triangle</h3>
+    <p> <button onclick="changeModePLT()" id="butPLT"> P/L/T </button> </p>
+    <p id="idPLT"> P/L/T </p>
+
+    <!--5. 큐브 x,y,z 축으로 이동 버튼-->
+    <h3>4. Cube Move Test</h3>
+    <p>
+        <button onclick="trXinc()">Translate X + 0.1</button> <button onclick="trXincmin()">Translate Xs - 0.1</button>
+        <button onclick="trYinc()">Translate Y + 0.1</button> <button onclick="trYincmin()">Translate Y - 0.1</button>
+        <button onclick="trZinc()">Translate Z + 0.1</button> <button onclick="trZincmin()">Translate Z - 0.1</button>
+    </p>
+
+    <p id="webTrX"> Translate X </p>
+    <p id="webTrY"> Translate Y </p>
+    <p id="webTrZ"> Translate Z </p>
+
+    <br />
+
+    <p>아주대학교 컴퓨터 그래픽스 기말프로젝트과제 - 이환용 교수님</p>
+    <p>이 페이지는 WebGL에서 5가지 기능을 테스트 할 수 있는 페이지입니다.만들어져 있는 큐브로 확인가능하며, 오른쪽 위에 돌아가고 있는 2개의 작은 큐브는 확인을 위해 회전상태로 계속 있습니다.</p>
+    <p>첫번째 - 배경이 되는 캔버스의 색깔을 RGB 버튼 6개를 통해 색깔을 조정할 수 있습니다.</p>
+    <p>두번째 - 큐브가 회전하는 속도를 증가시킬 수 있고, 멈추게 하거나 또한 회전축을 변경할 수 있습니다.</p>
+    <p>세번째 - Z buffer 테스트를 할 수 있습니다. 버튼을 통해 Depth test 가 적용된 경우와 적용되지 않은 경우를 확인할 수 있습니다.</p>
+    <p>네번째 - 각 vertex들로 표현되는 방식을 점, 선, 삼각형 3가지 방식으로 정할수 있습니다.</p>
+    <p>다섯번째 - 가운데 큐브가 x, y, z 축으로 0.1 씩 이동시켜볼 수 있습니다.</p>
+
+    <p><h1> (CC-NC-BY) 2019 CHEON HYERIM</h1> </p>
+
+
+</body>
+</html>
diff --git "a/student2019/201521046/\354\273\264\355\223\250\355\204\260\352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274/Project Code/trCube.js" "b/student2019/201521046/\354\273\264\355\223\250\355\204\260\352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274/Project Code/trCube.js"
new file mode 100644
index 0000000000000000000000000000000000000000..71e1954822183f4491faf8073cdd43093b131357
--- /dev/null
+++ "b/student2019/201521046/\354\273\264\355\223\250\355\204\260\352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274/Project Code/trCube.js"	
@@ -0,0 +1,816 @@
+/*
+(CC-NC-BY) õ���� 2019
+20190604 ��ǻ�ͱ׷��Ƚ� ��ȯ�� ������
+�⸻���� WebGL tutorial ����� 
+201521046 õ����
+
+    <p>���ִ��б� ��ǻ�� �׷��Ƚ� �⸻������Ʈ���� - ��ȯ�� ������</p>
+    <p>�� �������� WebGL���� 5���� ����� �׽�Ʈ �� �� �ִ� �������Դϴ�.������� �ִ� ť��� Ȯ�ΰ����ϸ�, ������ ���� ���ư��� �ִ� 2���� ���� ť��� Ȯ���� ���� ȸ�����·� ��� �ֽ��ϴ�.</p>
+    <p>ù��° - ����� �Ǵ� ĵ������ ������ RGB ��ư 6���� ���� ������ ������ �� �ֽ��ϴ�.</p>
+    <p>�ι�° - ť�갡 ȸ���ϴ� �ӵ��� ������ų �� �ְ�, ���߰� �ϰų� ���� ȸ������ ������ �� �ֽ��ϴ�.</p>
+    <p>����° - Z buffer �׽�Ʈ�� �� �� �ֽ��ϴ�. ��ư�� ���� Depth test �� ����� ���� ������� ���� ��츦 Ȯ���� �� �ֽ��ϴ�.</p>
+    <p>�׹�° - �� vertex��� ǥ���Ǵ� ����� ��, ��, �ﰢ�� 3���� ������� ���Ҽ� �ֽ��ϴ�.</p>
+    <p>�ټ���° - ��� ť�갡 x, y, z ������ 0.1 �� �̵����Ѻ� �� �ֽ��ϴ�.</p>
+
+*/
+var gl;
+
+// GL ���� �׽�Ʈ 
+function testGLError(functionLastCalled) {
+
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+
+    return true;
+}
+
+//ĵ���� �ʱ�ȭ
+function initialiseGL(canvas) {
+    try {
+ // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+
+    return true;
+}
+
+var shaderProgram;
+
+// ���� �ʱ�ȭ 
+function initialiseBuffer() {
+     // Create a texture.
+    var texture = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, texture);
+    // Fill the texture with a 1x1 blue pixel.
+    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
+	new Uint8Array([0, 0, 255, 255]));
+    // Asynchronously load an image
+    var image = new Image();
+    // ���̽�64 ������Ʈ �ڵ带 ���� ��, ���̽� ���ڵ��� �� https://www.base64-image.de/
+    // ���� ��ǻ�Ϳ��� �̹��� ���� ������ �� ����Ʈ�� �ְ� ������Ʈ �ڵ带 ���� ���ڵ�����
+    image.src = "data:image/png;base64,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";
+   
+    image.addEventListener('load', function () {
+        // Now that the image has loaded make copy it to the texture.
+        gl.bindTexture(gl.TEXTURE_2D, texture);
+        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
+        gl.generateMipmap(gl.TEXTURE_2D);
+    });
+
+
+    var vertexData = [
+		-0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		0.0, 1.0,  0.0, 1.0, 0.0, //3  ���� 3�� �븻 ���� 
+        0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		1.0, 1.0,  0.0, 1.0, 0.0, //1
+		0.5, 0.5, -0.5,		1.0, 1.0, 1.0, 0.5,		1.0, 1.0,  0.0, 1.0, 0.0, //2
+				
+		-0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		0.0, 1.0,  0.0, 1.0, 0.0, //3
+		0.5, 0.5, -0.5,		1.0, 1.0, 1.0, 0.5,		1.0, 1.0,  0.0, 1.0, 0.0, //2
+		-0.5, 0.5, -0.5,	1.0, 1.0, 1.0, 0.5,		0.0, 1.0,  0.0, 1.0, 0.0, //4
+		 
+		0.5, 0.5, -0.5,		0.0, 0.0, 0.0, 0.5,		1.0, 1.0,  0.0, 0.0, -1.0, //2
+		0.5, -0.5, -0.5,	0.0, 0.0, 0.0, 0.5,		1.0, 0.0,  0.0, 0.0, -1.0, //6
+		-0.5,-0.5,-0.5,		0.0, 0.0, 0.0, 0.5,		0.0, 0.0,  0.0, 0.0, -1.0, //8
+		   
+		-0.5, 0.5, -0.5,	0.0, 0.0, 0.0, 0.5,		0.0, 1.0,  0.0, 0.0, -1.0, //4
+		0.5, 0.5, -0.5,		0.0, 0.0, 0.0, 0.5,		1.0, 1.0,  0.0, 0.0, -1.0, //2
+		-0.5,-0.5,-0.5,		0.0, 0.0, 0.0, 0.5,		0.0, 0.0,  0.0, 0.0, -1.0, //8
+			
+		0.5, -0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		0.0, 1.0,  1.0, 0.0, 0.0, //5
+		0.5, -0.5, -0.5,	1.0, 0.5, 0.0, 0.5,		0.0, 1.0,  1.0, 0.0, 0.0, //6
+		0.5, 0.5, -0.5,		1.0, 0.5, 0.0, 0.5,		1.0, 1.0,  1.0, 0.0, 0.0, //2
+
+		0.5, -0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		0.0, 1.0,  1.0, 0.0, 0.0, //5
+		0.5, 0.5, -0.5,		1.0, 0.5, 0.0, 0.5,		1.0, 1.0,  1.0, 0.0, 0.0, //2
+		0.5, 0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		1.0, 1.0,  1.0, 0.0, 0.0, //1
+				 
+		-0.5, 0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 1.0,  -1.0, 0.0, 0.0, //4
+		-0.5,-0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 0.0,  -1.0, 0.0, 0.0, //8
+		-0.5, -0.5, 0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 0.0,  -1.0, 0.0, 0.0, //7
+		
+		-0.5, 0.5, 0.5,		1.0, 0.0, 0.0, 0.5,		0.0, 1.0, -1.0, 0.0, 0.0, //3
+		-0.5, 0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 1.0, -1.0, 0.0, 0.0, //4
+		-0.5, -0.5, 0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 0.0, -1.0, 0.0, 0.0, //7
+		
+        //8,9��° �Ķ���� �� �ٲ�� ������ ���� �ȵǰ� ����� ���� 
+		-0.5, -0.5, 0.5,	0.0, 0.0, 1.0, 0.5,		0.0, 1.0, 0.0, 0.0, 1.0, //7
+		0.5, -0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		1.0, 1.0, 0.0, 0.0, 1.0, //5
+		0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		1.0, 0.0, 0.0, 0.0, 1.0, //1
+				 
+		-0.5, -0.5, 0.5,	0.0, 0.0, 1.0, 0.5,		0.0, 1.0, 0.0, 0.0, 1.0, //7
+		0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		1.0, 0.0, 0.0, 0.0, 1.0, //1
+		-0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		0.0, 0.0, 0.0, 0.0, 1.0, //3
+		
+		 0.5, -0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		1.0, 0.0, 0.0, -1.0, 0.0, //6
+		 0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		1.0, 0.0, 0.0, -1.0, 0.0, //5
+		-0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		0.0, 0.0, 0.0, -1.0, 0.0, //7
+		
+		-0.5,-0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		0.0, 0.0, 0.0, -1.0, 0.0, //8
+		 0.5, -0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		1.0, 0.0, 0.0, -1.0, 0.0, //6
+		-0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		0.0, 0.0, 0.0, -1.0, 0.0, //7
+    ];
+	
+    // Generate a buffer object
+    gl.vertexBuffer = gl.createBuffer();
+    // Bind buffer as a vertex buffer so we can fill it with data
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    return testGLError("initialiseBuffers");
+}
+
+// ������ �ʱ�ȭ 
+function initialiseShaders() {
+
+    // �ؽ�ó�� ť���� ������ �ݹ� ���´�.
+        var fragmentShaderSource = '\
+			varying mediump vec4 color; \
+			varying mediump vec2 texCoord;\
+			uniform sampler2D sampler2d; \
+			void main(void) \
+			{ \
+				gl_FragColor = 0.5 * color + 0.5 * texture2D(sampler2d, texCoord); \
+			}';
+ 
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    // �븻���͸� ����Ͽ� �� ���̵��� ���־���.
+    var vertexShaderSource = '\
+			attribute highp vec3 myVertex; \
+			attribute highp vec4 myColor; \
+			attribute highp vec2 myUV; \
+			attribute highp vec3 myNormal; \
+			uniform mediump mat4 Pmatrix; \
+			uniform mediump mat4 Vmatrix; \
+			uniform mediump mat4 Mmatrix; \
+			uniform mediump mat4 Nmatrix; \
+			varying mediump vec4 color; \
+			varying mediump vec2 texCoord;\
+			void main(void)  \
+			{ \
+                vec4 nN; ;\
+                vec4 v1, v2, v3, v4 ;\
+                vec3 v5 ;\
+                v1 = Mmatrix * vec4(myVertex, 1.0);\
+                v2 = Mmatrix * vec4(myVertex + myNormal, 1.0);\
+                v1.xyz = v1.xyz/v1.w;\
+                v2.xyz = v2.xyz/v2.w;\
+                v3 = v2 - v1;\
+                v5 = normalize(v3.xyz);\
+				gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(myVertex, 1.0);\
+                nN = Mmatrix * vec4(myNormal, 1.0) ;\
+					/* \
+				if (gl_Position.w != 0.0) \
+					gl_Position.x /= gl_Position.w; \
+				gl_Position.x += 1.0; \
+				if (gl_Position.w != 1.0) \
+					gl_Position.x *= gl_Position.w; */ \
+                color = 0.2*myColor + vec4(0.8, 0.8, 0.8, 1.0) * 0.5 * (dot(v5 ,vec3(1, 1, 1))+0.1) ;\
+				color.a = 1.0; \
+				texCoord = myUV; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    gl.programObject = gl.createProgram();
+
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex"); // ������
+    gl.bindAttribLocation(gl.programObject, 1, "myColor"); // ����
+	gl.bindAttribLocation(gl.programObject, 2, "myUV");   // �ؽ�ó 
+	gl.bindAttribLocation(gl.programObject, 3, "myNormal"); // �븻����
+
+    // Link the program
+    gl.linkProgram(gl.programObject);
+
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+
+    return testGLError("initialiseShaders");
+}
+
+
+			
+// PMV ��Ʈ���� ����
+var proj_matrix = get_projection(30, 1.0, 1, 8.0);
+var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+
+// translating z - ī�޶��
+view_matrix[14] = view_matrix[14]-5;//zoom
+
+// Depth test ������ ���� �Լ�
+var zbuffermode = ["Depth Test ON", "Depth Test Off"];
+var zbufferonoff = 1;
+function Zbuffer() {
+    if (zbufferonoff == 0) zbufferonoff = 1;
+    else zbufferonoff = 0;
+    console.log("zbufferonoff =" + zbufferonoff);
+    document.getElementById("idZbuffer").innerHTML = zbuffermode[zbufferonoff];
+}
+
+// projection ��� �Լ� 
+function get_projection(angle, a, zMin, zMax) {
+    var ang = Math.tan((angle * .5) * Math.PI / 180);//angle*.5
+    return [
+    	0.5 / ang, 0, 0, 0,
+        0, 0.5 * a / ang, 0, 0,
+        0, 0, -(zMax + zMin) / (zMax - zMin), -1,
+        0, 0, (-2 * zMax * zMin) / (zMax - zMin), 0];
+}
+
+//glm �Լ� ������
+function rotateX(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+        // If the source and destination differ, copy the unchanged rows
+        out[0] = a[0];
+        out[1] = a[1];
+        out[2] = a[2];
+        out[3] = a[3];
+        out[12] = a[12];
+        out[13] = a[13];
+        out[14] = a[14];
+        out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[4] = a10 * c + a20 * s;
+    out[5] = a11 * c + a21 * s;
+    out[6] = a12 * c + a22 * s;
+    out[7] = a13 * c + a23 * s;
+    out[8] = a20 * c - a10 * s;
+    out[9] = a21 * c - a11 * s;
+    out[10] = a22 * c - a12 * s;
+    out[11] = a23 * c - a13 * s;
+    return out;
+}
+//glm �Լ� ������
+function rotateY(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a20 = a[8];
+    var a21 = a[9];
+    var a22 = a[10];
+    var a23 = a[11];
+
+    if (a !== out) {
+        // If the source and destination differ, copy the unchanged rows
+        out[4] = a[4];
+        out[5] = a[5];
+        out[6] = a[6];
+        out[7] = a[7];
+        out[12] = a[12];
+        out[13] = a[13];
+        out[14] = a[14];
+        out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c - a20 * s;
+    out[1] = a01 * c - a21 * s;
+    out[2] = a02 * c - a22 * s;
+    out[3] = a03 * c - a23 * s;
+    out[8] = a00 * s + a20 * c;
+    out[9] = a01 * s + a21 * c;
+    out[10] = a02 * s + a22 * c;
+    out[11] = a03 * s + a23 * c;
+    return out;
+}
+//glm �Լ� ������
+function rotateZ(out, a, rad) {
+    var s = Math.sin(rad);
+    var c = Math.cos(rad);
+    var a00 = a[0];
+    var a01 = a[1];
+    var a02 = a[2];
+    var a03 = a[3];
+    var a10 = a[4];
+    var a11 = a[5];
+    var a12 = a[6];
+    var a13 = a[7];
+
+    if (a !== out) {
+        // If the source and destination differ, copy the unchanged last row
+        out[8] = a[8];
+        out[9] = a[9];
+        out[10] = a[10];
+        out[11] = a[11];
+        out[12] = a[12];
+        out[13] = a[13];
+        out[14] = a[14];
+        out[15] = a[15];
+    } // Perform axis-specific matrix multiplication
+
+
+    out[0] = a00 * c + a10 * s;
+    out[1] = a01 * c + a11 * s;
+    out[2] = a02 * c + a12 * s;
+    out[3] = a03 * c + a13 * s;
+    out[4] = a10 * c - a00 * s;
+    out[5] = a11 * c - a01 * s;
+    out[6] = a12 * c - a02 * s;
+    out[7] = a13 * c - a03 * s;
+    return out;
+}
+
+function normalizeVec3(v)
+{
+	sq = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; 
+	sq = Math.sqrt(sq);
+	if (sq < 0.000001 ) // Too Small
+		return -1; 
+	v[0] /= sq; v[1] /= sq; v[2] /= sq; 
+}
+
+function rotateArbAxis(m, angle, axis)
+{
+	var axis_rot = [0,0,0];
+	var ux, uy, uz;
+	var rm = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; 
+    var c = Math.cos(angle);
+	var c1 = 1.0 - c; 
+    var s = Math.sin(angle);
+	axis_rot[0] = axis[0]; 
+	axis_rot[1] = axis[1]; 
+	axis_rot[2] = axis[2]; 
+	if (normalizeVec3(axis_rot) == -1 )
+		return -1; 
+	ux = axis_rot[0]; uy = axis_rot[1]; uz = axis_rot[2];
+	console.log("Log", angle);
+	rm[0] = c + ux * ux * c1;
+	rm[1] = uy * ux * c1 + uz * s;
+	rm[2] = uz * ux * c1 - uy * s;
+	rm[3] = 0;
+
+	rm[4] = ux * uy * c1 - uz * s;
+	rm[5] = c + uy * uy * c1;
+	rm[6] = uz * uy * c1 + ux * s;
+	rm[7] = 0;
+
+	rm[8] = ux * uz * c1 + uy * s;
+	rm[9] = uy * uz * c1 - ux * s;
+	rm[10] = c + uz * uz * c1;
+	rm[11] = 0;
+
+	rm[12] = 0;
+	rm[13] = 0;
+	rm[14] = 0;
+	rm[15] = 1;
+
+	m = multiply$3(m, m, rm);
+
+}
+
+rotValue = 0.0; 
+rotValueSmall = 0.0; 
+incRotValue = 0.0;
+incRotValueSmall = 0.02; 
+
+transX = 0.0;
+transY = 0.0;
+transZ = 0.0;
+frames = 1;
+tempRotValue = 0.0; 
+
+// ȸ�� �ӵ� ������Ű�� �Լ� & ȸ�� �ߴ��ϴ� �Լ� 
+function animRotate()
+{
+	incRotValue += 0.01;
+}
+function stopRotate() {
+    if (incRotValue == 0.0) {
+        incRotValue = tempRotValue;
+    }
+    else {
+        tempRotValue = incRotValue;
+        incRotValue = 0.0;
+    }
+}
+
+// ť�긦 xyz �� �̵��ϱ� ���� �Լ� 6��
+function trXinc()
+{
+	transX += 0.01;
+	document.getElementById("webTrX").innerHTML = "transX : " + transX.toFixed(4);
+}
+function trXincmin() {
+    transX -= 0.01;
+    document.getElementById("webTrX").innerHTML = "transX : " + transX.toFixed(4);
+}
+
+function trYinc() {
+    transY += 0.01;
+    document.getElementById("webTrY").innerHTML = "transY : " + transY.toFixed(4);
+}
+function trYincmin() {
+    transY -= 0.01;
+    document.getElementById("webTrY").innerHTML = "transY : " + transY.toFixed(4);
+}
+
+function trZinc() {
+    transZ += 0.01;
+    document.getElementById("webTrZ").innerHTML = "transZ : " + transZ.toFixed(4);
+}
+function trZincmin() {
+    transZ -= 0.01;
+    document.getElementById("webTrZ").innerHTML = "transZ : " + transZ.toFixed(4);
+}
+
+// glm �Լ� ������ identity / multiply / translate / scale
+function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+}
+function multiply$3(out, a, b) {
+    var a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
+    var a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
+    var a30 = a[12],
+        a31 = a[13],
+        a32 = a[14],
+        a33 = a[15]; // Cache only the current line of the second matrix
+
+    var b0 = b[0],
+        b1 = b[1],
+        b2 = b[2],
+        b3 = b[3];
+    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[4];
+    b1 = b[5];
+    b2 = b[6];
+    b3 = b[7];
+    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[8];
+    b1 = b[9];
+    b2 = b[10];
+    b3 = b[11];
+    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    b0 = b[12];
+    b1 = b[13];
+    b2 = b[14];
+    b3 = b[15];
+    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+    return out;
+}
+function translate$2(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    var a00, a01, a02, a03;
+    var a10, a11, a12, a13;
+    var a20, a21, a22, a23;
+
+    if (a === out) {
+        out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+        out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+        out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+        out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+    } else {
+        a00 = a[0];
+        a01 = a[1];
+        a02 = a[2];
+        a03 = a[3];
+        a10 = a[4];
+        a11 = a[5];
+        a12 = a[6];
+        a13 = a[7];
+        a20 = a[8];
+        a21 = a[9];
+        a22 = a[10];
+        a23 = a[11];
+        out[0] = a00;
+        out[1] = a01;
+        out[2] = a02;
+        out[3] = a03;
+        out[4] = a10;
+        out[5] = a11;
+        out[6] = a12;
+        out[7] = a13;
+        out[8] = a20;
+        out[9] = a21;
+        out[10] = a22;
+        out[11] = a23;
+        out[12] = a00 * x + a10 * y + a20 * z + a[12];
+        out[13] = a01 * x + a11 * y + a21 * z + a[13];
+        out[14] = a02 * x + a12 * y + a22 * z + a[14];
+        out[15] = a03 * x + a13 * y + a23 * z + a[15];
+    }
+
+    return out;
+}
+function scale$3(out, a, v) {
+    var x = v[0],
+        y = v[1],
+        z = v[2];
+    out[0] = a[0] * x;
+    out[1] = a[1] * x;
+    out[2] = a[2] * x;
+    out[3] = a[3] * x;
+    out[4] = a[4] * y;
+    out[5] = a[5] * y;
+    out[6] = a[6] * y;
+    out[7] = a[7] * y;
+    out[8] = a[8] * z;
+    out[9] = a[9] * z;
+    out[10] = a[10] * z;
+    out[11] = a[11] * z;
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+    return out;
+}
+
+//primitive ��� ���� �Լ�
+var modeName = ["Triangle", "Point", "Line"];
+var modePLT = 0;
+function changeModePLT() {
+    modePLT++;
+    modePLT %= 3;
+    console.log("modePLT =" + modePLT);
+    document.getElementById("idPLT").innerHTML = modeName[modePLT];
+}
+
+// rotate ��� ���� �Լ� 
+var rotmode = 0;
+var rotAxis = [1, 1, 0];
+function romode(){
+    if (rotmode == 0) {
+        rotmode = 1;
+        rotAxis = [0, 1, 1];
+    }
+    else {
+        if (rotmode == 1) {
+            rotmode = 2;
+            rotAxis = [1, 0, 1];
+        }
+        else {
+            // rotmode == 2
+            rotmode = 0;
+            rotAxis = [1, 1, 0];
+        }
+    }
+}
+
+// ĵ���� ���� ���� �Լ� �� ����
+var Rvalue = 1;
+var Gvalue = 1;
+var Bvalue = 1;
+function changeR() {
+    if (Rvalue+0.1 <= 1) {
+        Rvalue += 0.1;
+    }
+}
+function changeRmin() {
+    if (Rvalue - 0.1 >= 0) {
+        Rvalue -= 0.1;
+    }
+}
+function changeG() {
+    if (Gvalue + 0.1 <= 1) {
+        Gvalue += 0.1;
+    }
+}
+function changeGmin() {
+    if (Gvalue - 0.1 >= 0) {
+        Gvalue -= 0.1;
+    }
+}
+function changeB() {
+    if (Bvalue + 0.1 <= 1) {
+        Bvalue += 0.1;
+    }
+}
+function changeBmin() {
+    if (Bvalue - 0.1 >= 0) {
+        Bvalue -= 0.1;
+    }
+}
+
+
+// ������ 
+function renderScene() {
+
+    //console.log("Frame "+frames+"\n");
+    frames += 1 ;
+	//srotAxis = [1,1,0];
+
+    var Pmatrix = gl.getUniformLocation(gl.programObject, "Pmatrix");
+    var Vmatrix = gl.getUniformLocation(gl.programObject, "Vmatrix");
+    var Mmatrix = gl.getUniformLocation(gl.programObject, "Mmatrix");
+    var Nmatrix = gl.getUniformLocation(gl.programObject, "Nmatrix");
+    var translateparameter = [0.0, 0.0, 0.0];
+    var scaleparameter = [0, 0, 0];
+
+    identity$3(mov_matrix);
+	rotateArbAxis(mov_matrix, rotValue, rotAxis);
+    rotValue += incRotValue; 
+    rotValueSmall += incRotValueSmall;
+    translateparameter = [transX, transY, transZ];
+    translate$2(mov_matrix, mov_matrix, translateparameter);
+
+    gl.uniformMatrix4fv(Pmatrix, false, proj_matrix);
+    gl.uniformMatrix4fv(Vmatrix, false, view_matrix);
+    gl.uniformMatrix4fv(Mmatrix, false, mov_matrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 48, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 48, 12);
+	gl.enableVertexAttribArray(2);
+    gl.vertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 48, 28);
+	gl.enableVertexAttribArray(3);
+    gl.vertexAttribPointer(3, 3, gl.FLOAT, gl.FALSE, 48, 36); // 3�� �븻�� ���� / ���ؽ� �߰��� 36���� 48 �� 
+
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+    // zbuffer �׽�Ʈ Ȯ�� ������ zbufferonoff ���� ���� ���� zbuffer �� �Ѱ� ����.
+    if (zbufferonoff == 0) {
+        gl.enable(gl.DEPTH_TEST);
+        gl.enable(gl.BLEND);
+        gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+        gl.blendEquation(gl.FUNC_ADD);
+    }
+    else {
+        gl.disable(gl.DEPTH_TEST);
+        gl.enable(gl.BLEND);
+        gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+        gl.blendEquation(gl.FUNC_ADD);
+    }
+
+    // ���� ���� 
+    gl.clearColor(Rvalue, Gvalue, Bvalue, 1.0);
+    gl.clearDepth(1.0); 
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+    // vertex���� modePLT ���� ���� ��,��,�ﰢ������ ǥ���Ѵ�.
+    if (modePLT == 0)
+        gl.drawArrays(gl.TRIANGLES, 0, 36);
+    else if (modePLT == 1)
+        gl.drawArrays(gl.POINTS, 0, 36);
+    else
+        gl.drawArrays(gl.LINES, 0, 36);
+
+
+    // ���� 1
+	var mov_matrix2 = mov_matrix.slice();
+	translateparameter = [0.75, 0.75, 0.75];
+	translate$2(mov_matrix2, mov_matrix2, translateparameter);
+	rotateY(mov_matrix2, mov_matrix2, rotValueSmall);    
+	scaleparameter = [0.25, 0.25, 0.25];
+	scale$3(mov_matrix2, mov_matrix2, scaleparameter);
+    gl.uniformMatrix4fv(Mmatrix, false, mov_matrix2);
+    if (modePLT == 0)
+        gl.drawArrays(gl.TRIANGLES, 0, 36);
+    else if (modePLT == 1)
+        gl.drawArrays(gl.POINTS, 0, 36);
+    else
+        gl.drawArrays(gl.LINES, 0, 36);
+
+
+    // ���� 2
+	var mov_matrix3 = mov_matrix2.slice();
+	translateparameter = [0.75, -0.75, 0.75];
+	translate$2(mov_matrix3, mov_matrix3, translateparameter);
+	rotateY(mov_matrix3, mov_matrix3, rotValueSmall);
+	scaleparameter = [0.25, 0.25, 0.25];
+	scale$3(mov_matrix3, mov_matrix3, scaleparameter);
+    gl.uniformMatrix4fv(Mmatrix, false, mov_matrix3);
+    if (modePLT == 0)
+        gl.drawArrays(gl.TRIANGLES, 0, 36);
+    else if (modePLT == 1)
+        gl.drawArrays(gl.POINTS, 0, 36);
+    else
+        gl.drawArrays(gl.LINES, 0, 36);
+
+
+
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+ 
+//���� �κ�
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+    console.log("Start");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+    // Render loop
+    requestAnimFrame = (
+	function () {
+        //	return window.requestAnimationFrame || window.webkitRequestAnimationFrame 
+	//	|| window.mozRequestAnimationFrame || 
+	   	return function (callback) {
+			    // console.log("Callback is"+callback); 
+			    window.setTimeout(callback, 10, 10); };
+    })();
+
+    (function renderLoop(param) {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
diff --git "a/student2019/201521046/\354\273\264\355\223\250\355\204\260\352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274/\354\273\264\355\223\250\355\204\260 \352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \353\263\264\352\263\240\354\204\234 - \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274.docx" "b/student2019/201521046/\354\273\264\355\223\250\355\204\260\352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274/\354\273\264\355\223\250\355\204\260 \352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \353\263\264\352\263\240\354\204\234 - \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274.docx"
new file mode 100644
index 0000000000000000000000000000000000000000..930d346349c2f8bbe28c491143348be77a4d4536
Binary files /dev/null and "b/student2019/201521046/\354\273\264\355\223\250\355\204\260\352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274/\354\273\264\355\223\250\355\204\260 \352\267\270\353\236\230\355\224\275\354\212\244 \352\270\260\353\247\220\352\263\274\354\240\234 \353\263\264\352\263\240\354\204\234 - \354\206\214\355\224\204\355\212\270\354\233\250\354\226\264\355\225\231\352\263\274 201521046 \354\262\234\355\230\234\353\246\274.docx" differ
diff --git a/student2019/201523484/index.html b/student2019/201523484/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..b42573de5d4c5deaf7e7c12d909766102bf80762
--- /dev/null
+++ b/student2019/201523484/index.html
@@ -0,0 +1,108 @@
+
+<!-- 
+	(CC-NC-BY) Choi Ji Won 2019 
+-->
+
+<html>
+
+<head>
+	<title>WebGL Blending Tutorial</title>
+	<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+	<link rel="stylesheet" type="text/css" href="mystyle.css">
+	<script type="text/javascript" src="webgl.js"> </script>
+</head>
+
+<body onload="main()">
+
+<h1> WebGL Blending Tutorial </h1>
+
+<div>
+	<canvas id="webglCanvas" width="400" height="400"></canvas>
+</div>
+
+<div>
+	<b>Cube rotate : </b>
+	<button onclick="animRotate()">Rotate Start</button>
+	<button onclick="animPause()">Rotate Pause</button>
+</div>
+
+<div>
+	<b>Blend : </b>
+	<input type="checkbox" id="chk_ble" checked> Enable 
+</div>
+
+<div>
+	<table>
+		<tr>
+			<th>gl.blendEquation(<i>mode</i>)</th>
+			<th>gl.blendFunc(<i><u>sfactor</u>, dfactor</i>)</th>
+			<th>gl.blendFunc(<i>sfactor, <u>dfactor</u></i>)</th>
+		</tr>
+
+		<tr>
+			<th>
+				<select id="sel_equ">
+				  <option value="FUNC_ADD" selected="selected">gl.FUNC_ADD</option>
+				  <option value="FUNC_SUBTRACT">gl.FUNC_SUBTRACT</option>
+				  <option value="FUNC_REVERSE_SUBTRACT">gl.FUNC_REVERSE_SUBTRACT</option>
+				</select>
+			</th>
+			<th>
+				<select id="sel_src">
+				  <option value="ZERO">gl.ZERO</option>
+				  <option value="ONE">gl.ONE</option>
+				  <option value="SRC_COLOR">gl.SRC_COLOR</option>
+				  <option value="ONE_MINUS_SRC_COLOR">gl.ONE_MINUS_SRC_COLOR</option>
+				  <option value="DST_COLOR">gl.DST_COLOR</option>
+				  <option value="ONE_MINUS_DST_COLOR">gl.ONE_MINUS_DST_COLOR</option>
+				  <option value="SRC_ALPHA" selected="selected">gl.SRC_ALPHA</option>
+				  <option value="ONE_MINUS_SRC_ALPHA">gl.ONE_MINUS_SRC_ALPHA</option>
+				  <option value="DST_ALPHA">gl.DST_ALPHA</option>
+				  <option value="ONE_MINUS_DST_ALPHA">gl.ONE_MINUS_DST_ALPHA</option>
+				  <option value="CONSTANT_COLOR">gl.CONSTANT_COLOR</option>
+				  <option value="ONE_MINUS_CONSTANT_COLOR">gl.ONE_MINUS_CONSTANT_COLOR</option>
+				  <option value="CONSTANT_ALPHA">gl.CONSTANT_ALPHA</option>
+				  <option value="ONE_MINUS_CONSTANT_ALPHA">gl.ONE_MINUS_CONSTANT_ALPHA</option>
+				  <option value="SRC_ALPHA_SATURATE">gl.SRC_ALPHA_SATURATE</option>
+				</select>
+			</th>
+			<th>
+				<select id="sel_dst">
+				  <option value="ZERO">gl.ZERO</option>
+				  <option value="ONE">gl.ONE</option>
+				  <option value="SRC_COLOR">gl.SRC_COLOR</option>
+				  <option value="dONE_MINUS_SRC_COLOR4">gl.ONE_MINUS_SRC_COLOR</option>
+				  <option value="DST_COLOR">gl.DST_COLOR</option>
+				  <option value="ONE_MINUS_DST_COLOR">gl.ONE_MINUS_DST_COLOR</option>
+				  <option value="SRC_ALPHA">gl.SRC_ALPHA</option>
+				  <option value="ONE_MINUS_SRC_ALPHA" selected="selected">gl.ONE_MINUS_SRC_ALPHA</option>
+				  <option value="DST_ALPHA">gl.DST_ALPHA</option>
+				  <option value="ONE_MINUS_DST_ALPHA">gl.ONE_MINUS_DST_ALPHA</option>
+				  <option value="CONSTANT_COLOR">gl.CONSTANT_COLOR</option>
+				  <option value="ONE_MINUS_CONSTANT_COLOR">gl.ONE_MINUS_CONSTANT_COLOR</option>
+				  <option value="CONSTANT_ALPHA">gl.CONSTANT_ALPHA</option>
+				  <option value="ONE_MINUS_CONSTANT_ALPHA">gl.ONE_MINUS_CONSTANT_ALPHA</option>
+				</select>
+			</th>
+		</tr>
+
+		<tr>
+			<th><div id="txt_equ">equation information</div></th>
+			<th>
+				<div id="txt_src">source information</div>
+			</th>
+			<th><div id="txt_dst">destination information</div></th>
+		</tr>
+	</table>
+</div>
+
+<div id="txt_code">
+	<b>// Code in WebGL.js (before gl.drawArrays())</b><br>
+	<span id="code_ena">gl.enable(gl.BLEND);</span><br>
+    gl.blendEquation(gl.<span id="code_mode">FUNC_ADD</span>);<br>
+	gl.blendFunc(gl.<span id="code_sfactor">SRC_ALPHA</span>, gl.<span id="code_dfactor">ONE_MINUS_SRC_ALPHA</span>);
+</div>
+
+</body>
+
+</html>
\ No newline at end of file
diff --git a/student2019/201523484/mystyle.css b/student2019/201523484/mystyle.css
new file mode 100644
index 0000000000000000000000000000000000000000..46f6b0526a9a56b7c1eae6eeba55c39bf892a4b4
--- /dev/null
+++ b/student2019/201523484/mystyle.css
@@ -0,0 +1,35 @@
+
+/*
+    (CC-NC-BY) Choi Ji Won 2019
+*/
+
+h1 {
+	margin-left: 5px;
+	margin-top: 10px;
+}
+
+div {
+	border: none;
+	padding: 5px;
+}
+
+th {
+	border-right: 1px solid gray;
+	border-left: 1px solid gray;
+}
+
+table {
+	border: 1px solid gray;
+	width: 500px;
+}
+
+#txt_equ, #txt_src, #txt_dst {
+	font-size: 10px;
+}
+
+#txt_code {
+	border: 1px solid gray;
+	padding: 10px;
+	margin: 5px;
+	width: 750px;
+}
\ No newline at end of file
diff --git a/student2019/201523484/webgl.js b/student2019/201523484/webgl.js
new file mode 100644
index 0000000000000000000000000000000000000000..36608f51c0c1e78d45ababaf30b56ee5f3488658
--- /dev/null
+++ b/student2019/201523484/webgl.js
@@ -0,0 +1,569 @@
+
+/*
+    (CC-NC-BY) Choi Ji Won 2019
+*/
+
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+
+    return true;
+}
+
+var shaderProgram;
+
+function initialiseBuffer() {
+    var vertexData = [
+        -0.5, 0.5, 0.5,     1.0, 1.0, 1.0, 0.5,     0.0, 1.0,//3
+        0.5, 0.5, 0.5,      1.0, 1.0, 1.0, 0.5,     1.0, 1.0,//1
+        0.5, 0.5, -0.5,     1.0, 1.0, 1.0, 0.5,     1.0, 1.0,//2
+                
+        -0.5, 0.5, 0.5,     1.0, 1.0, 1.0, 0.5,     0.0, 1.0,//3
+        0.5, 0.5, -0.5,     1.0, 1.0, 1.0, 0.5,     1.0, 1.0,//2
+        -0.5, 0.5, -0.5,    1.0, 1.0, 1.0, 0.5,     0.0, 1.0,//4
+         
+        0.5, 0.5, -0.5,     0.0, 0.0, 0.0, 0.5,     1.0, 1.0,//2
+        0.5, -0.5, -0.5,    0.0, 0.0, 0.0, 0.5,     1.0, 0.0,//6
+        -0.5,-0.5,-0.5,     0.0, 0.0, 0.0, 0.5,     0.0, 0.0,//8
+           
+        -0.5, 0.5, -0.5,    0.0, 0.0, 0.0, 0.5,     0.0, 1.0,//4
+        0.5, 0.5, -0.5,     0.0, 0.0, 0.0, 0.5,     1.0, 1.0,//2
+        -0.5,-0.5,-0.5,     0.0, 0.0, 0.0, 0.5,     0.0, 0.0,//8
+            
+        0.5, -0.5, 0.5,     1.0, 0.5, 0.0, 0.5,     0.0, 1.0,//5
+        0.5, -0.5, -0.5,    1.0, 0.5, 0.0, 0.5,     0.0, 1.0,//6
+        0.5, 0.5, -0.5,     1.0, 0.5, 0.0, 0.5,     1.0, 1.0,//2
+
+        0.5, -0.5, 0.5,     1.0, 0.5, 0.0, 0.5,     0.0, 1.0,//5
+        0.5, 0.5, -0.5,     1.0, 0.5, 0.0, 0.5,     1.0, 1.0,//2
+        0.5, 0.5, 0.5,      1.0, 0.5, 0.0, 0.5,     1.0, 1.0,//1
+                 
+        -0.5, 0.5, -0.5,    1.0, 0.0, 0.0, 0.5,     0.0, 1.0,//4
+        -0.5,-0.5, -0.5,    1.0, 0.0, 0.0, 0.5,     0.0, 0.0,//8
+        -0.5, -0.5, 0.5,    1.0, 0.0, 0.0, 0.5,     0.0, 0.0,//7
+        
+        -0.5, 0.5, 0.5,     1.0, 0.0, 0.0, 0.5,     0.0, 1.0,//3
+        -0.5, 0.5, -0.5,    1.0, 0.0, 0.0, 0.5,     0.0, 1.0,//4
+        -0.5, -0.5, 0.5,    1.0, 0.0, 0.0, 0.5,     0.0, 0.0,//7
+        
+        -0.5, -0.5, 0.5,    0.0, 0.0, 1.0, 0.5,     0.0, 0.0,//7
+        0.5, -0.5, 0.5,     0.0, 0.0, 1.0, 0.5,     1.0, 0.0,//5
+        0.5, 0.5, 0.5,      0.0, 0.0, 1.0, 0.5,     1.0, 1.0,//1
+                 
+        -0.5, -0.5, 0.5,    0.0, 0.0, 1.0, 0.5,     0.0, 0.0,//7
+        0.5, 0.5, 0.5,      0.0, 0.0, 1.0, 0.5,     1.0, 1.0,//1
+        -0.5, 0.5, 0.5,     0.0, 0.0, 1.0, 0.5,     0.0, 1.0,//3
+        
+         0.5, -0.5, -0.5,   0.0, 1.0, 0.0, 0.5,     1.0, 0.0,//6
+         0.5, -0.5, 0.5,    0.0, 1.0, 0.0, 0.5,     1.0, 0.0,//5
+        -0.5, -0.5, 0.5,    0.0, 1.0, 0.0, 0.5,     0.0, 0.0,//7
+        
+        -0.5,-0.5, -0.5,    0.0, 1.0, 0.0, 0.5,     0.0, 0.0,//8
+         0.5, -0.5, -0.5,   0.0, 1.0, 0.0, 0.5,     1.0, 0.0,//6
+        -0.5, -0.5, 0.5,    0.0, 1.0, 0.0, 0.5,     0.0, 0.0,//7
+    ];
+
+    gl.vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+	var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color; \
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    var vertexShaderSource = '\
+			attribute highp vec3 myVertex; \
+            attribute highp vec4 myColor; \
+            attribute highp vec2 myUV; \
+            uniform mediump mat4 Pmatrix; \
+            uniform mediump mat4 Vmatrix; \
+            uniform mediump mat4 Mmatrix; \
+            varying mediump vec4 color; \
+            varying mediump vec2 texCoord;\
+            void main(void)  \
+            { \
+                gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(myVertex, 1.0);\
+                color = 1.0 * myColor;\
+                texCoord = myUV; \
+            }';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    gl.programObject = gl.createProgram();
+
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+    gl.bindAttribLocation(gl.programObject, 2, "myUV");
+
+    gl.linkProgram(gl.programObject);
+
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+
+    return testGLError("initialiseShaders");
+}
+
+/**
+ * identity matrix function by gl-matrix.js
+ *
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+*/
+
+function identity$3(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    out[4] = 0;
+    out[5] = 1;
+    out[6] = 0;
+    out[7] = 0;
+    out[8] = 0;
+    out[9] = 0;
+    out[10] = 1;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+}
+
+var EPSILON = 0.000001;
+
+/**
+ * rotate matrix function by gl-matrix.js
+ *
+ * Creates a matrix from a given angle around a given axis
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.rotate(dest, dest, rad, axis);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+
+function fromRotation$3(out, rad, axis) {
+    var x = axis[0],
+        y = axis[1],
+        z = axis[2];
+    var len = Math.hypot(x, y, z);
+    var s, c, t;
+
+    if (len < EPSILON) {
+      return null;
+    }
+
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c; // Perform rotation-specific matrix multiplication
+
+    out[0] = x * x * t + c;
+    out[1] = y * x * t + z * s;
+    out[2] = z * x * t - y * s;
+    out[3] = 0;
+    out[4] = x * y * t - z * s;
+    out[5] = y * y * t + c;
+    out[6] = z * y * t + x * s;
+    out[7] = 0;
+    out[8] = x * z * t + y * s;
+    out[9] = y * z * t - x * s;
+    out[10] = z * z * t + c;
+    out[11] = 0;
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
+    return out;
+}
+
+var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+
+rotValue = 0.0; 
+animRotValue = 0.0;
+
+/*
+ * button onclick callback function
+ */
+function animRotate() {
+    animRotValue = 0.03;
+}
+
+function animPause() {
+    animRotValue = 0.0;
+}
+
+function renderScene() {
+
+    gl.clearColor(0.6, 0.8, 1.0, 1.0);
+    gl.clearDepth(1.0);
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+    var locPmatrix = gl.getUniformLocation(gl.programObject, "Pmatrix");
+    var locVmatrix = gl.getUniformLocation(gl.programObject, "Vmatrix");
+    var locMmatrix = gl.getUniformLocation(gl.programObject, "Mmatrix");
+
+    rotAxis = [1,1,0];
+    identity$3(mov_matrix);
+    fromRotation$3(mov_matrix, rotValue, rotAxis);
+    rotValue += animRotValue;
+
+    gl.uniformMatrix4fv(locPmatrix, false, view_matrix);
+    gl.uniformMatrix4fv(locVmatrix, false, view_matrix);
+    gl.uniformMatrix4fv(locMmatrix, false, mov_matrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 36, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 36, 12);
+    gl.enableVertexAttribArray(2);
+    gl.vertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 36, 28);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+    //select 에서 값 불러오는 부분
+    var se = document.getElementById("sel_equ");
+    var sel_equ = se.options[se.selectedIndex].value;
+
+    var ss = document.getElementById("sel_src");
+    var sel_src = ss.options[ss.selectedIndex].value;
+
+    var sd = document.getElementById("sel_dst");
+    var sel_dst = sd.options[sd.selectedIndex].value;
+
+    //파라미터 값 저장해놓는 변수
+    var mode, sfactor, dfactor;
+
+    //gl.blendEquation 선택하는 부분 - 각 파라미터 별 설명 변경 및 파라미터 값 저장
+    switch(sel_equ) {
+        case "FUNC_ADD":
+            document.getElementById("txt_equ").innerHTML = "source + destination";
+            mode = gl.FUNC_ADD;
+            break;
+        case "FUNC_SUBTRACT":
+            document.getElementById("txt_equ").innerHTML = "source - destination";
+            mode = gl.FUNC_SUBTRACT;
+            break;
+        case "FUNC_REVERSE_SUBTRACT":
+            document.getElementById("txt_equ").innerHTML = "destination - source";
+            mode = gl.FUNC_REVERSE_SUBTRACT;
+            break;
+    }
+
+    //gl.blendFunc(sfactor, dfactor) 중에서 sfactor 선택하는 부분 - 각 파라미터 별 설명 변경 및 파라미터 값 저장
+    //CONSTANT_COLOR와 CONSTANT_ALPHA를 sfactor와 dfactor 동시에 쓰이면 gl.INVALID_ENUM error exception때문에
+    //해당 파라미터 선택 시 disabled 처리
+    switch(sel_src) {
+        case "ZERO":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by 0.";
+            sfactor = gl.ZERO;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+        case "ONE":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by 1.";
+            sfactor = gl.ONE;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+        case "SRC_COLOR":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by the source colors.";
+            sfactor = gl.SRC_COLOR;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+        case "ONE_MINUS_SRC_COLOR":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by 1 minus each source color.";
+            sfactor = gl.ONE_MINUS_SRC_COLOR;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+        case "DST_COLOR":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by the destination color.";
+            sfactor = gl.DST_COLOR;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+        case "ONE_MINUS_DST_COLOR":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by 1 minus each destination color.";
+            sfactor = gl.ONE_MINUS_DST_COLOR;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+        case "SRC_ALPHA":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by the source alpha value.";
+            sfactor = gl.SRC_ALPHA;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+        case "ONE_MINUS_SRC_ALPHA":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by 1 minus the source alpha value.";
+            sfactor = gl.ONE_MINUS_SRC_ALPHA;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+        case "DST_ALPHA":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by the destination alpha value.";
+            sfactor = gl.DST_ALPHA;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+        case "ONE_MINUS_DST_ALPHA":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by 1 minus the destination alpha value.n";
+            sfactor = gl.ONE_MINUS_DST_ALPHA;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+        case "CONSTANT_COLOR":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by a constant color."
+            +"<br><br>Warning : If a constant color and a constant alpha value are used together as source and destination factors, "
+            +"a gl.INVALID_ENUM error is thrown.";
+            sfactor = gl.CONSTANT_COLOR;
+            sd.options[12].disabled = true;
+            sd.options[10].disabled = false;
+            break;
+        case "ONE_MINUS_CONSTANT_COLOR":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by 1 minus a constant color.";
+            sfactor = gl.ONE_MINUS_CONSTANT_COLOR;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+        case "CONSTANT_ALPHA":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by a constant alpha value.e"
+            +"<br><br>Warning : If a constant color and a constant alpha value are used together as source and destination factors, "
+            +"a gl.INVALID_ENUM error is thrown.";
+            sfactor = gl.CONSTANT_ALPHA;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = true;
+            break;
+        case "ONE_MINUS_CONSTANT_ALPHA":
+            document.getElementById("txt_src").innerHTML = "Multiplies all colors by 1 minus a constant alpha value.";
+            sfactor = gl.ONE_MINUS_CONSTANT_ALPHA;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+        case "SRC_ALPHA_SATURATE":
+            document.getElementById("txt_src").innerHTML = "Multiplies the RGB colors by the smaller of either the source alpha value or the value of 1 minus the destination alpha value. The alpha value is multiplied by 1.";
+            sfactor = gl.SRC_ALPHA_SATURATE;
+            sd.options[12].disabled = false;
+            sd.options[10].disabled = false;
+            break;
+    }
+
+    //gl.blendFunc(sfactor, dfactor) 중에서 dfactor 선택하는 부분 - 각 파라미터 별 설명 변경 및 파라미터 값 저장
+    switch(sel_dst) {
+        case "ZERO":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by 0.";
+            dfactor = gl.ZERO;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = false;
+            break;
+        case "ONE":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by 1.";
+            dfactor = gl.ONE;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = false;
+            break;
+        case "SRC_COLOR":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by the source colors.";
+            dfactor = gl.SRC_COLOR;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = false;
+            break;
+        case "ONE_MINUS_SRC_COLOR":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by 1 minus each source color.";
+            dfactor = gl.ONE_MINUS_SRC_COLOR;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = false;
+            break;
+        case "DST_COLOR":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by the destination color.";
+            dfactor = gl.DST_COLOR;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = false;
+            break;
+        case "ONE_MINUS_DST_COLOR":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by 1 minus each destination color.";
+            dfactor = gl.ONE_MINUS_DST_COLOR;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = false;
+            break;
+        case "SRC_ALPHA":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by the source alpha value.";
+            dfactor = gl.SRC_ALPHA;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = false;
+            break;
+        case "ONE_MINUS_SRC_ALPHA":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by 1 minus the source alpha value.";
+            dfactor = gl.ONE_MINUS_SRC_ALPHA;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = false;
+            break;
+        case "DST_ALPHA":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by the destination alpha value.";
+            dfactor = gl.DST_ALPHA;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = false;
+            break;
+        case "ONE_MINUS_DST_ALPHA":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by 1 minus the destination alpha value.n";
+            dfactor = gl.ONE_MINUS_DST_ALPHA;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = false;
+            break;
+        case "CONSTANT_COLOR":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by a constant color."
+            +"<br><br>Warning : If a constant color and a constant alpha value are used together as source and destination factors, "
+            +"a gl.INVALID_ENUM error is thrown.";
+            dfactor = gl.CONSTANT_COLOR;
+            ss.options[12].disabled = true;
+            ss.options[10].disabled = false;
+            break;
+        case "ONE_MINUS_CONSTANT_COLOR":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by 1 minus a constant color.";
+            dfactor = gl.ONE_MINUS_CONSTANT_COLOR;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = false;
+            break;
+        case "CONSTANT_ALPHA":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by a constant alpha value.e"
+            +"<br><br>Warning : If a constant color and a constant alpha value are used together as source and destination factors, "
+            +"a gl.INVALID_ENUM error is thrown.";
+            dfactor = gl.CONSTANT_ALPHA;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = true;
+            break;
+        case "ONE_MINUS_CONSTANT_ALPHA":
+            document.getElementById("txt_dst").innerHTML = "Multiplies all colors by 1 minus a constant alpha value.";
+            dfactor = gl.ONE_MINUS_CONSTANT_ALPHA;
+            ss.options[12].disabled = false;
+            ss.options[10].disabled = false;
+            break;
+    }
+
+    //blend enable 체크박스 값 받아오는 부분
+    if(document.getElementById("chk_ble").checked) {    //체크한 경우(default)
+        gl.enable(gl.BLEND);
+        document.getElementById("code_ena").innerHTML = "gl.enable(gl.BLEND);"
+    }
+    else {  //체크를 해제한 경우
+        gl.disable(gl.BLEND);
+        document.getElementById("code_ena").innerHTML = "//gl.enable(gl.BLEND);"
+    }
+    
+    //blend함수 적용
+    gl.blendEquation(mode);
+    gl.blendFunc(sfactor, dfactor);
+
+    //코드 박스 부분 변경
+    document.getElementById("code_mode").innerHTML = sel_equ;
+    document.getElementById("code_sfactor").innerHTML = sel_src;
+    document.getElementById("code_dfactor").innerHTML = sel_dst;
+    
+    gl.drawArrays(gl.TRIANGLES, 0, 36);
+
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("webglCanvas");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
\ No newline at end of file
diff --git a/student2019/201620955/README.md b/student2019/201620955/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..62314a16c6f65453d9c1da6de8c7db8c0d310439
--- /dev/null
+++ b/student2019/201620955/README.md
@@ -0,0 +1,67 @@
+# 컴퓨터그래픽스 최종 프로젝트
+
+
+#### 201620955 소프트웨어학과 원정연
+
+<br>
+
+## Topic
+#### After-image of rotating cube(회전하는 큐브의 잔상 표현)
+
+![demo](http://git.ajou.ac.kr/WJY/webgl_project/raw/master/readme_image/demo.gif)
+
+계속적으로 움직이는 물체에 대해서, openGL(webGL)에서는 1개의 frame마다 canvas에 draw를 해준다. 
+이를 이용하여 큐브가 회전할 때 잔상이 남도록 이전 혹은 더 이전 frame들을 저장하였다. 
+
+가장 최근에 저장된 것부터 가장 오래 전 것까지 각각의 큐브를 draw해주는 동안 점점 색이 옅어지도록 해서 수십개의 큐브 그림이 마치 잔상이 남는 것처럼 보이도록 표현해주었다.
+
+<br>
+
+### 기능
+1. Translation
+2. Rotation
+3. After-image
+
+<br>
+
+#### Translation
+
+![translation](http://git.ajou.ac.kr/WJY/webgl_project/raw/master/readme_image/translation.JPG)
+
+수업시간에 배운 translation을 더 세세하기 컨트롤할 수 있도록 버튼을 추가하였다.
+translation에서는 X, Y, Z 좌표를 (+) 방향뿐만 아니라 - 방향으로도 움직일 수 있도록 하였다.
+
+또한 얼만큼 움직였는지 알 수 있도록 p tag의 content로 표시해주었다.
+
+<br>
+
+#### Rotation
+
+![rotation](http://git.ajou.ac.kr/WJY/webgl_project/raw/master/readme_image/rotation.JPG)
+
+단순히 rotation 속도를 증가하고, 멈추는 것뿐만 아니라 속도를 감소시키는 기능으로 반대로 회전도 가능하도록 하였다.
+
+또한 회전 축을 원하는 대로 설정할 수 있으며 체크박스를 클릭하는 즉시 회전하는 축이 바뀐다.
+
+<br>
+
+#### After-image
+
+![After-image](http://git.ajou.ac.kr/WJY/webgl_project/raw/master/readme_image/afterimage.JPG)
+
+frame이 지날 때마다 그때의 큐브의 위치 정보를 배열에 저장한다. 
+새로운 frame이 rendering되면 이때도 마찬가지로 큐브의 위치 정보를 저장하며, 이전까지 저장된 큐브의 위치정보 배열을 가지고 마치 잔상이 남는 것처럼 표현해주었다.
+original 큐브 및 각 잔상들이 그려질 때마다 vertex buffer에 data를 새로 넣어주었는데, 이때 color의 a값이 점점 감소하도록 하였다.
+
+이런 방식을 이용해서 잔상을 표현해주었는데, 사용자가 직접 잔상으로 남길 큐브의 개수와 잔상을 표현할 frame의 빈도를 설정해줄 수 있다. 
+또한 잔상의 색깔을 원래 큐브 색, 흰색, 회색 중 선택할 수 있도록 하였다.
+
+
+<br><br>
+
+### Reference
+#### HTML Tab
+https://www.w3schools.com/howto/howto_js_tabs.asp
+
+#### After image
+https://threejs.org/examples/webgl_postprocessing_afterimage.html
diff --git a/student2019/201620955/final_project.css b/student2019/201620955/final_project.css
new file mode 100644
index 0000000000000000000000000000000000000000..e34e41ff6d1580503f929cb8aa34862bf42d1d52
--- /dev/null
+++ b/student2019/201620955/final_project.css
@@ -0,0 +1,109 @@
+/* (CC-NC-BY) JungYeun Won 2019
+   WebGL 1.0 Tutorial - After-images of  roatating Cube */
+
+body {
+  padding: 30px;
+  background: #ebf9ff
+}
+
+.layout-td {
+    padding: 20px;
+    /* background: pink; */
+    vertical-align: top;
+}
+
+.cont_btn {
+    border: 1px solid #8795d3;
+    background-color: #dde4ff;
+    outline: none;
+    cursor: pointer;
+    padding: 10px 12px;
+    margin: 5px;
+}
+
+
+.tab {
+    overflow: hidden;
+    border: 1px solid #8795d3;
+    background-color: #d0d9ff;
+  }
+
+  .tab button {
+    background-color: inherit;
+    float: left;
+    border: none;
+    outline: none;
+    cursor: pointer;
+    padding: 14px 16px;
+    transition: 0.3s;
+    font-weight: bold;
+  }
+  
+  /* Change background color of buttons on hover */
+  .tab button:hover {
+    background-color: #9ba9e5;
+  }
+  
+  /* Create an active/current tablink class */
+  .tab button.active {
+    background-color: #8795d3;
+  }
+
+  .tabcontent {
+    display: none;
+    padding: 6px 12px;
+    animation: fadeEffect 1s; /* Fading effect takes 1 second */
+  }
+
+  /* Go from zero to full opacity */
+  @keyframes fadeEffect {
+    from {opacity: 0;}
+    to {opacity: 1;}
+  }
+
+  .slider {
+    -webkit-appearance: none;  /* Override default CSS styles */
+    appearance: none;
+    width: 100%; /* Full-width */
+    height: 10px; /* Specified height */
+    background: #d0d9ff; /* Grey background */
+    outline: none; /* Remove outline */
+    opacity: 0.7; /* Set transparency (for mouse-over effects on hover) */
+    -webkit-transition: .2s; /* 0.2 seconds transition on hover */
+    transition: opacity .2s;
+  }
+
+  .slider:hover {
+    opacity: 1; /* Fully shown on mouse-over */
+  }
+
+
+.cont_btn2 {
+  border: 1px solid #4f98c2;
+  background-color: #bfe4fc;
+  outline: none;
+  cursor: pointer;
+  padding: 10px 12px;
+  margin: 5px;
+}
+
+.cont_btn2:hover {
+  background-color: #9cd5fc;
+}
+
+#code-box {
+  visibility: hidden;
+  width: 450px;
+  height: 600px;
+  background: #daf1ff;
+  border: 1px solid #4f98c2;
+  margin: 5px;
+  padding: 10px;
+  overflow:scroll;
+}
+
+#code-content {
+  font-size: 15px;
+  word-wrap: break-word;
+  white-space: pre-wrap;
+}
\ No newline at end of file
diff --git a/student2019/201620955/final_project.html b/student2019/201620955/final_project.html
new file mode 100644
index 0000000000000000000000000000000000000000..382b468672257be5c83b5bb8a547bf14fe8abf25
--- /dev/null
+++ b/student2019/201620955/final_project.html
@@ -0,0 +1,116 @@
+<!-- (CC-NC-BY) JungYeun Won 2019 -->
+<!-- WebGL 1.0 Tutorial - After-images of  roatating Cube -->
+
+<html>
+
+<head>
+    <title>201620955 wonjungyeun</title>
+    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+	<script type="text/javascript" src="final_project.js"></script>
+	<link rel="stylesheet" href="final_project.css">
+
+
+</head>
+
+<body onload="main()">
+    <H1> WebGL - After-images of rotating Cube </H1>
+    <p style="width:800px">
+		This demo shows the after-images when the 3D cube rotates.
+		Each after-image has a location coordinate where the cube was at previous frames.
+		The older after-image, the fainter it is, and you can control the number of after-images.
+		The after-image is saved every frame. If you change the frequency of after-images, you can set to display the after-image every n frames.
+	</p>
+	<br><div>
+			<h2>About After-image</h2>
+			<p style="width:800px">
+				In OpenGL, it 'draw' every frame. So in order to display the after-images, the location coordinate of the cube at that time should be stored every frame. In this demo, the set number of after-image(saved as the cube moves) is set number * frequency and the rest is deleted for saving memory. And after drawing the cube, it 'draw' after-image more and more transparent  from the most recent saved.
+			</p>
+		</div>
+	<table>
+		<tr>
+			<tr>
+				<td class="layout-td">
+					<canvas id="helloapicanvas" style="border: none;margin-top: 50px" width="500" height="500"></canvas><br><br>
+					<table border=2> 
+						<tr > 
+						<td id="matrix0"> 	<td id="matrix4">  	<td id="matrix8">  	<td id="matrix12"> 
+						<tr> 
+						<td id="matrix1"> 	<td id="matrix5">  	<td id="matrix9">  	<td id="matrix13"> 
+						<tr> 
+						<td id="matrix2"> 	<td id="matrix6">  	<td id="matrix10">  	<td id="matrix14"> 
+						<tr> 
+						<td id="matrix3"> 	<td id="matrix7">  	<td id="matrix11">  	<td id="matrix15"> 
+						</table>
+
+				</td>
+				<td class="layout-td">
+						<h3>Controls</h3>
+						<div class="tab">
+							<button class="tablinks" id="clickedBtn" onclick="openControls(event, 'Translation')">Translation</button>
+							<button class="tablinks" onclick="openControls(event, 'Rotation')">Rotation</button>
+							<button class="tablinks" onclick="openControls(event, 'After-image')">After-image</button>
+						</div>
+
+						<div id="Translation" class="tabcontent"><br>
+							<button class="cont_btn" onclick="trXinc('+')">X + 0.1</button>
+							<button class="cont_btn" onclick="trYinc('+')">Y + 0.1</button>
+							<button class="cont_btn" onclick="trZinc('+')">Z + 0.1</button>
+							<br>
+							<button class="cont_btn" onclick="trXinc('-')">X - 0.1</button>
+							<button class="cont_btn" onclick="trYinc('-')">Y - 0.1</button>
+							<button class="cont_btn" onclick="trZinc('-')">Z - 0.1</button>
+							<br><br>
+							<p id="webTrX">Control X of the Cube</p>
+							<p id="webTrY">Control Y of the Cube</p>
+							<p id="webTrZ">Control Z of the Cube</p>
+						</div>
+						  
+						<div id="Rotation" class="tabcontent"><br>
+							<button class="cont_btn" onclick="animRotate('+')">Animation Rotate + 0.01</button><br>
+							<button class="cont_btn" onclick="animRotate('-')">Animation Rotate - 0.01</button>
+							<br>
+							<button class="cont_btn" onclick="animPause()">Animation Pause</button>
+							<br><br>
+							<input type="checkbox" name="rotAxis" value="X" checked onclick="changeRotAxis(this.value)"> X-axis 
+							<input type="checkbox" name="rotAxis" value="Y" onclick="changeRotAxis(this.value)"> Y-axis 
+							<input type="checkbox" name="rotAxis" value="Z" checked onclick="changeRotAxis(this.value)"> Z-axis 
+							<br><br>
+							<p id="animRot">Rotation speed: 0.0100</p>
+						</div>
+						
+						<div id="After-image" class="tabcontent">
+							<p id="val_traceNum">The Number of After-image: 20</p>
+							<div class="slidecontainer">
+								<input type="range" class="slider" min="1" max="50" value="20" class="slider" id="traceNum" onchange="changeTraceNum(this.value)">
+							</div>
+							<br>
+							<p id="val_traceFreq">Frequency of After-image: 1</p>
+							<div class="slidecontainer">
+								<input type="range" class="slider" min="1" max="5" value="1" class="slider" id="traceFreq" onchange="changeTraceFreq(this.value)">
+							</div>
+							<h4>Color of After-image</h4>
+							<button class="cont_btn" onclick="changeTraceColor('color')">Original</button>
+							<button class="cont_btn" onclick="changeTraceColor('white')">White</button>
+							<button class="cont_btn" onclick="changeTraceColor('gray')">Gray</button>
+						</div>
+
+
+				</td>
+				<td class="layout-td">
+					<h3>JavaScript code</h3>
+					<button class="cont_btn2" onclick="showCode('rendering')">Rendering</button>
+					<button class="cont_btn2" onclick="showCode('control')">Controls</button>
+					<button class="cont_btn2" onclick="showCode('shader')">Shader</button>
+					<div id="code-box">
+						<pre id="code-content">
+						</pre>
+					</div>
+				</td>
+			</tr>
+		</tr>
+	</table>
+
+    <p> (CC-NC-BY) 2019 JungYeun Won </p>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/student2019/201620955/final_project.js b/student2019/201620955/final_project.js
new file mode 100644
index 0000000000000000000000000000000000000000..660a0af8e1294f626df8a9a1b034ee5125e55bef
--- /dev/null
+++ b/student2019/201620955/final_project.js
@@ -0,0 +1,709 @@
+// (CC-NC-BY) JungYeun Won 2019
+// WebGL 1.0 Tutorial - After-images of  roatating Cube
+
+var gl;
+
+function testGLError(functionLastCalled) {
+
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+
+    return true;
+}
+
+function initialiseGL(canvas) {
+
+    try {
+ // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+
+    return true;
+}
+
+var shaderProgram;
+
+function vertexData(color_a, mode){
+    var vertex = [];
+    if(mode == "color"){
+        vertex = [
+            -0.5, 0.5, 0.5,		1.0, 0.0, 0.5, color_a,		0.0, 1.0,//3
+            0.5, 0.5, 0.5,		1.0, 0.0, 0.5, color_a,		1.0, 1.0,//1
+            0.5, 0.5, -0.5,		1.0, 0.0, 0.5, color_a,		1.0, 1.0,//2
+                    
+            -0.5, 0.5, 0.5,		1.0, 0.0, 0.5, color_a,		0.0, 1.0,//3
+            0.5, 0.5, -0.5,		1.0, 0.0, 0.5, color_a,		1.0, 1.0,//2
+            -0.5, 0.5, -0.5,	1.0, 0.0, 0.5, color_a,		0.0, 1.0,//4
+            
+            0.5, 0.5, -0.5,		0.0, 0.5, 0.0, color_a,		1.0, 1.0,//2
+            0.5, -0.5, -0.5,	0.0, 0.5, 0.0, color_a,		1.0, 0.0,//6
+            -0.5,-0.5,-0.5,		0.0, 0.5, 0.0, color_a,		0.0, 0.0,//8
+            
+            -0.5, 0.5, -0.5,	0.0, 0.5, 0.0, color_a,		0.0, 1.0,//4
+            0.5, 0.5, -0.5,		0.0, 0.5, 0.0, color_a,		1.0, 1.0,//2
+            -0.5,-0.5,-0.5,		0.0, 0.5, 0.0, color_a,		0.0, 0.0,//8
+                
+            0.5, -0.5, 0.5,		1.0, 0.5, 0.0, color_a,		0.0, 1.0,//5
+            0.5, -0.5, -0.5,	1.0, 0.5, 0.0, color_a,		0.0, 1.0,//6
+            0.5, 0.5, -0.5,		1.0, 0.5, 0.0, color_a,		1.0, 1.0,//2
+
+            0.5, -0.5, 0.5,		1.0, 0.5, 0.0, color_a,		0.0, 1.0,//5
+            0.5, 0.5, -0.5,		1.0, 0.5, 0.0, color_a,		1.0, 1.0,//2
+            0.5, 0.5, 0.5,		1.0, 0.5, 0.0, color_a,		1.0, 1.0,//1
+                    
+            -0.5, 0.5, -0.5,	1.0, 0.0, 0.0, color_a,		0.0, 1.0,//4
+            -0.5,-0.5, -0.5,	1.0, 0.0, 0.0, color_a,		0.0, 0.0,//8
+            -0.5, -0.5, 0.5,	1.0, 0.0, 0.0, color_a,		0.0, 0.0,//7
+            
+            -0.5, 0.5, 0.5,		1.0, 0.0, 0.0, color_a,		0.0, 1.0,//3
+            -0.5, 0.5, -0.5,	1.0, 0.0, 0.0, color_a,		0.0, 1.0,//4
+            -0.5, -0.5, 0.5,	1.0, 0.0, 0.0, color_a,		0.0, 0.0,//7
+            
+            -0.5, -0.5, 0.5,	0.0, 0.0, 1.0, color_a,		0.0, 0.0,//7
+            0.5, -0.5, 0.5,		0.0, 0.0, 1.0, color_a,		1.0, 0.0,//5
+            0.5, 0.5, 0.5,		0.0, 0.0, 1.0, color_a,		1.0, 1.0,//1
+                    
+            -0.5, -0.5, 0.5,	0.0, 0.0, 1.0, color_a,		0.0, 0.0,//7
+            0.5, 0.5, 0.5,		0.0, 0.0, 1.0, color_a,		1.0, 1.0,//1
+            -0.5, 0.5, 0.5,		0.0, 0.0, 1.0, color_a,		0.0, 1.0,//3
+            
+            0.5, -0.5, -0.5,	0.0, 1.0, 0.0, color_a,		1.0, 0.0,//6
+            0.5, -0.5, 0.5,	    0.0, 1.0, 0.0, color_a,		1.0, 0.0,//5
+            -0.5, -0.5, 0.5,	0.0, 1.0, 0.0, color_a,		0.0, 0.0,//7
+            
+            -0.5,-0.5, -0.5,	0.0, 1.0, 0.0, color_a,		0.0, 0.0,//8
+            0.5, -0.5, -0.5,	0.0, 1.0, 0.0, color_a,		1.0, 0.0,//6
+            -0.5, -0.5, 0.5,	0.0, 1.0, 0.0, color_a,		0.0, 0.0,//7
+        ];
+    } else{
+        var color;
+        if(mode == "white")
+            color = 1.0;
+        else if(mode == "gray")
+            color = 0.0;
+        vertex = [
+            -0.5, 0.5, 0.5,		color, color, color, color_a,		0.0, 1.0,//3
+            0.5, 0.5, 0.5,		color, color, color, color_a,		1.0, 1.0,//1
+            0.5, 0.5, -0.5,		color, color, color, color_a,		1.0, 1.0,//2
+                    
+            -0.5, 0.5, 0.5,		color, color, color, color_a,		0.0, 1.0,//3
+            0.5, 0.5, -0.5,		color, color, color, color_a,		1.0, 1.0,//2
+            -0.5, 0.5, -0.5,	color, color, color, color_a,		0.0, 1.0,//4
+            
+            0.5, 0.5, -0.5,		color, color, color, color_a,		1.0, 1.0,//2
+            0.5, -0.5, -0.5,	color, color, color, color_a,		1.0, 0.0,//6
+            -0.5,-0.5,-0.5,		color, color, color, color_a,		0.0, 0.0,//8
+            
+            -0.5, 0.5, -0.5,	color, color, color, color_a,		0.0, 1.0,//4
+            0.5, 0.5, -0.5,		color, color, color, color_a,		1.0, 1.0,//2
+            -0.5,-0.5,-0.5,		color, color, color, color_a,		0.0, 0.0,//8
+                
+            0.5, -0.5, 0.5,		color, color, color, color_a,		0.0, 1.0,//5
+            0.5, -0.5, -0.5,	color, color, color, color_a,		0.0, 1.0,//6
+            0.5, 0.5, -0.5,		color, color, color, color_a,		1.0, 1.0,//2
+
+            0.5, -0.5, 0.5,		color, color, color, color_a,		0.0, 1.0,//5
+            0.5, 0.5, -0.5,		color, color, color, color_a,		1.0, 1.0,//2
+            0.5, 0.5, 0.5,		color, color, color, color_a,		1.0, 1.0,//1
+                    
+            -0.5, 0.5, -0.5,	color, color, color, color_a,		0.0, 1.0,//4
+            -0.5,-0.5, -0.5,	color, color, color, color_a,		0.0, 0.0,//8
+            -0.5, -0.5, 0.5,	color, color, color, color_a,		0.0, 0.0,//7
+            
+            -0.5, 0.5, 0.5,		color, color, color, color_a,		0.0, 1.0,//3
+            -0.5, 0.5, -0.5,	color, color, color, color_a,		0.0, 1.0,//4
+            -0.5, -0.5, 0.5,	color, color, color, color_a,		0.0, 0.0,//7
+            
+            -0.5, -0.5, 0.5,	color, color, color, color_a,		0.0, 0.0,//7
+            0.5, -0.5, 0.5,		color, color, color, color_a,		1.0, 0.0,//5
+            0.5, 0.5, 0.5,		color, color, color, color_a,		1.0, 1.0,//1
+                    
+            -0.5, -0.5, 0.5,	color, color, color, color_a,		0.0, 0.0,//7
+            0.5, 0.5, 0.5,		color, color, color, color_a,		1.0, 1.0,//1
+            -0.5, 0.5, 0.5,		color, color, color, color_a,		0.0, 1.0,//3
+            
+            0.5, -0.5, -0.5,	color, color, color, color_a,		1.0, 0.0,//6
+            0.5, -0.5, 0.5,	    color, color, color, color_a,		1.0, 0.0,//5
+            -0.5, -0.5, 0.5,	color, color, color, color_a,		0.0, 0.0,//7
+            
+            -0.5,-0.5, -0.5,	color, color, color, color_a,		0.0, 0.0,//8
+            0.5, -0.5, -0.5,	color, color, color, color_a,		1.0, 0.0,//6
+            -0.5, -0.5, 0.5,	color, color, color, color_a,		0.0, 0.0,//7
+        ];
+    }
+    
+    return vertex;
+}
+
+
+function initialiseBuffer() {
+    // Generate a buffer object
+    gl.vertexBuffer = gl.createBuffer();
+    // Bind buffer as a vertex buffer so we can fill it with data
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData(1.0, "color")), gl.STATIC_DRAW);
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying mediump vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = 1.0 * color;\
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    var vertexShaderSource = '\
+			attribute highp vec3 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 Pmatrix; \
+			uniform mediump mat4 Vmatrix; \
+			uniform mediump mat4 Mmatrix; \
+			varying mediump vec4 color; \
+			void main(void)  \
+			{ \
+                gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(myVertex, 1.0); \
+				color = myColor;\
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    gl.programObject = gl.createProgram();
+
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+
+    // Bind the custom vertex attribute
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+
+    // Link the program
+    gl.linkProgram(gl.programObject);
+
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+
+    return testGLError("initialiseShaders");
+}
+
+// FOV, Aspect Ratio, Near, Far 
+function get_projection(angle, a, zMin, zMax) {
+    var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
+    return [
+    	0.5/ang, 0 , 0, 0,
+        0, 0.5*a/ang, 0, 0,
+        0, 0, -(zMax+zMin)/(zMax-zMin), -1,
+        0, 0, (-2*zMax*zMin)/(zMax-zMin), 0 ];
+}
+			
+var proj_matrix = get_projection(30, 1.0, 0, 5.0);
+var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+
+view_matrix[14] = view_matrix[14]-2;//zoom
+
+rotValue = 0.0;
+animRotValue = 0.01;
+transX = 0.0; transY = 0.0; transZ = 0.0;
+frames = 1;
+var rotAxis = [1,0,1];
+var isTranslate = false;
+
+function animRotate(sign)   //  increase or decrease rotation speed
+{
+    if (sign=='+')
+        animRotValue += 0.01;
+    else
+        animRotValue -= 0.01;
+
+    document.getElementById("animRot").innerHTML = "Rotation speed: "+ animRotValue.toFixed(4);
+}
+
+function animPause(){   // pause the rotating cube
+    animRotValue = 0.0;
+    document.getElementById("animRot").innerHTML = "Rotation speed: "+ animRotValue.toFixed(4);
+}
+
+function changeRotAxis(axis){   // change rotating direction
+    switch(axis){
+        case 'X':
+            if (rotAxis[0]==1)
+                rotAxis[0]=0;
+            else
+                rotAxis[0]=1;
+            break;
+        case 'Y':
+            if (rotAxis[1]==1)
+                rotAxis[1]=0;
+            else
+                rotAxis[1]=1;
+            break;
+        case 'Z':
+            if (rotAxis[2]==1)
+                rotAxis[2]=0;
+            else
+                rotAxis[2]=1;
+            break;
+    }
+    // trace = [];
+}
+
+function trXinc(sign) // translate X increase or decrease
+{
+    isTranslate = true;
+    if(sign=='+')
+        transX += 0.01;
+    else
+        transX -= 0.01;
+
+    if(transX == -0.0)
+        transX = 0.0;
+    
+    if (transX == 0.0)
+        document.getElementById("webTrX").innerHTML = "Control X of the Cube";
+    else
+	    document.getElementById("webTrX").innerHTML = "Translation X : " + transX.toFixed(4);
+}
+
+function trYinc(sign) // translate Y increase or decrease
+{
+    isTranslate = true;
+	if(sign=='+')
+        transY += 0.01;
+    else
+        transY -= 0.01;
+
+    if(transY == -0.0)
+        transY = 0.0;
+
+    if (transY == 0.0)
+        document.getElementById("webTrY").innerHTML = "Control Y of the Cube";
+    else
+	    document.getElementById("webTrY").innerHTML = "Translation Y : " + transY.toFixed(4);
+}
+
+function trZinc(sign) // translate Z increase or decrease
+{
+    isTranslate = true;
+	if(sign=='+')
+        transZ += 0.01;
+    else
+        transZ -= 0.01;
+
+    if(transZ == -0.0)
+        transZ = 0.0;
+
+    if (transZ == 0.0)
+        document.getElementById("webTrZ").innerHTML = "Control Z of the Cube";
+    else
+	    document.getElementById("webTrZ").innerHTML = "Translation Z : " + transZ.toFixed(4);
+}
+
+// About Trace(After-image)
+var trace = [];
+var traceNum = 20;
+var traceFreq = 1;
+var traceTotalNum = traceNum * traceFreq;
+var trace_alpha = 0.3/traceNum;
+var traceColor = "color";
+var slider_traceNum = document.getElementById("traceNum");
+
+function addTrace(mat){
+    if(animRotValue != 0.0 && animRotValue != -0.0){
+        if(trace.length>=traceTotalNum){
+            trace = trace.slice(1,traceTotalNum);
+        }
+        trace.push(mat);
+    } else if(isTranslate == true){
+        if(trace.length>=traceTotalNum){
+            trace = trace.slice(1,traceTotalNum);
+        }
+        trace.push(mat);
+        isTranslate = false;
+    }
+}
+
+function changeTraceNum(num){
+    traceNum = num;
+    traceTotalNum = num * traceFreq;
+    document.getElementById("val_traceNum").innerHTML = "The Number of After-image: "+ num;
+}
+
+function changeTraceFreq(freq){
+    traceFreq = freq;
+    traceTotalNum = traceNum * freq;
+    document.getElementById("val_traceFreq").innerHTML = "The Frequency of After-image: "+ freq;
+}
+
+function changeTraceColor(type){
+    traceColor = type;
+}
+
+function renderScene() {
+
+    frames += 1 ;
+
+    var locPmatrix = gl.getUniformLocation(gl.programObject, "Pmatrix");
+    var locVmatrix = gl.getUniformLocation(gl.programObject, "Vmatrix");
+    var locMmatrix = gl.getUniformLocation(gl.programObject, "Mmatrix");
+
+    gl.uniformMatrix4fv(locPmatrix, false, proj_matrix);
+    gl.uniformMatrix4fv(locVmatrix, false, view_matrix);
+    // gl.uniformMatrix4fv(locMmatrix, false, mov_matrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+    // gl.enable(gl.DEPTH_TEST);
+    // gl.depthFunc(gl.LEQUAL); 
+	gl.enable(gl.CULL_FACE);
+	gl.enable(gl.BLEND);
+    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+    gl.blendEquation(gl.FUNC_ADD);
+    gl.clearColor(0.6, 0.8, 1.0, 1.0);  // set background color
+    gl.clearDepth(1.0); 
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);    
+
+    gl.enableVertexAttribArray(0); // coordinates
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 36, 0);
+    gl.enableVertexAttribArray(1); // color
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 36, 12);
+	gl.enableVertexAttribArray(2); // texture
+    gl.vertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 36, 28);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+    glMatrix.mat4.identity(mov_matrix);
+    glMatrix.mat4.rotate(mov_matrix,mov_matrix,rotValue, rotAxis);
+    glMatrix.mat4.translate(mov_matrix, mov_matrix, [transX,transY,transZ]);
+    rotValue += animRotValue; 
+    gl.uniformMatrix4fv(locMmatrix, false, mov_matrix);
+
+    var mov_matrix_child = mov_matrix.slice();
+    addTrace(mov_matrix_child);
+
+    // draw original cube
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData(1.0, "color")), gl.STATIC_DRAW);
+    gl.uniformMatrix4fv(locMmatrix, false, trace[trace.length -1].slice());
+    gl.drawArrays(gl.TRIANGLES, 0, 36);
+
+    // draw trace of cube
+    color_a = 0.3;
+    for (var i = trace.length -1; i>=0;i-=traceFreq){
+        color_a -= trace_alpha;
+        gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData(color_a, traceColor)), gl.STATIC_DRAW);
+        gl.uniformMatrix4fv(locMmatrix, false, trace[i].slice());
+        if (color_a > 0.0)
+            gl.drawArrays(gl.TRIANGLES, 0, 36);
+    }
+    
+    document.getElementById("matrix0").innerHTML = mov_matrix[0].toFixed(4);
+	document.getElementById("matrix1").innerHTML = mov_matrix[1].toFixed(4);
+	document.getElementById("matrix2").innerHTML = mov_matrix[2].toFixed(4);
+	document.getElementById("matrix3").innerHTML = mov_matrix[3].toFixed(4);
+	document.getElementById("matrix4").innerHTML = mov_matrix[4].toFixed(4);
+	document.getElementById("matrix5").innerHTML = mov_matrix[5].toFixed(4);
+	document.getElementById("matrix6").innerHTML = mov_matrix[6].toFixed(4);
+	document.getElementById("matrix7").innerHTML = mov_matrix[7].toFixed(4);
+	document.getElementById("matrix8").innerHTML = mov_matrix[8].toFixed(4);
+	document.getElementById("matrix9").innerHTML = mov_matrix[9].toFixed(4);
+	document.getElementById("matrix10").innerHTML = mov_matrix[10].toFixed(4);
+	document.getElementById("matrix11").innerHTML = mov_matrix[11].toFixed(4);
+	document.getElementById("matrix12").innerHTML = mov_matrix[12].toFixed(4);
+	document.getElementById("matrix13").innerHTML = mov_matrix[13].toFixed(4);
+	document.getElementById("matrix14").innerHTML = mov_matrix[14].toFixed(4);
+	document.getElementById("matrix15").innerHTML = mov_matrix[15].toFixed(4);
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+    document.getElementById("clickedBtn").click();
+    console.log("Start");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+    // Render loop
+    requestAnimFrame = (
+	function () {
+        //	return window.requestAnimationFrame || window.webkitRequestAnimationFrame 
+	//	|| window.mozRequestAnimationFrame || 
+	   	return function (callback) {
+			    // console.log("Callback is"+callback); 
+			    window.setTimeout(callback, 10, 10); };
+    })();
+
+    (function renderLoop(param) {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
+
+// Show Javascript code on HTML
+function showCode(type){
+    document.getElementById("code-box").style.visibility = "visible";
+    var codeContent = document.getElementById("code-content");
+
+    if(type=='rendering'){
+        codeContent.innerHTML = 
+`// This is code of 'renderScene' function.
+// This code run every frame and draw the original cube and after-image of it.
+
+// gl.enable(gl.DEPTH_TEST);
+// gl.depthFunc(gl.LEQUAL); 
+gl.enable(gl.CULL_FACE);
+gl.enable(gl.BLEND);
+gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+gl.blendEquation(gl.FUNC_ADD);
+gl.clearColor(0.6, 0.8, 1.0, 1.0);  // set background color
+gl.clearDepth(1.0); 
+gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);    
+
+gl.enableVertexAttribArray(0); // coordinates
+gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 36, 0);
+gl.enableVertexAttribArray(1); // color
+gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 36, 12);
+
+if (!testGLError("gl.vertexAttribPointer")) {
+    return false;
+}
+
+glMatrix.mat4.identity(mov_matrix);
+glMatrix.mat4.rotate(mov_matrix,mov_matrix,rotValue, rotAxis);
+glMatrix.mat4.translate(mov_matrix, mov_matrix, [transX,transY,transZ]);
+rotValue += animRotValue; 
+gl.uniformMatrix4fv(locMmatrix, false, mov_matrix);
+
+var mov_matrix_child = mov_matrix.slice();
+addTrace(mov_matrix_child);
+
+// draw original cube
+gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData(1.0, "color")), gl.STATIC_DRAW);
+gl.uniformMatrix4fv(locMmatrix, false, trace[trace.length -1].slice());
+gl.drawArrays(gl.TRIANGLES, 0, 36);
+
+// draw trace of cube
+color_a = 0.3;
+for (var i = trace.length -1; i>=0;i-=traceFreq){
+    color_a -= trace_alpha;
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData(color_a, traceColor)), gl.STATIC_DRAW);
+    gl.uniformMatrix4fv(locMmatrix, false, trace[i].slice());
+    if (color_a > 0.0)
+        gl.drawArrays(gl.TRIANGLES, 0, 36);
+}`;
+    }
+    else if(type=="control"){
+        codeContent.innerHTML = 
+`// This is code of functions that control basic parameters
+
+// translate X increase or decrease
+function trXinc(sign) 
+{
+    if(sign=='+')
+        transX += 0.01;
+    else
+        transX -= 0.01;
+}
+
+// translate Y increase or decrease
+function trYinc(sign) 
+{
+	if(sign=='+')
+        transY += 0.01;
+    else
+        transY -= 0.01;
+}
+
+// translate Z increase or decrease
+function trZinc(sign) 
+{
+	if(sign=='+')
+        transZ += 0.01;
+    else
+        transZ -= 0.01;
+}
+
+//  increase or decrease rotation speed
+function animRotate(sign)
+{
+    if (sign=='+')
+        animRotValue += 0.01;
+    else
+        animRotValue -= 0.01;
+}
+
+// pause the rotating cube
+function animPause(){
+    animRotValue = 0.0;
+}
+
+// change rotating direction
+// 'rotAxis' is an array that its length is 3.
+// ex) rotAxis = [0,0,1]
+function changeRotAxis(axis){
+    switch(axis){
+        case 'X':
+            if (rotAxis[0]==1)
+                rotAxis[0]=0;
+            else
+                rotAxis[0]=1;
+            break;
+        case 'Y':
+            if (rotAxis[1]==1)
+                rotAxis[1]=0;
+            else
+                rotAxis[1]=1;
+            break;
+        case 'Z':
+            if (rotAxis[2]==1)
+                rotAxis[2]=0;
+            else
+                rotAxis[2]=1;
+            break;
+    }
+    // clear trace array when change rotating direction
+    trace = []; 
+}`;
+    }
+    else {
+        codeContent.innerHTML =
+`// This is code of 'initialiseShaders' fuction.
+
+var fragmentShaderSource = '
+    varying mediump vec4 color; 
+    void main(void) 
+    { 
+        gl_FragColor = 1.0 * color;
+    }';
+
+gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+gl.shaderSource(gl.fragShader, fragmentShaderSource);
+gl.compileShader(gl.fragShader);
+if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+    alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+    return false;
+}
+
+var vertexShaderSource = '
+    attribute highp vec3 myVertex; 
+    attribute highp vec4 myColor; 
+    uniform mediump mat4 Pmatrix; 
+    uniform mediump mat4 Vmatrix; 
+    uniform mediump mat4 Mmatrix; 
+    varying mediump vec4 color; 
+    void main(void)  
+    { 
+        gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(myVertex, 1.0); 
+        color = myColor;
+    }';
+
+gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+gl.shaderSource(gl.vertexShader, vertexShaderSource);
+gl.compileShader(gl.vertexShader);
+if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+    alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+    return false;
+}
+
+gl.programObject = gl.createProgram();
+
+// Attach the fragment and vertex shaders to it
+gl.attachShader(gl.programObject, gl.fragShader);
+gl.attachShader(gl.programObject, gl.vertexShader);
+
+// Bind the custom vertex attribute
+gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+gl.bindAttribLocation(gl.programObject, 1, "myColor");
+
+// Link the program
+gl.linkProgram(gl.programObject);
+
+if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+    alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+    return false;
+}
+
+gl.useProgram(gl.programObject);`
+    }
+    
+
+}
+
+// Show Control Tabs
+function openControls(evt, contName) {
+    // Declare all variables
+    var i, tabcontent, tablinks;
+  
+    // Get all elements with class="tabcontent" and hide them
+    tabcontent = document.getElementsByClassName("tabcontent");
+    for (i = 0; i < tabcontent.length; i++) {
+      tabcontent[i].style.display = "none";
+    }
+  
+    // Get all elements with class="tablinks" and remove the class "active"
+    tablinks = document.getElementsByClassName("tablinks");
+    for (i = 0; i < tablinks.length; i++) {
+      tablinks[i].className = tablinks[i].className.replace(" active", "");
+    }
+  
+    // Show the current tab, and add an "active" class to the button that opened the tab
+    document.getElementById(contName).style.display = "block";
+    evt.currentTarget.className += " active";
+  }
+
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t=t||self).glMatrix={})}(this,function(t){"use strict";var n=1e-6,a="undefined"!=typeof Float32Array?Float32Array:Array,r=Math.random;var u=Math.PI/180;Math.hypot||(Math.hypot=function(){for(var t=0,n=arguments.length;n--;)t+=arguments[n]*arguments[n];return Math.sqrt(t)});var e=Object.freeze({EPSILON:n,get ARRAY_TYPE(){return a},RANDOM:r,setMatrixArrayType:function(t){a=t},toRadian:function(t){return t*u},equals:function(t,a){return Math.abs(t-a)<=n*Math.max(1,Math.abs(t),Math.abs(a))}});function o(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*i+e*c,t[1]=u*i+o*c,t[2]=r*h+e*s,t[3]=u*h+o*s,t}function i(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}var c=o,h=i,s=Object.freeze({create:function(){var t=new a(4);return a!=Float32Array&&(t[1]=0,t[2]=0),t[0]=1,t[3]=1,t},clone:function(t){var n=new a(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t},fromValues:function(t,n,r,u){var e=new a(4);return e[0]=t,e[1]=n,e[2]=r,e[3]=u,e},set:function(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t},transpose:function(t,n){if(t===n){var a=n[1];t[1]=n[2],t[2]=a}else t[0]=n[0],t[1]=n[2],t[2]=n[1],t[3]=n[3];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*e-u*r;return o?(o=1/o,t[0]=e*o,t[1]=-r*o,t[2]=-u*o,t[3]=a*o,t):null},adjoint:function(t,n){var a=n[0];return t[0]=n[3],t[1]=-n[1],t[2]=-n[2],t[3]=a,t},determinant:function(t){return t[0]*t[3]-t[2]*t[1]},multiply:o,rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+e*i,t[1]=u*c+o*i,t[2]=r*-i+e*c,t[3]=u*-i+o*c,t},scale:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1];return t[0]=r*i,t[1]=u*i,t[2]=e*c,t[3]=o*c,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t},str:function(t){return"mat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3])},LDU:function(t,n,a,r){return t[2]=r[2]/r[0],a[0]=r[0],a[1]=r[1],a[3]=r[3]-t[2]*a[1],[t,n,a]},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t},subtract:i,exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=a[0],c=a[1],h=a[2],s=a[3];return Math.abs(r-i)<=n*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-c)<=n*Math.max(1,Math.abs(u),Math.abs(c))&&Math.abs(e-h)<=n*Math.max(1,Math.abs(e),Math.abs(h))&&Math.abs(o-s)<=n*Math.max(1,Math.abs(o),Math.abs(s))},multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t},mul:c,sub:h});function M(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return t[0]=r*h+e*s,t[1]=u*h+o*s,t[2]=r*M+e*f,t[3]=u*M+o*f,t[4]=r*l+e*v+i,t[5]=u*l+o*v+c,t}function f(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t}var l=M,v=f,b=Object.freeze({create:function(){var t=new a(6);return a!=Float32Array&&(t[1]=0,t[2]=0,t[4]=0,t[5]=0),t[0]=1,t[3]=1,t},clone:function(t){var n=new a(6);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t},fromValues:function(t,n,r,u,e,o){var i=new a(6);return i[0]=t,i[1]=n,i[2]=r,i[3]=u,i[4]=e,i[5]=o,i},set:function(t,n,a,r,u,e,o){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=a*e-r*u;return c?(c=1/c,t[0]=e*c,t[1]=-r*c,t[2]=-u*c,t[3]=a*c,t[4]=(u*i-e*o)*c,t[5]=(r*o-a*i)*c,t):null},determinant:function(t){return t[0]*t[3]-t[1]*t[2]},multiply:M,rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=Math.sin(a),s=Math.cos(a);return t[0]=r*s+e*h,t[1]=u*s+o*h,t[2]=r*-h+e*s,t[3]=u*-h+o*s,t[4]=i,t[5]=c,t},scale:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1];return t[0]=r*h,t[1]=u*h,t[2]=e*s,t[3]=o*s,t[4]=i,t[5]=c,t},translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=r*h+e*s+i,t[5]=u*h+o*s+c,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t[4]=0,t[5]=0,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t[4]=0,t[5]=0,t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=n[0],t[5]=n[1],t},str:function(t){return"mat2d("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],1)},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t},subtract:f,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return Math.abs(r-h)<=n*Math.max(1,Math.abs(r),Math.abs(h))&&Math.abs(u-s)<=n*Math.max(1,Math.abs(u),Math.abs(s))&&Math.abs(e-M)<=n*Math.max(1,Math.abs(e),Math.abs(M))&&Math.abs(o-f)<=n*Math.max(1,Math.abs(o),Math.abs(f))&&Math.abs(i-l)<=n*Math.max(1,Math.abs(i),Math.abs(l))&&Math.abs(c-v)<=n*Math.max(1,Math.abs(c),Math.abs(v))},mul:l,sub:v});function m(){var t=new a(9);return a!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function d(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],p=a[7],y=a[8];return t[0]=f*r+l*o+v*h,t[1]=f*u+l*i+v*s,t[2]=f*e+l*c+v*M,t[3]=b*r+m*o+d*h,t[4]=b*u+m*i+d*s,t[5]=b*e+m*c+d*M,t[6]=x*r+p*o+y*h,t[7]=x*u+p*i+y*s,t[8]=x*e+p*c+y*M,t}function x(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t}var p=d,y=x,q=Object.freeze({create:m,fromMat4:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[4],t[4]=n[5],t[5]=n[6],t[6]=n[8],t[7]=n[9],t[8]=n[10],t},clone:function(t){var n=new a(9);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromValues:function(t,n,r,u,e,o,i,c,h){var s=new a(9);return s[0]=t,s[1]=n,s[2]=r,s[3]=u,s[4]=e,s[5]=o,s[6]=i,s[7]=c,s[8]=h,s},set:function(t,n,a,r,u,e,o,i,c,h){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t[8]=h,t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},transpose:function(t,n){if(t===n){var a=n[1],r=n[2],u=n[5];t[1]=n[3],t[2]=n[6],t[3]=a,t[5]=n[7],t[6]=r,t[7]=u}else t[0]=n[0],t[1]=n[3],t[2]=n[6],t[3]=n[1],t[4]=n[4],t[5]=n[7],t[6]=n[2],t[7]=n[5],t[8]=n[8];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=s*o-i*h,f=-s*e+i*c,l=h*e-o*c,v=a*M+r*f+u*l;return v?(v=1/v,t[0]=M*v,t[1]=(-s*r+u*h)*v,t[2]=(i*r-u*o)*v,t[3]=f*v,t[4]=(s*a-u*c)*v,t[5]=(-i*a+u*e)*v,t[6]=l*v,t[7]=(-h*a+r*c)*v,t[8]=(o*a-r*e)*v,t):null},adjoint:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8];return t[0]=o*s-i*h,t[1]=u*h-r*s,t[2]=r*i-u*o,t[3]=i*c-e*s,t[4]=a*s-u*c,t[5]=u*e-a*i,t[6]=e*h-o*c,t[7]=r*c-a*h,t[8]=a*o-r*e,t},determinant:function(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],c=t[7],h=t[8];return n*(h*e-o*c)+a*(-h*u+o*i)+r*(c*u-e*i)},multiply:d,translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=a[0],l=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=c,t[6]=f*r+l*o+h,t[7]=f*u+l*i+s,t[8]=f*e+l*c+M,t},rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=Math.sin(a),l=Math.cos(a);return t[0]=l*r+f*o,t[1]=l*u+f*i,t[2]=l*e+f*c,t[3]=l*o-f*r,t[4]=l*i-f*u,t[5]=l*c-f*e,t[6]=h,t[7]=s,t[8]=M,t},scale:function(t,n,a){var r=a[0],u=a[1];return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=u*n[3],t[4]=u*n[4],t[5]=u*n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=n[0],t[7]=n[1],t[8]=1,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=-a,t[4]=r,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=n[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromMat2d:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=0,t[3]=n[2],t[4]=n[3],t[5]=0,t[6]=n[4],t[7]=n[5],t[8]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,c=u+u,h=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*c,b=e*o,m=e*i,d=e*c;return t[0]=1-M-v,t[3]=s-d,t[6]=f+m,t[1]=s+d,t[4]=1-h-v,t[7]=l-b,t[2]=f-m,t[5]=l+b,t[8]=1-h-M,t},normalFromMat4:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*c-u*o,y=a*h-e*o,q=r*c-u*i,g=r*h-e*i,A=u*h-e*c,w=s*b-M*v,R=s*m-f*v,z=s*d-l*v,P=M*m-f*b,j=M*d-l*b,I=f*d-l*m,S=x*I-p*j+y*P+q*z-g*R+A*w;return S?(S=1/S,t[0]=(i*I-c*j+h*P)*S,t[1]=(c*z-o*I-h*R)*S,t[2]=(o*j-i*z+h*w)*S,t[3]=(u*j-r*I-e*P)*S,t[4]=(a*I-u*z+e*R)*S,t[5]=(r*z-a*j-e*w)*S,t[6]=(b*A-m*g+d*q)*S,t[7]=(m*y-v*A-d*p)*S,t[8]=(v*g-b*y+d*x)*S,t):null},projection:function(t,n,a){return t[0]=2/n,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/a,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t},str:function(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t},subtract:x,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=t[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],p=a[7],y=a[8];return Math.abs(r-f)<=n*Math.max(1,Math.abs(r),Math.abs(f))&&Math.abs(u-l)<=n*Math.max(1,Math.abs(u),Math.abs(l))&&Math.abs(e-v)<=n*Math.max(1,Math.abs(e),Math.abs(v))&&Math.abs(o-b)<=n*Math.max(1,Math.abs(o),Math.abs(b))&&Math.abs(i-m)<=n*Math.max(1,Math.abs(i),Math.abs(m))&&Math.abs(c-d)<=n*Math.max(1,Math.abs(c),Math.abs(d))&&Math.abs(h-x)<=n*Math.max(1,Math.abs(h),Math.abs(x))&&Math.abs(s-p)<=n*Math.max(1,Math.abs(s),Math.abs(p))&&Math.abs(M-y)<=n*Math.max(1,Math.abs(M),Math.abs(y))},mul:p,sub:y});function g(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function A(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],b=n[12],m=n[13],d=n[14],x=n[15],p=a[0],y=a[1],q=a[2],g=a[3];return t[0]=p*r+y*i+q*M+g*b,t[1]=p*u+y*c+q*f+g*m,t[2]=p*e+y*h+q*l+g*d,t[3]=p*o+y*s+q*v+g*x,p=a[4],y=a[5],q=a[6],g=a[7],t[4]=p*r+y*i+q*M+g*b,t[5]=p*u+y*c+q*f+g*m,t[6]=p*e+y*h+q*l+g*d,t[7]=p*o+y*s+q*v+g*x,p=a[8],y=a[9],q=a[10],g=a[11],t[8]=p*r+y*i+q*M+g*b,t[9]=p*u+y*c+q*f+g*m,t[10]=p*e+y*h+q*l+g*d,t[11]=p*o+y*s+q*v+g*x,p=a[12],y=a[13],q=a[14],g=a[15],t[12]=p*r+y*i+q*M+g*b,t[13]=p*u+y*c+q*f+g*m,t[14]=p*e+y*h+q*l+g*d,t[15]=p*o+y*s+q*v+g*x,t}function w(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=r+r,c=u+u,h=e+e,s=r*i,M=r*c,f=r*h,l=u*c,v=u*h,b=e*h,m=o*i,d=o*c,x=o*h;return t[0]=1-(l+b),t[1]=M+x,t[2]=f-d,t[3]=0,t[4]=M-x,t[5]=1-(s+b),t[6]=v+m,t[7]=0,t[8]=f+d,t[9]=v-m,t[10]=1-(s+l),t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t}function R(t,n){return t[0]=n[12],t[1]=n[13],t[2]=n[14],t}function z(t,n){var a=n[0],r=n[1],u=n[2],e=n[4],o=n[5],i=n[6],c=n[8],h=n[9],s=n[10];return t[0]=Math.hypot(a,r,u),t[1]=Math.hypot(e,o,i),t[2]=Math.hypot(c,h,s),t}function P(t,n){var r=new a(3);z(r,n);var u=1/r[0],e=1/r[1],o=1/r[2],i=n[0]*u,c=n[1]*e,h=n[2]*o,s=n[4]*u,M=n[5]*e,f=n[6]*o,l=n[8]*u,v=n[9]*e,b=n[10]*o,m=i+M+b,d=0;return m>0?(d=2*Math.sqrt(m+1),t[3]=.25*d,t[0]=(f-v)/d,t[1]=(l-h)/d,t[2]=(c-s)/d):i>M&&i>b?(d=2*Math.sqrt(1+i-M-b),t[3]=(f-v)/d,t[0]=.25*d,t[1]=(c+s)/d,t[2]=(l+h)/d):M>b?(d=2*Math.sqrt(1+M-i-b),t[3]=(l-h)/d,t[0]=(c+s)/d,t[1]=.25*d,t[2]=(f+v)/d):(d=2*Math.sqrt(1+b-i-M),t[3]=(c-s)/d,t[0]=(l+h)/d,t[1]=(f+v)/d,t[2]=.25*d),t}function j(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t[9]=n[9]-a[9],t[10]=n[10]-a[10],t[11]=n[11]-a[11],t[12]=n[12]-a[12],t[13]=n[13]-a[13],t[14]=n[14]-a[14],t[15]=n[15]-a[15],t}var I=A,S=j,E=Object.freeze({create:function(){var t=new a(16);return a!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0),t[0]=1,t[5]=1,t[10]=1,t[15]=1,t},clone:function(t){var n=new a(16);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n[9]=t[9],n[10]=t[10],n[11]=t[11],n[12]=t[12],n[13]=t[13],n[14]=t[14],n[15]=t[15],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},fromValues:function(t,n,r,u,e,o,i,c,h,s,M,f,l,v,b,m){var d=new a(16);return d[0]=t,d[1]=n,d[2]=r,d[3]=u,d[4]=e,d[5]=o,d[6]=i,d[7]=c,d[8]=h,d[9]=s,d[10]=M,d[11]=f,d[12]=l,d[13]=v,d[14]=b,d[15]=m,d},set:function(t,n,a,r,u,e,o,i,c,h,s,M,f,l,v,b,m){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t[8]=h,t[9]=s,t[10]=M,t[11]=f,t[12]=l,t[13]=v,t[14]=b,t[15]=m,t},identity:g,transpose:function(t,n){if(t===n){var a=n[1],r=n[2],u=n[3],e=n[6],o=n[7],i=n[11];t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=a,t[6]=n[9],t[7]=n[13],t[8]=r,t[9]=e,t[11]=n[14],t[12]=u,t[13]=o,t[14]=i}else t[0]=n[0],t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=n[1],t[5]=n[5],t[6]=n[9],t[7]=n[13],t[8]=n[2],t[9]=n[6],t[10]=n[10],t[11]=n[14],t[12]=n[3],t[13]=n[7],t[14]=n[11],t[15]=n[15];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*c-u*o,y=a*h-e*o,q=r*c-u*i,g=r*h-e*i,A=u*h-e*c,w=s*b-M*v,R=s*m-f*v,z=s*d-l*v,P=M*m-f*b,j=M*d-l*b,I=f*d-l*m,S=x*I-p*j+y*P+q*z-g*R+A*w;return S?(S=1/S,t[0]=(i*I-c*j+h*P)*S,t[1]=(u*j-r*I-e*P)*S,t[2]=(b*A-m*g+d*q)*S,t[3]=(f*g-M*A-l*q)*S,t[4]=(c*z-o*I-h*R)*S,t[5]=(a*I-u*z+e*R)*S,t[6]=(m*y-v*A-d*p)*S,t[7]=(s*A-f*y+l*p)*S,t[8]=(o*j-i*z+h*w)*S,t[9]=(r*z-a*j-e*w)*S,t[10]=(v*g-b*y+d*x)*S,t[11]=(M*y-s*g-l*x)*S,t[12]=(i*R-o*P-c*w)*S,t[13]=(a*P-r*R+u*w)*S,t[14]=(b*p-v*q-m*x)*S,t[15]=(s*q-M*p+f*x)*S,t):null},adjoint:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15];return t[0]=i*(f*d-l*m)-M*(c*d-h*m)+b*(c*l-h*f),t[1]=-(r*(f*d-l*m)-M*(u*d-e*m)+b*(u*l-e*f)),t[2]=r*(c*d-h*m)-i*(u*d-e*m)+b*(u*h-e*c),t[3]=-(r*(c*l-h*f)-i*(u*l-e*f)+M*(u*h-e*c)),t[4]=-(o*(f*d-l*m)-s*(c*d-h*m)+v*(c*l-h*f)),t[5]=a*(f*d-l*m)-s*(u*d-e*m)+v*(u*l-e*f),t[6]=-(a*(c*d-h*m)-o*(u*d-e*m)+v*(u*h-e*c)),t[7]=a*(c*l-h*f)-o*(u*l-e*f)+s*(u*h-e*c),t[8]=o*(M*d-l*b)-s*(i*d-h*b)+v*(i*l-h*M),t[9]=-(a*(M*d-l*b)-s*(r*d-e*b)+v*(r*l-e*M)),t[10]=a*(i*d-h*b)-o*(r*d-e*b)+v*(r*h-e*i),t[11]=-(a*(i*l-h*M)-o*(r*l-e*M)+s*(r*h-e*i)),t[12]=-(o*(M*m-f*b)-s*(i*m-c*b)+v*(i*f-c*M)),t[13]=a*(M*m-f*b)-s*(r*m-u*b)+v*(r*f-u*M),t[14]=-(a*(i*m-c*b)-o*(r*m-u*b)+v*(r*c-u*i)),t[15]=a*(i*f-c*M)-o*(r*f-u*M)+s*(r*c-u*i),t},determinant:function(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],c=t[7],h=t[8],s=t[9],M=t[10],f=t[11],l=t[12],v=t[13],b=t[14],m=t[15];return(n*o-a*e)*(M*m-f*b)-(n*i-r*e)*(s*m-f*v)+(n*c-u*e)*(s*b-M*v)+(a*i-r*o)*(h*m-f*l)-(a*c-u*o)*(h*b-M*l)+(r*c-u*i)*(h*v-s*l)},multiply:A,translate:function(t,n,a){var r,u,e,o,i,c,h,s,M,f,l,v,b=a[0],m=a[1],d=a[2];return n===t?(t[12]=n[0]*b+n[4]*m+n[8]*d+n[12],t[13]=n[1]*b+n[5]*m+n[9]*d+n[13],t[14]=n[2]*b+n[6]*m+n[10]*d+n[14],t[15]=n[3]*b+n[7]*m+n[11]*d+n[15]):(r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=c,t[6]=h,t[7]=s,t[8]=M,t[9]=f,t[10]=l,t[11]=v,t[12]=r*b+i*m+M*d+n[12],t[13]=u*b+c*m+f*d+n[13],t[14]=e*b+h*m+l*d+n[14],t[15]=o*b+s*m+v*d+n[15]),t},scale:function(t,n,a){var r=a[0],u=a[1],e=a[2];return t[0]=n[0]*r,t[1]=n[1]*r,t[2]=n[2]*r,t[3]=n[3]*r,t[4]=n[4]*u,t[5]=n[5]*u,t[6]=n[6]*u,t[7]=n[7]*u,t[8]=n[8]*e,t[9]=n[9]*e,t[10]=n[10]*e,t[11]=n[11]*e,t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},rotate:function(t,a,r,u){var e,o,i,c,h,s,M,f,l,v,b,m,d,x,p,y,q,g,A,w,R,z,P,j,I=u[0],S=u[1],E=u[2],O=Math.hypot(I,S,E);return O<n?null:(I*=O=1/O,S*=O,E*=O,e=Math.sin(r),i=1-(o=Math.cos(r)),c=a[0],h=a[1],s=a[2],M=a[3],f=a[4],l=a[5],v=a[6],b=a[7],m=a[8],d=a[9],x=a[10],p=a[11],y=I*I*i+o,q=S*I*i+E*e,g=E*I*i-S*e,A=I*S*i-E*e,w=S*S*i+o,R=E*S*i+I*e,z=I*E*i+S*e,P=S*E*i-I*e,j=E*E*i+o,t[0]=c*y+f*q+m*g,t[1]=h*y+l*q+d*g,t[2]=s*y+v*q+x*g,t[3]=M*y+b*q+p*g,t[4]=c*A+f*w+m*R,t[5]=h*A+l*w+d*R,t[6]=s*A+v*w+x*R,t[7]=M*A+b*w+p*R,t[8]=c*z+f*P+m*j,t[9]=h*z+l*P+d*j,t[10]=s*z+v*P+x*j,t[11]=M*z+b*P+p*j,a!==t&&(t[12]=a[12],t[13]=a[13],t[14]=a[14],t[15]=a[15]),t)},rotateX:function(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[4],o=n[5],i=n[6],c=n[7],h=n[8],s=n[9],M=n[10],f=n[11];return n!==t&&(t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[4]=e*u+h*r,t[5]=o*u+s*r,t[6]=i*u+M*r,t[7]=c*u+f*r,t[8]=h*u-e*r,t[9]=s*u-o*r,t[10]=M*u-i*r,t[11]=f*u-c*r,t},rotateY:function(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[0],o=n[1],i=n[2],c=n[3],h=n[8],s=n[9],M=n[10],f=n[11];return n!==t&&(t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[0]=e*u-h*r,t[1]=o*u-s*r,t[2]=i*u-M*r,t[3]=c*u-f*r,t[8]=e*r+h*u,t[9]=o*r+s*u,t[10]=i*r+M*u,t[11]=c*r+f*u,t},rotateZ:function(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[0],o=n[1],i=n[2],c=n[3],h=n[4],s=n[5],M=n[6],f=n[7];return n!==t&&(t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[0]=e*u+h*r,t[1]=o*u+s*r,t[2]=i*u+M*r,t[3]=c*u+f*r,t[4]=h*u-e*r,t[5]=s*u-o*r,t[6]=M*u-i*r,t[7]=f*u-c*r,t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=n[0],t[13]=n[1],t[14]=n[2],t[15]=1,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=n[1],t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=n[2],t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromRotation:function(t,a,r){var u,e,o,i=r[0],c=r[1],h=r[2],s=Math.hypot(i,c,h);return s<n?null:(i*=s=1/s,c*=s,h*=s,u=Math.sin(a),o=1-(e=Math.cos(a)),t[0]=i*i*o+e,t[1]=c*i*o+h*u,t[2]=h*i*o-c*u,t[3]=0,t[4]=i*c*o-h*u,t[5]=c*c*o+e,t[6]=h*c*o+i*u,t[7]=0,t[8]=i*h*o+c*u,t[9]=c*h*o-i*u,t[10]=h*h*o+e,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t)},fromXRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=r,t[6]=a,t[7]=0,t[8]=0,t[9]=-a,t[10]=r,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromYRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=0,t[2]=-a,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=a,t[9]=0,t[10]=r,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromZRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=0,t[4]=-a,t[5]=r,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromRotationTranslation:w,fromQuat2:function(t,n){var r=new a(3),u=-n[0],e=-n[1],o=-n[2],i=n[3],c=n[4],h=n[5],s=n[6],M=n[7],f=u*u+e*e+o*o+i*i;return f>0?(r[0]=2*(c*i+M*u+h*o-s*e)/f,r[1]=2*(h*i+M*e+s*u-c*o)/f,r[2]=2*(s*i+M*o+c*e-h*u)/f):(r[0]=2*(c*i+M*u+h*o-s*e),r[1]=2*(h*i+M*e+s*u-c*o),r[2]=2*(s*i+M*o+c*e-h*u)),w(t,n,r),t},getTranslation:R,getScaling:z,getRotation:P,fromRotationTranslationScale:function(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3],c=u+u,h=e+e,s=o+o,M=u*c,f=u*h,l=u*s,v=e*h,b=e*s,m=o*s,d=i*c,x=i*h,p=i*s,y=r[0],q=r[1],g=r[2];return t[0]=(1-(v+m))*y,t[1]=(f+p)*y,t[2]=(l-x)*y,t[3]=0,t[4]=(f-p)*q,t[5]=(1-(M+m))*q,t[6]=(b+d)*q,t[7]=0,t[8]=(l+x)*g,t[9]=(b-d)*g,t[10]=(1-(M+v))*g,t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t},fromRotationTranslationScaleOrigin:function(t,n,a,r,u){var e=n[0],o=n[1],i=n[2],c=n[3],h=e+e,s=o+o,M=i+i,f=e*h,l=e*s,v=e*M,b=o*s,m=o*M,d=i*M,x=c*h,p=c*s,y=c*M,q=r[0],g=r[1],A=r[2],w=u[0],R=u[1],z=u[2],P=(1-(b+d))*q,j=(l+y)*q,I=(v-p)*q,S=(l-y)*g,E=(1-(f+d))*g,O=(m+x)*g,T=(v+p)*A,D=(m-x)*A,F=(1-(f+b))*A;return t[0]=P,t[1]=j,t[2]=I,t[3]=0,t[4]=S,t[5]=E,t[6]=O,t[7]=0,t[8]=T,t[9]=D,t[10]=F,t[11]=0,t[12]=a[0]+w-(P*w+S*R+T*z),t[13]=a[1]+R-(j*w+E*R+D*z),t[14]=a[2]+z-(I*w+O*R+F*z),t[15]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,c=u+u,h=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*c,b=e*o,m=e*i,d=e*c;return t[0]=1-M-v,t[1]=s+d,t[2]=f-m,t[3]=0,t[4]=s-d,t[5]=1-h-v,t[6]=l+b,t[7]=0,t[8]=f+m,t[9]=l-b,t[10]=1-h-M,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},frustum:function(t,n,a,r,u,e,o){var i=1/(a-n),c=1/(u-r),h=1/(e-o);return t[0]=2*e*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*e*c,t[6]=0,t[7]=0,t[8]=(a+n)*i,t[9]=(u+r)*c,t[10]=(o+e)*h,t[11]=-1,t[12]=0,t[13]=0,t[14]=o*e*2*h,t[15]=0,t},perspective:function(t,n,a,r,u){var e,o=1/Math.tan(n/2);return t[0]=o/a,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=o,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=-1,t[12]=0,t[13]=0,t[15]=0,null!=u&&u!==1/0?(e=1/(r-u),t[10]=(u+r)*e,t[14]=2*u*r*e):(t[10]=-1,t[14]=-2*r),t},perspectiveFromFieldOfView:function(t,n,a,r){var u=Math.tan(n.upDegrees*Math.PI/180),e=Math.tan(n.downDegrees*Math.PI/180),o=Math.tan(n.leftDegrees*Math.PI/180),i=Math.tan(n.rightDegrees*Math.PI/180),c=2/(o+i),h=2/(u+e);return t[0]=c,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=h,t[6]=0,t[7]=0,t[8]=-(o-i)*c*.5,t[9]=(u-e)*h*.5,t[10]=r/(a-r),t[11]=-1,t[12]=0,t[13]=0,t[14]=r*a/(a-r),t[15]=0,t},ortho:function(t,n,a,r,u,e,o){var i=1/(n-a),c=1/(r-u),h=1/(e-o);return t[0]=-2*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*c,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*h,t[11]=0,t[12]=(n+a)*i,t[13]=(u+r)*c,t[14]=(o+e)*h,t[15]=1,t},lookAt:function(t,a,r,u){var e,o,i,c,h,s,M,f,l,v,b=a[0],m=a[1],d=a[2],x=u[0],p=u[1],y=u[2],q=r[0],A=r[1],w=r[2];return Math.abs(b-q)<n&&Math.abs(m-A)<n&&Math.abs(d-w)<n?g(t):(M=b-q,f=m-A,l=d-w,e=p*(l*=v=1/Math.hypot(M,f,l))-y*(f*=v),o=y*(M*=v)-x*l,i=x*f-p*M,(v=Math.hypot(e,o,i))?(e*=v=1/v,o*=v,i*=v):(e=0,o=0,i=0),c=f*i-l*o,h=l*e-M*i,s=M*o-f*e,(v=Math.hypot(c,h,s))?(c*=v=1/v,h*=v,s*=v):(c=0,h=0,s=0),t[0]=e,t[1]=c,t[2]=M,t[3]=0,t[4]=o,t[5]=h,t[6]=f,t[7]=0,t[8]=i,t[9]=s,t[10]=l,t[11]=0,t[12]=-(e*b+o*m+i*d),t[13]=-(c*b+h*m+s*d),t[14]=-(M*b+f*m+l*d),t[15]=1,t)},targetTo:function(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=r[0],c=r[1],h=r[2],s=u-a[0],M=e-a[1],f=o-a[2],l=s*s+M*M+f*f;l>0&&(s*=l=1/Math.sqrt(l),M*=l,f*=l);var v=c*f-h*M,b=h*s-i*f,m=i*M-c*s;return(l=v*v+b*b+m*m)>0&&(v*=l=1/Math.sqrt(l),b*=l,m*=l),t[0]=v,t[1]=b,t[2]=m,t[3]=0,t[4]=M*m-f*b,t[5]=f*v-s*m,t[6]=s*b-M*v,t[7]=0,t[8]=s,t[9]=M,t[10]=f,t[11]=0,t[12]=u,t[13]=e,t[14]=o,t[15]=1,t},str:function(t){return"mat4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+", "+t[9]+", "+t[10]+", "+t[11]+", "+t[12]+", "+t[13]+", "+t[14]+", "+t[15]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t[9]=n[9]+a[9],t[10]=n[10]+a[10],t[11]=n[11]+a[11],t[12]=n[12]+a[12],t[13]=n[13]+a[13],t[14]=n[14]+a[14],t[15]=n[15]+a[15],t},subtract:j,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=n[11]*a,t[12]=n[12]*a,t[13]=n[13]*a,t[14]=n[14]*a,t[15]=n[15]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t[9]=n[9]+a[9]*r,t[10]=n[10]+a[10]*r,t[11]=n[11]+a[11]*r,t[12]=n[12]+a[12]*r,t[13]=n[13]+a[13]*r,t[14]=n[14]+a[14]*r,t[15]=n[15]+a[15]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]&&t[9]===n[9]&&t[10]===n[10]&&t[11]===n[11]&&t[12]===n[12]&&t[13]===n[13]&&t[14]===n[14]&&t[15]===n[15]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=t[8],f=t[9],l=t[10],v=t[11],b=t[12],m=t[13],d=t[14],x=t[15],p=a[0],y=a[1],q=a[2],g=a[3],A=a[4],w=a[5],R=a[6],z=a[7],P=a[8],j=a[9],I=a[10],S=a[11],E=a[12],O=a[13],T=a[14],D=a[15];return Math.abs(r-p)<=n*Math.max(1,Math.abs(r),Math.abs(p))&&Math.abs(u-y)<=n*Math.max(1,Math.abs(u),Math.abs(y))&&Math.abs(e-q)<=n*Math.max(1,Math.abs(e),Math.abs(q))&&Math.abs(o-g)<=n*Math.max(1,Math.abs(o),Math.abs(g))&&Math.abs(i-A)<=n*Math.max(1,Math.abs(i),Math.abs(A))&&Math.abs(c-w)<=n*Math.max(1,Math.abs(c),Math.abs(w))&&Math.abs(h-R)<=n*Math.max(1,Math.abs(h),Math.abs(R))&&Math.abs(s-z)<=n*Math.max(1,Math.abs(s),Math.abs(z))&&Math.abs(M-P)<=n*Math.max(1,Math.abs(M),Math.abs(P))&&Math.abs(f-j)<=n*Math.max(1,Math.abs(f),Math.abs(j))&&Math.abs(l-I)<=n*Math.max(1,Math.abs(l),Math.abs(I))&&Math.abs(v-S)<=n*Math.max(1,Math.abs(v),Math.abs(S))&&Math.abs(b-E)<=n*Math.max(1,Math.abs(b),Math.abs(E))&&Math.abs(m-O)<=n*Math.max(1,Math.abs(m),Math.abs(O))&&Math.abs(d-T)<=n*Math.max(1,Math.abs(d),Math.abs(T))&&Math.abs(x-D)<=n*Math.max(1,Math.abs(x),Math.abs(D))},mul:I,sub:S});function O(){var t=new a(3);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function T(t){var n=t[0],a=t[1],r=t[2];return Math.hypot(n,a,r)}function D(t,n,r){var u=new a(3);return u[0]=t,u[1]=n,u[2]=r,u}function F(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t}function L(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t}function V(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t}function Q(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return Math.hypot(a,r,u)}function Y(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return a*a+r*r+u*u}function X(t){var n=t[0],a=t[1],r=t[2];return n*n+a*a+r*r}function Z(t,n){var a=n[0],r=n[1],u=n[2],e=a*a+r*r+u*u;return e>0&&(e=1/Math.sqrt(e)),t[0]=n[0]*e,t[1]=n[1]*e,t[2]=n[2]*e,t}function _(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function B(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],c=a[2];return t[0]=u*c-e*i,t[1]=e*o-r*c,t[2]=r*i-u*o,t}var N,k=F,U=L,W=V,C=Q,G=Y,H=T,J=X,K=(N=O(),function(t,n,a,r,u,e){var o,i;for(n||(n=3),a||(a=0),i=r?Math.min(r*n+a,t.length):t.length,o=a;o<i;o+=n)N[0]=t[o],N[1]=t[o+1],N[2]=t[o+2],u(N,N,e),t[o]=N[0],t[o+1]=N[1],t[o+2]=N[2];return t}),$=Object.freeze({create:O,clone:function(t){var n=new a(3);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n},length:T,fromValues:D,copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t},set:function(t,n,a,r){return t[0]=n,t[1]=a,t[2]=r,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t},subtract:F,multiply:L,divide:V,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t[2]=Math.ceil(n[2]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t[2]=Math.floor(n[2]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t[2]=Math.min(n[2],a[2]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t[2]=Math.max(n[2],a[2]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t[2]=Math.round(n[2]),t},scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t},scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t},distance:Q,squaredDistance:Y,squaredLength:X,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t[2]=1/n[2],t},normalize:Z,dot:_,cross:B,lerp:function(t,n,a,r){var u=n[0],e=n[1],o=n[2];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t[2]=o+r*(a[2]-o),t},hermite:function(t,n,a,r,u,e){var o=e*e,i=o*(2*e-3)+1,c=o*(e-2)+e,h=o*(e-1),s=o*(3-2*e);return t[0]=n[0]*i+a[0]*c+r[0]*h+u[0]*s,t[1]=n[1]*i+a[1]*c+r[1]*h+u[1]*s,t[2]=n[2]*i+a[2]*c+r[2]*h+u[2]*s,t},bezier:function(t,n,a,r,u,e){var o=1-e,i=o*o,c=e*e,h=i*o,s=3*e*i,M=3*c*o,f=c*e;return t[0]=n[0]*h+a[0]*s+r[0]*M+u[0]*f,t[1]=n[1]*h+a[1]*s+r[1]*M+u[1]*f,t[2]=n[2]*h+a[2]*s+r[2]*M+u[2]*f,t},random:function(t,n){n=n||1;var a=2*r()*Math.PI,u=2*r()-1,e=Math.sqrt(1-u*u)*n;return t[0]=Math.cos(a)*e,t[1]=Math.sin(a)*e,t[2]=u*n,t},transformMat4:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[3]*r+a[7]*u+a[11]*e+a[15];return o=o||1,t[0]=(a[0]*r+a[4]*u+a[8]*e+a[12])/o,t[1]=(a[1]*r+a[5]*u+a[9]*e+a[13])/o,t[2]=(a[2]*r+a[6]*u+a[10]*e+a[14])/o,t},transformMat3:function(t,n,a){var r=n[0],u=n[1],e=n[2];return t[0]=r*a[0]+u*a[3]+e*a[6],t[1]=r*a[1]+u*a[4]+e*a[7],t[2]=r*a[2]+u*a[5]+e*a[8],t},transformQuat:function(t,n,a){var r=a[0],u=a[1],e=a[2],o=a[3],i=n[0],c=n[1],h=n[2],s=u*h-e*c,M=e*i-r*h,f=r*c-u*i,l=u*f-e*M,v=e*s-r*f,b=r*M-u*s,m=2*o;return s*=m,M*=m,f*=m,l*=2,v*=2,b*=2,t[0]=i+s+l,t[1]=c+M+v,t[2]=h+f+b,t},rotateX:function(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[0],e[1]=u[1]*Math.cos(r)-u[2]*Math.sin(r),e[2]=u[1]*Math.sin(r)+u[2]*Math.cos(r),t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t},rotateY:function(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[2]*Math.sin(r)+u[0]*Math.cos(r),e[1]=u[1],e[2]=u[2]*Math.cos(r)-u[0]*Math.sin(r),t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t},rotateZ:function(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[0]*Math.cos(r)-u[1]*Math.sin(r),e[1]=u[0]*Math.sin(r)+u[1]*Math.cos(r),e[2]=u[2],t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t},angle:function(t,n){var a=D(t[0],t[1],t[2]),r=D(n[0],n[1],n[2]);Z(a,a),Z(r,r);var u=_(a,r);return u>1?0:u<-1?Math.PI:Math.acos(u)},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t},str:function(t){return"vec3("+t[0]+", "+t[1]+", "+t[2]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=a[0],i=a[1],c=a[2];return Math.abs(r-o)<=n*Math.max(1,Math.abs(r),Math.abs(o))&&Math.abs(u-i)<=n*Math.max(1,Math.abs(u),Math.abs(i))&&Math.abs(e-c)<=n*Math.max(1,Math.abs(e),Math.abs(c))},sub:k,mul:U,div:W,dist:C,sqrDist:G,len:H,sqrLen:J,forEach:K});function tt(){var t=new a(4);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[3]=0),t}function nt(t){var n=new a(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n}function at(t,n,r,u){var e=new a(4);return e[0]=t,e[1]=n,e[2]=r,e[3]=u,e}function rt(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t}function ut(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t}function et(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t}function ot(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}function it(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t[3]=n[3]*a[3],t}function ct(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t[3]=n[3]/a[3],t}function ht(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t}function st(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2],e=n[3]-t[3];return Math.hypot(a,r,u,e)}function Mt(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2],e=n[3]-t[3];return a*a+r*r+u*u+e*e}function ft(t){var n=t[0],a=t[1],r=t[2],u=t[3];return Math.hypot(n,a,r,u)}function lt(t){var n=t[0],a=t[1],r=t[2],u=t[3];return n*n+a*a+r*r+u*u}function vt(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e;return o>0&&(o=1/Math.sqrt(o)),t[0]=a*o,t[1]=r*o,t[2]=u*o,t[3]=e*o,t}function bt(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]+t[3]*n[3]}function mt(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t[2]=o+r*(a[2]-o),t[3]=i+r*(a[3]-i),t}function dt(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]}function xt(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=a[0],c=a[1],h=a[2],s=a[3];return Math.abs(r-i)<=n*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-c)<=n*Math.max(1,Math.abs(u),Math.abs(c))&&Math.abs(e-h)<=n*Math.max(1,Math.abs(e),Math.abs(h))&&Math.abs(o-s)<=n*Math.max(1,Math.abs(o),Math.abs(s))}var pt=ot,yt=it,qt=ct,gt=st,At=Mt,wt=ft,Rt=lt,zt=function(){var t=tt();return function(n,a,r,u,e,o){var i,c;for(a||(a=4),r||(r=0),c=u?Math.min(u*a+r,n.length):n.length,i=r;i<c;i+=a)t[0]=n[i],t[1]=n[i+1],t[2]=n[i+2],t[3]=n[i+3],e(t,t,o),n[i]=t[0],n[i+1]=t[1],n[i+2]=t[2],n[i+3]=t[3];return n}}(),Pt=Object.freeze({create:tt,clone:nt,fromValues:at,copy:rt,set:ut,add:et,subtract:ot,multiply:it,divide:ct,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t[2]=Math.ceil(n[2]),t[3]=Math.ceil(n[3]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t[2]=Math.floor(n[2]),t[3]=Math.floor(n[3]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t[2]=Math.min(n[2],a[2]),t[3]=Math.min(n[3],a[3]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t[2]=Math.max(n[2],a[2]),t[3]=Math.max(n[3],a[3]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t[2]=Math.round(n[2]),t[3]=Math.round(n[3]),t},scale:ht,scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t},distance:st,squaredDistance:Mt,length:ft,squaredLength:lt,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=-n[3],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t[2]=1/n[2],t[3]=1/n[3],t},normalize:vt,dot:bt,cross:function(t,n,a,r){var u=a[0]*r[1]-a[1]*r[0],e=a[0]*r[2]-a[2]*r[0],o=a[0]*r[3]-a[3]*r[0],i=a[1]*r[2]-a[2]*r[1],c=a[1]*r[3]-a[3]*r[1],h=a[2]*r[3]-a[3]*r[2],s=n[0],M=n[1],f=n[2],l=n[3];return t[0]=M*h-f*c+l*i,t[1]=-s*h+f*o-l*e,t[2]=s*c-M*o+l*u,t[3]=-s*i+M*e-f*u,t},lerp:mt,random:function(t,n){var a,u,e,o,i,c;n=n||1;do{i=(a=2*r()-1)*a+(u=2*r()-1)*u}while(i>=1);do{c=(e=2*r()-1)*e+(o=2*r()-1)*o}while(c>=1);var h=Math.sqrt((1-i)/c);return t[0]=n*a,t[1]=n*u,t[2]=n*e*h,t[3]=n*o*h,t},transformMat4:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3];return t[0]=a[0]*r+a[4]*u+a[8]*e+a[12]*o,t[1]=a[1]*r+a[5]*u+a[9]*e+a[13]*o,t[2]=a[2]*r+a[6]*u+a[10]*e+a[14]*o,t[3]=a[3]*r+a[7]*u+a[11]*e+a[15]*o,t},transformQuat:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],c=a[2],h=a[3],s=h*r+i*e-c*u,M=h*u+c*r-o*e,f=h*e+o*u-i*r,l=-o*r-i*u-c*e;return t[0]=s*h+l*-o+M*-c-f*-i,t[1]=M*h+l*-i+f*-o-s*-c,t[2]=f*h+l*-c+s*-i-M*-o,t[3]=n[3],t},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=0,t},str:function(t){return"vec4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},exactEquals:dt,equals:xt,sub:pt,mul:yt,div:qt,dist:gt,sqrDist:At,len:wt,sqrLen:Rt,forEach:zt});function jt(){var t=new a(4);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t[3]=1,t}function It(t,n,a){a*=.5;var r=Math.sin(a);return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=Math.cos(a),t}function St(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*s+o*i+u*h-e*c,t[1]=u*s+o*c+e*i-r*h,t[2]=e*s+o*h+r*c-u*i,t[3]=o*s-r*i-u*c-e*h,t}function Et(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+o*i,t[1]=u*c+e*i,t[2]=e*c-u*i,t[3]=o*c-r*i,t}function Ot(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c-e*i,t[1]=u*c+o*i,t[2]=e*c+r*i,t[3]=o*c-u*i,t}function Tt(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+u*i,t[1]=u*c-r*i,t[2]=e*c+o*i,t[3]=o*c-e*i,t}function Dt(t,a,r,u){var e,o,i,c,h,s=a[0],M=a[1],f=a[2],l=a[3],v=r[0],b=r[1],m=r[2],d=r[3];return(o=s*v+M*b+f*m+l*d)<0&&(o=-o,v=-v,b=-b,m=-m,d=-d),1-o>n?(e=Math.acos(o),i=Math.sin(e),c=Math.sin((1-u)*e)/i,h=Math.sin(u*e)/i):(c=1-u,h=u),t[0]=c*s+h*v,t[1]=c*M+h*b,t[2]=c*f+h*m,t[3]=c*l+h*d,t}function Ft(t,n){var a,r=n[0]+n[4]+n[8];if(r>0)a=Math.sqrt(r+1),t[3]=.5*a,a=.5/a,t[0]=(n[5]-n[7])*a,t[1]=(n[6]-n[2])*a,t[2]=(n[1]-n[3])*a;else{var u=0;n[4]>n[0]&&(u=1),n[8]>n[3*u+u]&&(u=2);var e=(u+1)%3,o=(u+2)%3;a=Math.sqrt(n[3*u+u]-n[3*e+e]-n[3*o+o]+1),t[u]=.5*a,a=.5/a,t[3]=(n[3*e+o]-n[3*o+e])*a,t[e]=(n[3*e+u]+n[3*u+e])*a,t[o]=(n[3*o+u]+n[3*u+o])*a}return t}var Lt,Vt,Qt,Yt,Xt,Zt,_t=nt,Bt=at,Nt=rt,kt=ut,Ut=et,Wt=St,Ct=ht,Gt=bt,Ht=mt,Jt=ft,Kt=Jt,$t=lt,tn=$t,nn=vt,an=dt,rn=xt,un=(Lt=O(),Vt=D(1,0,0),Qt=D(0,1,0),function(t,n,a){var r=_(n,a);return r<-.999999?(B(Lt,Vt,n),H(Lt)<1e-6&&B(Lt,Qt,n),Z(Lt,Lt),It(t,Lt,Math.PI),t):r>.999999?(t[0]=0,t[1]=0,t[2]=0,t[3]=1,t):(B(Lt,n,a),t[0]=Lt[0],t[1]=Lt[1],t[2]=Lt[2],t[3]=1+r,nn(t,t))}),en=(Yt=jt(),Xt=jt(),function(t,n,a,r,u,e){return Dt(Yt,n,u,e),Dt(Xt,a,r,e),Dt(t,Yt,Xt,2*e*(1-e)),t}),on=(Zt=m(),function(t,n,a,r){return Zt[0]=a[0],Zt[3]=a[1],Zt[6]=a[2],Zt[1]=r[0],Zt[4]=r[1],Zt[7]=r[2],Zt[2]=-n[0],Zt[5]=-n[1],Zt[8]=-n[2],nn(t,Ft(t,Zt))}),cn=Object.freeze({create:jt,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t},setAxisAngle:It,getAxisAngle:function(t,a){var r=2*Math.acos(a[3]),u=Math.sin(r/2);return u>n?(t[0]=a[0]/u,t[1]=a[1]/u,t[2]=a[2]/u):(t[0]=1,t[1]=0,t[2]=0),r},multiply:St,rotateX:Et,rotateY:Ot,rotateZ:Tt,calculateW:function(t,n){var a=n[0],r=n[1],u=n[2];return t[0]=a,t[1]=r,t[2]=u,t[3]=Math.sqrt(Math.abs(1-a*a-r*r-u*u)),t},slerp:Dt,random:function(t){var n=r(),a=r(),u=r(),e=Math.sqrt(1-n),o=Math.sqrt(n);return t[0]=e*Math.sin(2*Math.PI*a),t[1]=e*Math.cos(2*Math.PI*a),t[2]=o*Math.sin(2*Math.PI*u),t[3]=o*Math.cos(2*Math.PI*u),t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e,i=o?1/o:0;return t[0]=-a*i,t[1]=-r*i,t[2]=-u*i,t[3]=e*i,t},conjugate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t},fromMat3:Ft,fromEuler:function(t,n,a,r){var u=.5*Math.PI/180;n*=u,a*=u,r*=u;var e=Math.sin(n),o=Math.cos(n),i=Math.sin(a),c=Math.cos(a),h=Math.sin(r),s=Math.cos(r);return t[0]=e*c*s-o*i*h,t[1]=o*i*s+e*c*h,t[2]=o*c*h-e*i*s,t[3]=o*c*s+e*i*h,t},str:function(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},clone:_t,fromValues:Bt,copy:Nt,set:kt,add:Ut,mul:Wt,scale:Ct,dot:Gt,lerp:Ht,length:Jt,len:Kt,squaredLength:$t,sqrLen:tn,normalize:nn,exactEquals:an,equals:rn,rotationTo:un,sqlerp:en,setAxes:on});function hn(t,n,a){var r=.5*a[0],u=.5*a[1],e=.5*a[2],o=n[0],i=n[1],c=n[2],h=n[3];return t[0]=o,t[1]=i,t[2]=c,t[3]=h,t[4]=r*h+u*c-e*i,t[5]=u*h+e*o-r*c,t[6]=e*h+r*i-u*o,t[7]=-r*o-u*i-e*c,t}function sn(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t}var Mn=Nt;var fn=Nt;function ln(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[4],c=a[5],h=a[6],s=a[7],M=n[4],f=n[5],l=n[6],v=n[7],b=a[0],m=a[1],d=a[2],x=a[3];return t[0]=r*x+o*b+u*d-e*m,t[1]=u*x+o*m+e*b-r*d,t[2]=e*x+o*d+r*m-u*b,t[3]=o*x-r*b-u*m-e*d,t[4]=r*s+o*i+u*h-e*c+M*x+v*b+f*d-l*m,t[5]=u*s+o*c+e*i-r*h+f*x+v*m+l*b-M*d,t[6]=e*s+o*h+r*c-u*i+l*x+v*d+M*m-f*b,t[7]=o*s-r*i-u*c-e*h+v*x-M*b-f*m-l*d,t}var vn=ln;var bn=Gt;var mn=Jt,dn=mn,xn=$t,pn=xn;var yn=Object.freeze({create:function(){var t=new a(8);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[4]=0,t[5]=0,t[6]=0,t[7]=0),t[3]=1,t},clone:function(t){var n=new a(8);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n},fromValues:function(t,n,r,u,e,o,i,c){var h=new a(8);return h[0]=t,h[1]=n,h[2]=r,h[3]=u,h[4]=e,h[5]=o,h[6]=i,h[7]=c,h},fromRotationTranslationValues:function(t,n,r,u,e,o,i){var c=new a(8);c[0]=t,c[1]=n,c[2]=r,c[3]=u;var h=.5*e,s=.5*o,M=.5*i;return c[4]=h*u+s*r-M*n,c[5]=s*u+M*t-h*r,c[6]=M*u+h*n-s*t,c[7]=-h*t-s*n-M*r,c},fromRotationTranslation:hn,fromTranslation:function(t,n){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=.5*n[0],t[5]=.5*n[1],t[6]=.5*n[2],t[7]=0,t},fromRotation:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},fromMat4:function(t,n){var r=jt();P(r,n);var u=new a(3);return R(u,n),hn(t,r,u),t},copy:sn,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},set:function(t,n,a,r,u,e,o,i,c){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t},getReal:Mn,getDual:function(t,n){return t[0]=n[4],t[1]=n[5],t[2]=n[6],t[3]=n[7],t},setReal:fn,setDual:function(t,n){return t[4]=n[0],t[5]=n[1],t[6]=n[2],t[7]=n[3],t},getTranslation:function(t,n){var a=n[4],r=n[5],u=n[6],e=n[7],o=-n[0],i=-n[1],c=-n[2],h=n[3];return t[0]=2*(a*h+e*o+r*c-u*i),t[1]=2*(r*h+e*i+u*o-a*c),t[2]=2*(u*h+e*c+a*i-r*o),t},translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=.5*a[0],c=.5*a[1],h=.5*a[2],s=n[4],M=n[5],f=n[6],l=n[7];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=o*i+u*h-e*c+s,t[5]=o*c+e*i-r*h+M,t[6]=o*h+r*c-u*i+f,t[7]=-r*i-u*c-e*h+l,t},rotateX:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Et(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateY:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Ot(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateZ:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Tt(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateByQuatAppend:function(t,n,a){var r=a[0],u=a[1],e=a[2],o=a[3],i=n[0],c=n[1],h=n[2],s=n[3];return t[0]=i*o+s*r+c*e-h*u,t[1]=c*o+s*u+h*r-i*e,t[2]=h*o+s*e+i*u-c*r,t[3]=s*o-i*r-c*u-h*e,i=n[4],c=n[5],h=n[6],s=n[7],t[4]=i*o+s*r+c*e-h*u,t[5]=c*o+s*u+h*r-i*e,t[6]=h*o+s*e+i*u-c*r,t[7]=s*o-i*r-c*u-h*e,t},rotateByQuatPrepend:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*s+o*i+u*h-e*c,t[1]=u*s+o*c+e*i-r*h,t[2]=e*s+o*h+r*c-u*i,t[3]=o*s-r*i-u*c-e*h,i=a[4],c=a[5],h=a[6],s=a[7],t[4]=r*s+o*i+u*h-e*c,t[5]=u*s+o*c+e*i-r*h,t[6]=e*s+o*h+r*c-u*i,t[7]=o*s-r*i-u*c-e*h,t},rotateAroundAxis:function(t,a,r,u){if(Math.abs(u)<n)return sn(t,a);var e=Math.hypot(r[0],r[1],r[2]);u*=.5;var o=Math.sin(u),i=o*r[0]/e,c=o*r[1]/e,h=o*r[2]/e,s=Math.cos(u),M=a[0],f=a[1],l=a[2],v=a[3];t[0]=M*s+v*i+f*h-l*c,t[1]=f*s+v*c+l*i-M*h,t[2]=l*s+v*h+M*c-f*i,t[3]=v*s-M*i-f*c-l*h;var b=a[4],m=a[5],d=a[6],x=a[7];return t[4]=b*s+x*i+m*h-d*c,t[5]=m*s+x*c+d*i-b*h,t[6]=d*s+x*h+b*c-m*i,t[7]=x*s-b*i-m*c-d*h,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t},multiply:ln,mul:vn,scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t},dot:bn,lerp:function(t,n,a,r){var u=1-r;return bn(n,a)<0&&(r=-r),t[0]=n[0]*u+a[0]*r,t[1]=n[1]*u+a[1]*r,t[2]=n[2]*u+a[2]*r,t[3]=n[3]*u+a[3]*r,t[4]=n[4]*u+a[4]*r,t[5]=n[5]*u+a[5]*r,t[6]=n[6]*u+a[6]*r,t[7]=n[7]*u+a[7]*r,t},invert:function(t,n){var a=xn(n);return t[0]=-n[0]/a,t[1]=-n[1]/a,t[2]=-n[2]/a,t[3]=n[3]/a,t[4]=-n[4]/a,t[5]=-n[5]/a,t[6]=-n[6]/a,t[7]=n[7]/a,t},conjugate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t[4]=-n[4],t[5]=-n[5],t[6]=-n[6],t[7]=n[7],t},length:mn,len:dn,squaredLength:xn,sqrLen:pn,normalize:function(t,n){var a=xn(n);if(a>0){a=Math.sqrt(a);var r=n[0]/a,u=n[1]/a,e=n[2]/a,o=n[3]/a,i=n[4],c=n[5],h=n[6],s=n[7],M=r*i+u*c+e*h+o*s;t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=(i-r*M)/a,t[5]=(c-u*M)/a,t[6]=(h-e*M)/a,t[7]=(s-o*M)/a}return t},str:function(t){return"quat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=a[0],f=a[1],l=a[2],v=a[3],b=a[4],m=a[5],d=a[6],x=a[7];return Math.abs(r-M)<=n*Math.max(1,Math.abs(r),Math.abs(M))&&Math.abs(u-f)<=n*Math.max(1,Math.abs(u),Math.abs(f))&&Math.abs(e-l)<=n*Math.max(1,Math.abs(e),Math.abs(l))&&Math.abs(o-v)<=n*Math.max(1,Math.abs(o),Math.abs(v))&&Math.abs(i-b)<=n*Math.max(1,Math.abs(i),Math.abs(b))&&Math.abs(c-m)<=n*Math.max(1,Math.abs(c),Math.abs(m))&&Math.abs(h-d)<=n*Math.max(1,Math.abs(h),Math.abs(d))&&Math.abs(s-x)<=n*Math.max(1,Math.abs(s),Math.abs(x))}});function qn(){var t=new a(2);return a!=Float32Array&&(t[0]=0,t[1]=0),t}function gn(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t}function An(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t}function wn(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t}function Rn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return Math.hypot(a,r)}function zn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return a*a+r*r}function Pn(t){var n=t[0],a=t[1];return Math.hypot(n,a)}function jn(t){var n=t[0],a=t[1];return n*n+a*a}var In=Pn,Sn=gn,En=An,On=wn,Tn=Rn,Dn=zn,Fn=jn,Ln=function(){var t=qn();return function(n,a,r,u,e,o){var i,c;for(a||(a=2),r||(r=0),c=u?Math.min(u*a+r,n.length):n.length,i=r;i<c;i+=a)t[0]=n[i],t[1]=n[i+1],e(t,t,o),n[i]=t[0],n[i+1]=t[1];return n}}(),Vn=Object.freeze({create:qn,clone:function(t){var n=new a(2);return n[0]=t[0],n[1]=t[1],n},fromValues:function(t,n){var r=new a(2);return r[0]=t,r[1]=n,r},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t},set:function(t,n,a){return t[0]=n,t[1]=a,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t},subtract:gn,multiply:An,divide:wn,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t},scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t},scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t},distance:Rn,squaredDistance:zn,length:Pn,squaredLength:jn,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t},normalize:function(t,n){var a=n[0],r=n[1],u=a*a+r*r;return u>0&&(u=1/Math.sqrt(u)),t[0]=n[0]*u,t[1]=n[1]*u,t},dot:function(t,n){return t[0]*n[0]+t[1]*n[1]},cross:function(t,n,a){var r=n[0]*a[1]-n[1]*a[0];return t[0]=t[1]=0,t[2]=r,t},lerp:function(t,n,a,r){var u=n[0],e=n[1];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t},random:function(t,n){n=n||1;var a=2*r()*Math.PI;return t[0]=Math.cos(a)*n,t[1]=Math.sin(a)*n,t},transformMat2:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u,t[1]=a[1]*r+a[3]*u,t},transformMat2d:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u+a[4],t[1]=a[1]*r+a[3]*u+a[5],t},transformMat3:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[3]*u+a[6],t[1]=a[1]*r+a[4]*u+a[7],t},transformMat4:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[4]*u+a[12],t[1]=a[1]*r+a[5]*u+a[13],t},rotate:function(t,n,a,r){var u=n[0]-a[0],e=n[1]-a[1],o=Math.sin(r),i=Math.cos(r);return t[0]=u*i-e*o+a[0],t[1]=u*o+e*i+a[1],t},angle:function(t,n){var a=t[0],r=t[1],u=n[0],e=n[1],o=a*a+r*r;o>0&&(o=1/Math.sqrt(o));var i=u*u+e*e;i>0&&(i=1/Math.sqrt(i));var c=(a*u+r*e)*o*i;return c>1?0:c<-1?Math.PI:Math.acos(c)},zero:function(t){return t[0]=0,t[1]=0,t},str:function(t){return"vec2("+t[0]+", "+t[1]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]},equals:function(t,a){var r=t[0],u=t[1],e=a[0],o=a[1];return Math.abs(r-e)<=n*Math.max(1,Math.abs(r),Math.abs(e))&&Math.abs(u-o)<=n*Math.max(1,Math.abs(u),Math.abs(o))},len:In,sub:Sn,mul:En,div:On,dist:Tn,sqrDist:Dn,sqrLen:Fn,forEach:Ln});t.glMatrix=e,t.mat2=s,t.mat2d=b,t.mat3=q,t.mat4=E,t.quat=cn,t.quat2=yn,t.vec2=Vn,t.vec3=$,t.vec4=Pt,Object.defineProperty(t,"__esModule",{value:!0})});
diff --git a/student2019/201620963/README.md b/student2019/201620963/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..91d57c0382133129d3593619ea925db458bf6b07
--- /dev/null
+++ b/student2019/201620963/README.md
@@ -0,0 +1,160 @@
+# Advanced mouse inputs in WebGL: Cube following mouse cursor
+#### Introduction
+This tutorial's goal is to practice mouse input when using WebGL.
+In specific, we will create a rotating box following the mouse cursor over a canvas.
+Throughout the tutorial, it will cover the way HTML DOM is handled, and how such information is translated to coordinate used in WebGL,
+and little fundamental functions from GLMatrix library at a basic level.
+
+### How to use tutorial page
+If you move the mouse cursor over the black canvas of rendered page, a rotating cube will follow the cursor.
+The numbers above the canvas denotes coordinate of mouse in terms of canvas pixel, and WebGL normalized position.
+
+By pressing the button at the top, you can toggle the way cursor position is measured. 
+To fill the difference, resize the web browser window to be smaller than black canvas.
+Move window around and scroll window page and move the mouse cursor over the black canvas.
+
+### Detail
+#### Canvas
+Canvas is one of the elements provided for HTML.
+It uses `<canvas>` tag, and its structure looks quite simmilar to `<img>`
+It originally has `width` and `height` property, but other properties may be added.
+Some common options would be `id` property to identify one canvas from others, and `style` property to set its apperence.
+```
+<canvas id="helloapicanvas" style="border: none;" width="800" height="800"></canvas>
+```
+This Example will create canvas that has `helloapicanvas` as `id` without border in 500x500 size.
+
+#### Event Listener
+In Javascript, you can add event listener to HTML DOM with `addEventLister(event, function, useCapture)` function.
+As canvas is also one of the DOMs, you can register event lister as following.
+```
+canvas.addEventListener('mousedown', function(e) {
+    /* code to handle input */
+});
+```
+The `mousedown` is event denoting mouse button being pressed.
+Other useful event types would be `mouseover`, `mousemove`, `mouseleave` and so on.
+Especially `mousemove` is used in our implementation to track the moving mouse position over the canvas.
+Furthremore, `mouseleave` will be used to check if the cursor has left the canvas.
+
+#### Handling mouse input
+The registered event listener will now be triggered when an event is caught.
+However, there must be several more steps before using the coordinates right away.
+The actual information that an mouse event holds is not yet normalized to the canvas.
+In specific, the mouse event holds the mouse position in physical CSS pixels.
+Such pixel value is calculated from HTML scope  regardless to canvas and webgl.
+The coordinate can even be greater than canvas.
+
+Furthermore, the pixel value differs as different notation is used.
+The value shall be relational value from an origin point.
+These options should be set carefully to provide consistent functionality regardless of physical contraints.
+
+There are options denoting the position of mouse as following.
+- `pageX` `pageY`
+
+    The reference point is the top left of fully rendered content area in browser.
+    This makes huge different, when there scrolling get involved.
+    The user cursor at the top of browser, can be padded with the amount of pixel scrolled downwards.
+- `screenX` `screenY`
+
+    The reference point is the top left of physical screen / monitor.
+    This can implement some what like using web browser a limited vew window,
+    However in most case, it won't be used that much.
+- `clientX` `ClientY`
+
+    The reference point is the top left of viewport of the browser window.
+    This measure will provide constant coordinate regardless of scrolled or physical status.
+    This option is some what new functionality,
+    but all modern web browsers provide them, so does not need to be concerned.
+
+To make the cube follow the mouse position, `clientX` and `clientY` is our go-to choice,
+as we want it to be at exact same position with cursor from the client's viewpoint.
+
+To feel the difference yourself, change the modes using the button.
+
+#### Processing coordinate of mouse input
+To use coordinate in WebGL, we should process the coordinate.
+
+First, we should get the reference point of current client screen.
+To do this, we can use `getBoundingClientRect()` function provided for HTML DOMs.
+It will give us the css border of current client view.
+To be more specific, with following variable rect,
+```
+const rect = canvas.getBoundingClientRect();
+```
+(`rect.left`, `rect.top`) is our reference point.
+Therefore, we can you now convert mouse position into pixel coordinate of canvas by
+```
+x = event.clientX - rect.left;
+y = event.clientY - rect.top;
+```
+
+Next step, we need to normalize the coordinate used in WebGL.
+This can be done by deviding the width and height of the coordination.
+```
+glx = y / gl.canvas.width * 2 - 1;
+gly = x / gl.canvas.height * -2 + 1;
+```
+
+### Implementation
+The code for GLM library is added at the top of the script with its shortest form from `gl-matrix-min.js` 
+
+First of all, for the The following code will be registered to `mousemove` listener.
+```
+function getCursorPosition(canvas, event) {
+    const rect = canvas.getBoundingClientRect();
+    // calculate position according to mouse event type
+    x = eval("event." + mouseEventTypes[modeMET] + "X - rect.left");
+    y = eval("event." + mouseEventTypes[modeMET] + "Y - rect.top");
+    // normalize given value to WebGL coordinate
+    glx = x / gl.canvas.width * 2 - 1;
+    gly = y / gl.canvas.height * -2 + 1;
+    // Update element in HTML
+	document.getElementById("pixelxybar").innerHTML = "Pixel>> X: " + x + " Y: " + y;
+	document.getElementById("webglxybar").innerHTML = "WebGL>> X: " + glx + " Y: " + gly;
+}
+```
+This code will calculate update global variable according to mouse position.
+
+Then, we should calculate translation matrix to be applied to vertex.
+To do so, first create 4x4 identity matrix.
+```
+var transformationMatrix = glMatrix.mat4.create();
+```
+Then, make quaternion to denote rotation.
+A quaternion is an efficient way of denoting rotation and is also provided in GLM library.
+```
+var q = glMatrix.quat.create();
+glMatrix.quat.fromEuler(q, rot_z, 0, 0);
+```
+
+Next, create the transformation matrix for rotation, and translation, and scaling.
+GLM matrix provides convinient factory function to calculate all those three at once.
+```
+glMatrix.mat4.fromRotationTranslationScale(
+    transformationMatrix, q,
+    glMatrix.vec3.fromValues(glx, gly, 0),
+    glMatrix.vec3.fromValues(0.1, 0.1, 0.1)
+    );
+```
+This code will scale the cube into 1/10 size in every axis,
+rotate the cube according to the predefined quaternion,
+and translate cube to glx, and gly variable, which is normalized position of mouse cursor.
+
+Furthurmore, when cursor leaves the canvas,
+the cube will not be rendered by following if statement.
+```
+    if(glx && gly)
+	    gl.drawArrays(gl.TRIANGLES, 0, 12);
+```
+
+### Reference
+[stackoverflow question on canvas](https://stackoverflow.com/questions/9880279/how-do-i-add-a-simple-onclick-event-handler-to-a-canvas-element)
+
+[MDN canvas documentation](https://developer.mozilla.org/ko/docs/Web/HTML/Canvas)
+
+[w3schools addEventListner](https://www.w3schools.com/jsref/met_document_addeventlistener.asp)
+
+[stackoverflow question on mouse properties](https://stackoverflow.com/questions/6073505/what-is-the-difference-between-screenx-y-clientx-y-and-pagex-y)
+
+[GLMatrix Documentation](http://glmatrix.net/docs/index.html)
diff --git a/student2019/201620963/WebGLHelloAPI.js b/student2019/201620963/WebGLHelloAPI.js
new file mode 100644
index 0000000000000000000000000000000000000000..f91ebd4d2a1d642cb311f3076608c1223defe04c
--- /dev/null
+++ b/student2019/201620963/WebGLHelloAPI.js
@@ -0,0 +1,283 @@
+// (CC-NC-BY) Jinwoo Hwang 2019
+var gl;
+var x = null, y = null; // denotes position of mouse in pixel
+var glx = null, gly = null; // denotes position of mouse in gl coordinate
+
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t=t||self).glMatrix={})}(this,function(t){"use strict";var n=1e-6,a="undefined"!=typeof Float32Array?Float32Array:Array,r=Math.random;var u=Math.PI/180;Math.hypot||(Math.hypot=function(){for(var t=0,n=arguments.length;n--;)t+=arguments[n]*arguments[n];return Math.sqrt(t)});var e=Object.freeze({EPSILON:n,get ARRAY_TYPE(){return a},RANDOM:r,setMatrixArrayType:function(t){a=t},toRadian:function(t){return t*u},equals:function(t,a){return Math.abs(t-a)<=n*Math.max(1,Math.abs(t),Math.abs(a))}});function o(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*i+e*c,t[1]=u*i+o*c,t[2]=r*h+e*s,t[3]=u*h+o*s,t}function i(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}var c=o,h=i,s=Object.freeze({create:function(){var t=new a(4);return a!=Float32Array&&(t[1]=0,t[2]=0),t[0]=1,t[3]=1,t},clone:function(t){var n=new a(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t},fromValues:function(t,n,r,u){var e=new a(4);return e[0]=t,e[1]=n,e[2]=r,e[3]=u,e},set:function(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t},transpose:function(t,n){if(t===n){var a=n[1];t[1]=n[2],t[2]=a}else t[0]=n[0],t[1]=n[2],t[2]=n[1],t[3]=n[3];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*e-u*r;return o?(o=1/o,t[0]=e*o,t[1]=-r*o,t[2]=-u*o,t[3]=a*o,t):null},adjoint:function(t,n){var a=n[0];return t[0]=n[3],t[1]=-n[1],t[2]=-n[2],t[3]=a,t},determinant:function(t){return t[0]*t[3]-t[2]*t[1]},multiply:o,rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+e*i,t[1]=u*c+o*i,t[2]=r*-i+e*c,t[3]=u*-i+o*c,t},scale:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1];return t[0]=r*i,t[1]=u*i,t[2]=e*c,t[3]=o*c,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t},str:function(t){return"mat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3])},LDU:function(t,n,a,r){return t[2]=r[2]/r[0],a[0]=r[0],a[1]=r[1],a[3]=r[3]-t[2]*a[1],[t,n,a]},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t},subtract:i,exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=a[0],c=a[1],h=a[2],s=a[3];return Math.abs(r-i)<=n*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-c)<=n*Math.max(1,Math.abs(u),Math.abs(c))&&Math.abs(e-h)<=n*Math.max(1,Math.abs(e),Math.abs(h))&&Math.abs(o-s)<=n*Math.max(1,Math.abs(o),Math.abs(s))},multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t},mul:c,sub:h});function M(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return t[0]=r*h+e*s,t[1]=u*h+o*s,t[2]=r*M+e*f,t[3]=u*M+o*f,t[4]=r*l+e*v+i,t[5]=u*l+o*v+c,t}function f(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t}var l=M,v=f,b=Object.freeze({create:function(){var t=new a(6);return a!=Float32Array&&(t[1]=0,t[2]=0,t[4]=0,t[5]=0),t[0]=1,t[3]=1,t},clone:function(t){var n=new a(6);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t},fromValues:function(t,n,r,u,e,o){var i=new a(6);return i[0]=t,i[1]=n,i[2]=r,i[3]=u,i[4]=e,i[5]=o,i},set:function(t,n,a,r,u,e,o){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=a*e-r*u;return c?(c=1/c,t[0]=e*c,t[1]=-r*c,t[2]=-u*c,t[3]=a*c,t[4]=(u*i-e*o)*c,t[5]=(r*o-a*i)*c,t):null},determinant:function(t){return t[0]*t[3]-t[1]*t[2]},multiply:M,rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=Math.sin(a),s=Math.cos(a);return t[0]=r*s+e*h,t[1]=u*s+o*h,t[2]=r*-h+e*s,t[3]=u*-h+o*s,t[4]=i,t[5]=c,t},scale:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1];return t[0]=r*h,t[1]=u*h,t[2]=e*s,t[3]=o*s,t[4]=i,t[5]=c,t},translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=a[0],s=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=r*h+e*s+i,t[5]=u*h+o*s+c,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t[4]=0,t[5]=0,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t[4]=0,t[5]=0,t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=n[0],t[5]=n[1],t},str:function(t){return"mat2d("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],1)},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t},subtract:f,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return Math.abs(r-h)<=n*Math.max(1,Math.abs(r),Math.abs(h))&&Math.abs(u-s)<=n*Math.max(1,Math.abs(u),Math.abs(s))&&Math.abs(e-M)<=n*Math.max(1,Math.abs(e),Math.abs(M))&&Math.abs(o-f)<=n*Math.max(1,Math.abs(o),Math.abs(f))&&Math.abs(i-l)<=n*Math.max(1,Math.abs(i),Math.abs(l))&&Math.abs(c-v)<=n*Math.max(1,Math.abs(c),Math.abs(v))},mul:l,sub:v});function m(){var t=new a(9);return a!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function d(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],p=a[7],y=a[8];return t[0]=f*r+l*o+v*h,t[1]=f*u+l*i+v*s,t[2]=f*e+l*c+v*M,t[3]=b*r+m*o+d*h,t[4]=b*u+m*i+d*s,t[5]=b*e+m*c+d*M,t[6]=x*r+p*o+y*h,t[7]=x*u+p*i+y*s,t[8]=x*e+p*c+y*M,t}function x(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t}var p=d,y=x,q=Object.freeze({create:m,fromMat4:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[4],t[4]=n[5],t[5]=n[6],t[6]=n[8],t[7]=n[9],t[8]=n[10],t},clone:function(t){var n=new a(9);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromValues:function(t,n,r,u,e,o,i,c,h){var s=new a(9);return s[0]=t,s[1]=n,s[2]=r,s[3]=u,s[4]=e,s[5]=o,s[6]=i,s[7]=c,s[8]=h,s},set:function(t,n,a,r,u,e,o,i,c,h){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t[8]=h,t},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},transpose:function(t,n){if(t===n){var a=n[1],r=n[2],u=n[5];t[1]=n[3],t[2]=n[6],t[3]=a,t[5]=n[7],t[6]=r,t[7]=u}else t[0]=n[0],t[1]=n[3],t[2]=n[6],t[3]=n[1],t[4]=n[4],t[5]=n[7],t[6]=n[2],t[7]=n[5],t[8]=n[8];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=s*o-i*h,f=-s*e+i*c,l=h*e-o*c,v=a*M+r*f+u*l;return v?(v=1/v,t[0]=M*v,t[1]=(-s*r+u*h)*v,t[2]=(i*r-u*o)*v,t[3]=f*v,t[4]=(s*a-u*c)*v,t[5]=(-i*a+u*e)*v,t[6]=l*v,t[7]=(-h*a+r*c)*v,t[8]=(o*a-r*e)*v,t):null},adjoint:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8];return t[0]=o*s-i*h,t[1]=u*h-r*s,t[2]=r*i-u*o,t[3]=i*c-e*s,t[4]=a*s-u*c,t[5]=u*e-a*i,t[6]=e*h-o*c,t[7]=r*c-a*h,t[8]=a*o-r*e,t},determinant:function(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],c=t[7],h=t[8];return n*(h*e-o*c)+a*(-h*u+o*i)+r*(c*u-e*i)},multiply:d,translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=a[0],l=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=c,t[6]=f*r+l*o+h,t[7]=f*u+l*i+s,t[8]=f*e+l*c+M,t},rotate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=Math.sin(a),l=Math.cos(a);return t[0]=l*r+f*o,t[1]=l*u+f*i,t[2]=l*e+f*c,t[3]=l*o-f*r,t[4]=l*i-f*u,t[5]=l*c-f*e,t[6]=h,t[7]=s,t[8]=M,t},scale:function(t,n,a){var r=a[0],u=a[1];return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=u*n[3],t[4]=u*n[4],t[5]=u*n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=n[0],t[7]=n[1],t[8]=1,t},fromRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=-a,t[4]=r,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=n[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},fromMat2d:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=0,t[3]=n[2],t[4]=n[3],t[5]=0,t[6]=n[4],t[7]=n[5],t[8]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,c=u+u,h=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*c,b=e*o,m=e*i,d=e*c;return t[0]=1-M-v,t[3]=s-d,t[6]=f+m,t[1]=s+d,t[4]=1-h-v,t[7]=l-b,t[2]=f-m,t[5]=l+b,t[8]=1-h-M,t},normalFromMat4:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*c-u*o,y=a*h-e*o,q=r*c-u*i,g=r*h-e*i,A=u*h-e*c,w=s*b-M*v,R=s*m-f*v,z=s*d-l*v,P=M*m-f*b,j=M*d-l*b,I=f*d-l*m,S=x*I-p*j+y*P+q*z-g*R+A*w;return S?(S=1/S,t[0]=(i*I-c*j+h*P)*S,t[1]=(c*z-o*I-h*R)*S,t[2]=(o*j-i*z+h*w)*S,t[3]=(u*j-r*I-e*P)*S,t[4]=(a*I-u*z+e*R)*S,t[5]=(r*z-a*j-e*w)*S,t[6]=(b*A-m*g+d*q)*S,t[7]=(m*y-v*A-d*p)*S,t[8]=(v*g-b*y+d*x)*S,t):null},projection:function(t,n,a){return t[0]=2/n,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/a,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t},str:function(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t},subtract:x,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=t[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],p=a[7],y=a[8];return Math.abs(r-f)<=n*Math.max(1,Math.abs(r),Math.abs(f))&&Math.abs(u-l)<=n*Math.max(1,Math.abs(u),Math.abs(l))&&Math.abs(e-v)<=n*Math.max(1,Math.abs(e),Math.abs(v))&&Math.abs(o-b)<=n*Math.max(1,Math.abs(o),Math.abs(b))&&Math.abs(i-m)<=n*Math.max(1,Math.abs(i),Math.abs(m))&&Math.abs(c-d)<=n*Math.max(1,Math.abs(c),Math.abs(d))&&Math.abs(h-x)<=n*Math.max(1,Math.abs(h),Math.abs(x))&&Math.abs(s-p)<=n*Math.max(1,Math.abs(s),Math.abs(p))&&Math.abs(M-y)<=n*Math.max(1,Math.abs(M),Math.abs(y))},mul:p,sub:y});function g(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function A(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],b=n[12],m=n[13],d=n[14],x=n[15],p=a[0],y=a[1],q=a[2],g=a[3];return t[0]=p*r+y*i+q*M+g*b,t[1]=p*u+y*c+q*f+g*m,t[2]=p*e+y*h+q*l+g*d,t[3]=p*o+y*s+q*v+g*x,p=a[4],y=a[5],q=a[6],g=a[7],t[4]=p*r+y*i+q*M+g*b,t[5]=p*u+y*c+q*f+g*m,t[6]=p*e+y*h+q*l+g*d,t[7]=p*o+y*s+q*v+g*x,p=a[8],y=a[9],q=a[10],g=a[11],t[8]=p*r+y*i+q*M+g*b,t[9]=p*u+y*c+q*f+g*m,t[10]=p*e+y*h+q*l+g*d,t[11]=p*o+y*s+q*v+g*x,p=a[12],y=a[13],q=a[14],g=a[15],t[12]=p*r+y*i+q*M+g*b,t[13]=p*u+y*c+q*f+g*m,t[14]=p*e+y*h+q*l+g*d,t[15]=p*o+y*s+q*v+g*x,t}function w(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=r+r,c=u+u,h=e+e,s=r*i,M=r*c,f=r*h,l=u*c,v=u*h,b=e*h,m=o*i,d=o*c,x=o*h;return t[0]=1-(l+b),t[1]=M+x,t[2]=f-d,t[3]=0,t[4]=M-x,t[5]=1-(s+b),t[6]=v+m,t[7]=0,t[8]=f+d,t[9]=v-m,t[10]=1-(s+l),t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t}function R(t,n){return t[0]=n[12],t[1]=n[13],t[2]=n[14],t}function z(t,n){var a=n[0],r=n[1],u=n[2],e=n[4],o=n[5],i=n[6],c=n[8],h=n[9],s=n[10];return t[0]=Math.hypot(a,r,u),t[1]=Math.hypot(e,o,i),t[2]=Math.hypot(c,h,s),t}function P(t,n){var r=new a(3);z(r,n);var u=1/r[0],e=1/r[1],o=1/r[2],i=n[0]*u,c=n[1]*e,h=n[2]*o,s=n[4]*u,M=n[5]*e,f=n[6]*o,l=n[8]*u,v=n[9]*e,b=n[10]*o,m=i+M+b,d=0;return m>0?(d=2*Math.sqrt(m+1),t[3]=.25*d,t[0]=(f-v)/d,t[1]=(l-h)/d,t[2]=(c-s)/d):i>M&&i>b?(d=2*Math.sqrt(1+i-M-b),t[3]=(f-v)/d,t[0]=.25*d,t[1]=(c+s)/d,t[2]=(l+h)/d):M>b?(d=2*Math.sqrt(1+M-i-b),t[3]=(l-h)/d,t[0]=(c+s)/d,t[1]=.25*d,t[2]=(f+v)/d):(d=2*Math.sqrt(1+b-i-M),t[3]=(c-s)/d,t[0]=(l+h)/d,t[1]=(f+v)/d,t[2]=.25*d),t}function j(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t[9]=n[9]-a[9],t[10]=n[10]-a[10],t[11]=n[11]-a[11],t[12]=n[12]-a[12],t[13]=n[13]-a[13],t[14]=n[14]-a[14],t[15]=n[15]-a[15],t}var I=A,S=j,E=Object.freeze({create:function(){var t=new a(16);return a!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0),t[0]=1,t[5]=1,t[10]=1,t[15]=1,t},clone:function(t){var n=new a(16);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n[9]=t[9],n[10]=t[10],n[11]=t[11],n[12]=t[12],n[13]=t[13],n[14]=t[14],n[15]=t[15],n},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},fromValues:function(t,n,r,u,e,o,i,c,h,s,M,f,l,v,b,m){var d=new a(16);return d[0]=t,d[1]=n,d[2]=r,d[3]=u,d[4]=e,d[5]=o,d[6]=i,d[7]=c,d[8]=h,d[9]=s,d[10]=M,d[11]=f,d[12]=l,d[13]=v,d[14]=b,d[15]=m,d},set:function(t,n,a,r,u,e,o,i,c,h,s,M,f,l,v,b,m){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t[8]=h,t[9]=s,t[10]=M,t[11]=f,t[12]=l,t[13]=v,t[14]=b,t[15]=m,t},identity:g,transpose:function(t,n){if(t===n){var a=n[1],r=n[2],u=n[3],e=n[6],o=n[7],i=n[11];t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=a,t[6]=n[9],t[7]=n[13],t[8]=r,t[9]=e,t[11]=n[14],t[12]=u,t[13]=o,t[14]=i}else t[0]=n[0],t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=n[1],t[5]=n[5],t[6]=n[9],t[7]=n[13],t[8]=n[2],t[9]=n[6],t[10]=n[10],t[11]=n[14],t[12]=n[3],t[13]=n[7],t[14]=n[11],t[15]=n[15];return t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,p=a*c-u*o,y=a*h-e*o,q=r*c-u*i,g=r*h-e*i,A=u*h-e*c,w=s*b-M*v,R=s*m-f*v,z=s*d-l*v,P=M*m-f*b,j=M*d-l*b,I=f*d-l*m,S=x*I-p*j+y*P+q*z-g*R+A*w;return S?(S=1/S,t[0]=(i*I-c*j+h*P)*S,t[1]=(u*j-r*I-e*P)*S,t[2]=(b*A-m*g+d*q)*S,t[3]=(f*g-M*A-l*q)*S,t[4]=(c*z-o*I-h*R)*S,t[5]=(a*I-u*z+e*R)*S,t[6]=(m*y-v*A-d*p)*S,t[7]=(s*A-f*y+l*p)*S,t[8]=(o*j-i*z+h*w)*S,t[9]=(r*z-a*j-e*w)*S,t[10]=(v*g-b*y+d*x)*S,t[11]=(M*y-s*g-l*x)*S,t[12]=(i*R-o*P-c*w)*S,t[13]=(a*P-r*R+u*w)*S,t[14]=(b*p-v*q-m*x)*S,t[15]=(s*q-M*p+f*x)*S,t):null},adjoint:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],c=n[6],h=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15];return t[0]=i*(f*d-l*m)-M*(c*d-h*m)+b*(c*l-h*f),t[1]=-(r*(f*d-l*m)-M*(u*d-e*m)+b*(u*l-e*f)),t[2]=r*(c*d-h*m)-i*(u*d-e*m)+b*(u*h-e*c),t[3]=-(r*(c*l-h*f)-i*(u*l-e*f)+M*(u*h-e*c)),t[4]=-(o*(f*d-l*m)-s*(c*d-h*m)+v*(c*l-h*f)),t[5]=a*(f*d-l*m)-s*(u*d-e*m)+v*(u*l-e*f),t[6]=-(a*(c*d-h*m)-o*(u*d-e*m)+v*(u*h-e*c)),t[7]=a*(c*l-h*f)-o*(u*l-e*f)+s*(u*h-e*c),t[8]=o*(M*d-l*b)-s*(i*d-h*b)+v*(i*l-h*M),t[9]=-(a*(M*d-l*b)-s*(r*d-e*b)+v*(r*l-e*M)),t[10]=a*(i*d-h*b)-o*(r*d-e*b)+v*(r*h-e*i),t[11]=-(a*(i*l-h*M)-o*(r*l-e*M)+s*(r*h-e*i)),t[12]=-(o*(M*m-f*b)-s*(i*m-c*b)+v*(i*f-c*M)),t[13]=a*(M*m-f*b)-s*(r*m-u*b)+v*(r*f-u*M),t[14]=-(a*(i*m-c*b)-o*(r*m-u*b)+v*(r*c-u*i)),t[15]=a*(i*f-c*M)-o*(r*f-u*M)+s*(r*c-u*i),t},determinant:function(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],c=t[7],h=t[8],s=t[9],M=t[10],f=t[11],l=t[12],v=t[13],b=t[14],m=t[15];return(n*o-a*e)*(M*m-f*b)-(n*i-r*e)*(s*m-f*v)+(n*c-u*e)*(s*b-M*v)+(a*i-r*o)*(h*m-f*l)-(a*c-u*o)*(h*b-M*l)+(r*c-u*i)*(h*v-s*l)},multiply:A,translate:function(t,n,a){var r,u,e,o,i,c,h,s,M,f,l,v,b=a[0],m=a[1],d=a[2];return n===t?(t[12]=n[0]*b+n[4]*m+n[8]*d+n[12],t[13]=n[1]*b+n[5]*m+n[9]*d+n[13],t[14]=n[2]*b+n[6]*m+n[10]*d+n[14],t[15]=n[3]*b+n[7]*m+n[11]*d+n[15]):(r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=c,t[6]=h,t[7]=s,t[8]=M,t[9]=f,t[10]=l,t[11]=v,t[12]=r*b+i*m+M*d+n[12],t[13]=u*b+c*m+f*d+n[13],t[14]=e*b+h*m+l*d+n[14],t[15]=o*b+s*m+v*d+n[15]),t},scale:function(t,n,a){var r=a[0],u=a[1],e=a[2];return t[0]=n[0]*r,t[1]=n[1]*r,t[2]=n[2]*r,t[3]=n[3]*r,t[4]=n[4]*u,t[5]=n[5]*u,t[6]=n[6]*u,t[7]=n[7]*u,t[8]=n[8]*e,t[9]=n[9]*e,t[10]=n[10]*e,t[11]=n[11]*e,t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t},rotate:function(t,a,r,u){var e,o,i,c,h,s,M,f,l,v,b,m,d,x,p,y,q,g,A,w,R,z,P,j,I=u[0],S=u[1],E=u[2],O=Math.hypot(I,S,E);return O<n?null:(I*=O=1/O,S*=O,E*=O,e=Math.sin(r),i=1-(o=Math.cos(r)),c=a[0],h=a[1],s=a[2],M=a[3],f=a[4],l=a[5],v=a[6],b=a[7],m=a[8],d=a[9],x=a[10],p=a[11],y=I*I*i+o,q=S*I*i+E*e,g=E*I*i-S*e,A=I*S*i-E*e,w=S*S*i+o,R=E*S*i+I*e,z=I*E*i+S*e,P=S*E*i-I*e,j=E*E*i+o,t[0]=c*y+f*q+m*g,t[1]=h*y+l*q+d*g,t[2]=s*y+v*q+x*g,t[3]=M*y+b*q+p*g,t[4]=c*A+f*w+m*R,t[5]=h*A+l*w+d*R,t[6]=s*A+v*w+x*R,t[7]=M*A+b*w+p*R,t[8]=c*z+f*P+m*j,t[9]=h*z+l*P+d*j,t[10]=s*z+v*P+x*j,t[11]=M*z+b*P+p*j,a!==t&&(t[12]=a[12],t[13]=a[13],t[14]=a[14],t[15]=a[15]),t)},rotateX:function(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[4],o=n[5],i=n[6],c=n[7],h=n[8],s=n[9],M=n[10],f=n[11];return n!==t&&(t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[4]=e*u+h*r,t[5]=o*u+s*r,t[6]=i*u+M*r,t[7]=c*u+f*r,t[8]=h*u-e*r,t[9]=s*u-o*r,t[10]=M*u-i*r,t[11]=f*u-c*r,t},rotateY:function(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[0],o=n[1],i=n[2],c=n[3],h=n[8],s=n[9],M=n[10],f=n[11];return n!==t&&(t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[0]=e*u-h*r,t[1]=o*u-s*r,t[2]=i*u-M*r,t[3]=c*u-f*r,t[8]=e*r+h*u,t[9]=o*r+s*u,t[10]=i*r+M*u,t[11]=c*r+f*u,t},rotateZ:function(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[0],o=n[1],i=n[2],c=n[3],h=n[4],s=n[5],M=n[6],f=n[7];return n!==t&&(t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[0]=e*u+h*r,t[1]=o*u+s*r,t[2]=i*u+M*r,t[3]=c*u+f*r,t[4]=h*u-e*r,t[5]=s*u-o*r,t[6]=M*u-i*r,t[7]=f*u-c*r,t},fromTranslation:function(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=n[0],t[13]=n[1],t[14]=n[2],t[15]=1,t},fromScaling:function(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=n[1],t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=n[2],t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromRotation:function(t,a,r){var u,e,o,i=r[0],c=r[1],h=r[2],s=Math.hypot(i,c,h);return s<n?null:(i*=s=1/s,c*=s,h*=s,u=Math.sin(a),o=1-(e=Math.cos(a)),t[0]=i*i*o+e,t[1]=c*i*o+h*u,t[2]=h*i*o-c*u,t[3]=0,t[4]=i*c*o-h*u,t[5]=c*c*o+e,t[6]=h*c*o+i*u,t[7]=0,t[8]=i*h*o+c*u,t[9]=c*h*o-i*u,t[10]=h*h*o+e,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t)},fromXRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=r,t[6]=a,t[7]=0,t[8]=0,t[9]=-a,t[10]=r,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromYRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=0,t[2]=-a,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=a,t[9]=0,t[10]=r,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromZRotation:function(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=0,t[4]=-a,t[5]=r,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},fromRotationTranslation:w,fromQuat2:function(t,n){var r=new a(3),u=-n[0],e=-n[1],o=-n[2],i=n[3],c=n[4],h=n[5],s=n[6],M=n[7],f=u*u+e*e+o*o+i*i;return f>0?(r[0]=2*(c*i+M*u+h*o-s*e)/f,r[1]=2*(h*i+M*e+s*u-c*o)/f,r[2]=2*(s*i+M*o+c*e-h*u)/f):(r[0]=2*(c*i+M*u+h*o-s*e),r[1]=2*(h*i+M*e+s*u-c*o),r[2]=2*(s*i+M*o+c*e-h*u)),w(t,n,r),t},getTranslation:R,getScaling:z,getRotation:P,fromRotationTranslationScale:function(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3],c=u+u,h=e+e,s=o+o,M=u*c,f=u*h,l=u*s,v=e*h,b=e*s,m=o*s,d=i*c,x=i*h,p=i*s,y=r[0],q=r[1],g=r[2];return t[0]=(1-(v+m))*y,t[1]=(f+p)*y,t[2]=(l-x)*y,t[3]=0,t[4]=(f-p)*q,t[5]=(1-(M+m))*q,t[6]=(b+d)*q,t[7]=0,t[8]=(l+x)*g,t[9]=(b-d)*g,t[10]=(1-(M+v))*g,t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t},fromRotationTranslationScaleOrigin:function(t,n,a,r,u){var e=n[0],o=n[1],i=n[2],c=n[3],h=e+e,s=o+o,M=i+i,f=e*h,l=e*s,v=e*M,b=o*s,m=o*M,d=i*M,x=c*h,p=c*s,y=c*M,q=r[0],g=r[1],A=r[2],w=u[0],R=u[1],z=u[2],P=(1-(b+d))*q,j=(l+y)*q,I=(v-p)*q,S=(l-y)*g,E=(1-(f+d))*g,O=(m+x)*g,T=(v+p)*A,D=(m-x)*A,F=(1-(f+b))*A;return t[0]=P,t[1]=j,t[2]=I,t[3]=0,t[4]=S,t[5]=E,t[6]=O,t[7]=0,t[8]=T,t[9]=D,t[10]=F,t[11]=0,t[12]=a[0]+w-(P*w+S*R+T*z),t[13]=a[1]+R-(j*w+E*R+D*z),t[14]=a[2]+z-(I*w+O*R+F*z),t[15]=1,t},fromQuat:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,c=u+u,h=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*c,b=e*o,m=e*i,d=e*c;return t[0]=1-M-v,t[1]=s+d,t[2]=f-m,t[3]=0,t[4]=s-d,t[5]=1-h-v,t[6]=l+b,t[7]=0,t[8]=f+m,t[9]=l-b,t[10]=1-h-M,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},frustum:function(t,n,a,r,u,e,o){var i=1/(a-n),c=1/(u-r),h=1/(e-o);return t[0]=2*e*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*e*c,t[6]=0,t[7]=0,t[8]=(a+n)*i,t[9]=(u+r)*c,t[10]=(o+e)*h,t[11]=-1,t[12]=0,t[13]=0,t[14]=o*e*2*h,t[15]=0,t},perspective:function(t,n,a,r,u){var e,o=1/Math.tan(n/2);return t[0]=o/a,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=o,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=-1,t[12]=0,t[13]=0,t[15]=0,null!=u&&u!==1/0?(e=1/(r-u),t[10]=(u+r)*e,t[14]=2*u*r*e):(t[10]=-1,t[14]=-2*r),t},perspectiveFromFieldOfView:function(t,n,a,r){var u=Math.tan(n.upDegrees*Math.PI/180),e=Math.tan(n.downDegrees*Math.PI/180),o=Math.tan(n.leftDegrees*Math.PI/180),i=Math.tan(n.rightDegrees*Math.PI/180),c=2/(o+i),h=2/(u+e);return t[0]=c,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=h,t[6]=0,t[7]=0,t[8]=-(o-i)*c*.5,t[9]=(u-e)*h*.5,t[10]=r/(a-r),t[11]=-1,t[12]=0,t[13]=0,t[14]=r*a/(a-r),t[15]=0,t},ortho:function(t,n,a,r,u,e,o){var i=1/(n-a),c=1/(r-u),h=1/(e-o);return t[0]=-2*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*c,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*h,t[11]=0,t[12]=(n+a)*i,t[13]=(u+r)*c,t[14]=(o+e)*h,t[15]=1,t},lookAt:function(t,a,r,u){var e,o,i,c,h,s,M,f,l,v,b=a[0],m=a[1],d=a[2],x=u[0],p=u[1],y=u[2],q=r[0],A=r[1],w=r[2];return Math.abs(b-q)<n&&Math.abs(m-A)<n&&Math.abs(d-w)<n?g(t):(M=b-q,f=m-A,l=d-w,e=p*(l*=v=1/Math.hypot(M,f,l))-y*(f*=v),o=y*(M*=v)-x*l,i=x*f-p*M,(v=Math.hypot(e,o,i))?(e*=v=1/v,o*=v,i*=v):(e=0,o=0,i=0),c=f*i-l*o,h=l*e-M*i,s=M*o-f*e,(v=Math.hypot(c,h,s))?(c*=v=1/v,h*=v,s*=v):(c=0,h=0,s=0),t[0]=e,t[1]=c,t[2]=M,t[3]=0,t[4]=o,t[5]=h,t[6]=f,t[7]=0,t[8]=i,t[9]=s,t[10]=l,t[11]=0,t[12]=-(e*b+o*m+i*d),t[13]=-(c*b+h*m+s*d),t[14]=-(M*b+f*m+l*d),t[15]=1,t)},targetTo:function(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=r[0],c=r[1],h=r[2],s=u-a[0],M=e-a[1],f=o-a[2],l=s*s+M*M+f*f;l>0&&(s*=l=1/Math.sqrt(l),M*=l,f*=l);var v=c*f-h*M,b=h*s-i*f,m=i*M-c*s;return(l=v*v+b*b+m*m)>0&&(v*=l=1/Math.sqrt(l),b*=l,m*=l),t[0]=v,t[1]=b,t[2]=m,t[3]=0,t[4]=M*m-f*b,t[5]=f*v-s*m,t[6]=s*b-M*v,t[7]=0,t[8]=s,t[9]=M,t[10]=f,t[11]=0,t[12]=u,t[13]=e,t[14]=o,t[15]=1,t},str:function(t){return"mat4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+", "+t[9]+", "+t[10]+", "+t[11]+", "+t[12]+", "+t[13]+", "+t[14]+", "+t[15]+")"},frob:function(t){return Math.hypot(t[0],t[1],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15])},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t[9]=n[9]+a[9],t[10]=n[10]+a[10],t[11]=n[11]+a[11],t[12]=n[12]+a[12],t[13]=n[13]+a[13],t[14]=n[14]+a[14],t[15]=n[15]+a[15],t},subtract:j,multiplyScalar:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=n[11]*a,t[12]=n[12]*a,t[13]=n[13]*a,t[14]=n[14]*a,t[15]=n[15]*a,t},multiplyScalarAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t[9]=n[9]+a[9]*r,t[10]=n[10]+a[10]*r,t[11]=n[11]+a[11]*r,t[12]=n[12]+a[12]*r,t[13]=n[13]+a[13]*r,t[14]=n[14]+a[14]*r,t[15]=n[15]+a[15]*r,t},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]&&t[9]===n[9]&&t[10]===n[10]&&t[11]===n[11]&&t[12]===n[12]&&t[13]===n[13]&&t[14]===n[14]&&t[15]===n[15]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=t[8],f=t[9],l=t[10],v=t[11],b=t[12],m=t[13],d=t[14],x=t[15],p=a[0],y=a[1],q=a[2],g=a[3],A=a[4],w=a[5],R=a[6],z=a[7],P=a[8],j=a[9],I=a[10],S=a[11],E=a[12],O=a[13],T=a[14],D=a[15];return Math.abs(r-p)<=n*Math.max(1,Math.abs(r),Math.abs(p))&&Math.abs(u-y)<=n*Math.max(1,Math.abs(u),Math.abs(y))&&Math.abs(e-q)<=n*Math.max(1,Math.abs(e),Math.abs(q))&&Math.abs(o-g)<=n*Math.max(1,Math.abs(o),Math.abs(g))&&Math.abs(i-A)<=n*Math.max(1,Math.abs(i),Math.abs(A))&&Math.abs(c-w)<=n*Math.max(1,Math.abs(c),Math.abs(w))&&Math.abs(h-R)<=n*Math.max(1,Math.abs(h),Math.abs(R))&&Math.abs(s-z)<=n*Math.max(1,Math.abs(s),Math.abs(z))&&Math.abs(M-P)<=n*Math.max(1,Math.abs(M),Math.abs(P))&&Math.abs(f-j)<=n*Math.max(1,Math.abs(f),Math.abs(j))&&Math.abs(l-I)<=n*Math.max(1,Math.abs(l),Math.abs(I))&&Math.abs(v-S)<=n*Math.max(1,Math.abs(v),Math.abs(S))&&Math.abs(b-E)<=n*Math.max(1,Math.abs(b),Math.abs(E))&&Math.abs(m-O)<=n*Math.max(1,Math.abs(m),Math.abs(O))&&Math.abs(d-T)<=n*Math.max(1,Math.abs(d),Math.abs(T))&&Math.abs(x-D)<=n*Math.max(1,Math.abs(x),Math.abs(D))},mul:I,sub:S});function O(){var t=new a(3);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function T(t){var n=t[0],a=t[1],r=t[2];return Math.hypot(n,a,r)}function D(t,n,r){var u=new a(3);return u[0]=t,u[1]=n,u[2]=r,u}function F(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t}function L(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t}function V(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t}function Q(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return Math.hypot(a,r,u)}function Y(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return a*a+r*r+u*u}function X(t){var n=t[0],a=t[1],r=t[2];return n*n+a*a+r*r}function Z(t,n){var a=n[0],r=n[1],u=n[2],e=a*a+r*r+u*u;return e>0&&(e=1/Math.sqrt(e)),t[0]=n[0]*e,t[1]=n[1]*e,t[2]=n[2]*e,t}function _(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function B(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],c=a[2];return t[0]=u*c-e*i,t[1]=e*o-r*c,t[2]=r*i-u*o,t}var N,k=F,U=L,W=V,C=Q,G=Y,H=T,J=X,K=(N=O(),function(t,n,a,r,u,e){var o,i;for(n||(n=3),a||(a=0),i=r?Math.min(r*n+a,t.length):t.length,o=a;o<i;o+=n)N[0]=t[o],N[1]=t[o+1],N[2]=t[o+2],u(N,N,e),t[o]=N[0],t[o+1]=N[1],t[o+2]=N[2];return t}),$=Object.freeze({create:O,clone:function(t){var n=new a(3);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n},length:T,fromValues:D,copy:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t},set:function(t,n,a,r){return t[0]=n,t[1]=a,t[2]=r,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t},subtract:F,multiply:L,divide:V,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t[2]=Math.ceil(n[2]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t[2]=Math.floor(n[2]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t[2]=Math.min(n[2],a[2]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t[2]=Math.max(n[2],a[2]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t[2]=Math.round(n[2]),t},scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t},scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t},distance:Q,squaredDistance:Y,squaredLength:X,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t[2]=1/n[2],t},normalize:Z,dot:_,cross:B,lerp:function(t,n,a,r){var u=n[0],e=n[1],o=n[2];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t[2]=o+r*(a[2]-o),t},hermite:function(t,n,a,r,u,e){var o=e*e,i=o*(2*e-3)+1,c=o*(e-2)+e,h=o*(e-1),s=o*(3-2*e);return t[0]=n[0]*i+a[0]*c+r[0]*h+u[0]*s,t[1]=n[1]*i+a[1]*c+r[1]*h+u[1]*s,t[2]=n[2]*i+a[2]*c+r[2]*h+u[2]*s,t},bezier:function(t,n,a,r,u,e){var o=1-e,i=o*o,c=e*e,h=i*o,s=3*e*i,M=3*c*o,f=c*e;return t[0]=n[0]*h+a[0]*s+r[0]*M+u[0]*f,t[1]=n[1]*h+a[1]*s+r[1]*M+u[1]*f,t[2]=n[2]*h+a[2]*s+r[2]*M+u[2]*f,t},random:function(t,n){n=n||1;var a=2*r()*Math.PI,u=2*r()-1,e=Math.sqrt(1-u*u)*n;return t[0]=Math.cos(a)*e,t[1]=Math.sin(a)*e,t[2]=u*n,t},transformMat4:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[3]*r+a[7]*u+a[11]*e+a[15];return o=o||1,t[0]=(a[0]*r+a[4]*u+a[8]*e+a[12])/o,t[1]=(a[1]*r+a[5]*u+a[9]*e+a[13])/o,t[2]=(a[2]*r+a[6]*u+a[10]*e+a[14])/o,t},transformMat3:function(t,n,a){var r=n[0],u=n[1],e=n[2];return t[0]=r*a[0]+u*a[3]+e*a[6],t[1]=r*a[1]+u*a[4]+e*a[7],t[2]=r*a[2]+u*a[5]+e*a[8],t},transformQuat:function(t,n,a){var r=a[0],u=a[1],e=a[2],o=a[3],i=n[0],c=n[1],h=n[2],s=u*h-e*c,M=e*i-r*h,f=r*c-u*i,l=u*f-e*M,v=e*s-r*f,b=r*M-u*s,m=2*o;return s*=m,M*=m,f*=m,l*=2,v*=2,b*=2,t[0]=i+s+l,t[1]=c+M+v,t[2]=h+f+b,t},rotateX:function(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[0],e[1]=u[1]*Math.cos(r)-u[2]*Math.sin(r),e[2]=u[1]*Math.sin(r)+u[2]*Math.cos(r),t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t},rotateY:function(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[2]*Math.sin(r)+u[0]*Math.cos(r),e[1]=u[1],e[2]=u[2]*Math.cos(r)-u[0]*Math.sin(r),t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t},rotateZ:function(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[0]*Math.cos(r)-u[1]*Math.sin(r),e[1]=u[0]*Math.sin(r)+u[1]*Math.cos(r),e[2]=u[2],t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t},angle:function(t,n){var a=D(t[0],t[1],t[2]),r=D(n[0],n[1],n[2]);Z(a,a),Z(r,r);var u=_(a,r);return u>1?0:u<-1?Math.PI:Math.acos(u)},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t},str:function(t){return"vec3("+t[0]+", "+t[1]+", "+t[2]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=a[0],i=a[1],c=a[2];return Math.abs(r-o)<=n*Math.max(1,Math.abs(r),Math.abs(o))&&Math.abs(u-i)<=n*Math.max(1,Math.abs(u),Math.abs(i))&&Math.abs(e-c)<=n*Math.max(1,Math.abs(e),Math.abs(c))},sub:k,mul:U,div:W,dist:C,sqrDist:G,len:H,sqrLen:J,forEach:K});function tt(){var t=new a(4);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[3]=0),t}function nt(t){var n=new a(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n}function at(t,n,r,u){var e=new a(4);return e[0]=t,e[1]=n,e[2]=r,e[3]=u,e}function rt(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t}function ut(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t}function et(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t}function ot(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}function it(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t[3]=n[3]*a[3],t}function ct(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t[3]=n[3]/a[3],t}function ht(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t}function st(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2],e=n[3]-t[3];return Math.hypot(a,r,u,e)}function Mt(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2],e=n[3]-t[3];return a*a+r*r+u*u+e*e}function ft(t){var n=t[0],a=t[1],r=t[2],u=t[3];return Math.hypot(n,a,r,u)}function lt(t){var n=t[0],a=t[1],r=t[2],u=t[3];return n*n+a*a+r*r+u*u}function vt(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e;return o>0&&(o=1/Math.sqrt(o)),t[0]=a*o,t[1]=r*o,t[2]=u*o,t[3]=e*o,t}function bt(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]+t[3]*n[3]}function mt(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t[2]=o+r*(a[2]-o),t[3]=i+r*(a[3]-i),t}function dt(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]}function xt(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=a[0],c=a[1],h=a[2],s=a[3];return Math.abs(r-i)<=n*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-c)<=n*Math.max(1,Math.abs(u),Math.abs(c))&&Math.abs(e-h)<=n*Math.max(1,Math.abs(e),Math.abs(h))&&Math.abs(o-s)<=n*Math.max(1,Math.abs(o),Math.abs(s))}var pt=ot,yt=it,qt=ct,gt=st,At=Mt,wt=ft,Rt=lt,zt=function(){var t=tt();return function(n,a,r,u,e,o){var i,c;for(a||(a=4),r||(r=0),c=u?Math.min(u*a+r,n.length):n.length,i=r;i<c;i+=a)t[0]=n[i],t[1]=n[i+1],t[2]=n[i+2],t[3]=n[i+3],e(t,t,o),n[i]=t[0],n[i+1]=t[1],n[i+2]=t[2],n[i+3]=t[3];return n}}(),Pt=Object.freeze({create:tt,clone:nt,fromValues:at,copy:rt,set:ut,add:et,subtract:ot,multiply:it,divide:ct,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t[2]=Math.ceil(n[2]),t[3]=Math.ceil(n[3]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t[2]=Math.floor(n[2]),t[3]=Math.floor(n[3]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t[2]=Math.min(n[2],a[2]),t[3]=Math.min(n[3],a[3]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t[2]=Math.max(n[2],a[2]),t[3]=Math.max(n[3],a[3]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t[2]=Math.round(n[2]),t[3]=Math.round(n[3]),t},scale:ht,scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t},distance:st,squaredDistance:Mt,length:ft,squaredLength:lt,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=-n[3],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t[2]=1/n[2],t[3]=1/n[3],t},normalize:vt,dot:bt,cross:function(t,n,a,r){var u=a[0]*r[1]-a[1]*r[0],e=a[0]*r[2]-a[2]*r[0],o=a[0]*r[3]-a[3]*r[0],i=a[1]*r[2]-a[2]*r[1],c=a[1]*r[3]-a[3]*r[1],h=a[2]*r[3]-a[3]*r[2],s=n[0],M=n[1],f=n[2],l=n[3];return t[0]=M*h-f*c+l*i,t[1]=-s*h+f*o-l*e,t[2]=s*c-M*o+l*u,t[3]=-s*i+M*e-f*u,t},lerp:mt,random:function(t,n){var a,u,e,o,i,c;n=n||1;do{i=(a=2*r()-1)*a+(u=2*r()-1)*u}while(i>=1);do{c=(e=2*r()-1)*e+(o=2*r()-1)*o}while(c>=1);var h=Math.sqrt((1-i)/c);return t[0]=n*a,t[1]=n*u,t[2]=n*e*h,t[3]=n*o*h,t},transformMat4:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3];return t[0]=a[0]*r+a[4]*u+a[8]*e+a[12]*o,t[1]=a[1]*r+a[5]*u+a[9]*e+a[13]*o,t[2]=a[2]*r+a[6]*u+a[10]*e+a[14]*o,t[3]=a[3]*r+a[7]*u+a[11]*e+a[15]*o,t},transformQuat:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],c=a[2],h=a[3],s=h*r+i*e-c*u,M=h*u+c*r-o*e,f=h*e+o*u-i*r,l=-o*r-i*u-c*e;return t[0]=s*h+l*-o+M*-c-f*-i,t[1]=M*h+l*-i+f*-o-s*-c,t[2]=f*h+l*-c+s*-i-M*-o,t[3]=n[3],t},zero:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=0,t},str:function(t){return"vec4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},exactEquals:dt,equals:xt,sub:pt,mul:yt,div:qt,dist:gt,sqrDist:At,len:wt,sqrLen:Rt,forEach:zt});function jt(){var t=new a(4);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t[3]=1,t}function It(t,n,a){a*=.5;var r=Math.sin(a);return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=Math.cos(a),t}function St(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*s+o*i+u*h-e*c,t[1]=u*s+o*c+e*i-r*h,t[2]=e*s+o*h+r*c-u*i,t[3]=o*s-r*i-u*c-e*h,t}function Et(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+o*i,t[1]=u*c+e*i,t[2]=e*c-u*i,t[3]=o*c-r*i,t}function Ot(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c-e*i,t[1]=u*c+o*i,t[2]=e*c+r*i,t[3]=o*c-u*i,t}function Tt(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),c=Math.cos(a);return t[0]=r*c+u*i,t[1]=u*c-r*i,t[2]=e*c+o*i,t[3]=o*c-e*i,t}function Dt(t,a,r,u){var e,o,i,c,h,s=a[0],M=a[1],f=a[2],l=a[3],v=r[0],b=r[1],m=r[2],d=r[3];return(o=s*v+M*b+f*m+l*d)<0&&(o=-o,v=-v,b=-b,m=-m,d=-d),1-o>n?(e=Math.acos(o),i=Math.sin(e),c=Math.sin((1-u)*e)/i,h=Math.sin(u*e)/i):(c=1-u,h=u),t[0]=c*s+h*v,t[1]=c*M+h*b,t[2]=c*f+h*m,t[3]=c*l+h*d,t}function Ft(t,n){var a,r=n[0]+n[4]+n[8];if(r>0)a=Math.sqrt(r+1),t[3]=.5*a,a=.5/a,t[0]=(n[5]-n[7])*a,t[1]=(n[6]-n[2])*a,t[2]=(n[1]-n[3])*a;else{var u=0;n[4]>n[0]&&(u=1),n[8]>n[3*u+u]&&(u=2);var e=(u+1)%3,o=(u+2)%3;a=Math.sqrt(n[3*u+u]-n[3*e+e]-n[3*o+o]+1),t[u]=.5*a,a=.5/a,t[3]=(n[3*e+o]-n[3*o+e])*a,t[e]=(n[3*e+u]+n[3*u+e])*a,t[o]=(n[3*o+u]+n[3*u+o])*a}return t}var Lt,Vt,Qt,Yt,Xt,Zt,_t=nt,Bt=at,Nt=rt,kt=ut,Ut=et,Wt=St,Ct=ht,Gt=bt,Ht=mt,Jt=ft,Kt=Jt,$t=lt,tn=$t,nn=vt,an=dt,rn=xt,un=(Lt=O(),Vt=D(1,0,0),Qt=D(0,1,0),function(t,n,a){var r=_(n,a);return r<-.999999?(B(Lt,Vt,n),H(Lt)<1e-6&&B(Lt,Qt,n),Z(Lt,Lt),It(t,Lt,Math.PI),t):r>.999999?(t[0]=0,t[1]=0,t[2]=0,t[3]=1,t):(B(Lt,n,a),t[0]=Lt[0],t[1]=Lt[1],t[2]=Lt[2],t[3]=1+r,nn(t,t))}),en=(Yt=jt(),Xt=jt(),function(t,n,a,r,u,e){return Dt(Yt,n,u,e),Dt(Xt,a,r,e),Dt(t,Yt,Xt,2*e*(1-e)),t}),on=(Zt=m(),function(t,n,a,r){return Zt[0]=a[0],Zt[3]=a[1],Zt[6]=a[2],Zt[1]=r[0],Zt[4]=r[1],Zt[7]=r[2],Zt[2]=-n[0],Zt[5]=-n[1],Zt[8]=-n[2],nn(t,Ft(t,Zt))}),cn=Object.freeze({create:jt,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t},setAxisAngle:It,getAxisAngle:function(t,a){var r=2*Math.acos(a[3]),u=Math.sin(r/2);return u>n?(t[0]=a[0]/u,t[1]=a[1]/u,t[2]=a[2]/u):(t[0]=1,t[1]=0,t[2]=0),r},multiply:St,rotateX:Et,rotateY:Ot,rotateZ:Tt,calculateW:function(t,n){var a=n[0],r=n[1],u=n[2];return t[0]=a,t[1]=r,t[2]=u,t[3]=Math.sqrt(Math.abs(1-a*a-r*r-u*u)),t},slerp:Dt,random:function(t){var n=r(),a=r(),u=r(),e=Math.sqrt(1-n),o=Math.sqrt(n);return t[0]=e*Math.sin(2*Math.PI*a),t[1]=e*Math.cos(2*Math.PI*a),t[2]=o*Math.sin(2*Math.PI*u),t[3]=o*Math.cos(2*Math.PI*u),t},invert:function(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e,i=o?1/o:0;return t[0]=-a*i,t[1]=-r*i,t[2]=-u*i,t[3]=e*i,t},conjugate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t},fromMat3:Ft,fromEuler:function(t,n,a,r){var u=.5*Math.PI/180;n*=u,a*=u,r*=u;var e=Math.sin(n),o=Math.cos(n),i=Math.sin(a),c=Math.cos(a),h=Math.sin(r),s=Math.cos(r);return t[0]=e*c*s-o*i*h,t[1]=o*i*s+e*c*h,t[2]=o*c*h-e*i*s,t[3]=o*c*s+e*i*h,t},str:function(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"},clone:_t,fromValues:Bt,copy:Nt,set:kt,add:Ut,mul:Wt,scale:Ct,dot:Gt,lerp:Ht,length:Jt,len:Kt,squaredLength:$t,sqrLen:tn,normalize:nn,exactEquals:an,equals:rn,rotationTo:un,sqlerp:en,setAxes:on});function hn(t,n,a){var r=.5*a[0],u=.5*a[1],e=.5*a[2],o=n[0],i=n[1],c=n[2],h=n[3];return t[0]=o,t[1]=i,t[2]=c,t[3]=h,t[4]=r*h+u*c-e*i,t[5]=u*h+e*o-r*c,t[6]=e*h+r*i-u*o,t[7]=-r*o-u*i-e*c,t}function sn(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t}var Mn=Nt;var fn=Nt;function ln(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[4],c=a[5],h=a[6],s=a[7],M=n[4],f=n[5],l=n[6],v=n[7],b=a[0],m=a[1],d=a[2],x=a[3];return t[0]=r*x+o*b+u*d-e*m,t[1]=u*x+o*m+e*b-r*d,t[2]=e*x+o*d+r*m-u*b,t[3]=o*x-r*b-u*m-e*d,t[4]=r*s+o*i+u*h-e*c+M*x+v*b+f*d-l*m,t[5]=u*s+o*c+e*i-r*h+f*x+v*m+l*b-M*d,t[6]=e*s+o*h+r*c-u*i+l*x+v*d+M*m-f*b,t[7]=o*s-r*i-u*c-e*h+v*x-M*b-f*m-l*d,t}var vn=ln;var bn=Gt;var mn=Jt,dn=mn,xn=$t,pn=xn;var yn=Object.freeze({create:function(){var t=new a(8);return a!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[4]=0,t[5]=0,t[6]=0,t[7]=0),t[3]=1,t},clone:function(t){var n=new a(8);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n},fromValues:function(t,n,r,u,e,o,i,c){var h=new a(8);return h[0]=t,h[1]=n,h[2]=r,h[3]=u,h[4]=e,h[5]=o,h[6]=i,h[7]=c,h},fromRotationTranslationValues:function(t,n,r,u,e,o,i){var c=new a(8);c[0]=t,c[1]=n,c[2]=r,c[3]=u;var h=.5*e,s=.5*o,M=.5*i;return c[4]=h*u+s*r-M*n,c[5]=s*u+M*t-h*r,c[6]=M*u+h*n-s*t,c[7]=-h*t-s*n-M*r,c},fromRotationTranslation:hn,fromTranslation:function(t,n){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=.5*n[0],t[5]=.5*n[1],t[6]=.5*n[2],t[7]=0,t},fromRotation:function(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},fromMat4:function(t,n){var r=jt();P(r,n);var u=new a(3);return R(u,n),hn(t,r,u),t},copy:sn,identity:function(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t[6]=0,t[7]=0,t},set:function(t,n,a,r,u,e,o,i,c){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=c,t},getReal:Mn,getDual:function(t,n){return t[0]=n[4],t[1]=n[5],t[2]=n[6],t[3]=n[7],t},setReal:fn,setDual:function(t,n){return t[4]=n[0],t[5]=n[1],t[6]=n[2],t[7]=n[3],t},getTranslation:function(t,n){var a=n[4],r=n[5],u=n[6],e=n[7],o=-n[0],i=-n[1],c=-n[2],h=n[3];return t[0]=2*(a*h+e*o+r*c-u*i),t[1]=2*(r*h+e*i+u*o-a*c),t[2]=2*(u*h+e*c+a*i-r*o),t},translate:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=.5*a[0],c=.5*a[1],h=.5*a[2],s=n[4],M=n[5],f=n[6],l=n[7];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=o*i+u*h-e*c+s,t[5]=o*c+e*i-r*h+M,t[6]=o*h+r*c-u*i+f,t[7]=-r*i-u*c-e*h+l,t},rotateX:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Et(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateY:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Ot(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateZ:function(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],c=n[5],h=n[6],s=n[7],M=i*o+s*r+c*e-h*u,f=c*o+s*u+h*r-i*e,l=h*o+s*e+i*u-c*r,v=s*o-i*r-c*u-h*e;return Tt(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t},rotateByQuatAppend:function(t,n,a){var r=a[0],u=a[1],e=a[2],o=a[3],i=n[0],c=n[1],h=n[2],s=n[3];return t[0]=i*o+s*r+c*e-h*u,t[1]=c*o+s*u+h*r-i*e,t[2]=h*o+s*e+i*u-c*r,t[3]=s*o-i*r-c*u-h*e,i=n[4],c=n[5],h=n[6],s=n[7],t[4]=i*o+s*r+c*e-h*u,t[5]=c*o+s*u+h*r-i*e,t[6]=h*o+s*e+i*u-c*r,t[7]=s*o-i*r-c*u-h*e,t},rotateByQuatPrepend:function(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],c=a[1],h=a[2],s=a[3];return t[0]=r*s+o*i+u*h-e*c,t[1]=u*s+o*c+e*i-r*h,t[2]=e*s+o*h+r*c-u*i,t[3]=o*s-r*i-u*c-e*h,i=a[4],c=a[5],h=a[6],s=a[7],t[4]=r*s+o*i+u*h-e*c,t[5]=u*s+o*c+e*i-r*h,t[6]=e*s+o*h+r*c-u*i,t[7]=o*s-r*i-u*c-e*h,t},rotateAroundAxis:function(t,a,r,u){if(Math.abs(u)<n)return sn(t,a);var e=Math.hypot(r[0],r[1],r[2]);u*=.5;var o=Math.sin(u),i=o*r[0]/e,c=o*r[1]/e,h=o*r[2]/e,s=Math.cos(u),M=a[0],f=a[1],l=a[2],v=a[3];t[0]=M*s+v*i+f*h-l*c,t[1]=f*s+v*c+l*i-M*h,t[2]=l*s+v*h+M*c-f*i,t[3]=v*s-M*i-f*c-l*h;var b=a[4],m=a[5],d=a[6],x=a[7];return t[4]=b*s+x*i+m*h-d*c,t[5]=m*s+x*c+d*i-b*h,t[6]=d*s+x*h+b*c-m*i,t[7]=x*s-b*i-m*c-d*h,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t},multiply:ln,mul:vn,scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t},dot:bn,lerp:function(t,n,a,r){var u=1-r;return bn(n,a)<0&&(r=-r),t[0]=n[0]*u+a[0]*r,t[1]=n[1]*u+a[1]*r,t[2]=n[2]*u+a[2]*r,t[3]=n[3]*u+a[3]*r,t[4]=n[4]*u+a[4]*r,t[5]=n[5]*u+a[5]*r,t[6]=n[6]*u+a[6]*r,t[7]=n[7]*u+a[7]*r,t},invert:function(t,n){var a=xn(n);return t[0]=-n[0]/a,t[1]=-n[1]/a,t[2]=-n[2]/a,t[3]=n[3]/a,t[4]=-n[4]/a,t[5]=-n[5]/a,t[6]=-n[6]/a,t[7]=n[7]/a,t},conjugate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t[4]=-n[4],t[5]=-n[5],t[6]=-n[6],t[7]=n[7],t},length:mn,len:dn,squaredLength:xn,sqrLen:pn,normalize:function(t,n){var a=xn(n);if(a>0){a=Math.sqrt(a);var r=n[0]/a,u=n[1]/a,e=n[2]/a,o=n[3]/a,i=n[4],c=n[5],h=n[6],s=n[7],M=r*i+u*c+e*h+o*s;t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=(i-r*M)/a,t[5]=(c-u*M)/a,t[6]=(h-e*M)/a,t[7]=(s-o*M)/a}return t},str:function(t){return"quat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]},equals:function(t,a){var r=t[0],u=t[1],e=t[2],o=t[3],i=t[4],c=t[5],h=t[6],s=t[7],M=a[0],f=a[1],l=a[2],v=a[3],b=a[4],m=a[5],d=a[6],x=a[7];return Math.abs(r-M)<=n*Math.max(1,Math.abs(r),Math.abs(M))&&Math.abs(u-f)<=n*Math.max(1,Math.abs(u),Math.abs(f))&&Math.abs(e-l)<=n*Math.max(1,Math.abs(e),Math.abs(l))&&Math.abs(o-v)<=n*Math.max(1,Math.abs(o),Math.abs(v))&&Math.abs(i-b)<=n*Math.max(1,Math.abs(i),Math.abs(b))&&Math.abs(c-m)<=n*Math.max(1,Math.abs(c),Math.abs(m))&&Math.abs(h-d)<=n*Math.max(1,Math.abs(h),Math.abs(d))&&Math.abs(s-x)<=n*Math.max(1,Math.abs(s),Math.abs(x))}});function qn(){var t=new a(2);return a!=Float32Array&&(t[0]=0,t[1]=0),t}function gn(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t}function An(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t}function wn(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t}function Rn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return Math.hypot(a,r)}function zn(t,n){var a=n[0]-t[0],r=n[1]-t[1];return a*a+r*r}function Pn(t){var n=t[0],a=t[1];return Math.hypot(n,a)}function jn(t){var n=t[0],a=t[1];return n*n+a*a}var In=Pn,Sn=gn,En=An,On=wn,Tn=Rn,Dn=zn,Fn=jn,Ln=function(){var t=qn();return function(n,a,r,u,e,o){var i,c;for(a||(a=2),r||(r=0),c=u?Math.min(u*a+r,n.length):n.length,i=r;i<c;i+=a)t[0]=n[i],t[1]=n[i+1],e(t,t,o),n[i]=t[0],n[i+1]=t[1];return n}}(),Vn=Object.freeze({create:qn,clone:function(t){var n=new a(2);return n[0]=t[0],n[1]=t[1],n},fromValues:function(t,n){var r=new a(2);return r[0]=t,r[1]=n,r},copy:function(t,n){return t[0]=n[0],t[1]=n[1],t},set:function(t,n,a){return t[0]=n,t[1]=a,t},add:function(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t},subtract:gn,multiply:An,divide:wn,ceil:function(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t},floor:function(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t},min:function(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t},max:function(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t},round:function(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t},scale:function(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t},scaleAndAdd:function(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t},distance:Rn,squaredDistance:zn,length:Pn,squaredLength:jn,negate:function(t,n){return t[0]=-n[0],t[1]=-n[1],t},inverse:function(t,n){return t[0]=1/n[0],t[1]=1/n[1],t},normalize:function(t,n){var a=n[0],r=n[1],u=a*a+r*r;return u>0&&(u=1/Math.sqrt(u)),t[0]=n[0]*u,t[1]=n[1]*u,t},dot:function(t,n){return t[0]*n[0]+t[1]*n[1]},cross:function(t,n,a){var r=n[0]*a[1]-n[1]*a[0];return t[0]=t[1]=0,t[2]=r,t},lerp:function(t,n,a,r){var u=n[0],e=n[1];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t},random:function(t,n){n=n||1;var a=2*r()*Math.PI;return t[0]=Math.cos(a)*n,t[1]=Math.sin(a)*n,t},transformMat2:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u,t[1]=a[1]*r+a[3]*u,t},transformMat2d:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u+a[4],t[1]=a[1]*r+a[3]*u+a[5],t},transformMat3:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[3]*u+a[6],t[1]=a[1]*r+a[4]*u+a[7],t},transformMat4:function(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[4]*u+a[12],t[1]=a[1]*r+a[5]*u+a[13],t},rotate:function(t,n,a,r){var u=n[0]-a[0],e=n[1]-a[1],o=Math.sin(r),i=Math.cos(r);return t[0]=u*i-e*o+a[0],t[1]=u*o+e*i+a[1],t},angle:function(t,n){var a=t[0],r=t[1],u=n[0],e=n[1],o=a*a+r*r;o>0&&(o=1/Math.sqrt(o));var i=u*u+e*e;i>0&&(i=1/Math.sqrt(i));var c=(a*u+r*e)*o*i;return c>1?0:c<-1?Math.PI:Math.acos(c)},zero:function(t){return t[0]=0,t[1]=0,t},str:function(t){return"vec2("+t[0]+", "+t[1]+")"},exactEquals:function(t,n){return t[0]===n[0]&&t[1]===n[1]},equals:function(t,a){var r=t[0],u=t[1],e=a[0],o=a[1];return Math.abs(r-e)<=n*Math.max(1,Math.abs(r),Math.abs(e))&&Math.abs(u-o)<=n*Math.max(1,Math.abs(u),Math.abs(o))},len:In,sub:Sn,mul:En,div:On,dist:Tn,sqrDist:Dn,sqrLen:Fn,forEach:Ln});t.glMatrix=e,t.mat2=s,t.mat2d=b,t.mat3=q,t.mat4=E,t.quat=cn,t.quat2=yn,t.vec2=Vn,t.vec3=$,t.vec4=Pt,Object.defineProperty(t,"__esModule",{value:!0})});
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+        // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl")
+		       || canvas.getContext("experimental-webgl");
+        gl.viewport(0,0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+
+    return true;
+}
+
+var shaderProgram;
+
+function initialiseBuffer() {
+    var vertexData = [
+		-0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		//3
+        0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		//1
+		0.5, 0.5, -0.5,		1.0, 1.0, 1.0, 0.5,		//2
+
+		-0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		//3
+		0.5, 0.5, -0.5,		1.0, 1.0, 1.0, 0.5,		//2
+		-0.5, 0.5, -0.5,	1.0, 1.0, 1.0, 0.5,		//4
+
+		0.5, 0.5, -0.5,		0.0, 0.0, 0.0, 0.5,		 //2
+		0.5, -0.5, -0.5,	0.0, 0.0, 0.0, 0.5,		 //6
+		-0.5,-0.5,-0.5,		0.0, 0.0, 0.0, 0.5,		 //8
+
+		-0.5, 0.5, -0.5,	0.0, 0.0, 0.0, 0.5,		 //4
+		0.5, 0.5, -0.5,		0.0, 0.0, 0.0, 0.5,		 //2
+		-0.5,-0.5,-0.5,		0.0, 0.0, 0.0, 0.5,		 //8
+
+		0.5, -0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		//5
+		0.5, -0.5, -0.5,	1.0, 0.5, 0.0, 0.5,		//6
+		0.5, 0.5, -0.5,		1.0, 0.5, 0.0, 0.5,		//2
+
+		0.5, -0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		//5
+		0.5, 0.5, -0.5,		1.0, 0.5, 0.0, 0.5,		//2
+		0.5, 0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		//1
+
+		-0.5, 0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		 //4
+		-0.5,-0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		 //8
+		-0.5, -0.5, 0.5,	1.0, 0.0, 0.0, 0.5,		 //7
+
+		-0.5, 0.5, 0.5,		1.0, 0.0, 0.0, 0.5,		//3
+		-0.5, 0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		//4
+		-0.5, -0.5, 0.5,	1.0, 0.0, 0.0, 0.5,		//7
+
+		-0.5, -0.5, 0.5,	0.0, 0.0, 1.0, 0.5,		//7
+		0.5, -0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		//5
+		0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		//1
+
+		-0.5, -0.5, 0.5,	0.0, 0.0, 1.0, 0.5,		//7
+		0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		//1
+		-0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		//3
+
+		 0.5, -0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		//6
+		 0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		//5
+		-0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		//7
+
+		-0.5,-0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		//8
+		 0.5, -0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		//6
+		-0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		//7
+    ];
+
+    // Generate a buffer object
+    gl.vertexBuffer = gl.createBuffer();
+
+    // Bind buffer as a vertex buffer so we can fill it with data
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+    var fragmentShaderSource = '\
+			varying highp vec4 color; \
+			void main(void) \
+			{ \
+				gl_FragColor = color; \
+			}';
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    var vertexShaderSource = '\
+			attribute highp vec3 myVertex; \
+			attribute highp vec4 myColor; \
+			uniform mediump mat4 transformationMatrix; \
+			varying highp vec4 color; \
+			void main(void)  \
+			{ \
+				gl_Position = transformationMatrix * vec4(myVertex, 1); \
+				color = myColor; \
+			}';
+
+    // Create the vertex shader object
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+
+    // Load the source code into it
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+
+    // Compile the source code
+    gl.compileShader(gl.vertexShader);
+
+    // Check if compilation succeeded
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        // It didn't. Display the info log as to why
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    // Create the shader program
+    gl.programObject = gl.createProgram();
+
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+
+    // Link the program
+    gl.linkProgram(gl.programObject);
+
+    // Check if linking succeeded in a similar way we checked for compilation errors
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+
+    return testGLError("initialiseShaders");
+}
+
+var mouseEventTypes = ["client", "page", "screen"];
+
+var modeMET = 0;
+function changeMET()
+{
+	modeMET++;
+	modeMET%=3;
+	// console.log("mouseEventType =" + modeMET);
+	document.getElementById("butMET").innerHTML = mouseEventTypes[modeMET];
+}
+
+var rot_z = 0.0;
+
+function renderScene() {
+
+    gl.clearColor(0.2,0.2,0.2, 1.0);
+	gl.clear(gl.COLOR_BUFFER_BIT);
+
+    var matrixLocation = gl.getUniformLocation(gl.programObject, "transformationMatrix");
+
+    // create identity 4x4 matrix
+	var transformationMatrix = glMatrix.mat4.create();
+	rot_z += 1;
+    // transformationMatrix = glMatrix.mat4.fromRotation(transformationMatrix, rot_z, glMatrix.vec3.fromValues(1, 0, 0));
+    var q = glMatrix.quat.create();
+    glMatrix.quat.fromEuler(q, rot_z, 0, 0);
+    glMatrix.mat4.fromRotationTranslationScale(transformationMatrix, q, glMatrix.vec3.fromValues(glx, gly, 0), glMatrix.vec3.fromValues(0.1, 0.1, 0.1));
+
+    // Pass the identity transformation matrix to the shader using its location
+    gl.uniformMatrix4fv(matrixLocation, gl.FALSE, transformationMatrix);
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12);
+
+    // setting vertex color (out of scope of this tutorial)
+    gl.enable(gl.DEPTH_TEST);
+    gl.depthFunc(gl.LEQUAL);
+	gl.enable(gl.BLEND);
+	gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+
+    gl.clearColor(0.6, 0.8, 1.0, 1.0);
+    gl.clearDepth(1.0);
+    gl.clear(gl.DEPTH_BUFFER_BIT);
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+
+    // Do not render if any of glx or gly is null
+    if(glx && gly)
+	    gl.drawArrays(gl.TRIANGLES, 0, 36);
+
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function getCursorPosition(canvas, event) {
+    const rect = canvas.getBoundingClientRect();
+    // calculate position according to mouse event type
+    x = eval("event." + mouseEventTypes[modeMET] + "X - rect.left");
+    y = eval("event." + mouseEventTypes[modeMET] + "Y - rect.top");
+    // normalize given value to WebGL coordinate
+    glx = x / gl.canvas.width * 2 - 1;
+    gly = y / gl.canvas.height * -2 + 1;
+    // Update element in HTML
+	document.getElementById("pixelxybar").innerHTML = "Pixel>> X: " + x + " Y: " + y;
+	document.getElementById("webglxybar").innerHTML = "WebGL>> X: " + glx + " Y: " + gly;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+    if (!initialiseBuffer()) {
+        return;
+    }
+    if (!initialiseShaders()) {
+        return;
+    }
+
+    // Add handler for mousemove event
+    canvas.addEventListener('mousemove', function(e) {
+        getCursorPosition(canvas, e);
+    });
+
+    // Add hanler for mouseleave event
+    canvas.addEventListener('mouseleave', function(e) {
+	    document.getElementById("pixelxybar").innerHTML = "Mouse out of canvas";
+	    document.getElementById("webglxybar").innerHTML = "Mouse out of canvas";
+        glx = null;
+        gly = null;
+    });
+
+
+    // Render loop
+    requestAnimFrame = (function () {
+        return window.requestAnimationFrame ||
+		       window.webkitRequestAnimationFrame ||
+			   window.mozRequestAnimationFrame ||
+			function (callback) {
+			    window.setTimeout(callback, 1000, 60);
+			};
+    })();
+
+    (function renderLoop() {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            requestAnimFrame(renderLoop);
+        }
+    })();
+}
+
diff --git a/student2019/201620963/index.html b/student2019/201620963/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..f86bfee4e024df6255fd78280153b9d630ac537b
--- /dev/null
+++ b/student2019/201620963/index.html
@@ -0,0 +1,27 @@
+<!-- (CC-NC-BY) Jinwoo Hwang 2019 -->
+<html>
+
+<head>
+<title>WebGL Tutorial - Using mouse input</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+    <!-- use script from outside file -->
+    <script type="text/javascript" src="WebGLHelloAPI.js"> 
+</script>
+
+
+</head>
+<!-- main function will be called when body is loaded -->
+<body onload="main()"> 
+<H2> WebGL - Rotating Cube Following Mouse Cursor </H2>
+<H3>Reference Point type - client/page/screen</H3>
+<p id="pixelxybar" >Mouse out of canvas</p>
+<p id="webglxybar" >Mouse out of canvas</p>
+<!-- pressing button will call function to toggle mouse event type -->
+<button onclick="changeMET()" id="butMET"> client </button> </br>
+
+<!-- canvas the WebGL will be using -->
+<canvas id="helloapicanvas" style="border: none;" width="800" height="800"></canvas>
+
+<p> (CC-NC-BY) 2019 Jinwoo Hwang </p>
+</body>
+</html>
diff --git a/student2019/201621036/Thumbs.db b/student2019/201621036/Thumbs.db
new file mode 100644
index 0000000000000000000000000000000000000000..d00ed02c05e01a478d30cc1b9cbd15fd53cfe86b
Binary files /dev/null and b/student2019/201621036/Thumbs.db differ
diff --git a/student2019/201621036/gl-matrix.js b/student2019/201621036/gl-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..fcaf428550f58ab8fdb41a0607e93fbc8146a904
--- /dev/null
+++ b/student2019/201621036/gl-matrix.js
@@ -0,0 +1,6888 @@
+/**
+ * @fileoverview gl-matrix - High performance matrix and vector operations
+ * @author Brandon Jones
+ * @author Colin MacKenzie IV
+ * @version 2.4.0
+ */
+
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+(function webpackUniversalModuleDefinition(root, factory) {
+	if(typeof exports === 'object' && typeof module === 'object')
+		module.exports = factory();
+	else if(typeof define === 'function' && define.amd)
+		define([], factory);
+	else {
+		var a = factory();
+		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
+	}
+})(this, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+/******/
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+/******/
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId]) {
+/******/ 			return installedModules[moduleId].exports;
+/******/ 		}
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			i: moduleId,
+/******/ 			l: false,
+/******/ 			exports: {}
+/******/ 		};
+/******/
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ 		// Flag the module as loaded
+/******/ 		module.l = true;
+/******/
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+/******/
+/******/
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+/******/
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+/******/
+/******/ 	// define getter function for harmony exports
+/******/ 	__webpack_require__.d = function(exports, name, getter) {
+/******/ 		if(!__webpack_require__.o(exports, name)) {
+/******/ 			Object.defineProperty(exports, name, {
+/******/ 				configurable: false,
+/******/ 				enumerable: true,
+/******/ 				get: getter
+/******/ 			});
+/******/ 		}
+/******/ 	};
+/******/
+/******/ 	// getDefaultExport function for compatibility with non-harmony modules
+/******/ 	__webpack_require__.n = function(module) {
+/******/ 		var getter = module && module.__esModule ?
+/******/ 			function getDefault() { return module['default']; } :
+/******/ 			function getModuleExports() { return module; };
+/******/ 		__webpack_require__.d(getter, 'a', getter);
+/******/ 		return getter;
+/******/ 	};
+/******/
+/******/ 	// Object.prototype.hasOwnProperty.call
+/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+/******/
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(__webpack_require__.s = 4);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.setMatrixArrayType = setMatrixArrayType;
+exports.toRadian = toRadian;
+exports.equals = equals;
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+/**
+ * Common utilities
+ * @module glMatrix
+ */
+
+// Configuration Constants
+var EPSILON = exports.EPSILON = 0.000001;
+var ARRAY_TYPE = exports.ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+var RANDOM = exports.RANDOM = Math.random;
+
+/**
+ * Sets the type of array used when creating new vectors and matrices
+ *
+ * @param {Type} type Array type, such as Float32Array or Array
+ */
+function setMatrixArrayType(type) {
+  exports.ARRAY_TYPE = ARRAY_TYPE = type;
+}
+
+var degree = Math.PI / 180;
+
+/**
+ * Convert Degree To Radian
+ *
+ * @param {Number} a Angle in Degrees
+ */
+function toRadian(a) {
+  return a * degree;
+}
+
+/**
+ * Tests whether or not the arguments have approximately the same value, within an absolute
+ * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
+ * than or equal to 1.0, and a relative tolerance is used for larger values)
+ *
+ * @param {Number} a The first number to test.
+ * @param {Number} b The second number to test.
+ * @returns {Boolean} True if the numbers are approximately equal, false otherwise.
+ */
+function equals(a, b) {
+  return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
+}
+
+/***/ }),
+/* 1 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.sub = exports.mul = undefined;
+exports.create = create;
+exports.fromMat4 = fromMat4;
+exports.clone = clone;
+exports.copy = copy;
+exports.fromValues = fromValues;
+exports.set = set;
+exports.identity = identity;
+exports.transpose = transpose;
+exports.invert = invert;
+exports.adjoint = adjoint;
+exports.determinant = determinant;
+exports.multiply = multiply;
+exports.translate = translate;
+exports.rotate = rotate;
+exports.scale = scale;
+exports.fromTranslation = fromTranslation;
+exports.fromRotation = fromRotation;
+exports.fromScaling = fromScaling;
+exports.fromMat2d = fromMat2d;
+exports.fromQuat = fromQuat;
+exports.normalFromMat4 = normalFromMat4;
+exports.projection = projection;
+exports.str = str;
+exports.frob = frob;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiplyScalar = multiplyScalar;
+exports.multiplyScalarAndAdd = multiplyScalarAndAdd;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 3x3 Matrix
+ * @module mat3
+ */
+
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(9);
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 1;
+  out[5] = 0;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 1;
+  return out;
+}
+
+/**
+ * Copies the upper-left 3x3 values into the given mat3.
+ *
+ * @param {mat3} out the receiving 3x3 matrix
+ * @param {mat4} a   the source 4x4 matrix
+ * @returns {mat3} out
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function fromMat4(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[4];
+  out[4] = a[5];
+  out[5] = a[6];
+  out[6] = a[8];
+  out[7] = a[9];
+  out[8] = a[10];
+  return out;
+}
+
+/**
+ * Creates a new mat3 initialized with values from an existing matrix
+ *
+ * @param {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(9);
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  out[4] = a[4];
+  out[5] = a[5];
+  out[6] = a[6];
+  out[7] = a[7];
+  out[8] = a[8];
+  return out;
+}
+
+/**
+ * Copy the values from one mat3 to another
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  out[4] = a[4];
+  out[5] = a[5];
+  out[6] = a[6];
+  out[7] = a[7];
+  out[8] = a[8];
+  return out;
+}
+
+/**
+ * Create a new mat3 with the given values
+ *
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m10 Component in column 1, row 0 position (index 3)
+ * @param {Number} m11 Component in column 1, row 1 position (index 4)
+ * @param {Number} m12 Component in column 1, row 2 position (index 5)
+ * @param {Number} m20 Component in column 2, row 0 position (index 6)
+ * @param {Number} m21 Component in column 2, row 1 position (index 7)
+ * @param {Number} m22 Component in column 2, row 2 position (index 8)
+ * @returns {mat3} A new mat3
+ */
+function fromValues(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+  var out = new glMatrix.ARRAY_TYPE(9);
+  out[0] = m00;
+  out[1] = m01;
+  out[2] = m02;
+  out[3] = m10;
+  out[4] = m11;
+  out[5] = m12;
+  out[6] = m20;
+  out[7] = m21;
+  out[8] = m22;
+  return out;
+}
+
+/**
+ * Set the components of a mat3 to the given values
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m10 Component in column 1, row 0 position (index 3)
+ * @param {Number} m11 Component in column 1, row 1 position (index 4)
+ * @param {Number} m12 Component in column 1, row 2 position (index 5)
+ * @param {Number} m20 Component in column 2, row 0 position (index 6)
+ * @param {Number} m21 Component in column 2, row 1 position (index 7)
+ * @param {Number} m22 Component in column 2, row 2 position (index 8)
+ * @returns {mat3} out
+ */
+function set(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
+  out[0] = m00;
+  out[1] = m01;
+  out[2] = m02;
+  out[3] = m10;
+  out[4] = m11;
+  out[5] = m12;
+  out[6] = m20;
+  out[7] = m21;
+  out[8] = m22;
+  return out;
+}
+
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+function identity(out) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 1;
+  out[5] = 0;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 1;
+  return out;
+}
+
+/**
+ * Transpose the values of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+function transpose(out, a) {
+  // If we are transposing ourselves we can skip a few steps but have to cache some values
+  if (out === a) {
+    var a01 = a[1],
+        a02 = a[2],
+        a12 = a[5];
+    out[1] = a[3];
+    out[2] = a[6];
+    out[3] = a01;
+    out[5] = a[7];
+    out[6] = a02;
+    out[7] = a12;
+  } else {
+    out[0] = a[0];
+    out[1] = a[3];
+    out[2] = a[6];
+    out[3] = a[1];
+    out[4] = a[4];
+    out[5] = a[7];
+    out[6] = a[2];
+    out[7] = a[5];
+    out[8] = a[8];
+  }
+
+  return out;
+}
+
+/**
+ * Inverts a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+function invert(out, a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2];
+  var a10 = a[3],
+      a11 = a[4],
+      a12 = a[5];
+  var a20 = a[6],
+      a21 = a[7],
+      a22 = a[8];
+
+  var b01 = a22 * a11 - a12 * a21;
+  var b11 = -a22 * a10 + a12 * a20;
+  var b21 = a21 * a10 - a11 * a20;
+
+  // Calculate the determinant
+  var det = a00 * b01 + a01 * b11 + a02 * b21;
+
+  if (!det) {
+    return null;
+  }
+  det = 1.0 / det;
+
+  out[0] = b01 * det;
+  out[1] = (-a22 * a01 + a02 * a21) * det;
+  out[2] = (a12 * a01 - a02 * a11) * det;
+  out[3] = b11 * det;
+  out[4] = (a22 * a00 - a02 * a20) * det;
+  out[5] = (-a12 * a00 + a02 * a10) * det;
+  out[6] = b21 * det;
+  out[7] = (-a21 * a00 + a01 * a20) * det;
+  out[8] = (a11 * a00 - a01 * a10) * det;
+  return out;
+}
+
+/**
+ * Calculates the adjugate of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+function adjoint(out, a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2];
+  var a10 = a[3],
+      a11 = a[4],
+      a12 = a[5];
+  var a20 = a[6],
+      a21 = a[7],
+      a22 = a[8];
+
+  out[0] = a11 * a22 - a12 * a21;
+  out[1] = a02 * a21 - a01 * a22;
+  out[2] = a01 * a12 - a02 * a11;
+  out[3] = a12 * a20 - a10 * a22;
+  out[4] = a00 * a22 - a02 * a20;
+  out[5] = a02 * a10 - a00 * a12;
+  out[6] = a10 * a21 - a11 * a20;
+  out[7] = a01 * a20 - a00 * a21;
+  out[8] = a00 * a11 - a01 * a10;
+  return out;
+}
+
+/**
+ * Calculates the determinant of a mat3
+ *
+ * @param {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+function determinant(a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2];
+  var a10 = a[3],
+      a11 = a[4],
+      a12 = a[5];
+  var a20 = a[6],
+      a21 = a[7],
+      a22 = a[8];
+
+  return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+}
+
+/**
+ * Multiplies two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+function multiply(out, a, b) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2];
+  var a10 = a[3],
+      a11 = a[4],
+      a12 = a[5];
+  var a20 = a[6],
+      a21 = a[7],
+      a22 = a[8];
+
+  var b00 = b[0],
+      b01 = b[1],
+      b02 = b[2];
+  var b10 = b[3],
+      b11 = b[4],
+      b12 = b[5];
+  var b20 = b[6],
+      b21 = b[7],
+      b22 = b[8];
+
+  out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+  out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+  out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+
+  out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+  out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+  out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+
+  out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+  out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+  out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+  return out;
+}
+
+/**
+ * Translate a mat3 by the given vector
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to translate
+ * @param {vec2} v vector to translate by
+ * @returns {mat3} out
+ */
+function translate(out, a, v) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a10 = a[3],
+      a11 = a[4],
+      a12 = a[5],
+      a20 = a[6],
+      a21 = a[7],
+      a22 = a[8],
+      x = v[0],
+      y = v[1];
+
+  out[0] = a00;
+  out[1] = a01;
+  out[2] = a02;
+
+  out[3] = a10;
+  out[4] = a11;
+  out[5] = a12;
+
+  out[6] = x * a00 + y * a10 + a20;
+  out[7] = x * a01 + y * a11 + a21;
+  out[8] = x * a02 + y * a12 + a22;
+  return out;
+}
+
+/**
+ * Rotates a mat3 by the given angle
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+function rotate(out, a, rad) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a10 = a[3],
+      a11 = a[4],
+      a12 = a[5],
+      a20 = a[6],
+      a21 = a[7],
+      a22 = a[8],
+      s = Math.sin(rad),
+      c = Math.cos(rad);
+
+  out[0] = c * a00 + s * a10;
+  out[1] = c * a01 + s * a11;
+  out[2] = c * a02 + s * a12;
+
+  out[3] = c * a10 - s * a00;
+  out[4] = c * a11 - s * a01;
+  out[5] = c * a12 - s * a02;
+
+  out[6] = a20;
+  out[7] = a21;
+  out[8] = a22;
+  return out;
+};
+
+/**
+ * Scales the mat3 by the dimensions in the given vec2
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat3} out
+ **/
+function scale(out, a, v) {
+  var x = v[0],
+      y = v[1];
+
+  out[0] = x * a[0];
+  out[1] = x * a[1];
+  out[2] = x * a[2];
+
+  out[3] = y * a[3];
+  out[4] = y * a[4];
+  out[5] = y * a[5];
+
+  out[6] = a[6];
+  out[7] = a[7];
+  out[8] = a[8];
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector translation
+ * This is equivalent to (but much faster than):
+ *
+ *     mat3.identity(dest);
+ *     mat3.translate(dest, dest, vec);
+ *
+ * @param {mat3} out mat3 receiving operation result
+ * @param {vec2} v Translation vector
+ * @returns {mat3} out
+ */
+function fromTranslation(out, v) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 1;
+  out[5] = 0;
+  out[6] = v[0];
+  out[7] = v[1];
+  out[8] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from a given angle
+ * This is equivalent to (but much faster than):
+ *
+ *     mat3.identity(dest);
+ *     mat3.rotate(dest, dest, rad);
+ *
+ * @param {mat3} out mat3 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+function fromRotation(out, rad) {
+  var s = Math.sin(rad),
+      c = Math.cos(rad);
+
+  out[0] = c;
+  out[1] = s;
+  out[2] = 0;
+
+  out[3] = -s;
+  out[4] = c;
+  out[5] = 0;
+
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ *     mat3.identity(dest);
+ *     mat3.scale(dest, dest, vec);
+ *
+ * @param {mat3} out mat3 receiving operation result
+ * @param {vec2} v Scaling vector
+ * @returns {mat3} out
+ */
+function fromScaling(out, v) {
+  out[0] = v[0];
+  out[1] = 0;
+  out[2] = 0;
+
+  out[3] = 0;
+  out[4] = v[1];
+  out[5] = 0;
+
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 1;
+  return out;
+}
+
+/**
+ * Copies the values from a mat2d into a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat2d} a the matrix to copy
+ * @returns {mat3} out
+ **/
+function fromMat2d(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = 0;
+
+  out[3] = a[2];
+  out[4] = a[3];
+  out[5] = 0;
+
+  out[6] = a[4];
+  out[7] = a[5];
+  out[8] = 1;
+  return out;
+}
+
+/**
+* Calculates a 3x3 matrix from the given quaternion
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {quat} q Quaternion to create matrix from
+*
+* @returns {mat3} out
+*/
+function fromQuat(out, q) {
+  var x = q[0],
+      y = q[1],
+      z = q[2],
+      w = q[3];
+  var x2 = x + x;
+  var y2 = y + y;
+  var z2 = z + z;
+
+  var xx = x * x2;
+  var yx = y * x2;
+  var yy = y * y2;
+  var zx = z * x2;
+  var zy = z * y2;
+  var zz = z * z2;
+  var wx = w * x2;
+  var wy = w * y2;
+  var wz = w * z2;
+
+  out[0] = 1 - yy - zz;
+  out[3] = yx - wz;
+  out[6] = zx + wy;
+
+  out[1] = yx + wz;
+  out[4] = 1 - xx - zz;
+  out[7] = zy - wx;
+
+  out[2] = zx - wy;
+  out[5] = zy + wx;
+  out[8] = 1 - xx - yy;
+
+  return out;
+}
+
+/**
+* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {mat4} a Mat4 to derive the normal matrix from
+*
+* @returns {mat3} out
+*/
+function normalFromMat4(out, a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a03 = a[3];
+  var a10 = a[4],
+      a11 = a[5],
+      a12 = a[6],
+      a13 = a[7];
+  var a20 = a[8],
+      a21 = a[9],
+      a22 = a[10],
+      a23 = a[11];
+  var a30 = a[12],
+      a31 = a[13],
+      a32 = a[14],
+      a33 = a[15];
+
+  var b00 = a00 * a11 - a01 * a10;
+  var b01 = a00 * a12 - a02 * a10;
+  var b02 = a00 * a13 - a03 * a10;
+  var b03 = a01 * a12 - a02 * a11;
+  var b04 = a01 * a13 - a03 * a11;
+  var b05 = a02 * a13 - a03 * a12;
+  var b06 = a20 * a31 - a21 * a30;
+  var b07 = a20 * a32 - a22 * a30;
+  var b08 = a20 * a33 - a23 * a30;
+  var b09 = a21 * a32 - a22 * a31;
+  var b10 = a21 * a33 - a23 * a31;
+  var b11 = a22 * a33 - a23 * a32;
+
+  // Calculate the determinant
+  var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+  if (!det) {
+    return null;
+  }
+  det = 1.0 / det;
+
+  out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+  out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+  out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+
+  out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+  out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+  out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+
+  out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+  out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+  out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+
+  return out;
+}
+
+/**
+ * Generates a 2D projection matrix with the given bounds
+ *
+ * @param {mat3} out mat3 frustum matrix will be written into
+ * @param {number} width Width of your gl context
+ * @param {number} height Height of gl context
+ * @returns {mat3} out
+ */
+function projection(out, width, height) {
+  out[0] = 2 / width;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = -2 / height;
+  out[5] = 0;
+  out[6] = -1;
+  out[7] = 1;
+  out[8] = 1;
+  return out;
+}
+
+/**
+ * Returns a string representation of a mat3
+ *
+ * @param {mat3} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+function str(a) {
+  return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+}
+
+/**
+ * Returns Frobenius norm of a mat3
+ *
+ * @param {mat3} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+function frob(a) {
+  return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2));
+}
+
+/**
+ * Adds two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  out[2] = a[2] + b[2];
+  out[3] = a[3] + b[3];
+  out[4] = a[4] + b[4];
+  out[5] = a[5] + b[5];
+  out[6] = a[6] + b[6];
+  out[7] = a[7] + b[7];
+  out[8] = a[8] + b[8];
+  return out;
+}
+
+/**
+ * Subtracts matrix b from matrix a
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  out[2] = a[2] - b[2];
+  out[3] = a[3] - b[3];
+  out[4] = a[4] - b[4];
+  out[5] = a[5] - b[5];
+  out[6] = a[6] - b[6];
+  out[7] = a[7] - b[7];
+  out[8] = a[8] - b[8];
+  return out;
+}
+
+/**
+ * Multiply each element of the matrix by a scalar.
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat3} out
+ */
+function multiplyScalar(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  out[2] = a[2] * b;
+  out[3] = a[3] * b;
+  out[4] = a[4] * b;
+  out[5] = a[5] * b;
+  out[6] = a[6] * b;
+  out[7] = a[7] * b;
+  out[8] = a[8] * b;
+  return out;
+}
+
+/**
+ * Adds two mat3's after multiplying each element of the second operand by a scalar value.
+ *
+ * @param {mat3} out the receiving vector
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat3} out
+ */
+function multiplyScalarAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  out[2] = a[2] + b[2] * scale;
+  out[3] = a[3] + b[3] * scale;
+  out[4] = a[4] + b[4] * scale;
+  out[5] = a[5] + b[5] * scale;
+  out[6] = a[6] + b[6] * scale;
+  out[7] = a[7] + b[7] * scale;
+  out[8] = a[8] + b[8] * scale;
+  return out;
+}
+
+/**
+ * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {mat3} a The first matrix.
+ * @param {mat3} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
+}
+
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat3} a The first matrix.
+ * @param {mat3} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3],
+      a4 = a[4],
+      a5 = a[5],
+      a6 = a[6],
+      a7 = a[7],
+      a8 = a[8];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3],
+      b4 = b[4],
+      b5 = b[5],
+      b6 = b[6],
+      b7 = b[7],
+      b8 = b[8];
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8));
+}
+
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link mat3.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/***/ }),
+/* 2 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.forEach = exports.sqrLen = exports.len = exports.sqrDist = exports.dist = exports.div = exports.mul = exports.sub = undefined;
+exports.create = create;
+exports.clone = clone;
+exports.length = length;
+exports.fromValues = fromValues;
+exports.copy = copy;
+exports.set = set;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiply = multiply;
+exports.divide = divide;
+exports.ceil = ceil;
+exports.floor = floor;
+exports.min = min;
+exports.max = max;
+exports.round = round;
+exports.scale = scale;
+exports.scaleAndAdd = scaleAndAdd;
+exports.distance = distance;
+exports.squaredDistance = squaredDistance;
+exports.squaredLength = squaredLength;
+exports.negate = negate;
+exports.inverse = inverse;
+exports.normalize = normalize;
+exports.dot = dot;
+exports.cross = cross;
+exports.lerp = lerp;
+exports.hermite = hermite;
+exports.bezier = bezier;
+exports.random = random;
+exports.transformMat4 = transformMat4;
+exports.transformMat3 = transformMat3;
+exports.transformQuat = transformQuat;
+exports.rotateX = rotateX;
+exports.rotateY = rotateY;
+exports.rotateZ = rotateZ;
+exports.angle = angle;
+exports.str = str;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 3 Dimensional Vector
+ * @module vec3
+ */
+
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(3);
+  out[0] = 0;
+  out[1] = 0;
+  out[2] = 0;
+  return out;
+}
+
+/**
+ * Creates a new vec3 initialized with values from an existing vector
+ *
+ * @param {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(3);
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  return out;
+}
+
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+function length(a) {
+  var x = a[0];
+  var y = a[1];
+  var z = a[2];
+  return Math.sqrt(x * x + y * y + z * z);
+}
+
+/**
+ * Creates a new vec3 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} a new 3D vector
+ */
+function fromValues(x, y, z) {
+  var out = new glMatrix.ARRAY_TYPE(3);
+  out[0] = x;
+  out[1] = y;
+  out[2] = z;
+  return out;
+}
+
+/**
+ * Copy the values from one vec3 to another
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the source vector
+ * @returns {vec3} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  return out;
+}
+
+/**
+ * Set the components of a vec3 to the given values
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} out
+ */
+function set(out, x, y, z) {
+  out[0] = x;
+  out[1] = y;
+  out[2] = z;
+  return out;
+}
+
+/**
+ * Adds two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  out[2] = a[2] + b[2];
+  return out;
+}
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  out[2] = a[2] - b[2];
+  return out;
+}
+
+/**
+ * Multiplies two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function multiply(out, a, b) {
+  out[0] = a[0] * b[0];
+  out[1] = a[1] * b[1];
+  out[2] = a[2] * b[2];
+  return out;
+}
+
+/**
+ * Divides two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function divide(out, a, b) {
+  out[0] = a[0] / b[0];
+  out[1] = a[1] / b[1];
+  out[2] = a[2] / b[2];
+  return out;
+}
+
+/**
+ * Math.ceil the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to ceil
+ * @returns {vec3} out
+ */
+function ceil(out, a) {
+  out[0] = Math.ceil(a[0]);
+  out[1] = Math.ceil(a[1]);
+  out[2] = Math.ceil(a[2]);
+  return out;
+}
+
+/**
+ * Math.floor the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to floor
+ * @returns {vec3} out
+ */
+function floor(out, a) {
+  out[0] = Math.floor(a[0]);
+  out[1] = Math.floor(a[1]);
+  out[2] = Math.floor(a[2]);
+  return out;
+}
+
+/**
+ * Returns the minimum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function min(out, a, b) {
+  out[0] = Math.min(a[0], b[0]);
+  out[1] = Math.min(a[1], b[1]);
+  out[2] = Math.min(a[2], b[2]);
+  return out;
+}
+
+/**
+ * Returns the maximum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function max(out, a, b) {
+  out[0] = Math.max(a[0], b[0]);
+  out[1] = Math.max(a[1], b[1]);
+  out[2] = Math.max(a[2], b[2]);
+  return out;
+}
+
+/**
+ * Math.round the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to round
+ * @returns {vec3} out
+ */
+function round(out, a) {
+  out[0] = Math.round(a[0]);
+  out[1] = Math.round(a[1]);
+  out[2] = Math.round(a[2]);
+  return out;
+}
+
+/**
+ * Scales a vec3 by a scalar number
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec3} out
+ */
+function scale(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  out[2] = a[2] * b;
+  return out;
+}
+
+/**
+ * Adds two vec3's after scaling the second operand by a scalar value
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec3} out
+ */
+function scaleAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  out[2] = a[2] + b[2] * scale;
+  return out;
+}
+
+/**
+ * Calculates the euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} distance between a and b
+ */
+function distance(a, b) {
+  var x = b[0] - a[0];
+  var y = b[1] - a[1];
+  var z = b[2] - a[2];
+  return Math.sqrt(x * x + y * y + z * z);
+}
+
+/**
+ * Calculates the squared euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+function squaredDistance(a, b) {
+  var x = b[0] - a[0];
+  var y = b[1] - a[1];
+  var z = b[2] - a[2];
+  return x * x + y * y + z * z;
+}
+
+/**
+ * Calculates the squared length of a vec3
+ *
+ * @param {vec3} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+function squaredLength(a) {
+  var x = a[0];
+  var y = a[1];
+  var z = a[2];
+  return x * x + y * y + z * z;
+}
+
+/**
+ * Negates the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to negate
+ * @returns {vec3} out
+ */
+function negate(out, a) {
+  out[0] = -a[0];
+  out[1] = -a[1];
+  out[2] = -a[2];
+  return out;
+}
+
+/**
+ * Returns the inverse of the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to invert
+ * @returns {vec3} out
+ */
+function inverse(out, a) {
+  out[0] = 1.0 / a[0];
+  out[1] = 1.0 / a[1];
+  out[2] = 1.0 / a[2];
+  return out;
+}
+
+/**
+ * Normalize a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to normalize
+ * @returns {vec3} out
+ */
+function normalize(out, a) {
+  var x = a[0];
+  var y = a[1];
+  var z = a[2];
+  var len = x * x + y * y + z * z;
+  if (len > 0) {
+    //TODO: evaluate use of glm_invsqrt here?
+    len = 1 / Math.sqrt(len);
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+    out[2] = a[2] * len;
+  }
+  return out;
+}
+
+/**
+ * Calculates the dot product of two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+function dot(a, b) {
+  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+
+/**
+ * Computes the cross product of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+function cross(out, a, b) {
+  var ax = a[0],
+      ay = a[1],
+      az = a[2];
+  var bx = b[0],
+      by = b[1],
+      bz = b[2];
+
+  out[0] = ay * bz - az * by;
+  out[1] = az * bx - ax * bz;
+  out[2] = ax * by - ay * bx;
+  return out;
+}
+
+/**
+ * Performs a linear interpolation between two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+function lerp(out, a, b, t) {
+  var ax = a[0];
+  var ay = a[1];
+  var az = a[2];
+  out[0] = ax + t * (b[0] - ax);
+  out[1] = ay + t * (b[1] - ay);
+  out[2] = az + t * (b[2] - az);
+  return out;
+}
+
+/**
+ * Performs a hermite interpolation with two control points
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {vec3} c the third operand
+ * @param {vec3} d the fourth operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+function hermite(out, a, b, c, d, t) {
+  var factorTimes2 = t * t;
+  var factor1 = factorTimes2 * (2 * t - 3) + 1;
+  var factor2 = factorTimes2 * (t - 2) + t;
+  var factor3 = factorTimes2 * (t - 1);
+  var factor4 = factorTimes2 * (3 - 2 * t);
+
+  out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+  out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+  out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+
+  return out;
+}
+
+/**
+ * Performs a bezier interpolation with two control points
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {vec3} c the third operand
+ * @param {vec3} d the fourth operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+function bezier(out, a, b, c, d, t) {
+  var inverseFactor = 1 - t;
+  var inverseFactorTimesTwo = inverseFactor * inverseFactor;
+  var factorTimes2 = t * t;
+  var factor1 = inverseFactorTimesTwo * inverseFactor;
+  var factor2 = 3 * t * inverseFactorTimesTwo;
+  var factor3 = 3 * factorTimes2 * inverseFactor;
+  var factor4 = factorTimes2 * t;
+
+  out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+  out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+  out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+
+  return out;
+}
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec3} out
+ */
+function random(out, scale) {
+  scale = scale || 1.0;
+
+  var r = glMatrix.RANDOM() * 2.0 * Math.PI;
+  var z = glMatrix.RANDOM() * 2.0 - 1.0;
+  var zScale = Math.sqrt(1.0 - z * z) * scale;
+
+  out[0] = Math.cos(r) * zScale;
+  out[1] = Math.sin(r) * zScale;
+  out[2] = z * scale;
+  return out;
+}
+
+/**
+ * Transforms the vec3 with a mat4.
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec3} out
+ */
+function transformMat4(out, a, m) {
+  var x = a[0],
+      y = a[1],
+      z = a[2];
+  var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+  w = w || 1.0;
+  out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+  out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+  out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+  return out;
+}
+
+/**
+ * Transforms the vec3 with a mat3.
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat3} m the 3x3 matrix to transform with
+ * @returns {vec3} out
+ */
+function transformMat3(out, a, m) {
+  var x = a[0],
+      y = a[1],
+      z = a[2];
+  out[0] = x * m[0] + y * m[3] + z * m[6];
+  out[1] = x * m[1] + y * m[4] + z * m[7];
+  out[2] = x * m[2] + y * m[5] + z * m[8];
+  return out;
+}
+
+/**
+ * Transforms the vec3 with a quat
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec3} out
+ */
+function transformQuat(out, a, q) {
+  // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
+
+  var x = a[0],
+      y = a[1],
+      z = a[2];
+  var qx = q[0],
+      qy = q[1],
+      qz = q[2],
+      qw = q[3];
+
+  // calculate quat * vec
+  var ix = qw * x + qy * z - qz * y;
+  var iy = qw * y + qz * x - qx * z;
+  var iz = qw * z + qx * y - qy * x;
+  var iw = -qx * x - qy * y - qz * z;
+
+  // calculate result * inverse quat
+  out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+  out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+  out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+  return out;
+}
+
+/**
+ * Rotate a 3D vector around the x-axis
+ * @param {vec3} out The receiving vec3
+ * @param {vec3} a The vec3 point to rotate
+ * @param {vec3} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec3} out
+ */
+function rotateX(out, a, b, c) {
+  var p = [],
+      r = [];
+  //Translate point to the origin
+  p[0] = a[0] - b[0];
+  p[1] = a[1] - b[1];
+  p[2] = a[2] - b[2];
+
+  //perform rotation
+  r[0] = p[0];
+  r[1] = p[1] * Math.cos(c) - p[2] * Math.sin(c);
+  r[2] = p[1] * Math.sin(c) + p[2] * Math.cos(c);
+
+  //translate to correct position
+  out[0] = r[0] + b[0];
+  out[1] = r[1] + b[1];
+  out[2] = r[2] + b[2];
+
+  return out;
+}
+
+/**
+ * Rotate a 3D vector around the y-axis
+ * @param {vec3} out The receiving vec3
+ * @param {vec3} a The vec3 point to rotate
+ * @param {vec3} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec3} out
+ */
+function rotateY(out, a, b, c) {
+  var p = [],
+      r = [];
+  //Translate point to the origin
+  p[0] = a[0] - b[0];
+  p[1] = a[1] - b[1];
+  p[2] = a[2] - b[2];
+
+  //perform rotation
+  r[0] = p[2] * Math.sin(c) + p[0] * Math.cos(c);
+  r[1] = p[1];
+  r[2] = p[2] * Math.cos(c) - p[0] * Math.sin(c);
+
+  //translate to correct position
+  out[0] = r[0] + b[0];
+  out[1] = r[1] + b[1];
+  out[2] = r[2] + b[2];
+
+  return out;
+}
+
+/**
+ * Rotate a 3D vector around the z-axis
+ * @param {vec3} out The receiving vec3
+ * @param {vec3} a The vec3 point to rotate
+ * @param {vec3} b The origin of the rotation
+ * @param {Number} c The angle of rotation
+ * @returns {vec3} out
+ */
+function rotateZ(out, a, b, c) {
+  var p = [],
+      r = [];
+  //Translate point to the origin
+  p[0] = a[0] - b[0];
+  p[1] = a[1] - b[1];
+  p[2] = a[2] - b[2];
+
+  //perform rotation
+  r[0] = p[0] * Math.cos(c) - p[1] * Math.sin(c);
+  r[1] = p[0] * Math.sin(c) + p[1] * Math.cos(c);
+  r[2] = p[2];
+
+  //translate to correct position
+  out[0] = r[0] + b[0];
+  out[1] = r[1] + b[1];
+  out[2] = r[2] + b[2];
+
+  return out;
+}
+
+/**
+ * Get the angle between two 3D vectors
+ * @param {vec3} a The first operand
+ * @param {vec3} b The second operand
+ * @returns {Number} The angle in radians
+ */
+function angle(a, b) {
+  var tempA = fromValues(a[0], a[1], a[2]);
+  var tempB = fromValues(b[0], b[1], b[2]);
+
+  normalize(tempA, tempA);
+  normalize(tempB, tempB);
+
+  var cosine = dot(tempA, tempB);
+
+  if (cosine > 1.0) {
+    return 0;
+  } else if (cosine < -1.0) {
+    return Math.PI;
+  } else {
+    return Math.acos(cosine);
+  }
+}
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec3} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+function str(a) {
+  return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+}
+
+/**
+ * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {vec3} a The first vector.
+ * @param {vec3} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
+}
+
+/**
+ * Returns whether or not the vectors have approximately the same elements in the same position.
+ *
+ * @param {vec3} a The first vector.
+ * @param {vec3} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2];
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2));
+}
+
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+var div = exports.div = divide;
+
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+var dist = exports.dist = distance;
+
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+var sqrDist = exports.sqrDist = squaredDistance;
+
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+var len = exports.len = length;
+
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+var sqrLen = exports.sqrLen = squaredLength;
+
+/**
+ * Perform some operation over an array of vec3s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+var forEach = exports.forEach = function () {
+  var vec = create();
+
+  return function (a, stride, offset, count, fn, arg) {
+    var i = void 0,
+        l = void 0;
+    if (!stride) {
+      stride = 3;
+    }
+
+    if (!offset) {
+      offset = 0;
+    }
+
+    if (count) {
+      l = Math.min(count * stride + offset, a.length);
+    } else {
+      l = a.length;
+    }
+
+    for (i = offset; i < l; i += stride) {
+      vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2];
+      fn(vec, vec, arg);
+      a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2];
+    }
+
+    return a;
+  };
+}();
+
+/***/ }),
+/* 3 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.forEach = exports.sqrLen = exports.len = exports.sqrDist = exports.dist = exports.div = exports.mul = exports.sub = undefined;
+exports.create = create;
+exports.clone = clone;
+exports.fromValues = fromValues;
+exports.copy = copy;
+exports.set = set;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiply = multiply;
+exports.divide = divide;
+exports.ceil = ceil;
+exports.floor = floor;
+exports.min = min;
+exports.max = max;
+exports.round = round;
+exports.scale = scale;
+exports.scaleAndAdd = scaleAndAdd;
+exports.distance = distance;
+exports.squaredDistance = squaredDistance;
+exports.length = length;
+exports.squaredLength = squaredLength;
+exports.negate = negate;
+exports.inverse = inverse;
+exports.normalize = normalize;
+exports.dot = dot;
+exports.lerp = lerp;
+exports.random = random;
+exports.transformMat4 = transformMat4;
+exports.transformQuat = transformQuat;
+exports.str = str;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 4 Dimensional Vector
+ * @module vec4
+ */
+
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = 0;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  return out;
+}
+
+/**
+ * Creates a new vec4 initialized with values from an existing vector
+ *
+ * @param {vec4} a vector to clone
+ * @returns {vec4} a new 4D vector
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  return out;
+}
+
+/**
+ * Creates a new vec4 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
+ */
+function fromValues(x, y, z, w) {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = x;
+  out[1] = y;
+  out[2] = z;
+  out[3] = w;
+  return out;
+}
+
+/**
+ * Copy the values from one vec4 to another
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the source vector
+ * @returns {vec4} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  return out;
+}
+
+/**
+ * Set the components of a vec4 to the given values
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} out
+ */
+function set(out, x, y, z, w) {
+  out[0] = x;
+  out[1] = y;
+  out[2] = z;
+  out[3] = w;
+  return out;
+}
+
+/**
+ * Adds two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  out[2] = a[2] + b[2];
+  out[3] = a[3] + b[3];
+  return out;
+}
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  out[2] = a[2] - b[2];
+  out[3] = a[3] - b[3];
+  return out;
+}
+
+/**
+ * Multiplies two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function multiply(out, a, b) {
+  out[0] = a[0] * b[0];
+  out[1] = a[1] * b[1];
+  out[2] = a[2] * b[2];
+  out[3] = a[3] * b[3];
+  return out;
+}
+
+/**
+ * Divides two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function divide(out, a, b) {
+  out[0] = a[0] / b[0];
+  out[1] = a[1] / b[1];
+  out[2] = a[2] / b[2];
+  out[3] = a[3] / b[3];
+  return out;
+}
+
+/**
+ * Math.ceil the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to ceil
+ * @returns {vec4} out
+ */
+function ceil(out, a) {
+  out[0] = Math.ceil(a[0]);
+  out[1] = Math.ceil(a[1]);
+  out[2] = Math.ceil(a[2]);
+  out[3] = Math.ceil(a[3]);
+  return out;
+}
+
+/**
+ * Math.floor the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to floor
+ * @returns {vec4} out
+ */
+function floor(out, a) {
+  out[0] = Math.floor(a[0]);
+  out[1] = Math.floor(a[1]);
+  out[2] = Math.floor(a[2]);
+  out[3] = Math.floor(a[3]);
+  return out;
+}
+
+/**
+ * Returns the minimum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function min(out, a, b) {
+  out[0] = Math.min(a[0], b[0]);
+  out[1] = Math.min(a[1], b[1]);
+  out[2] = Math.min(a[2], b[2]);
+  out[3] = Math.min(a[3], b[3]);
+  return out;
+}
+
+/**
+ * Returns the maximum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+function max(out, a, b) {
+  out[0] = Math.max(a[0], b[0]);
+  out[1] = Math.max(a[1], b[1]);
+  out[2] = Math.max(a[2], b[2]);
+  out[3] = Math.max(a[3], b[3]);
+  return out;
+}
+
+/**
+ * Math.round the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to round
+ * @returns {vec4} out
+ */
+function round(out, a) {
+  out[0] = Math.round(a[0]);
+  out[1] = Math.round(a[1]);
+  out[2] = Math.round(a[2]);
+  out[3] = Math.round(a[3]);
+  return out;
+}
+
+/**
+ * Scales a vec4 by a scalar number
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec4} out
+ */
+function scale(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  out[2] = a[2] * b;
+  out[3] = a[3] * b;
+  return out;
+}
+
+/**
+ * Adds two vec4's after scaling the second operand by a scalar value
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec4} out
+ */
+function scaleAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  out[2] = a[2] + b[2] * scale;
+  out[3] = a[3] + b[3] * scale;
+  return out;
+}
+
+/**
+ * Calculates the euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} distance between a and b
+ */
+function distance(a, b) {
+  var x = b[0] - a[0];
+  var y = b[1] - a[1];
+  var z = b[2] - a[2];
+  var w = b[3] - a[3];
+  return Math.sqrt(x * x + y * y + z * z + w * w);
+}
+
+/**
+ * Calculates the squared euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+function squaredDistance(a, b) {
+  var x = b[0] - a[0];
+  var y = b[1] - a[1];
+  var z = b[2] - a[2];
+  var w = b[3] - a[3];
+  return x * x + y * y + z * z + w * w;
+}
+
+/**
+ * Calculates the length of a vec4
+ *
+ * @param {vec4} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+function length(a) {
+  var x = a[0];
+  var y = a[1];
+  var z = a[2];
+  var w = a[3];
+  return Math.sqrt(x * x + y * y + z * z + w * w);
+}
+
+/**
+ * Calculates the squared length of a vec4
+ *
+ * @param {vec4} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+function squaredLength(a) {
+  var x = a[0];
+  var y = a[1];
+  var z = a[2];
+  var w = a[3];
+  return x * x + y * y + z * z + w * w;
+}
+
+/**
+ * Negates the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to negate
+ * @returns {vec4} out
+ */
+function negate(out, a) {
+  out[0] = -a[0];
+  out[1] = -a[1];
+  out[2] = -a[2];
+  out[3] = -a[3];
+  return out;
+}
+
+/**
+ * Returns the inverse of the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to invert
+ * @returns {vec4} out
+ */
+function inverse(out, a) {
+  out[0] = 1.0 / a[0];
+  out[1] = 1.0 / a[1];
+  out[2] = 1.0 / a[2];
+  out[3] = 1.0 / a[3];
+  return out;
+}
+
+/**
+ * Normalize a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+function normalize(out, a) {
+  var x = a[0];
+  var y = a[1];
+  var z = a[2];
+  var w = a[3];
+  var len = x * x + y * y + z * z + w * w;
+  if (len > 0) {
+    len = 1 / Math.sqrt(len);
+    out[0] = x * len;
+    out[1] = y * len;
+    out[2] = z * len;
+    out[3] = w * len;
+  }
+  return out;
+}
+
+/**
+ * Calculates the dot product of two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+function dot(a, b) {
+  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+}
+
+/**
+ * Performs a linear interpolation between two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec4} out
+ */
+function lerp(out, a, b, t) {
+  var ax = a[0];
+  var ay = a[1];
+  var az = a[2];
+  var aw = a[3];
+  out[0] = ax + t * (b[0] - ax);
+  out[1] = ay + t * (b[1] - ay);
+  out[2] = az + t * (b[2] - az);
+  out[3] = aw + t * (b[3] - aw);
+  return out;
+}
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec4} out
+ */
+function random(out, vectorScale) {
+  vectorScale = vectorScale || 1.0;
+
+  //TODO: This is a pretty awful way of doing this. Find something better.
+  out[0] = glMatrix.RANDOM();
+  out[1] = glMatrix.RANDOM();
+  out[2] = glMatrix.RANDOM();
+  out[3] = glMatrix.RANDOM();
+  normalize(out, out);
+  scale(out, out, vectorScale);
+  return out;
+}
+
+/**
+ * Transforms the vec4 with a mat4.
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
+ */
+function transformMat4(out, a, m) {
+  var x = a[0],
+      y = a[1],
+      z = a[2],
+      w = a[3];
+  out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+  out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+  out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+  out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+  return out;
+}
+
+/**
+ * Transforms the vec4 with a quat
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
+ */
+function transformQuat(out, a, q) {
+  var x = a[0],
+      y = a[1],
+      z = a[2];
+  var qx = q[0],
+      qy = q[1],
+      qz = q[2],
+      qw = q[3];
+
+  // calculate quat * vec
+  var ix = qw * x + qy * z - qz * y;
+  var iy = qw * y + qz * x - qx * z;
+  var iz = qw * z + qx * y - qy * x;
+  var iw = -qx * x - qy * y - qz * z;
+
+  // calculate result * inverse quat
+  out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+  out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+  out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+  out[3] = a[3];
+  return out;
+}
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec4} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+function str(a) {
+  return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+}
+
+/**
+ * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {vec4} a The first vector.
+ * @param {vec4} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+}
+
+/**
+ * Returns whether or not the vectors have approximately the same elements in the same position.
+ *
+ * @param {vec4} a The first vector.
+ * @param {vec4} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3];
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+}
+
+/**
+ * Alias for {@link vec4.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/**
+ * Alias for {@link vec4.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link vec4.divide}
+ * @function
+ */
+var div = exports.div = divide;
+
+/**
+ * Alias for {@link vec4.distance}
+ * @function
+ */
+var dist = exports.dist = distance;
+
+/**
+ * Alias for {@link vec4.squaredDistance}
+ * @function
+ */
+var sqrDist = exports.sqrDist = squaredDistance;
+
+/**
+ * Alias for {@link vec4.length}
+ * @function
+ */
+var len = exports.len = length;
+
+/**
+ * Alias for {@link vec4.squaredLength}
+ * @function
+ */
+var sqrLen = exports.sqrLen = squaredLength;
+
+/**
+ * Perform some operation over an array of vec4s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+var forEach = exports.forEach = function () {
+  var vec = create();
+
+  return function (a, stride, offset, count, fn, arg) {
+    var i = void 0,
+        l = void 0;
+    if (!stride) {
+      stride = 4;
+    }
+
+    if (!offset) {
+      offset = 0;
+    }
+
+    if (count) {
+      l = Math.min(count * stride + offset, a.length);
+    } else {
+      l = a.length;
+    }
+
+    for (i = offset; i < l; i += stride) {
+      vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2];vec[3] = a[i + 3];
+      fn(vec, vec, arg);
+      a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2];a[i + 3] = vec[3];
+    }
+
+    return a;
+  };
+}();
+
+/***/ }),
+/* 4 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.vec4 = exports.vec3 = exports.vec2 = exports.quat = exports.mat4 = exports.mat3 = exports.mat2d = exports.mat2 = exports.glMatrix = undefined;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+var _mat = __webpack_require__(5);
+
+var mat2 = _interopRequireWildcard(_mat);
+
+var _mat2d = __webpack_require__(6);
+
+var mat2d = _interopRequireWildcard(_mat2d);
+
+var _mat2 = __webpack_require__(1);
+
+var mat3 = _interopRequireWildcard(_mat2);
+
+var _mat3 = __webpack_require__(7);
+
+var mat4 = _interopRequireWildcard(_mat3);
+
+var _quat = __webpack_require__(8);
+
+var quat = _interopRequireWildcard(_quat);
+
+var _vec = __webpack_require__(9);
+
+var vec2 = _interopRequireWildcard(_vec);
+
+var _vec2 = __webpack_require__(2);
+
+var vec3 = _interopRequireWildcard(_vec2);
+
+var _vec3 = __webpack_require__(3);
+
+var vec4 = _interopRequireWildcard(_vec3);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+exports.glMatrix = glMatrix;
+exports.mat2 = mat2;
+exports.mat2d = mat2d;
+exports.mat3 = mat3;
+exports.mat4 = mat4;
+exports.quat = quat;
+exports.vec2 = vec2;
+exports.vec3 = vec3;
+exports.vec4 = vec4; /**
+                      * @fileoverview gl-matrix - High performance matrix and vector operations
+                      * @author Brandon Jones
+                      * @author Colin MacKenzie IV
+                      * @version 2.4.0
+                      */
+
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+// END HEADER
+
+/***/ }),
+/* 5 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.sub = exports.mul = undefined;
+exports.create = create;
+exports.clone = clone;
+exports.copy = copy;
+exports.identity = identity;
+exports.fromValues = fromValues;
+exports.set = set;
+exports.transpose = transpose;
+exports.invert = invert;
+exports.adjoint = adjoint;
+exports.determinant = determinant;
+exports.multiply = multiply;
+exports.rotate = rotate;
+exports.scale = scale;
+exports.fromRotation = fromRotation;
+exports.fromScaling = fromScaling;
+exports.str = str;
+exports.frob = frob;
+exports.LDU = LDU;
+exports.add = add;
+exports.subtract = subtract;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+exports.multiplyScalar = multiplyScalar;
+exports.multiplyScalarAndAdd = multiplyScalarAndAdd;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 2x2 Matrix
+ * @module mat2
+ */
+
+/**
+ * Creates a new identity mat2
+ *
+ * @returns {mat2} a new 2x2 matrix
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  return out;
+}
+
+/**
+ * Creates a new mat2 initialized with values from an existing matrix
+ *
+ * @param {mat2} a matrix to clone
+ * @returns {mat2} a new 2x2 matrix
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  return out;
+}
+
+/**
+ * Copy the values from one mat2 to another
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  return out;
+}
+
+/**
+ * Set a mat2 to the identity matrix
+ *
+ * @param {mat2} out the receiving matrix
+ * @returns {mat2} out
+ */
+function identity(out) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  return out;
+}
+
+/**
+ * Create a new mat2 with the given values
+ *
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m10 Component in column 1, row 0 position (index 2)
+ * @param {Number} m11 Component in column 1, row 1 position (index 3)
+ * @returns {mat2} out A new 2x2 matrix
+ */
+function fromValues(m00, m01, m10, m11) {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = m00;
+  out[1] = m01;
+  out[2] = m10;
+  out[3] = m11;
+  return out;
+}
+
+/**
+ * Set the components of a mat2 to the given values
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m10 Component in column 1, row 0 position (index 2)
+ * @param {Number} m11 Component in column 1, row 1 position (index 3)
+ * @returns {mat2} out
+ */
+function set(out, m00, m01, m10, m11) {
+  out[0] = m00;
+  out[1] = m01;
+  out[2] = m10;
+  out[3] = m11;
+  return out;
+}
+
+/**
+ * Transpose the values of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+function transpose(out, a) {
+  // If we are transposing ourselves we can skip a few steps but have to cache
+  // some values
+  if (out === a) {
+    var a1 = a[1];
+    out[1] = a[2];
+    out[2] = a1;
+  } else {
+    out[0] = a[0];
+    out[1] = a[2];
+    out[2] = a[1];
+    out[3] = a[3];
+  }
+
+  return out;
+}
+
+/**
+ * Inverts a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+function invert(out, a) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+
+  // Calculate the determinant
+  var det = a0 * a3 - a2 * a1;
+
+  if (!det) {
+    return null;
+  }
+  det = 1.0 / det;
+
+  out[0] = a3 * det;
+  out[1] = -a1 * det;
+  out[2] = -a2 * det;
+  out[3] = a0 * det;
+
+  return out;
+}
+
+/**
+ * Calculates the adjugate of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+function adjoint(out, a) {
+  // Caching this value is nessecary if out == a
+  var a0 = a[0];
+  out[0] = a[3];
+  out[1] = -a[1];
+  out[2] = -a[2];
+  out[3] = a0;
+
+  return out;
+}
+
+/**
+ * Calculates the determinant of a mat2
+ *
+ * @param {mat2} a the source matrix
+ * @returns {Number} determinant of a
+ */
+function determinant(a) {
+  return a[0] * a[3] - a[2] * a[1];
+}
+
+/**
+ * Multiplies two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+function multiply(out, a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3];
+  out[0] = a0 * b0 + a2 * b1;
+  out[1] = a1 * b0 + a3 * b1;
+  out[2] = a0 * b2 + a2 * b3;
+  out[3] = a1 * b2 + a3 * b3;
+  return out;
+}
+
+/**
+ * Rotates a mat2 by the given angle
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+function rotate(out, a, rad) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+  out[0] = a0 * c + a2 * s;
+  out[1] = a1 * c + a3 * s;
+  out[2] = a0 * -s + a2 * c;
+  out[3] = a1 * -s + a3 * c;
+  return out;
+}
+
+/**
+ * Scales the mat2 by the dimensions in the given vec2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2} out
+ **/
+function scale(out, a, v) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var v0 = v[0],
+      v1 = v[1];
+  out[0] = a0 * v0;
+  out[1] = a1 * v0;
+  out[2] = a2 * v1;
+  out[3] = a3 * v1;
+  return out;
+}
+
+/**
+ * Creates a matrix from a given angle
+ * This is equivalent to (but much faster than):
+ *
+ *     mat2.identity(dest);
+ *     mat2.rotate(dest, dest, rad);
+ *
+ * @param {mat2} out mat2 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+function fromRotation(out, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+  out[0] = c;
+  out[1] = s;
+  out[2] = -s;
+  out[3] = c;
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ *     mat2.identity(dest);
+ *     mat2.scale(dest, dest, vec);
+ *
+ * @param {mat2} out mat2 receiving operation result
+ * @param {vec2} v Scaling vector
+ * @returns {mat2} out
+ */
+function fromScaling(out, v) {
+  out[0] = v[0];
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = v[1];
+  return out;
+}
+
+/**
+ * Returns a string representation of a mat2
+ *
+ * @param {mat2} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+function str(a) {
+  return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+}
+
+/**
+ * Returns Frobenius norm of a mat2
+ *
+ * @param {mat2} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+function frob(a) {
+  return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2));
+}
+
+/**
+ * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
+ * @param {mat2} L the lower triangular matrix
+ * @param {mat2} D the diagonal matrix
+ * @param {mat2} U the upper triangular matrix
+ * @param {mat2} a the input matrix to factorize
+ */
+
+function LDU(L, D, U, a) {
+  L[2] = a[2] / a[0];
+  U[0] = a[0];
+  U[1] = a[1];
+  U[3] = a[3] - L[2] * U[1];
+  return [L, D, U];
+}
+
+/**
+ * Adds two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  out[2] = a[2] + b[2];
+  out[3] = a[3] + b[3];
+  return out;
+}
+
+/**
+ * Subtracts matrix b from matrix a
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  out[2] = a[2] - b[2];
+  out[3] = a[3] - b[3];
+  return out;
+}
+
+/**
+ * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {mat2} a The first matrix.
+ * @param {mat2} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
+}
+
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat2} a The first matrix.
+ * @param {mat2} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3];
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
+}
+
+/**
+ * Multiply each element of the matrix by a scalar.
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat2} out
+ */
+function multiplyScalar(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  out[2] = a[2] * b;
+  out[3] = a[3] * b;
+  return out;
+}
+
+/**
+ * Adds two mat2's after multiplying each element of the second operand by a scalar value.
+ *
+ * @param {mat2} out the receiving vector
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat2} out
+ */
+function multiplyScalarAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  out[2] = a[2] + b[2] * scale;
+  out[3] = a[3] + b[3] * scale;
+  return out;
+}
+
+/**
+ * Alias for {@link mat2.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link mat2.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/***/ }),
+/* 6 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.sub = exports.mul = undefined;
+exports.create = create;
+exports.clone = clone;
+exports.copy = copy;
+exports.identity = identity;
+exports.fromValues = fromValues;
+exports.set = set;
+exports.invert = invert;
+exports.determinant = determinant;
+exports.multiply = multiply;
+exports.rotate = rotate;
+exports.scale = scale;
+exports.translate = translate;
+exports.fromRotation = fromRotation;
+exports.fromScaling = fromScaling;
+exports.fromTranslation = fromTranslation;
+exports.str = str;
+exports.frob = frob;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiplyScalar = multiplyScalar;
+exports.multiplyScalarAndAdd = multiplyScalarAndAdd;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 2x3 Matrix
+ * @module mat2d
+ *
+ * @description
+ * A mat2d contains six elements defined as:
+ * <pre>
+ * [a, c, tx,
+ *  b, d, ty]
+ * </pre>
+ * This is a short form for the 3x3 matrix:
+ * <pre>
+ * [a, c, tx,
+ *  b, d, ty,
+ *  0, 0, 1]
+ * </pre>
+ * The last row is ignored so the array is shorter and operations are faster.
+ */
+
+/**
+ * Creates a new identity mat2d
+ *
+ * @returns {mat2d} a new 2x3 matrix
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(6);
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  out[4] = 0;
+  out[5] = 0;
+  return out;
+}
+
+/**
+ * Creates a new mat2d initialized with values from an existing matrix
+ *
+ * @param {mat2d} a matrix to clone
+ * @returns {mat2d} a new 2x3 matrix
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(6);
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  out[4] = a[4];
+  out[5] = a[5];
+  return out;
+}
+
+/**
+ * Copy the values from one mat2d to another
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  out[4] = a[4];
+  out[5] = a[5];
+  return out;
+}
+
+/**
+ * Set a mat2d to the identity matrix
+ *
+ * @param {mat2d} out the receiving matrix
+ * @returns {mat2d} out
+ */
+function identity(out) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  out[4] = 0;
+  out[5] = 0;
+  return out;
+}
+
+/**
+ * Create a new mat2d with the given values
+ *
+ * @param {Number} a Component A (index 0)
+ * @param {Number} b Component B (index 1)
+ * @param {Number} c Component C (index 2)
+ * @param {Number} d Component D (index 3)
+ * @param {Number} tx Component TX (index 4)
+ * @param {Number} ty Component TY (index 5)
+ * @returns {mat2d} A new mat2d
+ */
+function fromValues(a, b, c, d, tx, ty) {
+  var out = new glMatrix.ARRAY_TYPE(6);
+  out[0] = a;
+  out[1] = b;
+  out[2] = c;
+  out[3] = d;
+  out[4] = tx;
+  out[5] = ty;
+  return out;
+}
+
+/**
+ * Set the components of a mat2d to the given values
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {Number} a Component A (index 0)
+ * @param {Number} b Component B (index 1)
+ * @param {Number} c Component C (index 2)
+ * @param {Number} d Component D (index 3)
+ * @param {Number} tx Component TX (index 4)
+ * @param {Number} ty Component TY (index 5)
+ * @returns {mat2d} out
+ */
+function set(out, a, b, c, d, tx, ty) {
+  out[0] = a;
+  out[1] = b;
+  out[2] = c;
+  out[3] = d;
+  out[4] = tx;
+  out[5] = ty;
+  return out;
+}
+
+/**
+ * Inverts a mat2d
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+function invert(out, a) {
+  var aa = a[0],
+      ab = a[1],
+      ac = a[2],
+      ad = a[3];
+  var atx = a[4],
+      aty = a[5];
+
+  var det = aa * ad - ab * ac;
+  if (!det) {
+    return null;
+  }
+  det = 1.0 / det;
+
+  out[0] = ad * det;
+  out[1] = -ab * det;
+  out[2] = -ac * det;
+  out[3] = aa * det;
+  out[4] = (ac * aty - ad * atx) * det;
+  out[5] = (ab * atx - aa * aty) * det;
+  return out;
+}
+
+/**
+ * Calculates the determinant of a mat2d
+ *
+ * @param {mat2d} a the source matrix
+ * @returns {Number} determinant of a
+ */
+function determinant(a) {
+  return a[0] * a[3] - a[1] * a[2];
+}
+
+/**
+ * Multiplies two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+function multiply(out, a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3],
+      a4 = a[4],
+      a5 = a[5];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3],
+      b4 = b[4],
+      b5 = b[5];
+  out[0] = a0 * b0 + a2 * b1;
+  out[1] = a1 * b0 + a3 * b1;
+  out[2] = a0 * b2 + a2 * b3;
+  out[3] = a1 * b2 + a3 * b3;
+  out[4] = a0 * b4 + a2 * b5 + a4;
+  out[5] = a1 * b4 + a3 * b5 + a5;
+  return out;
+}
+
+/**
+ * Rotates a mat2d by the given angle
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+function rotate(out, a, rad) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3],
+      a4 = a[4],
+      a5 = a[5];
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+  out[0] = a0 * c + a2 * s;
+  out[1] = a1 * c + a3 * s;
+  out[2] = a0 * -s + a2 * c;
+  out[3] = a1 * -s + a3 * c;
+  out[4] = a4;
+  out[5] = a5;
+  return out;
+}
+
+/**
+ * Scales the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2d} out
+ **/
+function scale(out, a, v) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3],
+      a4 = a[4],
+      a5 = a[5];
+  var v0 = v[0],
+      v1 = v[1];
+  out[0] = a0 * v0;
+  out[1] = a1 * v0;
+  out[2] = a2 * v1;
+  out[3] = a3 * v1;
+  out[4] = a4;
+  out[5] = a5;
+  return out;
+}
+
+/**
+ * Translates the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to translate the matrix by
+ * @returns {mat2d} out
+ **/
+function translate(out, a, v) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3],
+      a4 = a[4],
+      a5 = a[5];
+  var v0 = v[0],
+      v1 = v[1];
+  out[0] = a0;
+  out[1] = a1;
+  out[2] = a2;
+  out[3] = a3;
+  out[4] = a0 * v0 + a2 * v1 + a4;
+  out[5] = a1 * v0 + a3 * v1 + a5;
+  return out;
+}
+
+/**
+ * Creates a matrix from a given angle
+ * This is equivalent to (but much faster than):
+ *
+ *     mat2d.identity(dest);
+ *     mat2d.rotate(dest, dest, rad);
+ *
+ * @param {mat2d} out mat2d receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+function fromRotation(out, rad) {
+  var s = Math.sin(rad),
+      c = Math.cos(rad);
+  out[0] = c;
+  out[1] = s;
+  out[2] = -s;
+  out[3] = c;
+  out[4] = 0;
+  out[5] = 0;
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ *     mat2d.identity(dest);
+ *     mat2d.scale(dest, dest, vec);
+ *
+ * @param {mat2d} out mat2d receiving operation result
+ * @param {vec2} v Scaling vector
+ * @returns {mat2d} out
+ */
+function fromScaling(out, v) {
+  out[0] = v[0];
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = v[1];
+  out[4] = 0;
+  out[5] = 0;
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector translation
+ * This is equivalent to (but much faster than):
+ *
+ *     mat2d.identity(dest);
+ *     mat2d.translate(dest, dest, vec);
+ *
+ * @param {mat2d} out mat2d receiving operation result
+ * @param {vec2} v Translation vector
+ * @returns {mat2d} out
+ */
+function fromTranslation(out, v) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  out[4] = v[0];
+  out[5] = v[1];
+  return out;
+}
+
+/**
+ * Returns a string representation of a mat2d
+ *
+ * @param {mat2d} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+function str(a) {
+  return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+}
+
+/**
+ * Returns Frobenius norm of a mat2d
+ *
+ * @param {mat2d} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+function frob(a) {
+  return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1);
+}
+
+/**
+ * Adds two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  out[2] = a[2] + b[2];
+  out[3] = a[3] + b[3];
+  out[4] = a[4] + b[4];
+  out[5] = a[5] + b[5];
+  return out;
+}
+
+/**
+ * Subtracts matrix b from matrix a
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  out[2] = a[2] - b[2];
+  out[3] = a[3] - b[3];
+  out[4] = a[4] - b[4];
+  out[5] = a[5] - b[5];
+  return out;
+}
+
+/**
+ * Multiply each element of the matrix by a scalar.
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat2d} out
+ */
+function multiplyScalar(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  out[2] = a[2] * b;
+  out[3] = a[3] * b;
+  out[4] = a[4] * b;
+  out[5] = a[5] * b;
+  return out;
+}
+
+/**
+ * Adds two mat2d's after multiplying each element of the second operand by a scalar value.
+ *
+ * @param {mat2d} out the receiving vector
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat2d} out
+ */
+function multiplyScalarAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  out[2] = a[2] + b[2] * scale;
+  out[3] = a[3] + b[3] * scale;
+  out[4] = a[4] + b[4] * scale;
+  out[5] = a[5] + b[5] * scale;
+  return out;
+}
+
+/**
+ * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {mat2d} a The first matrix.
+ * @param {mat2d} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
+}
+
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat2d} a The first matrix.
+ * @param {mat2d} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3],
+      a4 = a[4],
+      a5 = a[5];
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3],
+      b4 = b[4],
+      b5 = b[5];
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5));
+}
+
+/**
+ * Alias for {@link mat2d.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link mat2d.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/***/ }),
+/* 7 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.sub = exports.mul = undefined;
+exports.create = create;
+exports.clone = clone;
+exports.copy = copy;
+exports.fromValues = fromValues;
+exports.set = set;
+exports.identity = identity;
+exports.transpose = transpose;
+exports.invert = invert;
+exports.adjoint = adjoint;
+exports.determinant = determinant;
+exports.multiply = multiply;
+exports.translate = translate;
+exports.scale = scale;
+exports.rotate = rotate;
+exports.rotateX = rotateX;
+exports.rotateY = rotateY;
+exports.rotateZ = rotateZ;
+exports.fromTranslation = fromTranslation;
+exports.fromScaling = fromScaling;
+exports.fromRotation = fromRotation;
+exports.fromXRotation = fromXRotation;
+exports.fromYRotation = fromYRotation;
+exports.fromZRotation = fromZRotation;
+exports.fromRotationTranslation = fromRotationTranslation;
+exports.getTranslation = getTranslation;
+exports.getScaling = getScaling;
+exports.getRotation = getRotation;
+exports.fromRotationTranslationScale = fromRotationTranslationScale;
+exports.fromRotationTranslationScaleOrigin = fromRotationTranslationScaleOrigin;
+exports.fromQuat = fromQuat;
+exports.frustum = frustum;
+exports.perspective = perspective;
+exports.perspectiveFromFieldOfView = perspectiveFromFieldOfView;
+exports.ortho = ortho;
+exports.lookAt = lookAt;
+exports.targetTo = targetTo;
+exports.str = str;
+exports.frob = frob;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiplyScalar = multiplyScalar;
+exports.multiplyScalarAndAdd = multiplyScalarAndAdd;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 4x4 Matrix
+ * @module mat4
+ */
+
+/**
+ * Creates a new identity mat4
+ *
+ * @returns {mat4} a new 4x4 matrix
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(16);
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = 1;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = 1;
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a new mat4 initialized with values from an existing matrix
+ *
+ * @param {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(16);
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  out[4] = a[4];
+  out[5] = a[5];
+  out[6] = a[6];
+  out[7] = a[7];
+  out[8] = a[8];
+  out[9] = a[9];
+  out[10] = a[10];
+  out[11] = a[11];
+  out[12] = a[12];
+  out[13] = a[13];
+  out[14] = a[14];
+  out[15] = a[15];
+  return out;
+}
+
+/**
+ * Copy the values from one mat4 to another
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  out[2] = a[2];
+  out[3] = a[3];
+  out[4] = a[4];
+  out[5] = a[5];
+  out[6] = a[6];
+  out[7] = a[7];
+  out[8] = a[8];
+  out[9] = a[9];
+  out[10] = a[10];
+  out[11] = a[11];
+  out[12] = a[12];
+  out[13] = a[13];
+  out[14] = a[14];
+  out[15] = a[15];
+  return out;
+}
+
+/**
+ * Create a new mat4 with the given values
+ *
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m03 Component in column 0, row 3 position (index 3)
+ * @param {Number} m10 Component in column 1, row 0 position (index 4)
+ * @param {Number} m11 Component in column 1, row 1 position (index 5)
+ * @param {Number} m12 Component in column 1, row 2 position (index 6)
+ * @param {Number} m13 Component in column 1, row 3 position (index 7)
+ * @param {Number} m20 Component in column 2, row 0 position (index 8)
+ * @param {Number} m21 Component in column 2, row 1 position (index 9)
+ * @param {Number} m22 Component in column 2, row 2 position (index 10)
+ * @param {Number} m23 Component in column 2, row 3 position (index 11)
+ * @param {Number} m30 Component in column 3, row 0 position (index 12)
+ * @param {Number} m31 Component in column 3, row 1 position (index 13)
+ * @param {Number} m32 Component in column 3, row 2 position (index 14)
+ * @param {Number} m33 Component in column 3, row 3 position (index 15)
+ * @returns {mat4} A new mat4
+ */
+function fromValues(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+  var out = new glMatrix.ARRAY_TYPE(16);
+  out[0] = m00;
+  out[1] = m01;
+  out[2] = m02;
+  out[3] = m03;
+  out[4] = m10;
+  out[5] = m11;
+  out[6] = m12;
+  out[7] = m13;
+  out[8] = m20;
+  out[9] = m21;
+  out[10] = m22;
+  out[11] = m23;
+  out[12] = m30;
+  out[13] = m31;
+  out[14] = m32;
+  out[15] = m33;
+  return out;
+}
+
+/**
+ * Set the components of a mat4 to the given values
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {Number} m00 Component in column 0, row 0 position (index 0)
+ * @param {Number} m01 Component in column 0, row 1 position (index 1)
+ * @param {Number} m02 Component in column 0, row 2 position (index 2)
+ * @param {Number} m03 Component in column 0, row 3 position (index 3)
+ * @param {Number} m10 Component in column 1, row 0 position (index 4)
+ * @param {Number} m11 Component in column 1, row 1 position (index 5)
+ * @param {Number} m12 Component in column 1, row 2 position (index 6)
+ * @param {Number} m13 Component in column 1, row 3 position (index 7)
+ * @param {Number} m20 Component in column 2, row 0 position (index 8)
+ * @param {Number} m21 Component in column 2, row 1 position (index 9)
+ * @param {Number} m22 Component in column 2, row 2 position (index 10)
+ * @param {Number} m23 Component in column 2, row 3 position (index 11)
+ * @param {Number} m30 Component in column 3, row 0 position (index 12)
+ * @param {Number} m31 Component in column 3, row 1 position (index 13)
+ * @param {Number} m32 Component in column 3, row 2 position (index 14)
+ * @param {Number} m33 Component in column 3, row 3 position (index 15)
+ * @returns {mat4} out
+ */
+function set(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
+  out[0] = m00;
+  out[1] = m01;
+  out[2] = m02;
+  out[3] = m03;
+  out[4] = m10;
+  out[5] = m11;
+  out[6] = m12;
+  out[7] = m13;
+  out[8] = m20;
+  out[9] = m21;
+  out[10] = m22;
+  out[11] = m23;
+  out[12] = m30;
+  out[13] = m31;
+  out[14] = m32;
+  out[15] = m33;
+  return out;
+}
+
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+ */
+function identity(out) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = 1;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = 1;
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Transpose the values of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+function transpose(out, a) {
+  // If we are transposing ourselves we can skip a few steps but have to cache some values
+  if (out === a) {
+    var a01 = a[1],
+        a02 = a[2],
+        a03 = a[3];
+    var a12 = a[6],
+        a13 = a[7];
+    var a23 = a[11];
+
+    out[1] = a[4];
+    out[2] = a[8];
+    out[3] = a[12];
+    out[4] = a01;
+    out[6] = a[9];
+    out[7] = a[13];
+    out[8] = a02;
+    out[9] = a12;
+    out[11] = a[14];
+    out[12] = a03;
+    out[13] = a13;
+    out[14] = a23;
+  } else {
+    out[0] = a[0];
+    out[1] = a[4];
+    out[2] = a[8];
+    out[3] = a[12];
+    out[4] = a[1];
+    out[5] = a[5];
+    out[6] = a[9];
+    out[7] = a[13];
+    out[8] = a[2];
+    out[9] = a[6];
+    out[10] = a[10];
+    out[11] = a[14];
+    out[12] = a[3];
+    out[13] = a[7];
+    out[14] = a[11];
+    out[15] = a[15];
+  }
+
+  return out;
+}
+
+/**
+ * Inverts a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+function invert(out, a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a03 = a[3];
+  var a10 = a[4],
+      a11 = a[5],
+      a12 = a[6],
+      a13 = a[7];
+  var a20 = a[8],
+      a21 = a[9],
+      a22 = a[10],
+      a23 = a[11];
+  var a30 = a[12],
+      a31 = a[13],
+      a32 = a[14],
+      a33 = a[15];
+
+  var b00 = a00 * a11 - a01 * a10;
+  var b01 = a00 * a12 - a02 * a10;
+  var b02 = a00 * a13 - a03 * a10;
+  var b03 = a01 * a12 - a02 * a11;
+  var b04 = a01 * a13 - a03 * a11;
+  var b05 = a02 * a13 - a03 * a12;
+  var b06 = a20 * a31 - a21 * a30;
+  var b07 = a20 * a32 - a22 * a30;
+  var b08 = a20 * a33 - a23 * a30;
+  var b09 = a21 * a32 - a22 * a31;
+  var b10 = a21 * a33 - a23 * a31;
+  var b11 = a22 * a33 - a23 * a32;
+
+  // Calculate the determinant
+  var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+  if (!det) {
+    return null;
+  }
+  det = 1.0 / det;
+
+  out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+  out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+  out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+  out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+  out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+  out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+  out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+  out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+  out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+  out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+  out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+  out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+  out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+  out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+  out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+  out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+
+  return out;
+}
+
+/**
+ * Calculates the adjugate of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+function adjoint(out, a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a03 = a[3];
+  var a10 = a[4],
+      a11 = a[5],
+      a12 = a[6],
+      a13 = a[7];
+  var a20 = a[8],
+      a21 = a[9],
+      a22 = a[10],
+      a23 = a[11];
+  var a30 = a[12],
+      a31 = a[13],
+      a32 = a[14],
+      a33 = a[15];
+
+  out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
+  out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+  out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
+  out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+  out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+  out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
+  out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+  out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
+  out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
+  out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+  out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
+  out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+  out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+  out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
+  out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+  out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
+  return out;
+}
+
+/**
+ * Calculates the determinant of a mat4
+ *
+ * @param {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+function determinant(a) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a03 = a[3];
+  var a10 = a[4],
+      a11 = a[5],
+      a12 = a[6],
+      a13 = a[7];
+  var a20 = a[8],
+      a21 = a[9],
+      a22 = a[10],
+      a23 = a[11];
+  var a30 = a[12],
+      a31 = a[13],
+      a32 = a[14],
+      a33 = a[15];
+
+  var b00 = a00 * a11 - a01 * a10;
+  var b01 = a00 * a12 - a02 * a10;
+  var b02 = a00 * a13 - a03 * a10;
+  var b03 = a01 * a12 - a02 * a11;
+  var b04 = a01 * a13 - a03 * a11;
+  var b05 = a02 * a13 - a03 * a12;
+  var b06 = a20 * a31 - a21 * a30;
+  var b07 = a20 * a32 - a22 * a30;
+  var b08 = a20 * a33 - a23 * a30;
+  var b09 = a21 * a32 - a22 * a31;
+  var b10 = a21 * a33 - a23 * a31;
+  var b11 = a22 * a33 - a23 * a32;
+
+  // Calculate the determinant
+  return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+}
+
+/**
+ * Multiplies two mat4s
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+function multiply(out, a, b) {
+  var a00 = a[0],
+      a01 = a[1],
+      a02 = a[2],
+      a03 = a[3];
+  var a10 = a[4],
+      a11 = a[5],
+      a12 = a[6],
+      a13 = a[7];
+  var a20 = a[8],
+      a21 = a[9],
+      a22 = a[10],
+      a23 = a[11];
+  var a30 = a[12],
+      a31 = a[13],
+      a32 = a[14],
+      a33 = a[15];
+
+  // Cache only the current line of the second matrix
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3];
+  out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+  out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+  out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+  out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+
+  b0 = b[4];b1 = b[5];b2 = b[6];b3 = b[7];
+  out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+  out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+  out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+  out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+
+  b0 = b[8];b1 = b[9];b2 = b[10];b3 = b[11];
+  out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+  out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+  out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+  out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+
+  b0 = b[12];b1 = b[13];b2 = b[14];b3 = b[15];
+  out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+  out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+  out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+  out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+  return out;
+}
+
+/**
+ * Translate a mat4 by the given vector
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to translate
+ * @param {vec3} v vector to translate by
+ * @returns {mat4} out
+ */
+function translate(out, a, v) {
+  var x = v[0],
+      y = v[1],
+      z = v[2];
+  var a00 = void 0,
+      a01 = void 0,
+      a02 = void 0,
+      a03 = void 0;
+  var a10 = void 0,
+      a11 = void 0,
+      a12 = void 0,
+      a13 = void 0;
+  var a20 = void 0,
+      a21 = void 0,
+      a22 = void 0,
+      a23 = void 0;
+
+  if (a === out) {
+    out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+    out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+    out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+    out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+  } else {
+    a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3];
+    a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7];
+    a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11];
+
+    out[0] = a00;out[1] = a01;out[2] = a02;out[3] = a03;
+    out[4] = a10;out[5] = a11;out[6] = a12;out[7] = a13;
+    out[8] = a20;out[9] = a21;out[10] = a22;out[11] = a23;
+
+    out[12] = a00 * x + a10 * y + a20 * z + a[12];
+    out[13] = a01 * x + a11 * y + a21 * z + a[13];
+    out[14] = a02 * x + a12 * y + a22 * z + a[14];
+    out[15] = a03 * x + a13 * y + a23 * z + a[15];
+  }
+
+  return out;
+}
+
+/**
+ * Scales the mat4 by the dimensions in the given vec3 not using vectorization
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {vec3} v the vec3 to scale the matrix by
+ * @returns {mat4} out
+ **/
+function scale(out, a, v) {
+  var x = v[0],
+      y = v[1],
+      z = v[2];
+
+  out[0] = a[0] * x;
+  out[1] = a[1] * x;
+  out[2] = a[2] * x;
+  out[3] = a[3] * x;
+  out[4] = a[4] * y;
+  out[5] = a[5] * y;
+  out[6] = a[6] * y;
+  out[7] = a[7] * y;
+  out[8] = a[8] * z;
+  out[9] = a[9] * z;
+  out[10] = a[10] * z;
+  out[11] = a[11] * z;
+  out[12] = a[12];
+  out[13] = a[13];
+  out[14] = a[14];
+  out[15] = a[15];
+  return out;
+}
+
+/**
+ * Rotates a mat4 by the given angle around the given axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+function rotate(out, a, rad, axis) {
+  var x = axis[0],
+      y = axis[1],
+      z = axis[2];
+  var len = Math.sqrt(x * x + y * y + z * z);
+  var s = void 0,
+      c = void 0,
+      t = void 0;
+  var a00 = void 0,
+      a01 = void 0,
+      a02 = void 0,
+      a03 = void 0;
+  var a10 = void 0,
+      a11 = void 0,
+      a12 = void 0,
+      a13 = void 0;
+  var a20 = void 0,
+      a21 = void 0,
+      a22 = void 0,
+      a23 = void 0;
+  var b00 = void 0,
+      b01 = void 0,
+      b02 = void 0;
+  var b10 = void 0,
+      b11 = void 0,
+      b12 = void 0;
+  var b20 = void 0,
+      b21 = void 0,
+      b22 = void 0;
+
+  if (Math.abs(len) < glMatrix.EPSILON) {
+    return null;
+  }
+
+  len = 1 / len;
+  x *= len;
+  y *= len;
+  z *= len;
+
+  s = Math.sin(rad);
+  c = Math.cos(rad);
+  t = 1 - c;
+
+  a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3];
+  a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7];
+  a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11];
+
+  // Construct the elements of the rotation matrix
+  b00 = x * x * t + c;b01 = y * x * t + z * s;b02 = z * x * t - y * s;
+  b10 = x * y * t - z * s;b11 = y * y * t + c;b12 = z * y * t + x * s;
+  b20 = x * z * t + y * s;b21 = y * z * t - x * s;b22 = z * z * t + c;
+
+  // Perform rotation-specific matrix multiplication
+  out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+  out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+  out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+  out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+  out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+  out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+  out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+  out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+  out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+  out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+  out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+  out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+  if (a !== out) {
+    // If the source and destination differ, copy the unchanged last row
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+  }
+  return out;
+}
+
+/**
+ * Rotates a matrix by the given angle around the X axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function rotateX(out, a, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+  var a10 = a[4];
+  var a11 = a[5];
+  var a12 = a[6];
+  var a13 = a[7];
+  var a20 = a[8];
+  var a21 = a[9];
+  var a22 = a[10];
+  var a23 = a[11];
+
+  if (a !== out) {
+    // If the source and destination differ, copy the unchanged rows
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+  }
+
+  // Perform axis-specific matrix multiplication
+  out[4] = a10 * c + a20 * s;
+  out[5] = a11 * c + a21 * s;
+  out[6] = a12 * c + a22 * s;
+  out[7] = a13 * c + a23 * s;
+  out[8] = a20 * c - a10 * s;
+  out[9] = a21 * c - a11 * s;
+  out[10] = a22 * c - a12 * s;
+  out[11] = a23 * c - a13 * s;
+  return out;
+}
+
+/**
+ * Rotates a matrix by the given angle around the Y axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function rotateY(out, a, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+  var a00 = a[0];
+  var a01 = a[1];
+  var a02 = a[2];
+  var a03 = a[3];
+  var a20 = a[8];
+  var a21 = a[9];
+  var a22 = a[10];
+  var a23 = a[11];
+
+  if (a !== out) {
+    // If the source and destination differ, copy the unchanged rows
+    out[4] = a[4];
+    out[5] = a[5];
+    out[6] = a[6];
+    out[7] = a[7];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+  }
+
+  // Perform axis-specific matrix multiplication
+  out[0] = a00 * c - a20 * s;
+  out[1] = a01 * c - a21 * s;
+  out[2] = a02 * c - a22 * s;
+  out[3] = a03 * c - a23 * s;
+  out[8] = a00 * s + a20 * c;
+  out[9] = a01 * s + a21 * c;
+  out[10] = a02 * s + a22 * c;
+  out[11] = a03 * s + a23 * c;
+  return out;
+}
+
+/**
+ * Rotates a matrix by the given angle around the Z axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function rotateZ(out, a, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+  var a00 = a[0];
+  var a01 = a[1];
+  var a02 = a[2];
+  var a03 = a[3];
+  var a10 = a[4];
+  var a11 = a[5];
+  var a12 = a[6];
+  var a13 = a[7];
+
+  if (a !== out) {
+    // If the source and destination differ, copy the unchanged last row
+    out[8] = a[8];
+    out[9] = a[9];
+    out[10] = a[10];
+    out[11] = a[11];
+    out[12] = a[12];
+    out[13] = a[13];
+    out[14] = a[14];
+    out[15] = a[15];
+  }
+
+  // Perform axis-specific matrix multiplication
+  out[0] = a00 * c + a10 * s;
+  out[1] = a01 * c + a11 * s;
+  out[2] = a02 * c + a12 * s;
+  out[3] = a03 * c + a13 * s;
+  out[4] = a10 * c - a00 * s;
+  out[5] = a11 * c - a01 * s;
+  out[6] = a12 * c - a02 * s;
+  out[7] = a13 * c - a03 * s;
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector translation
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.translate(dest, dest, vec);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+function fromTranslation(out, v) {
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = 1;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = 1;
+  out[11] = 0;
+  out[12] = v[0];
+  out[13] = v[1];
+  out[14] = v[2];
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from a vector scaling
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.scale(dest, dest, vec);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {vec3} v Scaling vector
+ * @returns {mat4} out
+ */
+function fromScaling(out, v) {
+  out[0] = v[0];
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = v[1];
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = v[2];
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from a given angle around a given axis
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.rotate(dest, dest, rad, axis);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+function fromRotation(out, rad, axis) {
+  var x = axis[0],
+      y = axis[1],
+      z = axis[2];
+  var len = Math.sqrt(x * x + y * y + z * z);
+  var s = void 0,
+      c = void 0,
+      t = void 0;
+
+  if (Math.abs(len) < glMatrix.EPSILON) {
+    return null;
+  }
+
+  len = 1 / len;
+  x *= len;
+  y *= len;
+  z *= len;
+
+  s = Math.sin(rad);
+  c = Math.cos(rad);
+  t = 1 - c;
+
+  // Perform rotation-specific matrix multiplication
+  out[0] = x * x * t + c;
+  out[1] = y * x * t + z * s;
+  out[2] = z * x * t - y * s;
+  out[3] = 0;
+  out[4] = x * y * t - z * s;
+  out[5] = y * y * t + c;
+  out[6] = z * y * t + x * s;
+  out[7] = 0;
+  out[8] = x * z * t + y * s;
+  out[9] = y * z * t - x * s;
+  out[10] = z * z * t + c;
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from the given angle around the X axis
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.rotateX(dest, dest, rad);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function fromXRotation(out, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+
+  // Perform axis-specific matrix multiplication
+  out[0] = 1;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = c;
+  out[6] = s;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = -s;
+  out[10] = c;
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from the given angle around the Y axis
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.rotateY(dest, dest, rad);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function fromYRotation(out, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+
+  // Perform axis-specific matrix multiplication
+  out[0] = c;
+  out[1] = 0;
+  out[2] = -s;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = 1;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = s;
+  out[9] = 0;
+  out[10] = c;
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from the given angle around the Z axis
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.rotateZ(dest, dest, rad);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+function fromZRotation(out, rad) {
+  var s = Math.sin(rad);
+  var c = Math.cos(rad);
+
+  // Perform axis-specific matrix multiplication
+  out[0] = c;
+  out[1] = s;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = -s;
+  out[5] = c;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = 1;
+  out[11] = 0;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Creates a matrix from a quaternion rotation and vector translation
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.translate(dest, vec);
+ *     let quatMat = mat4.create();
+ *     quat4.toMat4(quat, quatMat);
+ *     mat4.multiply(dest, quatMat);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+function fromRotationTranslation(out, q, v) {
+  // Quaternion math
+  var x = q[0],
+      y = q[1],
+      z = q[2],
+      w = q[3];
+  var x2 = x + x;
+  var y2 = y + y;
+  var z2 = z + z;
+
+  var xx = x * x2;
+  var xy = x * y2;
+  var xz = x * z2;
+  var yy = y * y2;
+  var yz = y * z2;
+  var zz = z * z2;
+  var wx = w * x2;
+  var wy = w * y2;
+  var wz = w * z2;
+
+  out[0] = 1 - (yy + zz);
+  out[1] = xy + wz;
+  out[2] = xz - wy;
+  out[3] = 0;
+  out[4] = xy - wz;
+  out[5] = 1 - (xx + zz);
+  out[6] = yz + wx;
+  out[7] = 0;
+  out[8] = xz + wy;
+  out[9] = yz - wx;
+  out[10] = 1 - (xx + yy);
+  out[11] = 0;
+  out[12] = v[0];
+  out[13] = v[1];
+  out[14] = v[2];
+  out[15] = 1;
+
+  return out;
+}
+
+/**
+ * Returns the translation vector component of a transformation
+ *  matrix. If a matrix is built with fromRotationTranslation,
+ *  the returned vector will be the same as the translation vector
+ *  originally supplied.
+ * @param  {vec3} out Vector to receive translation component
+ * @param  {mat4} mat Matrix to be decomposed (input)
+ * @return {vec3} out
+ */
+function getTranslation(out, mat) {
+  out[0] = mat[12];
+  out[1] = mat[13];
+  out[2] = mat[14];
+
+  return out;
+}
+
+/**
+ * Returns the scaling factor component of a transformation
+ *  matrix. If a matrix is built with fromRotationTranslationScale
+ *  with a normalized Quaternion paramter, the returned vector will be
+ *  the same as the scaling vector
+ *  originally supplied.
+ * @param  {vec3} out Vector to receive scaling factor component
+ * @param  {mat4} mat Matrix to be decomposed (input)
+ * @return {vec3} out
+ */
+function getScaling(out, mat) {
+  var m11 = mat[0];
+  var m12 = mat[1];
+  var m13 = mat[2];
+  var m21 = mat[4];
+  var m22 = mat[5];
+  var m23 = mat[6];
+  var m31 = mat[8];
+  var m32 = mat[9];
+  var m33 = mat[10];
+
+  out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);
+  out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);
+  out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);
+
+  return out;
+}
+
+/**
+ * Returns a quaternion representing the rotational component
+ *  of a transformation matrix. If a matrix is built with
+ *  fromRotationTranslation, the returned quaternion will be the
+ *  same as the quaternion originally supplied.
+ * @param {quat} out Quaternion to receive the rotation component
+ * @param {mat4} mat Matrix to be decomposed (input)
+ * @return {quat} out
+ */
+function getRotation(out, mat) {
+  // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
+  var trace = mat[0] + mat[5] + mat[10];
+  var S = 0;
+
+  if (trace > 0) {
+    S = Math.sqrt(trace + 1.0) * 2;
+    out[3] = 0.25 * S;
+    out[0] = (mat[6] - mat[9]) / S;
+    out[1] = (mat[8] - mat[2]) / S;
+    out[2] = (mat[1] - mat[4]) / S;
+  } else if (mat[0] > mat[5] & mat[0] > mat[10]) {
+    S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2;
+    out[3] = (mat[6] - mat[9]) / S;
+    out[0] = 0.25 * S;
+    out[1] = (mat[1] + mat[4]) / S;
+    out[2] = (mat[8] + mat[2]) / S;
+  } else if (mat[5] > mat[10]) {
+    S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2;
+    out[3] = (mat[8] - mat[2]) / S;
+    out[0] = (mat[1] + mat[4]) / S;
+    out[1] = 0.25 * S;
+    out[2] = (mat[6] + mat[9]) / S;
+  } else {
+    S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2;
+    out[3] = (mat[1] - mat[4]) / S;
+    out[0] = (mat[8] + mat[2]) / S;
+    out[1] = (mat[6] + mat[9]) / S;
+    out[2] = 0.25 * S;
+  }
+
+  return out;
+}
+
+/**
+ * Creates a matrix from a quaternion rotation, vector translation and vector scale
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.translate(dest, vec);
+ *     let quatMat = mat4.create();
+ *     quat4.toMat4(quat, quatMat);
+ *     mat4.multiply(dest, quatMat);
+ *     mat4.scale(dest, scale)
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @param {vec3} s Scaling vector
+ * @returns {mat4} out
+ */
+function fromRotationTranslationScale(out, q, v, s) {
+  // Quaternion math
+  var x = q[0],
+      y = q[1],
+      z = q[2],
+      w = q[3];
+  var x2 = x + x;
+  var y2 = y + y;
+  var z2 = z + z;
+
+  var xx = x * x2;
+  var xy = x * y2;
+  var xz = x * z2;
+  var yy = y * y2;
+  var yz = y * z2;
+  var zz = z * z2;
+  var wx = w * x2;
+  var wy = w * y2;
+  var wz = w * z2;
+  var sx = s[0];
+  var sy = s[1];
+  var sz = s[2];
+
+  out[0] = (1 - (yy + zz)) * sx;
+  out[1] = (xy + wz) * sx;
+  out[2] = (xz - wy) * sx;
+  out[3] = 0;
+  out[4] = (xy - wz) * sy;
+  out[5] = (1 - (xx + zz)) * sy;
+  out[6] = (yz + wx) * sy;
+  out[7] = 0;
+  out[8] = (xz + wy) * sz;
+  out[9] = (yz - wx) * sz;
+  out[10] = (1 - (xx + yy)) * sz;
+  out[11] = 0;
+  out[12] = v[0];
+  out[13] = v[1];
+  out[14] = v[2];
+  out[15] = 1;
+
+  return out;
+}
+
+/**
+ * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
+ * This is equivalent to (but much faster than):
+ *
+ *     mat4.identity(dest);
+ *     mat4.translate(dest, vec);
+ *     mat4.translate(dest, origin);
+ *     let quatMat = mat4.create();
+ *     quat4.toMat4(quat, quatMat);
+ *     mat4.multiply(dest, quatMat);
+ *     mat4.scale(dest, scale)
+ *     mat4.translate(dest, negativeOrigin);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @param {vec3} s Scaling vector
+ * @param {vec3} o The origin vector around which to scale and rotate
+ * @returns {mat4} out
+ */
+function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
+  // Quaternion math
+  var x = q[0],
+      y = q[1],
+      z = q[2],
+      w = q[3];
+  var x2 = x + x;
+  var y2 = y + y;
+  var z2 = z + z;
+
+  var xx = x * x2;
+  var xy = x * y2;
+  var xz = x * z2;
+  var yy = y * y2;
+  var yz = y * z2;
+  var zz = z * z2;
+  var wx = w * x2;
+  var wy = w * y2;
+  var wz = w * z2;
+
+  var sx = s[0];
+  var sy = s[1];
+  var sz = s[2];
+
+  var ox = o[0];
+  var oy = o[1];
+  var oz = o[2];
+
+  out[0] = (1 - (yy + zz)) * sx;
+  out[1] = (xy + wz) * sx;
+  out[2] = (xz - wy) * sx;
+  out[3] = 0;
+  out[4] = (xy - wz) * sy;
+  out[5] = (1 - (xx + zz)) * sy;
+  out[6] = (yz + wx) * sy;
+  out[7] = 0;
+  out[8] = (xz + wy) * sz;
+  out[9] = (yz - wx) * sz;
+  out[10] = (1 - (xx + yy)) * sz;
+  out[11] = 0;
+  out[12] = v[0] + ox - (out[0] * ox + out[4] * oy + out[8] * oz);
+  out[13] = v[1] + oy - (out[1] * ox + out[5] * oy + out[9] * oz);
+  out[14] = v[2] + oz - (out[2] * ox + out[6] * oy + out[10] * oz);
+  out[15] = 1;
+
+  return out;
+}
+
+/**
+ * Calculates a 4x4 matrix from the given quaternion
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat} q Quaternion to create matrix from
+ *
+ * @returns {mat4} out
+ */
+function fromQuat(out, q) {
+  var x = q[0],
+      y = q[1],
+      z = q[2],
+      w = q[3];
+  var x2 = x + x;
+  var y2 = y + y;
+  var z2 = z + z;
+
+  var xx = x * x2;
+  var yx = y * x2;
+  var yy = y * y2;
+  var zx = z * x2;
+  var zy = z * y2;
+  var zz = z * z2;
+  var wx = w * x2;
+  var wy = w * y2;
+  var wz = w * z2;
+
+  out[0] = 1 - yy - zz;
+  out[1] = yx + wz;
+  out[2] = zx - wy;
+  out[3] = 0;
+
+  out[4] = yx - wz;
+  out[5] = 1 - xx - zz;
+  out[6] = zy + wx;
+  out[7] = 0;
+
+  out[8] = zx + wy;
+  out[9] = zy - wx;
+  out[10] = 1 - xx - yy;
+  out[11] = 0;
+
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 0;
+  out[15] = 1;
+
+  return out;
+}
+
+/**
+ * Generates a frustum matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Number} left Left bound of the frustum
+ * @param {Number} right Right bound of the frustum
+ * @param {Number} bottom Bottom bound of the frustum
+ * @param {Number} top Top bound of the frustum
+ * @param {Number} near Near bound of the frustum
+ * @param {Number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+function frustum(out, left, right, bottom, top, near, far) {
+  var rl = 1 / (right - left);
+  var tb = 1 / (top - bottom);
+  var nf = 1 / (near - far);
+  out[0] = near * 2 * rl;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = near * 2 * tb;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = (right + left) * rl;
+  out[9] = (top + bottom) * tb;
+  out[10] = (far + near) * nf;
+  out[11] = -1;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = far * near * 2 * nf;
+  out[15] = 0;
+  return out;
+}
+
+/**
+ * Generates a perspective projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} fovy Vertical field of view in radians
+ * @param {number} aspect Aspect ratio. typically viewport width/height
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+function perspective(out, fovy, aspect, near, far) {
+  var f = 1.0 / Math.tan(fovy / 2);
+  var nf = 1 / (near - far);
+  out[0] = f / aspect;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = f;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = (far + near) * nf;
+  out[11] = -1;
+  out[12] = 0;
+  out[13] = 0;
+  out[14] = 2 * far * near * nf;
+  out[15] = 0;
+  return out;
+}
+
+/**
+ * Generates a perspective projection matrix with the given field of view.
+ * This is primarily useful for generating projection matrices to be used
+ * with the still experiemental WebVR API.
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+function perspectiveFromFieldOfView(out, fov, near, far) {
+  var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
+  var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
+  var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
+  var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
+  var xScale = 2.0 / (leftTan + rightTan);
+  var yScale = 2.0 / (upTan + downTan);
+
+  out[0] = xScale;
+  out[1] = 0.0;
+  out[2] = 0.0;
+  out[3] = 0.0;
+  out[4] = 0.0;
+  out[5] = yScale;
+  out[6] = 0.0;
+  out[7] = 0.0;
+  out[8] = -((leftTan - rightTan) * xScale * 0.5);
+  out[9] = (upTan - downTan) * yScale * 0.5;
+  out[10] = far / (near - far);
+  out[11] = -1.0;
+  out[12] = 0.0;
+  out[13] = 0.0;
+  out[14] = far * near / (near - far);
+  out[15] = 0.0;
+  return out;
+}
+
+/**
+ * Generates a orthogonal projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} left Left bound of the frustum
+ * @param {number} right Right bound of the frustum
+ * @param {number} bottom Bottom bound of the frustum
+ * @param {number} top Top bound of the frustum
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+function ortho(out, left, right, bottom, top, near, far) {
+  var lr = 1 / (left - right);
+  var bt = 1 / (bottom - top);
+  var nf = 1 / (near - far);
+  out[0] = -2 * lr;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 0;
+  out[4] = 0;
+  out[5] = -2 * bt;
+  out[6] = 0;
+  out[7] = 0;
+  out[8] = 0;
+  out[9] = 0;
+  out[10] = 2 * nf;
+  out[11] = 0;
+  out[12] = (left + right) * lr;
+  out[13] = (top + bottom) * bt;
+  out[14] = (far + near) * nf;
+  out[15] = 1;
+  return out;
+}
+
+/**
+ * Generates a look-at matrix with the given eye position, focal point, and up axis
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+function lookAt(out, eye, center, up) {
+  var x0 = void 0,
+      x1 = void 0,
+      x2 = void 0,
+      y0 = void 0,
+      y1 = void 0,
+      y2 = void 0,
+      z0 = void 0,
+      z1 = void 0,
+      z2 = void 0,
+      len = void 0;
+  var eyex = eye[0];
+  var eyey = eye[1];
+  var eyez = eye[2];
+  var upx = up[0];
+  var upy = up[1];
+  var upz = up[2];
+  var centerx = center[0];
+  var centery = center[1];
+  var centerz = center[2];
+
+  if (Math.abs(eyex - centerx) < glMatrix.EPSILON && Math.abs(eyey - centery) < glMatrix.EPSILON && Math.abs(eyez - centerz) < glMatrix.EPSILON) {
+    return mat4.identity(out);
+  }
+
+  z0 = eyex - centerx;
+  z1 = eyey - centery;
+  z2 = eyez - centerz;
+
+  len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
+  z0 *= len;
+  z1 *= len;
+  z2 *= len;
+
+  x0 = upy * z2 - upz * z1;
+  x1 = upz * z0 - upx * z2;
+  x2 = upx * z1 - upy * z0;
+  len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
+  if (!len) {
+    x0 = 0;
+    x1 = 0;
+    x2 = 0;
+  } else {
+    len = 1 / len;
+    x0 *= len;
+    x1 *= len;
+    x2 *= len;
+  }
+
+  y0 = z1 * x2 - z2 * x1;
+  y1 = z2 * x0 - z0 * x2;
+  y2 = z0 * x1 - z1 * x0;
+
+  len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
+  if (!len) {
+    y0 = 0;
+    y1 = 0;
+    y2 = 0;
+  } else {
+    len = 1 / len;
+    y0 *= len;
+    y1 *= len;
+    y2 *= len;
+  }
+
+  out[0] = x0;
+  out[1] = y0;
+  out[2] = z0;
+  out[3] = 0;
+  out[4] = x1;
+  out[5] = y1;
+  out[6] = z1;
+  out[7] = 0;
+  out[8] = x2;
+  out[9] = y2;
+  out[10] = z2;
+  out[11] = 0;
+  out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+  out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+  out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+  out[15] = 1;
+
+  return out;
+}
+
+/**
+ * Generates a matrix that makes something look at something else.
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+function targetTo(out, eye, target, up) {
+  var eyex = eye[0],
+      eyey = eye[1],
+      eyez = eye[2],
+      upx = up[0],
+      upy = up[1],
+      upz = up[2];
+
+  var z0 = eyex - target[0],
+      z1 = eyey - target[1],
+      z2 = eyez - target[2];
+
+  var len = z0 * z0 + z1 * z1 + z2 * z2;
+  if (len > 0) {
+    len = 1 / Math.sqrt(len);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
+  }
+
+  var x0 = upy * z2 - upz * z1,
+      x1 = upz * z0 - upx * z2,
+      x2 = upx * z1 - upy * z0;
+
+  out[0] = x0;
+  out[1] = x1;
+  out[2] = x2;
+  out[3] = 0;
+  out[4] = z1 * x2 - z2 * x1;
+  out[5] = z2 * x0 - z0 * x2;
+  out[6] = z0 * x1 - z1 * x0;
+  out[7] = 0;
+  out[8] = z0;
+  out[9] = z1;
+  out[10] = z2;
+  out[11] = 0;
+  out[12] = eyex;
+  out[13] = eyey;
+  out[14] = eyez;
+  out[15] = 1;
+  return out;
+};
+
+/**
+ * Returns a string representation of a mat4
+ *
+ * @param {mat4} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+function str(a) {
+  return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+}
+
+/**
+ * Returns Frobenius norm of a mat4
+ *
+ * @param {mat4} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
+ */
+function frob(a) {
+  return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2));
+}
+
+/**
+ * Adds two mat4's
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  out[2] = a[2] + b[2];
+  out[3] = a[3] + b[3];
+  out[4] = a[4] + b[4];
+  out[5] = a[5] + b[5];
+  out[6] = a[6] + b[6];
+  out[7] = a[7] + b[7];
+  out[8] = a[8] + b[8];
+  out[9] = a[9] + b[9];
+  out[10] = a[10] + b[10];
+  out[11] = a[11] + b[11];
+  out[12] = a[12] + b[12];
+  out[13] = a[13] + b[13];
+  out[14] = a[14] + b[14];
+  out[15] = a[15] + b[15];
+  return out;
+}
+
+/**
+ * Subtracts matrix b from matrix a
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  out[2] = a[2] - b[2];
+  out[3] = a[3] - b[3];
+  out[4] = a[4] - b[4];
+  out[5] = a[5] - b[5];
+  out[6] = a[6] - b[6];
+  out[7] = a[7] - b[7];
+  out[8] = a[8] - b[8];
+  out[9] = a[9] - b[9];
+  out[10] = a[10] - b[10];
+  out[11] = a[11] - b[11];
+  out[12] = a[12] - b[12];
+  out[13] = a[13] - b[13];
+  out[14] = a[14] - b[14];
+  out[15] = a[15] - b[15];
+  return out;
+}
+
+/**
+ * Multiply each element of the matrix by a scalar.
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {Number} b amount to scale the matrix's elements by
+ * @returns {mat4} out
+ */
+function multiplyScalar(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  out[2] = a[2] * b;
+  out[3] = a[3] * b;
+  out[4] = a[4] * b;
+  out[5] = a[5] * b;
+  out[6] = a[6] * b;
+  out[7] = a[7] * b;
+  out[8] = a[8] * b;
+  out[9] = a[9] * b;
+  out[10] = a[10] * b;
+  out[11] = a[11] * b;
+  out[12] = a[12] * b;
+  out[13] = a[13] * b;
+  out[14] = a[14] * b;
+  out[15] = a[15] * b;
+  return out;
+}
+
+/**
+ * Adds two mat4's after multiplying each element of the second operand by a scalar value.
+ *
+ * @param {mat4} out the receiving vector
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @param {Number} scale the amount to scale b's elements by before adding
+ * @returns {mat4} out
+ */
+function multiplyScalarAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  out[2] = a[2] + b[2] * scale;
+  out[3] = a[3] + b[3] * scale;
+  out[4] = a[4] + b[4] * scale;
+  out[5] = a[5] + b[5] * scale;
+  out[6] = a[6] + b[6] * scale;
+  out[7] = a[7] + b[7] * scale;
+  out[8] = a[8] + b[8] * scale;
+  out[9] = a[9] + b[9] * scale;
+  out[10] = a[10] + b[10] * scale;
+  out[11] = a[11] + b[11] * scale;
+  out[12] = a[12] + b[12] * scale;
+  out[13] = a[13] + b[13] * scale;
+  out[14] = a[14] + b[14] * scale;
+  out[15] = a[15] + b[15] * scale;
+  return out;
+}
+
+/**
+ * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {mat4} a The first matrix.
+ * @param {mat4} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
+}
+
+/**
+ * Returns whether or not the matrices have approximately the same elements in the same position.
+ *
+ * @param {mat4} a The first matrix.
+ * @param {mat4} b The second matrix.
+ * @returns {Boolean} True if the matrices are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var a4 = a[4],
+      a5 = a[5],
+      a6 = a[6],
+      a7 = a[7];
+  var a8 = a[8],
+      a9 = a[9],
+      a10 = a[10],
+      a11 = a[11];
+  var a12 = a[12],
+      a13 = a[13],
+      a14 = a[14],
+      a15 = a[15];
+
+  var b0 = b[0],
+      b1 = b[1],
+      b2 = b[2],
+      b3 = b[3];
+  var b4 = b[4],
+      b5 = b[5],
+      b6 = b[6],
+      b7 = b[7];
+  var b8 = b[8],
+      b9 = b[9],
+      b10 = b[10],
+      b11 = b[11];
+  var b12 = b[12],
+      b13 = b[13],
+      b14 = b[14],
+      b15 = b[15];
+
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15));
+}
+
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link mat4.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/***/ }),
+/* 8 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.setAxes = exports.sqlerp = exports.rotationTo = exports.equals = exports.exactEquals = exports.normalize = exports.sqrLen = exports.squaredLength = exports.len = exports.length = exports.lerp = exports.dot = exports.scale = exports.mul = exports.add = exports.set = exports.copy = exports.fromValues = exports.clone = undefined;
+exports.create = create;
+exports.identity = identity;
+exports.setAxisAngle = setAxisAngle;
+exports.getAxisAngle = getAxisAngle;
+exports.multiply = multiply;
+exports.rotateX = rotateX;
+exports.rotateY = rotateY;
+exports.rotateZ = rotateZ;
+exports.calculateW = calculateW;
+exports.slerp = slerp;
+exports.invert = invert;
+exports.conjugate = conjugate;
+exports.fromMat3 = fromMat3;
+exports.fromEuler = fromEuler;
+exports.str = str;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+var _mat = __webpack_require__(1);
+
+var mat3 = _interopRequireWildcard(_mat);
+
+var _vec = __webpack_require__(2);
+
+var vec3 = _interopRequireWildcard(_vec);
+
+var _vec2 = __webpack_require__(3);
+
+var vec4 = _interopRequireWildcard(_vec2);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * Quaternion
+ * @module quat
+ */
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(4);
+  out[0] = 0;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  return out;
+}
+
+/**
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+function identity(out) {
+  out[0] = 0;
+  out[1] = 0;
+  out[2] = 0;
+  out[3] = 1;
+  return out;
+}
+
+/**
+ * Sets a quat from the given angle and rotation axis,
+ * then returns it.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {vec3} axis the axis around which to rotate
+ * @param {Number} rad the angle in radians
+ * @returns {quat} out
+ **/
+function setAxisAngle(out, axis, rad) {
+  rad = rad * 0.5;
+  var s = Math.sin(rad);
+  out[0] = s * axis[0];
+  out[1] = s * axis[1];
+  out[2] = s * axis[2];
+  out[3] = Math.cos(rad);
+  return out;
+}
+
+/**
+ * Gets the rotation axis and angle for a given
+ *  quaternion. If a quaternion is created with
+ *  setAxisAngle, this method will return the same
+ *  values as providied in the original parameter list
+ *  OR functionally equivalent values.
+ * Example: The quaternion formed by axis [0, 0, 1] and
+ *  angle -90 is the same as the quaternion formed by
+ *  [0, 0, 1] and 270. This method favors the latter.
+ * @param  {vec3} out_axis  Vector receiving the axis of rotation
+ * @param  {quat} q     Quaternion to be decomposed
+ * @return {Number}     Angle, in radians, of the rotation
+ */
+function getAxisAngle(out_axis, q) {
+  var rad = Math.acos(q[3]) * 2.0;
+  var s = Math.sin(rad / 2.0);
+  if (s != 0.0) {
+    out_axis[0] = q[0] / s;
+    out_axis[1] = q[1] / s;
+    out_axis[2] = q[2] / s;
+  } else {
+    // If s is zero, return any axis (no rotation - axis does not matter)
+    out_axis[0] = 1;
+    out_axis[1] = 0;
+    out_axis[2] = 0;
+  }
+  return rad;
+}
+
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+function multiply(out, a, b) {
+  var ax = a[0],
+      ay = a[1],
+      az = a[2],
+      aw = a[3];
+  var bx = b[0],
+      by = b[1],
+      bz = b[2],
+      bw = b[3];
+
+  out[0] = ax * bw + aw * bx + ay * bz - az * by;
+  out[1] = ay * bw + aw * by + az * bx - ax * bz;
+  out[2] = az * bw + aw * bz + ax * by - ay * bx;
+  out[3] = aw * bw - ax * bx - ay * by - az * bz;
+  return out;
+}
+
+/**
+ * Rotates a quaternion by the given angle about the X axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+function rotateX(out, a, rad) {
+  rad *= 0.5;
+
+  var ax = a[0],
+      ay = a[1],
+      az = a[2],
+      aw = a[3];
+  var bx = Math.sin(rad),
+      bw = Math.cos(rad);
+
+  out[0] = ax * bw + aw * bx;
+  out[1] = ay * bw + az * bx;
+  out[2] = az * bw - ay * bx;
+  out[3] = aw * bw - ax * bx;
+  return out;
+}
+
+/**
+ * Rotates a quaternion by the given angle about the Y axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+function rotateY(out, a, rad) {
+  rad *= 0.5;
+
+  var ax = a[0],
+      ay = a[1],
+      az = a[2],
+      aw = a[3];
+  var by = Math.sin(rad),
+      bw = Math.cos(rad);
+
+  out[0] = ax * bw - az * by;
+  out[1] = ay * bw + aw * by;
+  out[2] = az * bw + ax * by;
+  out[3] = aw * bw - ay * by;
+  return out;
+}
+
+/**
+ * Rotates a quaternion by the given angle about the Z axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+function rotateZ(out, a, rad) {
+  rad *= 0.5;
+
+  var ax = a[0],
+      ay = a[1],
+      az = a[2],
+      aw = a[3];
+  var bz = Math.sin(rad),
+      bw = Math.cos(rad);
+
+  out[0] = ax * bw + ay * bz;
+  out[1] = ay * bw - ax * bz;
+  out[2] = az * bw + aw * bz;
+  out[3] = aw * bw - az * bz;
+  return out;
+}
+
+/**
+ * Calculates the W component of a quat from the X, Y, and Z components.
+ * Assumes that quaternion is 1 unit in length.
+ * Any existing W component will be ignored.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate W component of
+ * @returns {quat} out
+ */
+function calculateW(out, a) {
+  var x = a[0],
+      y = a[1],
+      z = a[2];
+
+  out[0] = x;
+  out[1] = y;
+  out[2] = z;
+  out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+  return out;
+}
+
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ */
+function slerp(out, a, b, t) {
+  // benchmarks:
+  //    http://jsperf.com/quaternion-slerp-implementations
+  var ax = a[0],
+      ay = a[1],
+      az = a[2],
+      aw = a[3];
+  var bx = b[0],
+      by = b[1],
+      bz = b[2],
+      bw = b[3];
+
+  var omega = void 0,
+      cosom = void 0,
+      sinom = void 0,
+      scale0 = void 0,
+      scale1 = void 0;
+
+  // calc cosine
+  cosom = ax * bx + ay * by + az * bz + aw * bw;
+  // adjust signs (if necessary)
+  if (cosom < 0.0) {
+    cosom = -cosom;
+    bx = -bx;
+    by = -by;
+    bz = -bz;
+    bw = -bw;
+  }
+  // calculate coefficients
+  if (1.0 - cosom > 0.000001) {
+    // standard case (slerp)
+    omega = Math.acos(cosom);
+    sinom = Math.sin(omega);
+    scale0 = Math.sin((1.0 - t) * omega) / sinom;
+    scale1 = Math.sin(t * omega) / sinom;
+  } else {
+    // "from" and "to" quaternions are very close
+    //  ... so we can do a linear interpolation
+    scale0 = 1.0 - t;
+    scale1 = t;
+  }
+  // calculate final values
+  out[0] = scale0 * ax + scale1 * bx;
+  out[1] = scale0 * ay + scale1 * by;
+  out[2] = scale0 * az + scale1 * bz;
+  out[3] = scale0 * aw + scale1 * bw;
+
+  return out;
+}
+
+/**
+ * Calculates the inverse of a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate inverse of
+ * @returns {quat} out
+ */
+function invert(out, a) {
+  var a0 = a[0],
+      a1 = a[1],
+      a2 = a[2],
+      a3 = a[3];
+  var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+  var invDot = dot ? 1.0 / dot : 0;
+
+  // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+  out[0] = -a0 * invDot;
+  out[1] = -a1 * invDot;
+  out[2] = -a2 * invDot;
+  out[3] = a3 * invDot;
+  return out;
+}
+
+/**
+ * Calculates the conjugate of a quat
+ * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate conjugate of
+ * @returns {quat} out
+ */
+function conjugate(out, a) {
+  out[0] = -a[0];
+  out[1] = -a[1];
+  out[2] = -a[2];
+  out[3] = a[3];
+  return out;
+}
+
+/**
+ * Creates a quaternion from the given 3x3 rotation matrix.
+ *
+ * NOTE: The resultant quaternion is not normalized, so you should be sure
+ * to renormalize the quaternion yourself where necessary.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {mat3} m rotation matrix
+ * @returns {quat} out
+ * @function
+ */
+function fromMat3(out, m) {
+  // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+  // article "Quaternion Calculus and Fast Animation".
+  var fTrace = m[0] + m[4] + m[8];
+  var fRoot = void 0;
+
+  if (fTrace > 0.0) {
+    // |w| > 1/2, may as well choose w > 1/2
+    fRoot = Math.sqrt(fTrace + 1.0); // 2w
+    out[3] = 0.5 * fRoot;
+    fRoot = 0.5 / fRoot; // 1/(4w)
+    out[0] = (m[5] - m[7]) * fRoot;
+    out[1] = (m[6] - m[2]) * fRoot;
+    out[2] = (m[1] - m[3]) * fRoot;
+  } else {
+    // |w| <= 1/2
+    var i = 0;
+    if (m[4] > m[0]) i = 1;
+    if (m[8] > m[i * 3 + i]) i = 2;
+    var j = (i + 1) % 3;
+    var k = (i + 2) % 3;
+
+    fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+    out[i] = 0.5 * fRoot;
+    fRoot = 0.5 / fRoot;
+    out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+    out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+    out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+  }
+
+  return out;
+}
+
+/**
+ * Creates a quaternion from the given euler angle x, y, z.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {x} Angle to rotate around X axis in degrees.
+ * @param {y} Angle to rotate around Y axis in degrees.
+ * @param {z} Angle to rotate around Z axis in degrees.
+ * @returns {quat} out
+ * @function
+ */
+function fromEuler(out, x, y, z) {
+  var halfToRad = 0.5 * Math.PI / 180.0;
+  x *= halfToRad;
+  y *= halfToRad;
+  z *= halfToRad;
+
+  var sx = Math.sin(x);
+  var cx = Math.cos(x);
+  var sy = Math.sin(y);
+  var cy = Math.cos(y);
+  var sz = Math.sin(z);
+  var cz = Math.cos(z);
+
+  out[0] = sx * cy * cz - cx * sy * sz;
+  out[1] = cx * sy * cz + sx * cy * sz;
+  out[2] = cx * cy * sz - sx * sy * cz;
+  out[3] = cx * cy * cz + sx * sy * sz;
+
+  return out;
+}
+
+/**
+ * Returns a string representation of a quatenion
+ *
+ * @param {quat} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+function str(a) {
+  return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+}
+
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
+ * @function
+ */
+var clone = exports.clone = vec4.clone;
+
+/**
+ * Creates a new quat initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} a new quaternion
+ * @function
+ */
+var fromValues = exports.fromValues = vec4.fromValues;
+
+/**
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
+ */
+var copy = exports.copy = vec4.copy;
+
+/**
+ * Set the components of a quat to the given values
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} out
+ * @function
+ */
+var set = exports.set = vec4.set;
+
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+var add = exports.add = vec4.add;
+
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {quat} out
+ * @function
+ */
+var scale = exports.scale = vec4.scale;
+
+/**
+ * Calculates the dot product of two quat's
+ *
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+var dot = exports.dot = vec4.dot;
+
+/**
+ * Performs a linear interpolation between two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ * @function
+ */
+var lerp = exports.lerp = vec4.lerp;
+
+/**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+var length = exports.length = vec4.length;
+
+/**
+ * Alias for {@link quat.length}
+ * @function
+ */
+var len = exports.len = length;
+
+/**
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+var squaredLength = exports.squaredLength = vec4.squaredLength;
+
+/**
+ * Alias for {@link quat.squaredLength}
+ * @function
+ */
+var sqrLen = exports.sqrLen = squaredLength;
+
+/**
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
+ */
+var normalize = exports.normalize = vec4.normalize;
+
+/**
+ * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
+ *
+ * @param {quat} a The first quaternion.
+ * @param {quat} b The second quaternion.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+var exactEquals = exports.exactEquals = vec4.exactEquals;
+
+/**
+ * Returns whether or not the quaternions have approximately the same elements in the same position.
+ *
+ * @param {quat} a The first vector.
+ * @param {quat} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+var equals = exports.equals = vec4.equals;
+
+/**
+ * Sets a quaternion to represent the shortest rotation from one
+ * vector to another.
+ *
+ * Both vectors are assumed to be unit length.
+ *
+ * @param {quat} out the receiving quaternion.
+ * @param {vec3} a the initial vector
+ * @param {vec3} b the destination vector
+ * @returns {quat} out
+ */
+var rotationTo = exports.rotationTo = function () {
+  var tmpvec3 = vec3.create();
+  var xUnitVec3 = vec3.fromValues(1, 0, 0);
+  var yUnitVec3 = vec3.fromValues(0, 1, 0);
+
+  return function (out, a, b) {
+    var dot = vec3.dot(a, b);
+    if (dot < -0.999999) {
+      vec3.cross(tmpvec3, xUnitVec3, a);
+      if (vec3.len(tmpvec3) < 0.000001) vec3.cross(tmpvec3, yUnitVec3, a);
+      vec3.normalize(tmpvec3, tmpvec3);
+      setAxisAngle(out, tmpvec3, Math.PI);
+      return out;
+    } else if (dot > 0.999999) {
+      out[0] = 0;
+      out[1] = 0;
+      out[2] = 0;
+      out[3] = 1;
+      return out;
+    } else {
+      vec3.cross(tmpvec3, a, b);
+      out[0] = tmpvec3[0];
+      out[1] = tmpvec3[1];
+      out[2] = tmpvec3[2];
+      out[3] = 1 + dot;
+      return normalize(out, out);
+    }
+  };
+}();
+
+/**
+ * Performs a spherical linear interpolation with two control points
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {quat} c the third operand
+ * @param {quat} d the fourth operand
+ * @param {Number} t interpolation amount
+ * @returns {quat} out
+ */
+var sqlerp = exports.sqlerp = function () {
+  var temp1 = create();
+  var temp2 = create();
+
+  return function (out, a, b, c, d, t) {
+    slerp(temp1, a, d, t);
+    slerp(temp2, b, c, t);
+    slerp(out, temp1, temp2, 2 * t * (1 - t));
+
+    return out;
+  };
+}();
+
+/**
+ * Sets the specified quaternion with values corresponding to the given
+ * axes. Each axis is a vec3 and is expected to be unit length and
+ * perpendicular to all other specified axes.
+ *
+ * @param {vec3} view  the vector representing the viewing direction
+ * @param {vec3} right the vector representing the local "right" direction
+ * @param {vec3} up    the vector representing the local "up" direction
+ * @returns {quat} out
+ */
+var setAxes = exports.setAxes = function () {
+  var matr = mat3.create();
+
+  return function (out, view, right, up) {
+    matr[0] = right[0];
+    matr[3] = right[1];
+    matr[6] = right[2];
+
+    matr[1] = up[0];
+    matr[4] = up[1];
+    matr[7] = up[2];
+
+    matr[2] = -view[0];
+    matr[5] = -view[1];
+    matr[8] = -view[2];
+
+    return normalize(out, fromMat3(out, matr));
+  };
+}();
+
+/***/ }),
+/* 9 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.forEach = exports.sqrLen = exports.sqrDist = exports.dist = exports.div = exports.mul = exports.sub = exports.len = undefined;
+exports.create = create;
+exports.clone = clone;
+exports.fromValues = fromValues;
+exports.copy = copy;
+exports.set = set;
+exports.add = add;
+exports.subtract = subtract;
+exports.multiply = multiply;
+exports.divide = divide;
+exports.ceil = ceil;
+exports.floor = floor;
+exports.min = min;
+exports.max = max;
+exports.round = round;
+exports.scale = scale;
+exports.scaleAndAdd = scaleAndAdd;
+exports.distance = distance;
+exports.squaredDistance = squaredDistance;
+exports.length = length;
+exports.squaredLength = squaredLength;
+exports.negate = negate;
+exports.inverse = inverse;
+exports.normalize = normalize;
+exports.dot = dot;
+exports.cross = cross;
+exports.lerp = lerp;
+exports.random = random;
+exports.transformMat2 = transformMat2;
+exports.transformMat2d = transformMat2d;
+exports.transformMat3 = transformMat3;
+exports.transformMat4 = transformMat4;
+exports.str = str;
+exports.exactEquals = exactEquals;
+exports.equals = equals;
+
+var _common = __webpack_require__(0);
+
+var glMatrix = _interopRequireWildcard(_common);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+/**
+ * 2 Dimensional Vector
+ * @module vec2
+ */
+
+/**
+ * Creates a new, empty vec2
+ *
+ * @returns {vec2} a new 2D vector
+ */
+function create() {
+  var out = new glMatrix.ARRAY_TYPE(2);
+  out[0] = 0;
+  out[1] = 0;
+  return out;
+}
+
+/**
+ * Creates a new vec2 initialized with values from an existing vector
+ *
+ * @param {vec2} a vector to clone
+ * @returns {vec2} a new 2D vector
+ */
+/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. */
+
+function clone(a) {
+  var out = new glMatrix.ARRAY_TYPE(2);
+  out[0] = a[0];
+  out[1] = a[1];
+  return out;
+}
+
+/**
+ * Creates a new vec2 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} a new 2D vector
+ */
+function fromValues(x, y) {
+  var out = new glMatrix.ARRAY_TYPE(2);
+  out[0] = x;
+  out[1] = y;
+  return out;
+}
+
+/**
+ * Copy the values from one vec2 to another
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the source vector
+ * @returns {vec2} out
+ */
+function copy(out, a) {
+  out[0] = a[0];
+  out[1] = a[1];
+  return out;
+}
+
+/**
+ * Set the components of a vec2 to the given values
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} out
+ */
+function set(out, x, y) {
+  out[0] = x;
+  out[1] = y;
+  return out;
+}
+
+/**
+ * Adds two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function add(out, a, b) {
+  out[0] = a[0] + b[0];
+  out[1] = a[1] + b[1];
+  return out;
+}
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function subtract(out, a, b) {
+  out[0] = a[0] - b[0];
+  out[1] = a[1] - b[1];
+  return out;
+}
+
+/**
+ * Multiplies two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function multiply(out, a, b) {
+  out[0] = a[0] * b[0];
+  out[1] = a[1] * b[1];
+  return out;
+};
+
+/**
+ * Divides two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function divide(out, a, b) {
+  out[0] = a[0] / b[0];
+  out[1] = a[1] / b[1];
+  return out;
+};
+
+/**
+ * Math.ceil the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to ceil
+ * @returns {vec2} out
+ */
+function ceil(out, a) {
+  out[0] = Math.ceil(a[0]);
+  out[1] = Math.ceil(a[1]);
+  return out;
+};
+
+/**
+ * Math.floor the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to floor
+ * @returns {vec2} out
+ */
+function floor(out, a) {
+  out[0] = Math.floor(a[0]);
+  out[1] = Math.floor(a[1]);
+  return out;
+};
+
+/**
+ * Returns the minimum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function min(out, a, b) {
+  out[0] = Math.min(a[0], b[0]);
+  out[1] = Math.min(a[1], b[1]);
+  return out;
+};
+
+/**
+ * Returns the maximum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+function max(out, a, b) {
+  out[0] = Math.max(a[0], b[0]);
+  out[1] = Math.max(a[1], b[1]);
+  return out;
+};
+
+/**
+ * Math.round the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to round
+ * @returns {vec2} out
+ */
+function round(out, a) {
+  out[0] = Math.round(a[0]);
+  out[1] = Math.round(a[1]);
+  return out;
+};
+
+/**
+ * Scales a vec2 by a scalar number
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec2} out
+ */
+function scale(out, a, b) {
+  out[0] = a[0] * b;
+  out[1] = a[1] * b;
+  return out;
+};
+
+/**
+ * Adds two vec2's after scaling the second operand by a scalar value
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec2} out
+ */
+function scaleAndAdd(out, a, b, scale) {
+  out[0] = a[0] + b[0] * scale;
+  out[1] = a[1] + b[1] * scale;
+  return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} distance between a and b
+ */
+function distance(a, b) {
+  var x = b[0] - a[0],
+      y = b[1] - a[1];
+  return Math.sqrt(x * x + y * y);
+};
+
+/**
+ * Calculates the squared euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+function squaredDistance(a, b) {
+  var x = b[0] - a[0],
+      y = b[1] - a[1];
+  return x * x + y * y;
+};
+
+/**
+ * Calculates the length of a vec2
+ *
+ * @param {vec2} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+function length(a) {
+  var x = a[0],
+      y = a[1];
+  return Math.sqrt(x * x + y * y);
+};
+
+/**
+ * Calculates the squared length of a vec2
+ *
+ * @param {vec2} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+function squaredLength(a) {
+  var x = a[0],
+      y = a[1];
+  return x * x + y * y;
+};
+
+/**
+ * Negates the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to negate
+ * @returns {vec2} out
+ */
+function negate(out, a) {
+  out[0] = -a[0];
+  out[1] = -a[1];
+  return out;
+};
+
+/**
+ * Returns the inverse of the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to invert
+ * @returns {vec2} out
+ */
+function inverse(out, a) {
+  out[0] = 1.0 / a[0];
+  out[1] = 1.0 / a[1];
+  return out;
+};
+
+/**
+ * Normalize a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to normalize
+ * @returns {vec2} out
+ */
+function normalize(out, a) {
+  var x = a[0],
+      y = a[1];
+  var len = x * x + y * y;
+  if (len > 0) {
+    //TODO: evaluate use of glm_invsqrt here?
+    len = 1 / Math.sqrt(len);
+    out[0] = a[0] * len;
+    out[1] = a[1] * len;
+  }
+  return out;
+};
+
+/**
+ * Calculates the dot product of two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+function dot(a, b) {
+  return a[0] * b[0] + a[1] * b[1];
+};
+
+/**
+ * Computes the cross product of two vec2's
+ * Note that the cross product must by definition produce a 3D vector
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec3} out
+ */
+function cross(out, a, b) {
+  var z = a[0] * b[1] - a[1] * b[0];
+  out[0] = out[1] = 0;
+  out[2] = z;
+  return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec2} out
+ */
+function lerp(out, a, b, t) {
+  var ax = a[0],
+      ay = a[1];
+  out[0] = ax + t * (b[0] - ax);
+  out[1] = ay + t * (b[1] - ay);
+  return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec2} out
+ */
+function random(out, scale) {
+  scale = scale || 1.0;
+  var r = glMatrix.RANDOM() * 2.0 * Math.PI;
+  out[0] = Math.cos(r) * scale;
+  out[1] = Math.sin(r) * scale;
+  return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2} m matrix to transform with
+ * @returns {vec2} out
+ */
+function transformMat2(out, a, m) {
+  var x = a[0],
+      y = a[1];
+  out[0] = m[0] * x + m[2] * y;
+  out[1] = m[1] * x + m[3] * y;
+  return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2d
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2d} m matrix to transform with
+ * @returns {vec2} out
+ */
+function transformMat2d(out, a, m) {
+  var x = a[0],
+      y = a[1];
+  out[0] = m[0] * x + m[2] * y + m[4];
+  out[1] = m[1] * x + m[3] * y + m[5];
+  return out;
+};
+
+/**
+ * Transforms the vec2 with a mat3
+ * 3rd vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat3} m matrix to transform with
+ * @returns {vec2} out
+ */
+function transformMat3(out, a, m) {
+  var x = a[0],
+      y = a[1];
+  out[0] = m[0] * x + m[3] * y + m[6];
+  out[1] = m[1] * x + m[4] * y + m[7];
+  return out;
+};
+
+/**
+ * Transforms the vec2 with a mat4
+ * 3rd vector component is implicitly '0'
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec2} out
+ */
+function transformMat4(out, a, m) {
+  var x = a[0];
+  var y = a[1];
+  out[0] = m[0] * x + m[4] * y + m[12];
+  out[1] = m[1] * x + m[5] * y + m[13];
+  return out;
+}
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec2} a vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+function str(a) {
+  return 'vec2(' + a[0] + ', ' + a[1] + ')';
+}
+
+/**
+ * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
+ *
+ * @param {vec2} a The first vector.
+ * @param {vec2} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function exactEquals(a, b) {
+  return a[0] === b[0] && a[1] === b[1];
+}
+
+/**
+ * Returns whether or not the vectors have approximately the same elements in the same position.
+ *
+ * @param {vec2} a The first vector.
+ * @param {vec2} b The second vector.
+ * @returns {Boolean} True if the vectors are equal, false otherwise.
+ */
+function equals(a, b) {
+  var a0 = a[0],
+      a1 = a[1];
+  var b0 = b[0],
+      b1 = b[1];
+  return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1));
+}
+
+/**
+ * Alias for {@link vec2.length}
+ * @function
+ */
+var len = exports.len = length;
+
+/**
+ * Alias for {@link vec2.subtract}
+ * @function
+ */
+var sub = exports.sub = subtract;
+
+/**
+ * Alias for {@link vec2.multiply}
+ * @function
+ */
+var mul = exports.mul = multiply;
+
+/**
+ * Alias for {@link vec2.divide}
+ * @function
+ */
+var div = exports.div = divide;
+
+/**
+ * Alias for {@link vec2.distance}
+ * @function
+ */
+var dist = exports.dist = distance;
+
+/**
+ * Alias for {@link vec2.squaredDistance}
+ * @function
+ */
+var sqrDist = exports.sqrDist = squaredDistance;
+
+/**
+ * Alias for {@link vec2.squaredLength}
+ * @function
+ */
+var sqrLen = exports.sqrLen = squaredLength;
+
+/**
+ * Perform some operation over an array of vec2s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+var forEach = exports.forEach = function () {
+  var vec = create();
+
+  return function (a, stride, offset, count, fn, arg) {
+    var i = void 0,
+        l = void 0;
+    if (!stride) {
+      stride = 2;
+    }
+
+    if (!offset) {
+      offset = 0;
+    }
+
+    if (count) {
+      l = Math.min(count * stride + offset, a.length);
+    } else {
+      l = a.length;
+    }
+
+    for (i = offset; i < l; i += stride) {
+      vec[0] = a[i];vec[1] = a[i + 1];
+      fn(vec, vec, arg);
+      a[i] = vec[0];a[i + 1] = vec[1];
+    }
+
+    return a;
+  };
+}();
+
+/***/ })
+/******/ ]);
+});
\ No newline at end of file
diff --git a/student2019/201621036/index.html b/student2019/201621036/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..374a7e75396c01864dfe643eec1a6c6d8016e818
--- /dev/null
+++ b/student2019/201621036/index.html
@@ -0,0 +1,28 @@
+<!-- "(CC-NC-BY) 2019 Yumi Choi" -->
+<!-- Reference to "https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Animating_textures_in_WebGL" -->
+<!-- "
+This is a tutorial for using video as a texture in webgl.
+Video textures are mapped to each side of the cube.
+First, Set up the video automatically using the base64. :setupVideo()
+Then, initialise a texture so that create and fill the texture with a 1x1 pixel. 
+Turn off mipmap and set wrapping so it will work regardless of the dimensions of the video. :initialiseTexture()
+Finally the video that has loaded make copy it to the texture.: updateTexture()
+" -->
+<html>
+
+<head>
+<title>WebGL Tutorial - Video Texture Example</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+<script type="text/javascript" src="gl-matrix.js"> </script>
+<script type="text/javascript" src="webgl.js"> </script>
+
+    
+</head>
+
+<body onload="main()">
+    <canvas id="webglcanvas" width="500" height="500"></canvas>
+<p> (CC-NC-BY) 2019 Yumi Choi </p>
+</body>
+
+  
+</html>
\ No newline at end of file
diff --git a/student2019/201621036/texture.mp4 b/student2019/201621036/texture.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..27376e9c3a13429fdd8c42651fff99b2b70a4b0f
Binary files /dev/null and b/student2019/201621036/texture.mp4 differ
diff --git a/student2019/201621036/webgl tutorial-video texture.docx b/student2019/201621036/webgl tutorial-video texture.docx
new file mode 100644
index 0000000000000000000000000000000000000000..c420d42a5ee15a1cd4505f42dec4e20fc2e38571
Binary files /dev/null and b/student2019/201621036/webgl tutorial-video texture.docx differ
diff --git a/student2019/201621036/webgl.js b/student2019/201621036/webgl.js
new file mode 100644
index 0000000000000000000000000000000000000000..310c8b26ec6ae81f595cdf2c124c12f840036872
--- /dev/null
+++ b/student2019/201621036/webgl.js
@@ -0,0 +1,471 @@
+// WebGL 1.0 Tutorial - Video Texture 
+// CC-NC-BY Yumi Choi
+//Reference to https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Animating_textures_in_WebGL
+var cubeRotation = 0.0;
+// will set to true when video can be copied to texture
+var startvideo = false;
+var gl;
+
+function testGLError(functionLastCalled) {
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+    return true;
+}
+
+function initialiseialiseGL(canvas) {
+    try {
+ // Try to grab the standard context. If it fails, fallback to experimental
+        gl = canvas.getContext("webgl"); 
+        gl.viewport(0, 0, canvas.width, canvas.height);
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialiseialise WebGL. Your browser may not support it");
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+  var canvas = document.getElementById("webglcanvas");
+  if (!initialiseialiseGL(canvas)) {
+        return;
+    }
+  
+  var shaderProgram = initialiseshader(gl);
+
+  // Collect all the info needed to use the shader program.
+  // Look up which attributes our shader program is using
+  // for aVertexPosition, aVertexNormal, aTextureCoord,
+  // and look up uniform locations.
+  var programInfo = {
+    program: shaderProgram,
+    attribLocations: {
+      vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
+      textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),
+    },
+    uniformLocations: {
+      projectionMatrix: gl.getUniformLocation(shaderProgram, 'Pmatrix'),
+      modelViewMatrix: gl.getUniformLocation(shaderProgram, 'Vmatrix'),
+      sampler2d: gl.getUniformLocation(shaderProgram, 'sampler2d'),
+    },
+  };
+
+  
+  var buffers = initialiseBuffers(gl);
+  var texture = initialiseTexture(gl);
+  var video = createVideo('texture.mp4');
+  var then = 0;
+
+  // Draw the scene repeatedly
+  function render(now) {
+    now *= 0.001;  // convert to seconds
+    var deltaTime = now - then;
+    then = now;
+
+    if (startvideo) {
+      updateTexture(gl, texture, video);
+    }
+
+    renderScene(gl, programInfo, buffers, texture, deltaTime);
+
+    requestAnimationFrame(render);
+  }
+  requestAnimationFrame(render);
+}
+
+
+
+//
+// initialiseBuffers
+function initialiseBuffers(gl) {
+
+  var positionBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+  var vertex = [
+    // Front face
+    -1.0, -1.0,  1.0,
+     1.0, -1.0,  1.0,
+     1.0,  1.0,  1.0,
+    -1.0,  1.0,  1.0,
+
+    // Back face
+    -1.0, -1.0, -1.0,
+    -1.0,  1.0, -1.0,
+     1.0,  1.0, -1.0,
+     1.0, -1.0, -1.0,
+
+    // Top face
+    -1.0,  1.0, -1.0,
+    -1.0,  1.0,  1.0,
+     1.0,  1.0,  1.0,
+     1.0,  1.0, -1.0,
+
+    // Bottom face
+    -1.0, -1.0, -1.0,
+     1.0, -1.0, -1.0,
+     1.0, -1.0,  1.0,
+    -1.0, -1.0,  1.0,
+
+    // Right face
+     1.0, -1.0, -1.0,
+     1.0,  1.0, -1.0,
+     1.0,  1.0,  1.0,
+     1.0, -1.0,  1.0,
+
+    // Left face
+    -1.0, -1.0, -1.0,
+    -1.0, -1.0,  1.0,
+    -1.0,  1.0,  1.0,
+    -1.0,  1.0, -1.0,
+  ];
+
+  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertex), gl.STATIC_DRAW);
+
+
+  var textureCoordBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
+
+  var textureCoordinates = [
+    // Front
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Back
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Top
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Bottom
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Right
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // Left
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+  ];
+
+  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates),
+                gl.STATIC_DRAW);
+
+
+  var indexBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+
+  var indices = [
+    0,  1,  2,      0,  2,  3,    // front
+    4,  5,  6,      4,  6,  7,    // back
+    8,  9,  10,     8,  10, 11,   // top
+    12, 13, 14,     12, 14, 15,   // bottom
+    16, 17, 18,     16, 18, 19,   // right
+    20, 21, 22,     20, 22, 23,   // left
+  ];
+
+  // Now send the element array to GL
+
+  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+      new Uint16Array(indices), gl.STATIC_DRAW);
+
+  return {
+    position: positionBuffer,
+    textureCoord: textureCoordBuffer,
+    indices: indexBuffer,
+  };
+}
+
+function createVideo() {
+  var video = document.createElement('video');
+  video.src = "data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAAAAG1wNDJtcDQxaXNvbWF2YzEAABm+bW9vdgAAAGxtdmhkAAAAANPBFj/TwRY/AAAAHgAAAdIAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAACFpb2RzAAAAABCAgIAQAE////9//w6AgIAEAAAAAQAAGSl0cmFrAAAAXHRraGQAAAAH08EWP9PBFj8AAAABAAAAAAAAAdIAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAoAAAAFoAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAAHSAAAAAgABAAAAABihbWRpYQAAACBtZGhkAAAAANPBFj/TwRY/AAAAHgAAAdJVxAAAAAAANmhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABMLVNNQVNIIFZpZGVvIEhhbmRsZXIAAAAYQ21pbmYAAAAUdm1oZAAAAAEAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAGANzdGJsAAAAvXN0c2QAAAAAAAAAAQAAAK1hdmMxAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAoABaABIAAAASAAAAAAAAAABCkFWQyBDb2RpbmcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AAAANGF2Y0MBTUAe/+EAHWdNQB7soFAX/LgLUGBQVAAAAwAEAAADAPA8WLZYAQAEaOvssgAAABNjb2xybmNseAAGAAUABQAAAAAQcGFzcAAAAAEAAAABAAAAGHN0dHMAAAAAAAAAAQAAAdIAAAABAAANGGN0dHMAAAAAAAABoQAAAAEAAAACAAAAAQAAAAMAAAABAAAAAQAAAAkAAAACAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAAAgAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAADAAAAAQAAAAEAAAACAAAAAgAAAAEAAAADAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAADAAAAAQAAAAEAAAABAAAAAgAAAAEAAAADAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAMAAAABAAAAAQAAAAIAAAACAAAAAQAAAAQAAAACAAAAAQAAAAEAAAAEAAAAAgAAAAEAAAABAAAAAgAAAAEAAAADAAAAAQAAAAEAAAABAAAAAwAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAAAwAAAAEAAAABAAAAAQAAAAMAAAABAAAAAQAAAAEAAAADAAAAAQAAAAEAAAABAAAABAAAAAIAAAABAAAAAQAAAAQAAAACAAAAAQAAAAEAAAADAAAAAQAAAAEAAAACAAAAAgAAAAEAAAADAAAAAQAAAAEAAAACAAAAAgAAAAEAAAADAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAAAwAAAAEAAAABAAAAAQAAAAMAAAABAAAAAQAAAAEAAAAEAAAAAgAAAAEAAAABAAAAAgAAAAEAAAADAAAAAQAAAAEAAAADAAAAAgAAAAEAAAADAAAAAQAAAAEAAAADAAAAAgAAAAEAAAADAAAAAQAAAAEAAAABAAAAAgAAAAEAAAAEAAAAAgAAAAEAAAABAAAABAAAAAIAAAABAAAAAQAAAAIAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAADAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAIAAAABAAAAAwAAAAEAAAABAAAAAQAAAAIAAAABAAAAAwAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAAAwAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAADAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAEAAAAAgAAAAEAAAABAAAAAwAAAAEAAAABAAAAAQAAAAMAAAABAAAAAQAAAAIAAAACAAAAAQAAAAQAAAACAAAAAQAAAAEAAAACAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAADAAAAAgAAAAEAAAADAAAAAQAAAAEAAAADAAAAAgAAAAEAAAADAAAAAQAAAAEAAAABAAAAAgAAAAEAAAADAAAAAQAAAAEAAAABAAAAAwAAAAEAAAABAAAAAwAAAAIAAAABAAAAAwAAAAEAAAABAAAAAQAAAAIAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAMAAAABAAAAAQAAAAEAAAADAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAQAAAACAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAQAAAACAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAMAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAQAAAACAAAAAQAAAAEAAAADAAAAAQAAAAEAAAABAAAAAwAAAAEAAAABAAAAAwAAAAIAAAABAAAAAwAAAAEAAAABAAAAAQAAAAMAAAABAAAAAQAAAAEAAAACAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAAAgAAAAEAAAADAAAAAQAAAAEAAAADAAAAAgAAAAEAAAADAAAAAQAAAAEAAAADAAAAAgAAAAEAAAADAAAAAQAAAAEAAAABAAAABAAAAAIAAAABAAAAAQAAAAMAAAABAAAAAQAAAAEAAAADAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAEAAAAAgAAAAEAAAABAAAAAgAAAAEAAAADAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABAAAAAIAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABAAAAAIAAAABAAAAAQAAAAMAAAABAAAAAQAAAAEAAAAEAAAAAgAAAAEAAAABAAAAAwAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAAAgAAAAEAAAADAAAAAQAAAAEAAAABAAAAAgAAAAEAAAAEAAAAAgAAAAEAAAABAAAAAwAAAAEAAAABAAAAAQAAAAMAAAABAAAAAQAAAAEAAAADAAAAAQAAAAEAAAABAAAAAgAAAAEAAAAEAAAAAgAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAACAAAAAQAAAAUAAAABAAAAAgAAAAEAAAAAAAAAAQAAAAEAAAABAAAABQAAAAEAAAACAAAAAQAAAAAAAAABAAAAAQAAAAEAAAAFAAAAAQAAAAIAAAABAAAAAAAAAAEAAAABAAAAAQAAAAQAAAACAAAAAQAAAChzdHNzAAAAAAAAAAYAAAABAAAAWwAAALUAAAEPAAABaQAAAcMAAAHec2R0cAAAAACmlpqmlpaWlqaWppaWlpqalpaWmpqWlpqalpaampaalpaWmpaWmpqWmpaWmpaWmpqWlpqalpqWlpaWmpaWmpaWmpaalpaampaalpqWmpaWmpaWmpaalpaWmpamlpqWlpqalpaampaWmpqWmpaalpaalpaalpaWlpqWlpaWmpaWlpqWlpqWlpaampaalpaampaWmpqWlpqWlpqWlpqalpqWlpqalpaampaalpaampaWmpaalpqmlpaWmpaWlpqalpaWlpqWlpaWmpaWmpaalpaWlpqWlpaampaWmpqWmpaalpaampaWmpqWlpqWlpqalpaampaWmpqWlpqalpaalpaampaalpaampaWmpaalpqmlpaWmpaalpaWmpqWlpqWlpaWmpaWlpaalpaalpqWmpaWmpqWlpqWlpqWlpqalpaampaWmpqWlpqalpaampaWmpqWlpqWlpqalpaalpqWlpqWmpaWmpqWlpqmlpaalpqWmpaalpaWmpaWmpqWlpqalpaampaWmpqWlpqalpaampaW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"
+  
+
+  var playing = false;
+  var timeupdate = false;
+
+  video.autoplay = true;
+  video.loop = true;
+
+  // Waiting for these 2 events ensures
+  // there is data in the video
+
+  video.addEventListener('playing', function() {
+     playing = true;
+     checkReady();
+  }, true);
+
+  video.addEventListener('timeupdate', function() {
+     timeupdate = true;
+     checkReady();
+  }, true);
+
+  function checkReady() {
+    if (playing && timeupdate) {
+      startvideo = true;
+    }
+  }
+  
+  video.play();
+  return video;
+}
+// initialise a texture.
+function initialiseTexture(gl) {
+  var texture = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, texture);
+
+  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
+	new Uint8Array([0, 0, 255, 255]));
+
+  // Turn off mips and set  wrapping to clamp to edge so it
+  // will work regardless of the dimensions of the video.
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+
+  return texture;
+}
+
+// copy the video texture
+function updateTexture(gl, texture, video) {
+  gl.bindTexture(gl.TEXTURE_2D, texture);
+  gl.texImage2D(gl.TEXTURE_2D, 0,  gl.RGBA,
+                gl.RGBA, gl.UNSIGNED_BYTE, video);
+}
+
+function isPowerOf2(value) {
+  return (value & (value - 1)) == 0;
+}
+
+// Draw the scene.
+function renderScene(gl, programInfo, buffers, texture, deltaTime) {
+  gl.clearColor(1.0, 0.0, 0.0, 1.0);  // Clear to black, fully opaque
+  gl.clearDepth(1.0);                 // Clear everything
+  gl.enable(gl.DEPTH_TEST);           // Enable depth testing
+  gl.depthFunc(gl.LEQUAL);            // Near things obscure far things
+
+  // Clear the canvas before we start drawing on it.
+
+  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+  // Create a perspective matrix, a special matrix that is
+  // used to simulate the distortion of perspective in a camera.
+  // Our field of view is 45 degrees, with a width/height
+  // ratio that matches the display size of the canvas
+  // and we only want to see objects between 0.1 units
+  // and 100 units away from the camera.
+
+  var fieldOfView = 45 * Math.PI / 180;   // in radians
+  var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
+  var zNear = 0.1;
+  var zFar = 100.0;
+  var projectionMatrix = mat4.create();
+
+  // note: glmatrix.js always has the first argument
+  // as the destination to receive the result.
+  mat4.perspective(projectionMatrix,
+                   fieldOfView,
+                   aspect,
+                   zNear,
+                   zFar);
+
+  // Set the drawing position to the "identity" point, which is
+  // the center of the scene.
+  var modelViewMatrix = mat4.create();
+
+  // Now move the drawing position a bit to where we want to
+  // start drawing the square.
+
+  mat4.translate(modelViewMatrix,     // destination matrix
+                 modelViewMatrix,     // matrix to translate
+                 [-0.0, 0.0, -6.0]);  // amount to translate
+  mat4.rotate(modelViewMatrix,  // destination matrix
+              modelViewMatrix,  // matrix to rotate
+              cubeRotation,     // amount to rotate in radians
+              [0, 0, 1]);       // axis to rotate around (Z)
+  mat4.rotate(modelViewMatrix,  // destination matrix
+              modelViewMatrix,  // matrix to rotate
+              cubeRotation * .7,// amount to rotate in radians
+              [0, 1, 0]);       // axis to rotate around (X)
+
+ 
+
+  // Tell WebGL how to pull out the vertex from the position
+  // buffer into the vertexPosition attribute
+  {
+    var numComponents = 3;
+    var type = gl.FLOAT;
+    var normalize = false;
+    var stride = 0;
+    var offset = 0;
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
+    gl.vertexAttribPointer(
+        programInfo.attribLocations.vertexPosition,
+        numComponents,
+        type,
+        normalize,
+        stride,
+        offset);
+    gl.enableVertexAttribArray(
+        programInfo.attribLocations.vertexPosition);
+  }
+
+  // Tell WebGL how to pull out the texture coordinates from
+  // the texture coordinate buffer into the textureCoord attribute.
+  {
+    var numComponents = 2;
+    var type = gl.FLOAT;
+    var normalize = false;
+    var stride = 0;
+    var offset = 0;
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureCoord);
+    gl.vertexAttribPointer(
+        programInfo.attribLocations.textureCoord,
+        numComponents,
+        type,
+        normalize,
+        stride,
+        offset);
+    gl.enableVertexAttribArray(
+        programInfo.attribLocations.textureCoord);
+  }
+
+  
+
+  // Tell WebGL which indices to use to index the vertices
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
+
+  // Tell WebGL to use our program when drawing
+
+  gl.useProgram(programInfo.program);
+
+  // Set the shader uniforms
+
+  gl.uniformMatrix4fv(
+      programInfo.uniformLocations.projectionMatrix,
+      false,
+      projectionMatrix);
+  gl.uniformMatrix4fv(
+      programInfo.uniformLocations.modelViewMatrix,
+      false,
+      modelViewMatrix);
+  
+
+  // Specify the texture to map onto the faces.
+
+  // Tell WebGL we want to affect texture unit 0
+  gl.activeTexture(gl.TEXTURE0);
+
+  // Bind the texture to texture unit 0
+  gl.bindTexture(gl.TEXTURE_2D, texture);
+
+  // Tell the shader we bound the texture to texture unit 0
+  gl.uniform1i(programInfo.uniformLocations.sampler2d, 0);
+
+  {
+    var vertexCount = 36;
+    var type = gl.UNSIGNED_SHORT;
+    var offset = 0;
+    gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
+  }
+
+  // Update the rotation for the next draw
+
+  cubeRotation += deltaTime;
+}
+
+//
+// initialiseialize a shader program, so WebGL knows how to draw our data
+//
+function initialiseshader(gl) {
+// Vertex shader source
+  var vsSource = `
+    attribute vec4 aVertexPosition;
+    attribute vec2 aTextureCoord;
+
+    uniform mat4 Vmatrix;
+    uniform mat4 Pmatrix;
+
+    varying highp vec2 vTextureCoord;
+   
+    void main(void) {
+      gl_Position = Pmatrix * Vmatrix * aVertexPosition;
+      vTextureCoord = aTextureCoord;
+      }
+  `;
+
+  // Fragment shader source
+  var fsSource = `
+    varying highp vec2 vTextureCoord;
+   
+    uniform sampler2D sampler2d;
+
+    void main(void) {
+      highp vec4 texelColor = texture2D(sampler2d, vTextureCoord);
+
+      gl_FragColor = vec4(texelColor.rgb , texelColor.a);
+    }
+  `;
+
+  var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
+  var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
+
+  // Create the shader program
+  var shaderProgram = gl.createProgram();
+  gl.attachShader(shaderProgram, vertexShader);
+  gl.attachShader(shaderProgram, fragmentShader);
+  gl.linkProgram(shaderProgram);
+
+  // If creating the shader program failed, alert
+  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
+    alert('Unable to initialiseialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
+    return null;
+  }
+
+  return shaderProgram;
+}
+
+//
+// creates a shader of the given type, uploads the source and
+// compiles it.
+//
+function loadShader(gl, type, source) {
+  var shader = gl.createShader(type);
+
+  // Send the source to the shader object
+
+  gl.shaderSource(shader, source);
+
+  // Compile the shader program
+
+  gl.compileShader(shader);
+
+  // See if it compiled successfully
+
+  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+    alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
+    gl.deleteShader(shader);
+    return null;
+  }
+
+  return shader;
+}
\ No newline at end of file
diff --git a/student2019/201720768/Readme.md.docx b/student2019/201720768/Readme.md.docx
new file mode 100644
index 0000000000000000000000000000000000000000..aff29bc80d96770718035dfe6cb52c85d22731a6
Binary files /dev/null and b/student2019/201720768/Readme.md.docx differ
diff --git a/student2019/201720768/cubeA.png b/student2019/201720768/cubeA.png
new file mode 100644
index 0000000000000000000000000000000000000000..b3a464be98d124ac0e0a0c4c366288e77ef7e518
Binary files /dev/null and b/student2019/201720768/cubeA.png differ
diff --git a/student2019/201720768/kim.png b/student2019/201720768/kim.png
new file mode 100644
index 0000000000000000000000000000000000000000..0feb675665eacd427025b6470c184de39bb3996a
Binary files /dev/null and b/student2019/201720768/kim.png differ
diff --git a/student2019/201720768/trCube.html b/student2019/201720768/trCube.html
new file mode 100644
index 0000000000000000000000000000000000000000..00d796a5deece5709a914b33b6aaaf0dfe0080b7
--- /dev/null
+++ b/student2019/201720768/trCube.html
@@ -0,0 +1,52 @@
+<html>
+
+<head>
+<title>WebGLHelloAPI</title>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+
+<script type="text/javascript" src="trCube
+.js">
+</script>
+
+
+</head>
+
+<body onload="main()">
+    <canvas id="helloapicanvas" style="border: none;" width="400" height="400"></canvas>
+    <br>
+    <button onclick="animRotate1()">1. rotate the cube B to see there are two cubes</button>
+    <button onclick="animRotate()">2. the next description on cube A</button>
+
+    <button onclick="renderScene().putTexture()">putTexture on cube B</button>
+
+    <button onclick="animPause()">Anim Pause</button>
+
+    <table border=1>
+
+        <tr>
+            <td id="matrix0">
+            <td id="matrix4">
+            <td id="matrix8">
+            <td id="matrix12">
+        <tr>
+            <td id="matrix1">
+            <td id="matrix5">
+            <td id="matrix9">
+            <td id="matrix13">
+        <tr>
+            <td id="matrix2">
+            <td id="matrix6">
+            <td id="matrix10">
+            <td id="matrix14">
+        <tr>
+            <td id="matrix3">
+            <td id="matrix7">
+            <td id="matrix11">
+            <td id="matrix15">
+    </table>
+    <p id="webTrX"> Test </p>
+    <img src="kim.png"></img>
+    <img src="cubeA.png"></img>
+</body>
+
+</html>
diff --git a/student2019/201720768/trCube.js b/student2019/201720768/trCube.js
new file mode 100644
index 0000000000000000000000000000000000000000..9a867b0c2b7278fb34f26a94b044b52cd02ad368
--- /dev/null
+++ b/student2019/201720768/trCube.js
@@ -0,0 +1,516 @@
+//(CC - NC - BY) ����� 2019
+
+var gl;
+
+function testGLError(functionLastCalled) {
+
+    var lastError = gl.getError();
+
+    if (lastError != gl.NO_ERROR) {
+        alert(functionLastCalled + " failed (" + lastError + ")");
+        return false;
+    }
+
+    return true;
+}
+
+function initialiseGL(canvas) {
+    try {
+ // Try to grab the standard context. If it fails, fallback to experimental
+
+        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+        var canvas = document.getElementById("helloapicanvas"), ctx = canvas.getContext("webgl");
+
+       gl.viewport(0, 0, canvas.width, canvas.height); 
+
+    }
+    catch (e) {
+    }
+
+    if (!gl) {
+        alert("Unable to initialise WebGL. Your browser may not support it");
+        return false;
+    }
+
+    return true;
+}
+
+var shaderProgram;
+
+function initialiseBuffer() {
+   
+   
+    var vertexData = [
+		-0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		0.0, 1.0,//3
+        0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		1.0, 1.0,//1
+		0.5, 0.5, -0.5,		1.0, 1.0, 1.0, 0.5,		1.0, 1.0,//2
+				
+		-0.5, 0.5, 0.5,		1.0, 1.0, 1.0, 0.5,		0.0, 1.0,//3
+		0.5, 0.5, -0.5,		1.0, 1.0, 1.0, 0.5,		1.0, 1.0,//2
+		-0.5, 0.5, -0.5,	1.0, 1.0, 1.0, 0.5,		0.0, 1.0,//4
+		 
+		0.5, 0.5, -0.5,		0.0, 0.0, 0.0, 0.5,		1.0, 1.0,//2
+		0.5, -0.5, -0.5,	0.0, 0.0, 0.0, 0.5,		1.0, 0.0,//6
+		-0.5,-0.5,-0.5,		0.0, 0.0, 0.0, 0.5,		0.0, 0.0,//8
+		   
+		-0.5, 0.5, -0.5,	0.0, 0.0, 0.0, 0.5,		0.0, 1.0,//4
+		0.5, 0.5, -0.5,		0.0, 0.0, 0.0, 0.5,		1.0, 1.0,//2
+		-0.5,-0.5,-0.5,		0.0, 0.0, 0.0, 0.5,		0.0, 0.0,//8
+			
+		0.5, -0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		0.0, 1.0,//5
+		0.5, -0.5, -0.5,	1.0, 0.5, 0.0, 0.5,		0.0, 1.0,//6
+		0.5, 0.5, -0.5,		1.0, 0.5, 0.0, 0.5,		1.0, 1.0,//2
+
+		0.5, -0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		0.0, 1.0,//5
+		0.5, 0.5, -0.5,		1.0, 0.5, 0.0, 0.5,		1.0, 1.0,//2
+		0.5, 0.5, 0.5,		1.0, 0.5, 0.0, 0.5,		1.0, 1.0,//1
+				 
+		-0.5, 0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 1.0,//4
+		-0.5,-0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 0.0,//8
+		-0.5, -0.5, 0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 0.0,//7
+		
+		-0.5, 0.5, 0.5,		1.0, 0.0, 0.0, 0.5,		0.0, 1.0,//3
+		-0.5, 0.5, -0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 1.0,//4
+		-0.5, -0.5, 0.5,	1.0, 0.0, 0.0, 0.5,		0.0, 0.0,//7
+		
+		-0.5, -0.5, 0.5,	0.0, 0.0, 1.0, 0.5,		0.0, 0.0,//7
+		0.5, -0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		1.0, 0.0,//5
+		0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		1.0, 1.0,//1
+				 
+		-0.5, -0.5, 0.5,	0.0, 0.0, 1.0, 0.5,		0.0, 0.0,//7
+		0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		1.0, 1.0,//1
+		-0.5, 0.5, 0.5,		0.0, 0.0, 1.0, 0.5,		0.0, 1.0,//3
+		
+		 0.5, -0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		1.0, 0.0,//6
+		 0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		1.0, 0.0,//5
+		-0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		0.0, 0.0,//7
+		
+		-0.5,-0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		0.0, 0.0,//8
+		 0.5, -0.5, -0.5,	0.0, 1.0, 0.0, 0.5,		1.0, 0.0,//6
+		-0.5, -0.5, 0.5,	0.0, 1.0, 0.0, 0.5,		0.0, 0.0,//7
+    ];
+	
+    // Generate a buffer object
+    gl.vertexBuffer = gl.createBuffer();
+    // Bind buffer as a vertex buffer so we can fill it with data
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+    return testGLError("initialiseBuffers");
+}
+
+function initialiseShaders() {
+
+    var fragmentShaderSource = '\
+			varying mediump vec4 color; \
+            varying mediump vec2 texCoord;\
+			uniform sampler2D sampler2d; \
+			void main(void) \
+			{ \
+               gl_FragColor = 0.1 * color + 0.6* texture2D(sampler2d, texCoord); \
+			}';
+
+    gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(gl.fragShader, fragmentShaderSource);
+    gl.compileShader(gl.fragShader);
+    if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader));
+        return false;
+    }
+
+    var vertexShaderSource = '\
+			attribute highp vec3 myVertex; \
+			attribute highp vec4 myColor; \
+			attribute highp vec2 myUV; \
+			uniform mediump mat4 Pmatrix; \
+			uniform mediump mat4 Vmatrix; \
+			uniform mediump mat4 Mmatrix; \
+			varying mediump vec4 color; \
+			varying mediump vec2 texCoord;\
+			void main(void)  \
+			{ \
+				gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(myVertex, 1.0);\
+				color = myColor;\
+				texCoord = myUV; \
+			}';
+
+    gl.vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(gl.vertexShader, vertexShaderSource);
+    gl.compileShader(gl.vertexShader);
+    if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) {
+        alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader));
+        return false;
+    }
+
+    gl.programObject = gl.createProgram();
+
+    // Attach the fragment and vertex shaders to it
+    gl.attachShader(gl.programObject, gl.fragShader);
+    gl.attachShader(gl.programObject, gl.vertexShader);
+
+    // Bind the custom vertex attribute "myVertex" to location 0
+    gl.bindAttribLocation(gl.programObject, 0, "myVertex");
+    gl.bindAttribLocation(gl.programObject, 1, "myColor");
+	gl.bindAttribLocation(gl.programObject, 2, "myUV");
+
+    // Link the program
+    gl.linkProgram(gl.programObject);
+
+    if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) {
+        alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject));
+        return false;
+    }
+
+    gl.useProgram(gl.programObject);
+
+    return testGLError("initialiseShaders");
+}
+
+// FOV, Aspect Ratio, Near, Far 
+function get_projection(angle, a, zMin, zMax) {
+    var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
+    return [
+    	0.5/ang, 0 , 0, 0,
+        0, 0.5*a/ang, 0, 0,
+        0, 0, -(zMax+zMin)/(zMax-zMin), -1,
+        0, 0, (-2*zMax*zMin)/(zMax-zMin), 0 ];
+}
+			
+var proj_matrix = get_projection(30, 1.0, 1, 10.0); 
+var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
+// translating z
+
+view_matrix[14] = view_matrix[14]-5;//zoom
+
+function idMatrix(m) {
+    m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 0; 
+    m[4] = 0; m[5] = 1; m[6] = 0; m[7] = 0; 
+    m[8] = 0; m[9] = 0; m[10] = 1; m[11] = 0; 
+    m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; 
+}
+
+function mulStoreMatrix(r, m, k) {
+    m0=m[0];m1=m[1];m2=m[2];m3=m[3];m4=m[4];m5=m[5];m6=m[6];m7=m[7];
+    m8=m[8];m9=m[9];m10=m[10];m11=m[11];m12=m[12];m13=m[13];m14=m[14];m15=m[15];
+    k0=k[0];k1=k[1];k2=k[2];k3=k[3];k4=k[4];k5=k[5];k6=k[6];k7=k[7];
+    k8=k[8];k9=k[9];k10=k[10];k11=k[11];k12=k[12];k13=k[13];k14=k[14];k15=k[15];
+
+    a0 = k0 * m0 + k3 * m12 + k1 * m4 + k2 * m8;
+    a4 = k4 * m0 + k7 * m12 + k5 * m4 + k6 * m8 ;
+    a8 = k8 * m0 + k11 * m12 + k9 * m4 + k10 * m8 ;
+    a12 = k12 * m0 + k15 * m12 + k13 * m4 + k14 * m8;
+
+    a1 = k0 * m1 + k3 * m13 + k1 * m5 + k2 * m9;
+    a5 = k4 * m1 + k7 * m13 + k5 * m5 + k6 * m9;
+    a9 = k8 * m1 + k11 * m13 + k9 * m5 + k10 * m9;
+    a13 = k12 * m1 + k15 * m13 + k13 * m5 + k14 * m9;
+
+    a2 = k2 * m10 + k3 * m14 + k0 * m2 + k1 * m6;
+    a6 =  k6 * m10 + k7 * m14 + k4 * m2 + k5 * m6;
+    a10 =  k10 * m10 + k11 * m14 + k8 * m2 + k9 * m6;
+    a14 = k14 * m10 + k15 * m14 + k12 * m2 + k13 * m6; 
+
+    a3 = k2 * m11 + k3 * m15 + k0 * m3 + k1 * m7;
+    a7 = k6 * m11 + k7 * m15 + k4 * m3 + k5 * m7;
+    a11 = k10 * m11 + k11 * m15 + k8 * m3 + k9 * m7;
+    a15 = k14 * m11 + k15 * m15 + k12 * m3 + k13 * m7;
+
+    r[0]=a0; r[1]=a1; r[2]=a2; r[3]=a3; r[4]=a4; r[5]=a5; r[6]=a6; r[7]=a7;
+    r[8]=a8; r[9]=a9; r[10]=a10; r[11]=a11; r[12]=a12; r[13]=a13; r[14]=a14; r[15]=a15;
+}
+
+function mulMatrix(m,k)
+{
+	mulStoreMatrix(m,m,k);
+}
+
+function translate(m, tx,ty,tz) {
+   var tm = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; 
+   tm[12] = tx; tm[13] = ty; tm[14] = tz; 
+   mulMatrix(m, tm); 
+}
+
+function scale(m, sx, sy, sz) {
+    var tm = [sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1];
+    mulMatrix(m, tm);
+}
+function rotateX(m, angle) {
+	var rm = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; 
+    var c = Math.cos(angle);
+    var s = Math.sin(angle);
+
+	rm[5] = c;  rm[6] = s; 
+	rm[9] = -s;  rm[10] = c;
+	mulMatrix(m, rm); 
+}
+
+function rotateY(m, angle) {
+	var rm = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; 
+    var c = Math.cos(angle);
+    var s = Math.sin(angle);
+
+	rm[0] = c;  rm[2] = -s;
+	rm[8] = s;  rm[10] = c; 
+	mulMatrix(m, rm); 
+}
+
+function rotateZ(m, angle) {
+	var rm = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; 
+    var c = Math.cos(angle);
+    var s = Math.sin(angle);
+
+	rm[0] = c;  rm[1] = s;
+	rm[4] = -s;  rm[5] = c; 
+	mulMatrix(m, rm); 
+}
+
+function normalizeVec3(v)
+{
+	sq = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; 
+	sq = Math.sqrt(sq);
+	if (sq < 0.000001 ) // Too Small
+		return -1; 
+	v[0] /= sq; v[1] /= sq; v[2] /= sq; 
+}
+
+function rotateArbAxis(m, angle, axis)
+{
+	var axis_rot = [0,0,0];
+	var ux, uy, uz;
+	var rm = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; 
+    var c = Math.cos(angle);
+	var c1 = 1.0 - c; 
+    var s = Math.sin(angle);
+	axis_rot[0] = axis[0]; 
+	axis_rot[1] = axis[1]; 
+	axis_rot[2] = axis[2]; 
+	if (normalizeVec3(axis_rot) == -1 )
+		return -1; 
+	ux = axis_rot[0]; uy = axis_rot[1]; uz = axis_rot[2];
+	console.log("Log", angle);
+	rm[0] = c + ux * ux * c1;
+	rm[1] = uy * ux * c1 + uz * s;
+	rm[2] = uz * ux * c1 - uy * s;
+	rm[3] = 0;
+
+	rm[4] = ux * uy * c1 - uz * s;
+	rm[5] = c + uy * uy * c1;
+	rm[6] = uz * uy * c1 + ux * s;
+	rm[7] = 0;
+
+	rm[8] = ux * uz * c1 + uy * s;
+	rm[9] = uy * uz * c1 - ux * s;
+	rm[10] = c + uz * uz * c1;
+	rm[11] = 0;
+
+	rm[12] = 0;
+	rm[13] = 0;
+	rm[14] = 0;
+	rm[15] = 1;
+
+	mulMatrix(m, rm);
+}
+
+rotValue = 0.0;
+rotValue1 = 0.0;
+animRotValue = 0.0;
+animRotValue1 = 0.0;
+sateliteRV = 0.0;
+sateliteRVmove = 0.0;
+transX = 0.0;
+transX1 = 0.0;
+transY1 = 0.0;
+transZ1 = 0.0;
+frames = 1;
+
+function animRotate()
+{
+    rotValue1 = 0.0;
+   animRotValue += 0.01;
+}
+
+function animRotate1() {
+    animRotValue1 += 0.01;
+}
+
+function anim1Rotate()
+{
+    sateliteRV += 0.01;
+}
+
+function animPause() {
+    animRotValue = 0.0;
+    animRotValue1 = 0.0;
+    sateliteRV = 0.0;
+}
+
+function trXinc()
+{
+	transX += 0.01;
+	document.getElementById("webTrX").innerHTML = "transX : " + transX.toFixed(4);
+}
+
+
+
+function renderScene() {
+
+    //console.log("Frame "+frames+"\n");
+    frames += 1 ;
+	rotAxis = [1,1,0];
+
+    var locPmatrix = gl.getUniformLocation(gl.programObject, "Pmatrix");
+    var locVmatrix = gl.getUniformLocation(gl.programObject, "Vmatrix");
+    var locMmatrix = gl.getUniformLocation(gl.programObject, "Mmatrix");
+
+    gl.uniformMatrix4fv(locMmatrix, false, mov_matrix);
+    gl.uniformMatrix4fv(locPmatrix, false, proj_matrix);
+    gl.uniformMatrix4fv(locVmatrix, false, view_matrix);
+   
+
+    if (!testGLError("gl.uniformMatrix4fv")) {
+        return false;
+    }
+
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 36, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 36, 12);
+	gl.enableVertexAttribArray(2);
+    gl.vertexAttribPointer(2, 2, gl.FLOAT, gl.FALSE, 36, 28);
+
+
+    if (!testGLError("gl.vertexAttribPointer")) {
+        return false;
+    }
+
+  
+    
+  //  translate(mov_matrix, transX, 0.0, 0.0); 
+    // gl.enable(gl.DEPTH_TEST);
+    // gl.depthFunc(gl.LEQUAL); 
+	// gl.enable(gl.CULL_FACE);
+	gl.enable(gl.BLEND);
+	gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+	gl.blendEquation(gl.FUNC_ADD);
+ 
+    gl.clearColor(0.9, 0.9, 0.9, 1.0);
+    gl.clearDepth(1.0); 
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+    idMatrix(mov_matrix);
+    translate(mov_matrix, transX, 0.0, 0.0);
+    scale(mov_matrix, 3.0, 3.0, 3.0);
+    rotateY(mov_matrix, rotValue);
+    gl.uniformMatrix4fv(locMmatrix, false, mov_matrix);
+    gl.drawArrays(gl.TRIANGLES, 0, 36);
+
+    var mov_matrix_save = mov_matrix.slice();
+    var texture = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, texture);
+    // Fill the texture with a 1x1 blue pixel.
+    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 255, 255]));
+    // Asynchronously load an image
+    var image = new Image();
+    image.src = "data:image/png;base64,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";
+    image.addEventListener('load', function () {
+        // Now that the image has loaded make copy it to the texture.
+        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
+        gl.bindTexture(gl.TEXTURE_2D, texture);
+        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
+        gl.generateMipmap(gl.TEXTURE_2D);//cube �ڷ� �̵� Ȥ�� ������ �̵��Ҷ� ������ �Ǵ� function 
+    });
+
+    translate(0,0,0,1.0);
+  //   translate(mov_matrix, transX1, transY1, -0.75 + transZ1);
+    scale(mov_matrix, 0.5, 0.5, 0.5);
+    rotateY(mov_matrix, rotValue1);
+   // rotateArbAxis(mov_matrix, rotValue1, rotAxis);
+    gl.uniformMatrix4fv(locMmatrix, false, mov_matrix);
+    gl.drawArrays(gl.TRIANGLES, 0, 36);
+    mov_matrix = mov_matrix_save.slice();
+
+
+    /*
+    translate(0, 0, 0, 3.0);
+    scale(mov_matrix, 4.0, 4.0, 4.0);
+    gl.drawArrays(gl.TRIANGLES, 0, 36);
+    mov_matrix = mov_matrix_save.slice();
+    */
+
+    rotValue += animRotValue;
+    rotValue1 += animRotValue1;
+    
+    if (rotValue == 1.6) {
+        rotValue == 0.0;
+    }
+
+    if (rotValue1 == 1.6) {
+        rotValue1 = 0.0;
+        animRotValue1 = 0.0;
+    }
+
+    rotValue1 += animRotValue1;
+   
+
+    sateliteRVmove += sateliteRV;
+
+    document.getElementById("matrix0").innerHTML = mov_matrix[0].toFixed(4);
+	document.getElementById("matrix1").innerHTML = mov_matrix[1].toFixed(4);
+	document.getElementById("matrix2").innerHTML = mov_matrix[2].toFixed(4);
+	document.getElementById("matrix3").innerHTML = mov_matrix[3].toFixed(4);
+	document.getElementById("matrix4").innerHTML = mov_matrix[4].toFixed(4);
+	document.getElementById("matrix5").innerHTML = mov_matrix[5].toFixed(4);
+	document.getElementById("matrix6").innerHTML = mov_matrix[6].toFixed(4);
+	document.getElementById("matrix7").innerHTML = mov_matrix[7].toFixed(4);
+	document.getElementById("matrix8").innerHTML = mov_matrix[8].toFixed(4);
+	document.getElementById("matrix9").innerHTML = mov_matrix[9].toFixed(4);
+	document.getElementById("matrix10").innerHTML = mov_matrix[10].toFixed(4);
+	document.getElementById("matrix11").innerHTML = mov_matrix[11].toFixed(4);
+	document.getElementById("matrix12").innerHTML = mov_matrix[12].toFixed(4);
+	document.getElementById("matrix13").innerHTML = mov_matrix[13].toFixed(4);
+	document.getElementById("matrix14").innerHTML = mov_matrix[14].toFixed(4);
+	document.getElementById("matrix15").innerHTML = mov_matrix[15].toFixed(4);
+    if (!testGLError("gl.drawArrays")) {
+        return false;
+    }
+
+    return true;
+}
+
+function main() {
+    var canvas = document.getElementById("helloapicanvas");
+    console.log("Start");
+
+    if (!initialiseGL(canvas)) {
+        return;
+    }
+
+    if (!initialiseBuffer()) {
+        return;
+    }
+
+    if (!initialiseShaders()) {
+        return;
+    }
+
+    // Render loop
+    requestAnimFrame = (
+	function () {
+        //	return window.requestAnimationFrame || window.webkitRequestAnimationFrame 
+	//	|| window.mozRequestAnimationFrame || 
+	   	return function (callback) {
+			    // console.log("Callback is"+callback); 
+			    window.setTimeout(callback, 10, 10); };
+        })();
+    (function renderLoop(param) {
+        if (renderScene()) {
+            // Everything was successful, request that we redraw our scene again in the future
+            if (rotValue <= 1.6){
+
+                    requestAnimFrame(renderLoop);
+                
+            }
+
+        }
+    })();
+}
diff --git a/student2019/201720798 b/student2019/201720798
new file mode 160000
index 0000000000000000000000000000000000000000..770503388cbeb5ef78f735bf848fa73dc4e84546
--- /dev/null
+++ b/student2019/201720798
@@ -0,0 +1 @@
+Subproject commit 770503388cbeb5ef78f735bf848fa73dc4e84546
diff --git a/student2019/201824634 b/student2019/201824634
new file mode 160000
index 0000000000000000000000000000000000000000..62db196195d8ad223637a2efa22dbfbbbc3da2e5
--- /dev/null
+++ b/student2019/201824634
@@ -0,0 +1 @@
+Subproject commit 62db196195d8ad223637a2efa22dbfbbbc3da2e5