You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by gi...@apache.org on 2026/05/28 06:29:12 UTC

(echarts-website) branch asf-site updated: Deploying to asf-site from @ apache/echarts-website@9f1a45a85b6ca9073e8bc933b39804f6d4cf8f8f 🚀

This is an automated email from the ASF dual-hosted git repository.

github-actions[bot] pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/echarts-website.git


The following commit(s) were added to refs/heads/asf-site by this push:
     new 3ae0e55d4 Deploying to asf-site from @ apache/echarts-website@9f1a45a85b6ca9073e8bc933b39804f6d4cf8f8f 🚀
3ae0e55d4 is described below

commit 3ae0e55d4fa69923feca88ddc3dee32b149178a6
Author: plainheart <pl...@users.noreply.github.com>
AuthorDate: Thu May 28 06:29:06 2026 +0000

    Deploying to asf-site from @ apache/echarts-website@9f1a45a85b6ca9073e8bc933b39804f6d4cf8f8f 🚀
---
 en/builder/echarts.html                            |     2 +-
 en/changelog.html                                  |   116 +-
 en/index.html                                      |     4 +-
 en/js/vendors/echarts-gl/README.md                 |     4 +
 en/js/vendors/echarts-gl/dist/echarts-gl.js        | 22150 ++++++++++---------
 en/js/vendors/echarts-gl/dist/echarts-gl.js.map    |     2 +-
 en/js/vendors/echarts-gl/dist/echarts-gl.min.js    |     2 +-
 .../echarts-gl/lib/chart/graphGL/install.js        |     9 +-
 .../echarts-gl/lib/chart/line3D/Line3DView.js      |    12 +-
 .../echarts-gl/lib/chart/lines3D/Lines3DSeries.js  |     3 +-
 .../echarts-gl/lib/chart/linesGL/LinesGLSeries.js  |     3 +-
 .../echarts-gl/lib/chart/map3D/Map3DSeries.js      |     3 +-
 .../lib/chart/polygons3D/Polygons3DSeries.js       |     3 +-
 .../echarts-gl/lib/component/geo3D/install.js      |     6 +
 .../echarts-gl/lib/component/grid3D/Grid3DAxis.js  |     4 +-
 en/js/vendors/echarts-gl/lib/echarts-gl.js         |    91 +-
 .../vendors/echarts-gl/lib/util/EChartsSurface.js  |    15 +-
 .../echarts-gl/lib/util/ZRTextureAtlasSurface.js   |    10 +-
 en/js/vendors/echarts-gl/lib/util/compatHelper.js  |    59 +
 .../echarts-gl/lib/util/mountEChartsNamespace.js   |    26 +
 en/js/vendors/echarts-gl/package.json              |     9 +-
 .../echarts-gl/src/chart/graphGL/install.js        |    13 +-
 .../echarts-gl/src/chart/line3D/Line3DView.js      |    12 +-
 .../echarts-gl/src/chart/lines3D/Lines3DSeries.js  |     3 +-
 .../echarts-gl/src/chart/linesGL/LinesGLSeries.js  |     3 +-
 .../echarts-gl/src/chart/map3D/Map3DSeries.js      |     3 +-
 .../src/chart/polygons3D/Polygons3DSeries.js       |     3 +-
 .../echarts-gl/src/component/geo3D/install.js      |     7 +
 .../echarts-gl/src/component/grid3D/Grid3DAxis.js  |     4 +-
 en/js/vendors/echarts-gl/src/echarts-gl.js         |   121 +-
 .../vendors/echarts-gl/src/util/EChartsSurface.js  |    11 +-
 .../echarts-gl/src/util/ZRTextureAtlasSurface.js   |     8 +-
 en/js/vendors/echarts-gl/src/util/compatHelper.js  |    63 +
 .../echarts-gl/src/util/mountEChartsNamespace.js   |    28 +
 en/spreadsheet.html                                |     4 +-
 examples/en/editor.html                            |     2 +-
 examples/en/index.html                             |     2 +-
 examples/en/view.html                              |     2 +-
 examples/zh/editor.html                            |     2 +-
 examples/zh/index.html                             |     2 +-
 examples/zh/view.html                              |     2 +-
 handbook/200.html                                  |     4 +-
 handbook/_nuxt/{95ba315.js => 009ff0d.js}          |     2 +-
 handbook/_nuxt/LICENSES                            |    40 +-
 ...933809521358945e.js => 224cefb366e5b93b5f3f.js} |     2 +-
 handbook/_nuxt/js/39f7c579d93b6dccc915.js          |     2 +
 handbook/_nuxt/js/be73192734b7baed345c.js          |     1 +
 handbook/_nuxt/js/d3262ade8b705f5d88c6.js          |     1 -
 handbook/_nuxt/js/fa73816a85b29fbf7562.js          |     2 -
 handbook/en/basics/download/index.html             |     4 +-
 handbook/en/basics/help/index.html                 |     4 +-
 handbook/en/basics/import/index.html               |     6 +-
 handbook/en/basics/release-note/5-2-0/index.html   |     6 +-
 handbook/en/basics/release-note/5-3-0/index.html   |     6 +-
 handbook/en/basics/release-note/5-4-0/index.html   |     4 +-
 handbook/en/basics/release-note/5-5-0/index.html   |     6 +-
 handbook/en/basics/release-note/5-6-0/index.html   |     6 +-
 .../en/basics/release-note/v5-feature/index.html   |     6 +-
 .../release-note/v5-upgrade-guide/index.html       |     6 +-
 .../en/basics/release-note/v6-feature/index.html   |     6 +-
 .../release-note/v6-upgrade-guide/index.html       |     6 +-
 handbook/en/best-practices/aria/index.html         |     6 +-
 .../en/best-practices/canvas-vs-svg/index.html     |     6 +-
 handbook/en/best-practices/security/index.html     |     6 +-
 handbook/en/concepts/axis/index.html               |     6 +-
 handbook/en/concepts/chart-size/index.html         |     6 +-
 handbook/en/concepts/data-transform/index.html     |     6 +-
 handbook/en/concepts/dataset/index.html            |     6 +-
 handbook/en/concepts/event/index.html              |     6 +-
 handbook/en/concepts/legend/index.html             |     6 +-
 handbook/en/concepts/style/index.html              |     6 +-
 handbook/en/concepts/visual-map/index.html         |     6 +-
 handbook/en/get-started/index.html                 |     6 +-
 handbook/en/how-to/animation/transition/index.html |     6 +-
 .../en/how-to/chart-types/bar/bar-race/index.html  |     6 +-
 .../en/how-to/chart-types/bar/basic-bar/index.html |     6 +-
 .../how-to/chart-types/bar/stacked-bar/index.html  |     6 +-
 .../en/how-to/chart-types/bar/waterfall/index.html |     6 +-
 .../how-to/chart-types/line/area-line/index.html   |     6 +-
 .../how-to/chart-types/line/basic-line/index.html  |     6 +-
 .../how-to/chart-types/line/smooth-line/index.html |     6 +-
 .../chart-types/line/stacked-line/index.html       |     6 +-
 .../how-to/chart-types/line/step-line/index.html   |     6 +-
 .../en/how-to/chart-types/pie/basic-pie/index.html |     6 +-
 .../en/how-to/chart-types/pie/doughnut/index.html  |     6 +-
 handbook/en/how-to/chart-types/pie/rose/index.html |     6 +-
 .../chart-types/scatter/basic-scatter/index.html   |     6 +-
 .../component-types/geo/svg-base-map/index.html    |     6 +-
 .../en/how-to/cross-platform/server/index.html     |     6 +-
 handbook/en/how-to/custom-series/index.html        |     6 +-
 handbook/en/how-to/data/dynamic-data/index.html    |     6 +-
 .../how-to/interaction/coarse-pointer/index.html   |     4 +-
 handbook/en/how-to/interaction/drag/index.html     |     6 +-
 handbook/en/how-to/label/rich-text/index.html      |     6 +-
 handbook/en/index.html                             |     4 +-
 handbook/en/meta/edit-guide/index.html             |     6 +-
 handbook/index.html                                |     4 +-
 handbook/zh/basics/download/index.html             |     4 +-
 handbook/zh/basics/help/index.html                 |     4 +-
 handbook/zh/basics/import/index.html               |     6 +-
 handbook/zh/basics/release-note/5-2-0/index.html   |     6 +-
 handbook/zh/basics/release-note/5-3-0/index.html   |     6 +-
 handbook/zh/basics/release-note/5-4-0/index.html   |     4 +-
 handbook/zh/basics/release-note/5-5-0/index.html   |     6 +-
 handbook/zh/basics/release-note/5-6-0/index.html   |     6 +-
 .../zh/basics/release-note/v5-feature/index.html   |     6 +-
 .../release-note/v5-upgrade-guide/index.html       |     6 +-
 .../zh/basics/release-note/v6-feature/index.html   |     6 +-
 .../release-note/v6-upgrade-guide/index.html       |     6 +-
 handbook/zh/best-practices/aria/index.html         |     6 +-
 .../zh/best-practices/canvas-vs-svg/index.html     |     6 +-
 handbook/zh/best-practices/security/index.html     |     6 +-
 handbook/zh/concepts/axis/index.html               |     6 +-
 handbook/zh/concepts/chart-size/index.html         |     6 +-
 handbook/zh/concepts/data-transform/index.html     |     6 +-
 handbook/zh/concepts/dataset/index.html            |     6 +-
 handbook/zh/concepts/event/index.html              |     6 +-
 handbook/zh/concepts/legend/index.html             |     6 +-
 handbook/zh/concepts/style/index.html              |     6 +-
 handbook/zh/concepts/visual-map/index.html         |     6 +-
 handbook/zh/get-started/index.html                 |     6 +-
 handbook/zh/how-to/animation/transition/index.html |     6 +-
 .../zh/how-to/chart-types/bar/bar-race/index.html  |     6 +-
 .../zh/how-to/chart-types/bar/basic-bar/index.html |     6 +-
 .../how-to/chart-types/bar/stacked-bar/index.html  |     6 +-
 .../zh/how-to/chart-types/bar/waterfall/index.html |     6 +-
 .../how-to/chart-types/line/area-line/index.html   |     6 +-
 .../how-to/chart-types/line/basic-line/index.html  |     6 +-
 .../how-to/chart-types/line/smooth-line/index.html |     6 +-
 .../chart-types/line/stacked-line/index.html       |     6 +-
 .../how-to/chart-types/line/step-line/index.html   |     6 +-
 .../zh/how-to/chart-types/pie/basic-pie/index.html |     6 +-
 .../zh/how-to/chart-types/pie/doughnut/index.html  |     6 +-
 handbook/zh/how-to/chart-types/pie/rose/index.html |     6 +-
 .../chart-types/scatter/basic-scatter/index.html   |     6 +-
 .../component-types/geo/svg-base-map/index.html    |     6 +-
 .../zh/how-to/cross-platform/baidu-app/index.html  |     4 +-
 .../zh/how-to/cross-platform/server/index.html     |     6 +-
 .../zh/how-to/cross-platform/wechat-app/index.html |     4 +-
 handbook/zh/how-to/custom-series/index.html        |     6 +-
 handbook/zh/how-to/data/dynamic-data/index.html    |     6 +-
 .../how-to/interaction/coarse-pointer/index.html   |     4 +-
 handbook/zh/how-to/interaction/drag/index.html     |     6 +-
 handbook/zh/how-to/label/rich-text/index.html      |     6 +-
 handbook/zh/index.html                             |     4 +-
 handbook/zh/meta/edit-guide/index.html             |     6 +-
 layouts/example-simple.html                        |     2 +-
 layouts/example.html                               |     2 +-
 zh/api.html                                        |     2 +-
 zh/builder/echarts.html                            |     2 +-
 zh/changelog.html                                  |   116 +-
 zh/css/only_for_cdn_ready_check.css                |     2 +-
 zh/index.html                                      |     4 +-
 zh/js/vendors/echarts-gl/README.md                 |     4 +
 zh/js/vendors/echarts-gl/dist/echarts-gl.js        | 22150 ++++++++++---------
 zh/js/vendors/echarts-gl/dist/echarts-gl.js.map    |     2 +-
 zh/js/vendors/echarts-gl/dist/echarts-gl.min.js    |     2 +-
 .../echarts-gl/lib/chart/graphGL/install.js        |     9 +-
 .../echarts-gl/lib/chart/line3D/Line3DView.js      |    12 +-
 .../echarts-gl/lib/chart/lines3D/Lines3DSeries.js  |     3 +-
 .../echarts-gl/lib/chart/linesGL/LinesGLSeries.js  |     3 +-
 .../echarts-gl/lib/chart/map3D/Map3DSeries.js      |     3 +-
 .../lib/chart/polygons3D/Polygons3DSeries.js       |     3 +-
 .../echarts-gl/lib/component/geo3D/install.js      |     6 +
 .../echarts-gl/lib/component/grid3D/Grid3DAxis.js  |     4 +-
 zh/js/vendors/echarts-gl/lib/echarts-gl.js         |    91 +-
 .../vendors/echarts-gl/lib/util/EChartsSurface.js  |    15 +-
 .../echarts-gl/lib/util/ZRTextureAtlasSurface.js   |    10 +-
 zh/js/vendors/echarts-gl/lib/util/compatHelper.js  |    59 +
 .../echarts-gl/lib/util/mountEChartsNamespace.js   |    26 +
 zh/js/vendors/echarts-gl/package.json              |     9 +-
 .../echarts-gl/src/chart/graphGL/install.js        |    13 +-
 .../echarts-gl/src/chart/line3D/Line3DView.js      |    12 +-
 .../echarts-gl/src/chart/lines3D/Lines3DSeries.js  |     3 +-
 .../echarts-gl/src/chart/linesGL/LinesGLSeries.js  |     3 +-
 .../echarts-gl/src/chart/map3D/Map3DSeries.js      |     3 +-
 .../src/chart/polygons3D/Polygons3DSeries.js       |     3 +-
 .../echarts-gl/src/component/geo3D/install.js      |     7 +
 .../echarts-gl/src/component/grid3D/Grid3DAxis.js  |     4 +-
 zh/js/vendors/echarts-gl/src/echarts-gl.js         |   121 +-
 .../vendors/echarts-gl/src/util/EChartsSurface.js  |    11 +-
 .../echarts-gl/src/util/ZRTextureAtlasSurface.js   |     8 +-
 zh/js/vendors/echarts-gl/src/util/compatHelper.js  |    63 +
 .../echarts-gl/src/util/mountEChartsNamespace.js   |    28 +
 zh/option-gl.html                                  |     2 +-
 zh/option.html                                     |     2 +-
 zh/spreadsheet.html                                |     6 +-
 zh/tutorial.html                                   |     2 +-
 188 files changed, 23311 insertions(+), 22959 deletions(-)

diff --git a/en/builder/echarts.html b/en/builder/echarts.html
index afdabee01..8ed2632b9 100644
--- a/en/builder/echarts.html
+++ b/en/builder/echarts.html
@@ -60,7 +60,7 @@
                 'rollup': 'lib/rollup.browser',
                 'transformDev': 'lib/transform-dev-bundle'
             },
-            urlArgs: 'v=1779725039701'
+            urlArgs: 'v=1779949681837'
         });
 
         require(['build']);
diff --git a/en/changelog.html b/en/changelog.html
index 77173e40a..f88a49e08 100644
--- a/en/changelog.html
+++ b/en/changelog.html
@@ -11,74 +11,74 @@
 <div class="time">2026-05-18</div>
 
 <ul>
-<li>[Feature] [axis]: Support <code>dataMin</code> and <code>dataMax</code> option for calculating a nice axis extent. <a href="https://github.com/apache/echarts/pull/20838">#20838</a> (<a href="https://github.com/Justin-ZS">Justin-ZS</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Feature] [axis]: Comprehensively enable all types of axis (i.e., <code>&quot;value&quot;</code>/<code>&quot;time&quot;</code>/<code>&quot;category&quot;</code>/<code>&quot;log&quot;</code>) to render series (typically <code>&quot;bar&quot;</code>/<code>&quot;pictorialBar&quot;</code>/<code>&quot;candlestick&quot;</code>/<code>&quot;boxplot&quot;</code>) without overflow (including the case <code>&quot;category&quot;</code> axis with <code>boundaryGap: false</code>); provide <code>co [...]
-<li>[Feature] [axis]: Automatically exclude non-positive series data values on <code>&quot;log&quot;</code> axis. <a href="https://github.com/apache/echarts/commit/dedc5dc18">dedc5dc18</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Feature] [axis]: Enable <code>axisLabel.formatter</code> to receive its index for working with <code>customValues</code>. <a href="https://github.com/apache/echarts/pull/21220">#21220</a> <a href="https://github.com/apache/echarts/pull/21432">#21432</a> (<a href="https://github.com/szymonpachucki">Szymon Pachucki</a>, <a href="https://github.com/Ovilia">Ovilia</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Feature] [line]: Add <code>triggerEvent</code> option for more control over mouse event. <a href="https://github.com/apache/echarts/pull/21001">#21001</a> (<a href="https://github.com/sjcobb">Steven Cobb</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Feature] [pie]: Add <code>tangential-noflip</code> rotation mode to keep labels tangential without flipping. <a href="https://github.com/apache/echarts/pull/21258">#21258</a> (<a href="https://github.com/MC-YCY">春秋半夏</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Feature] [gauge]: <code>progress.color</code> supports <code>&#39;auto&#39;</code>. <a href="https://github.com/apache/echarts/pull/21224">#21224</a> (<a href="https://github.com/StNimmerlein">StNimmerlein</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Feature] [radar]: Add <code>clockwise</code> option. <a href="https://github.com/apache/echarts/pull/21143">#21143</a> (<a href="https://github.com/daidr">Dai Xuezhou</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Feature] [candlestick,dataZoom]: Add <code>cursor</code> option for <code>candlestick</code> series and add <code>cursorGrab</code> option &amp; <code>cursorGrabbing</code> for <code>&#39;inside&#39;</code> dataZoom. <a href="https://github.com/apache/echarts/pull/21558">#21558</a> (<a href="https://github.com/diysimon">zuming</a>, <a href="https://github.com/Ovilia">Ovilia</a>, <a href="https://github.com/100pah">100pah</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Feature] [scatter,effectScatter,geo]: Enable <code>clip</code> option on <code>&quot;scatter&quot;</code>/<code>&quot;effectScatter&quot;</code> on <code>geo</code>. <a href="https://github.com/apache/echarts/commit/417592289">417592289</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Feature] [visualMap]: Add <code>seriesTargets</code> option for multiple series-dimension mappings. <a href="https://github.com/apache/echarts/pull/20703">#20703</a> (<a href="https://github.com/Justin-ZS">Justin-ZS</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Feature] [matrix]: Support <code>matrix.x/y.length</code> for conveniently creating a headless matrix without composing an array. <a href="https://github.com/apache/echarts/pull/21191">#21191</a> (<a href="https://github.com/100pah">100pah</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Feature] [matrix]: Add <code>triggerEvent</code> option to support triggering event on matrix cells. <a href="https://github.com/apache/echarts/pull/21390">#21390</a> (<a href="https://github.com/natsuokawai">Natsuo Kawai</a>, <a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Feature] [i18n]: add Latvian(LV) translation. <a href="https://github.com/apache/echarts/pull/21546">#21546</a> (<a href="https://github.com/EPoikans">EPoikans</a>)</li>
-<li>[Fix] [axis]: Change and clarify the rounding error and auto-precision utils and solutions. <a href="https://github.com/apache/echarts/commit/479dcd454">479dcd454</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [axis]: Fix chart does not work when using <code>customValues</code> with <code>formatter</code> in time axis (<code>axis.type: &#39;time&#39;</code>) label. <a href="https://github.com/apache/echarts/pull/21352">#21352</a> (<a href="https://github.com/Srajan-Sanjay-Saxena">Srajan Sanjay Saxena</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Fix] [axis]: Fix and clarify <code>alignTick</code> strategy, and fix <code>LogScale</code> precision. <a href="https://github.com/apache/echarts/commit/a6ab2458f">a6ab2458f</a> <a href="https://github.com/apache/echarts/commit/ffcc636fb">ffcc636fb</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [axis]: Fix duplicate ticks when using time axis (<code>axis.type: &#39;time&#39;</code>) or <code>customValues</code>, which causes jitter of <code>splitArea</code>; fix the <code>showMin/MaxLabel</code> handling of a category axis (<code>axis.type: &#39;category&#39;</code>); enable a uniform <code>bandWidth</code> calculation in numeric axis (<code>axis.type: &#39;value&#39; | &#39;time&#39; | &#39;log&#39;</code>). <a href="https://github.com/apache/echarts/commit/8de2b64fa [...]
-<li>[Fix] [axis]: Fix time axis (<code>axis.type: &#39;time&#39;</code>) bug when value scale is in millisecond. <a href="https://github.com/apache/echarts/commit/40b77b464">40b77b464</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [bar]: Fix wrong label position when bar series has a 0 width/height. <a href="https://github.com/apache/echarts/pull/21218">#21218</a> (<a href="https://github.com/Justin-ZS">Justin-ZS</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Fix] [scatter]: Fix jitter layout does not support progressive rendering and cause chart to be frozen and potential NPE. <a href="https://github.com/apache/echarts/pull/21436">#21436</a> (<a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Fix] [lines]: Fix effect symbol flip on unidirectional loop end when <code>roundTrip</code> is not enabled. <a href="https://github.com/apache/echarts/pull/21320">#21320</a> (<a href="https://github.com/mynk2611">Mayank Mehta</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Fix] [candlestick]: Fix candlestick render error with <code>series.encode</code> on horizontal layout. <a href="https://github.com/apache/echarts/pull/21325">#21325</a> (<a href="https://github.com/PPRAMANIK62">Purbayan Pramanik</a>, <a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [parallel]: Fix incorrect axis extent when any subsequent series has a larger value than the first. <a href="https://github.com/apache/echarts/pull/21387">#21387</a> (<a href="https://github.com/jackhickson">jackhickson</a>, <a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [pie]: Support axes extent union pie center automatically when pie is laid out on Cartesian (<code>grid</code> component). <a href="https://github.com/apache/echarts/commit/18a23a875">18a23a875</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [treemap]: Fix treemap can not be zoomed out after a zoom-in when <code>scaleLimit</code> is specified <a href="https://github.com/apache/echarts/pull/21427">#21427</a> (<a href="https://github.com/liuyizhou">TateLiu</a>, <a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [lines]: Fix potential <code>tooltip</code> XSS vulnerability in lines series (<code>series.type: &#39;lines&#39;</code>). <a href="https://github.com/apache/echarts/pull/21608">#21608</a> (<a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Fix] [map,geo]: Fix the failed synchronization and visual artifacts on geo roaming and animation. <a href="https://github.com/apache/echarts/commit/417592289">417592289</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [tooltip]: Fix <code>tooltip</code> content does not refresh when changing tooltip trigger from <code>&#39;axis&#39;</code> to <code>&#39;item&#39;</code>. <a href="https://github.com/apache/echarts/pull/20710">#20710</a> (<a href="https://github.com/Justin-ZS">Justin-ZS</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Fix] [tooltip]: <code>valueFormatter</code> callback param <code>dataIndex</code> should be <code>rawDataIndex</code> rather than <code>dataZoom</code> filtered <code>dataIndex</code>. <a href="https://github.com/apache/echarts/pull/21479">#21479</a> (<a href="https://github.com/100pah">100pah</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Fix] [axisPointer]: Fix <code>axisPointer</code> shadow and enable clipping - it is previously only applicable to <code>&quot;category&quot;</code> axis, but is buggy in numeric axis with <code>&quot;bar&quot;</code> series. <a href="https://github.com/apache/echarts/commit/8de2b64fa">8de2b64fa</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [axisPointer]: Fix visual artifacts caused by failed <code>axisPointer</code> restoration. <a href="https://github.com/apache/echarts/commit/56a32c0bb">56a32c0bb</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [hoverLayer]: Fix visual artifacts arisen on hover layer. <a href="https://github.com/ecomfe/zrender/pull/1151">zrender#1151</a> <a href="https://github.com/apache/echarts/commit/933585126">933585126</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [marker]: Fix <code>marker</code> fails to render with <code>dataset</code> and <code>encode</code>. <a href="https://github.com/apache/echarts/pull/21439">#21439</a> (<a href="https://github.com/plainheart">plainheart</a>, <a href="https://github.com/100pah">100pah</a>).</li>
-<li>[Fix] [dataZoom]: Fix wrong position of the <code>dataZoom</code> when the <code>series</code> has only one data point. <a href="https://github.com/apache/echarts/pull/21196">#21196</a> (<a href="https://github.com/alesmit">alesmit</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Fix] [dataZoom]: Fix <code>dataZoom</code> bug that data info disappears when dragging released; fix <code>dataZoom</code> dragging cursor style. <a href="https://github.com/apache/echarts/commit/64305a4b8">64305a4b8</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [dataZoom]: Apply a better auto-precision method; fix unexpected behaviors when <code>dataZoom</code> controls axes with <code>alignTicks: true</code>. <a href="https://github.com/apache/echarts/commit/d168bf237">d168bf237</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [dataZoom]: Fix <code>AxisProxy</code> can not be cleared when <code>dataZoom</code> option changed; fix related <code>onZero</code> behaviors. <a href="https://github.com/apache/echarts/commit/52ceb924a">52ceb924a</a> <a href="https://github.com/apache/echarts/commit/2e82d33c3">2e82d33c3</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [areaStyle]: Fix <code>areaStyle</code> render error when dimension name is empty string. <a href="https://github.com/apache/echarts/pull/21219">#21219</a> (<a href="https://github.com/Justin-ZS">Justin-ZS</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Fix] [sunburst]: Fix root node label may not be centered. <a href="https://github.com/apache/echarts/pull/21306">#21306</a> (<a href="https://github.com/akashsonune">Akash Sonune</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Fix] [matrix]: Fix matrix label formatter does not work. <a href="https://github.com/apache/echarts/pull/21410">#21410</a> (<a href="https://github.com/Justin-ZS">Justin-ZS</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Fix] [toolbox]: Fix <code>emphasis</code> color is the same as the default color. <a href="https://github.com/apache/echarts/pull/21384">#21384</a> (<a href="https://github.com/Ovilia">Ovilia</a>) <a href="https://github.com/apache/echarts/commit/b094f987d">b094f987d</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [toolbox]: Fix the <code>dataView</code> component does not fit the dark mode. <a href="https://github.com/apache/echarts/pull/21176">#21176</a> (<a href="https://github.com/notthistrain">notthistrain</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Fix] [progressive]: Fix progressive rendering issues. <a href="https://github.com/apache/echarts/commit/91a60fc76">91a60fc76</a> (<a href="https://github.com/100pah">100pah</a>)</li>
-<li>[Fix] [labelLine]: Fix <code>labelLine.smooth</code> can not be reset. <a href="https://github.com/apache/echarts/pull/21425">#21425</a> (<a href="https://github.com/fanwww">fanwww</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Fix] [graphic]: Fix stroke corner gap due to not closing path in <code>roundRect</code> helper. <a href="https://github.com/ecomfe/zrender/pull/1155">zrender#1155</a> (<a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Fix] [svg]: Enhance SVG <code>encodeBase64</code> compatibility to make it available in more environments like Web Worker/NodeJS/Bun. <a href="https://github.com/ecomfe/zrender/pull/1145">zrender#1145</a> (<a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Fix] [core]: Mark <code>echarts</code> instance object as <code>raw</code> in <code>Vue</code>. <a href="https://github.com/apache/echarts/pull/21293">#21293</a> (<a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Fix] [chord]: Add the missing export entry for chord chart. <a href="https://github.com/apache/echarts/pull/21197">#21197</a> (<a href="https://github.com/plainheart">plainheart</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Fix] [i18n]: Fix incorrect translation for custom series name in <code>langDE</code>. <a href="https://github.com/apache/echarts/pull/21571">#21571</a> (<a href="https://github.com/A-Loot">A-Loot</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Fix] [typescript]:<ul>
+<li>[Feature] [axis] Support <code>dataMin</code> and <code>dataMax</code> option for calculating a nice axis extent. <a href="https://github.com/apache/echarts/pull/20838">#20838</a> (<a href="https://github.com/Justin-ZS">Justin-ZS</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
+<li>[Feature] [axis] Comprehensively enable all types of axis (i.e., <code>&quot;value&quot;</code>/<code>&quot;time&quot;</code>/<code>&quot;category&quot;</code>/<code>&quot;log&quot;</code>) to render series (typically <code>&quot;bar&quot;</code>/<code>&quot;pictorialBar&quot;</code>/<code>&quot;candlestick&quot;</code>/<code>&quot;boxplot&quot;</code>) without overflow (including the case <code>&quot;category&quot;</code> axis with <code>boundaryGap: false</code>); provide <code>con [...]
+<li>[Feature] [axis] Automatically exclude non-positive series data values on <code>&quot;log&quot;</code> axis. <a href="https://github.com/apache/echarts/commit/dedc5dc18">dedc5dc18</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Feature] [axis] Enable <code>axisLabel.formatter</code> to receive its index for working with <code>customValues</code>. <a href="https://github.com/apache/echarts/pull/21220">#21220</a> <a href="https://github.com/apache/echarts/pull/21432">#21432</a> (<a href="https://github.com/szymonpachucki">Szymon Pachucki</a>, <a href="https://github.com/Ovilia">Ovilia</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Feature] [line] Add <code>triggerEvent</code> option for more control over mouse event. <a href="https://github.com/apache/echarts/pull/21001">#21001</a> (<a href="https://github.com/sjcobb">Steven Cobb</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Feature] [pie] Add <code>tangential-noflip</code> rotation mode to keep labels tangential without flipping. <a href="https://github.com/apache/echarts/pull/21258">#21258</a> (<a href="https://github.com/MC-YCY">春秋半夏</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
+<li>[Feature] [gauge] <code>progress.color</code> supports <code>&#39;auto&#39;</code>. <a href="https://github.com/apache/echarts/pull/21224">#21224</a> (<a href="https://github.com/StNimmerlein">StNimmerlein</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
+<li>[Feature] [radar] Add <code>clockwise</code> option. <a href="https://github.com/apache/echarts/pull/21143">#21143</a> (<a href="https://github.com/daidr">Dai Xuezhou</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
+<li>[Feature] [candlestick] [dataZoom] Add <code>cursor</code> option for <code>candlestick</code> series and add <code>cursorGrab</code> option &amp; <code>cursorGrabbing</code> for <code>&#39;inside&#39;</code> dataZoom. <a href="https://github.com/apache/echarts/pull/21558">#21558</a> (<a href="https://github.com/diysimon">zuming</a>, <a href="https://github.com/Ovilia">Ovilia</a>, <a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Feature] [scatter] [effectScatter] [geo] Enable <code>clip</code> option on <code>&quot;scatter&quot;</code>/<code>&quot;effectScatter&quot;</code> on <code>geo</code>. <a href="https://github.com/apache/echarts/commit/417592289">417592289</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Feature] [visualMap] Add <code>seriesTargets</code> option for multiple series-dimension mappings. <a href="https://github.com/apache/echarts/pull/20703">#20703</a> (<a href="https://github.com/Justin-ZS">Justin-ZS</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Feature] [matrix] Support <code>matrix.x/y.length</code> for conveniently creating a headless matrix without composing an array. <a href="https://github.com/apache/echarts/pull/21191">#21191</a> (<a href="https://github.com/100pah">100pah</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Feature] [matrix] Add <code>triggerEvent</code> option to support triggering event on matrix cells. <a href="https://github.com/apache/echarts/pull/21390">#21390</a> (<a href="https://github.com/natsuokawai">Natsuo Kawai</a>, <a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Feature] [i18n] add Latvian(LV) translation. <a href="https://github.com/apache/echarts/pull/21546">#21546</a> (<a href="https://github.com/EPoikans">EPoikans</a>)</li>
+<li>[Fix] [axis] Change and clarify the rounding error and auto-precision utils and solutions. <a href="https://github.com/apache/echarts/commit/479dcd454">479dcd454</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [axis] Fix chart does not work when using <code>customValues</code> with <code>formatter</code> in time axis (<code>axis.type: &#39;time&#39;</code>) label. <a href="https://github.com/apache/echarts/pull/21352">#21352</a> (<a href="https://github.com/Srajan-Sanjay-Saxena">Srajan Sanjay Saxena</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Fix] [axis] Fix and clarify <code>alignTick</code> strategy, and fix <code>LogScale</code> precision. <a href="https://github.com/apache/echarts/commit/a6ab2458f">a6ab2458f</a> <a href="https://github.com/apache/echarts/commit/ffcc636fb">ffcc636fb</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [axis] Fix duplicate ticks when using time axis (<code>axis.type: &#39;time&#39;</code>) or <code>customValues</code>, which causes jitter of <code>splitArea</code>; fix the <code>showMin/MaxLabel</code> handling of a category axis (<code>axis.type: &#39;category&#39;</code>); enable a uniform <code>bandWidth</code> calculation in numeric axis (<code>axis.type: &#39;value&#39; | &#39;time&#39; | &#39;log&#39;</code>). <a href="https://github.com/apache/echarts/commit/8de2b64fa" [...]
+<li>[Fix] [axis] Fix time axis (<code>axis.type: &#39;time&#39;</code>) bug when value scale is in millisecond. <a href="https://github.com/apache/echarts/commit/40b77b464">40b77b464</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [bar] Fix wrong label position when bar series has a 0 width/height. <a href="https://github.com/apache/echarts/pull/21218">#21218</a> (<a href="https://github.com/Justin-ZS">Justin-ZS</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
+<li>[Fix] [scatter] Fix jitter layout does not support progressive rendering and cause chart to be frozen and potential NPE. <a href="https://github.com/apache/echarts/pull/21436">#21436</a> (<a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Fix] [lines] Fix effect symbol flip on unidirectional loop end when <code>roundTrip</code> is not enabled. <a href="https://github.com/apache/echarts/pull/21320">#21320</a> (<a href="https://github.com/mynk2611">Mayank Mehta</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Fix] [candlestick] Fix candlestick render error with <code>series.encode</code> on horizontal layout. <a href="https://github.com/apache/echarts/pull/21325">#21325</a> (<a href="https://github.com/PPRAMANIK62">Purbayan Pramanik</a>, <a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [parallel] Fix incorrect axis extent when any subsequent series has a larger value than the first. <a href="https://github.com/apache/echarts/pull/21387">#21387</a> (<a href="https://github.com/jackhickson">jackhickson</a>, <a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [pie] Support axes extent union pie center automatically when pie is laid out on Cartesian (<code>grid</code> component). <a href="https://github.com/apache/echarts/commit/18a23a875">18a23a875</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [treemap] Fix treemap can not be zoomed out after a zoom-in when <code>scaleLimit</code> is specified <a href="https://github.com/apache/echarts/pull/21427">#21427</a> (<a href="https://github.com/liuyizhou">TateLiu</a>, <a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [lines] Fix potential <code>tooltip</code> XSS vulnerability in lines series (<code>series.type: &#39;lines&#39;</code>). <a href="https://github.com/apache/echarts/pull/21608">#21608</a> (<a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Fix] [map] [geo] Fix the failed synchronization and visual artifacts on geo roaming and animation. <a href="https://github.com/apache/echarts/commit/417592289">417592289</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [tooltip] Fix <code>tooltip</code> content does not refresh when changing tooltip trigger from <code>&#39;axis&#39;</code> to <code>&#39;item&#39;</code>. <a href="https://github.com/apache/echarts/pull/20710">#20710</a> (<a href="https://github.com/Justin-ZS">Justin-ZS</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Fix] [tooltip] <code>valueFormatter</code> callback param <code>dataIndex</code> should be <code>rawDataIndex</code> rather than <code>dataZoom</code> filtered <code>dataIndex</code>. <a href="https://github.com/apache/echarts/pull/21479">#21479</a> (<a href="https://github.com/100pah">100pah</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Fix] [axisPointer] Fix <code>axisPointer</code> shadow and enable clipping - it is previously only applicable to <code>&quot;category&quot;</code> axis, but is buggy in numeric axis with <code>&quot;bar&quot;</code> series. <a href="https://github.com/apache/echarts/commit/8de2b64fa">8de2b64fa</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [axisPointer] Fix visual artifacts caused by failed <code>axisPointer</code> restoration. <a href="https://github.com/apache/echarts/commit/56a32c0bb">56a32c0bb</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [hoverLayer] Fix visual artifacts arisen on hover layer. <a href="https://github.com/ecomfe/zrender/pull/1151">zrender#1151</a> <a href="https://github.com/apache/echarts/commit/933585126">933585126</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [marker] Fix <code>marker</code> fails to render with <code>dataset</code> and <code>encode</code>. <a href="https://github.com/apache/echarts/pull/21439">#21439</a> (<a href="https://github.com/plainheart">plainheart</a>, <a href="https://github.com/100pah">100pah</a>).</li>
+<li>[Fix] [dataZoom] Fix wrong position of the <code>dataZoom</code> when the <code>series</code> has only one data point. <a href="https://github.com/apache/echarts/pull/21196">#21196</a> (<a href="https://github.com/alesmit">alesmit</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
+<li>[Fix] [dataZoom] Fix <code>dataZoom</code> bug that data info disappears when dragging released; fix <code>dataZoom</code> dragging cursor style. <a href="https://github.com/apache/echarts/commit/64305a4b8">64305a4b8</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [dataZoom] Apply a better auto-precision method; fix unexpected behaviors when <code>dataZoom</code> controls axes with <code>alignTicks: true</code>. <a href="https://github.com/apache/echarts/commit/d168bf237">d168bf237</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [dataZoom] Fix <code>AxisProxy</code> can not be cleared when <code>dataZoom</code> option changed; fix related <code>onZero</code> behaviors. <a href="https://github.com/apache/echarts/commit/52ceb924a">52ceb924a</a> <a href="https://github.com/apache/echarts/commit/2e82d33c3">2e82d33c3</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [areaStyle] Fix <code>areaStyle</code> render error when dimension name is empty string. <a href="https://github.com/apache/echarts/pull/21219">#21219</a> (<a href="https://github.com/Justin-ZS">Justin-ZS</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
+<li>[Fix] [sunburst] Fix root node label may not be centered. <a href="https://github.com/apache/echarts/pull/21306">#21306</a> (<a href="https://github.com/akashsonune">Akash Sonune</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
+<li>[Fix] [matrix] Fix matrix label formatter does not work. <a href="https://github.com/apache/echarts/pull/21410">#21410</a> (<a href="https://github.com/Justin-ZS">Justin-ZS</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
+<li>[Fix] [toolbox] Fix <code>emphasis</code> color is the same as the default color. <a href="https://github.com/apache/echarts/pull/21384">#21384</a> (<a href="https://github.com/Ovilia">Ovilia</a>) <a href="https://github.com/apache/echarts/commit/b094f987d">b094f987d</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [toolbox] Fix the <code>dataView</code> component does not fit the dark mode. <a href="https://github.com/apache/echarts/pull/21176">#21176</a> (<a href="https://github.com/notthistrain">notthistrain</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
+<li>[Fix] [progressive] Fix progressive rendering issues. <a href="https://github.com/apache/echarts/commit/91a60fc76">91a60fc76</a> (<a href="https://github.com/100pah">100pah</a>)</li>
+<li>[Fix] [labelLine] Fix <code>labelLine.smooth</code> can not be reset. <a href="https://github.com/apache/echarts/pull/21425">#21425</a> (<a href="https://github.com/fanwww">fanwww</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Fix] [graphic] Fix stroke corner gap due to not closing path in <code>roundRect</code> helper. <a href="https://github.com/ecomfe/zrender/pull/1155">zrender#1155</a> (<a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Fix] [svg] Enhance SVG <code>encodeBase64</code> compatibility to make it available in more environments like Web Worker/NodeJS/Bun. <a href="https://github.com/ecomfe/zrender/pull/1145">zrender#1145</a> (<a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Fix] [core] Mark <code>echarts</code> instance object as <code>raw</code> in <code>Vue</code>. <a href="https://github.com/apache/echarts/pull/21293">#21293</a> (<a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Fix] [chord] Add the missing export entry for chord chart. <a href="https://github.com/apache/echarts/pull/21197">#21197</a> (<a href="https://github.com/plainheart">plainheart</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
+<li>[Fix] [i18n] Fix incorrect translation for custom series name in <code>langDE</code>. <a href="https://github.com/apache/echarts/pull/21571">#21571</a> (<a href="https://github.com/A-Loot">A-Loot</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Fix] [typescript]<ul>
 <li>Fix and enhance <code>TS</code>, <code>ESM</code> and <code>CJS</code> compatibility. <a href="https://github.com/apache/echarts/pull/21411">#21411</a> (<a href="https://github.com/akashsonune">Akash Sonune</a>, <a href="https://github.com/100pah">100pah</a>)</li>
 <li>Fix missing or mismatched <code>TS</code> export types. <a href="https://github.com/apache/echarts/pull/21147">#21147</a> (<a href="https://github.com/100pah">100pah</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
 <li>Fix <code>nodeScaleRatio</code> option type for <code>graph</code> series. <a href="https://github.com/apache/echarts/pull/21229">#21229</a> (<a href="https://github.com/ocshawn">ocshawn</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
 <li><code>emphasis.handleLabel</code> of <code>slider</code> <code>dataZoom</code> should be an optional type. <a href="https://github.com/apache/echarts/pull/21175">#21175</a> (<a href="https://github.com/Ovilia">Ovilia</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>Correct typo. <a href="https://github.com/apache/echarts/pull/21528">#21528</a> (<a href="https://github.com/unional">Homa Wong</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>Correct typo <code>Continous</code> → <code>Continuous</code> and deprecate typo&#39;d types. <a href="https://github.com/apache/echarts/pull/21528">#21528</a> (<a href="https://github.com/unional">Homa Wong</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
 </ul>
 </li>
-<li>[Chore] [refactor]:<ul>
+<li>[Chore] [refactor]<ul>
 <li>Refactor axis scale implementation. <a href="https://github.com/apache/echarts/commit/fe932a2aa">fe932a2aa</a> <a href="https://github.com/apache/echarts/commit/18a23a875">18a23a875</a> (<a href="https://github.com/100pah">100pah</a>)</li>
 <li>Unify series data union implementation. <a href="https://github.com/apache/echarts/commit/fe932a2aa">fe932a2aa</a> <a href="https://github.com/apache/echarts/commit/0f4561dbe">0f4561dbe</a> (<a href="https://github.com/100pah">100pah</a>)</li>
 <li>Unify the roaming implementation. <a href="https://github.com/apache/echarts/commit/417592289">417592289</a> (<a href="https://github.com/100pah">100pah</a>)</li>
 </ul>
 </li>
-<li>[Chore] [security]: Add security checking hints in PR template. <a href="https://github.com/apache/echarts/pull/21327">#21327</a> (<a href="https://github.com/100pah">100pah</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Chore]: Add <code>unpkg</code> entry to <code>package.json</code>. <a href="https://github.com/apache/echarts/pull/21177">#21177</a> (<a href="https://github.com/kingyue737">Yue JIN</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Chore]: Fix example description for the <code>each</code> method of <code>SeriesData</code>. <a href="https://github.com/apache/echarts/pull/21294">#21294</a> (<a href="https://github.com/Yurunsoft">Yurun</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
-<li>[Chore]: Fix the <code>test/webkit-dep.htm</code> test case. <a href="https://github.com/apache/echarts/pull/21508">#21508</a> (<a href="https://github.com/diysimon">zuming</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
+<li>[Chore] [security] Add security checking hints in PR template. <a href="https://github.com/apache/echarts/pull/21327">#21327</a> (<a href="https://github.com/100pah">100pah</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Chore] Add <code>unpkg</code> entry to <code>package.json</code>. <a href="https://github.com/apache/echarts/pull/21177">#21177</a> (<a href="https://github.com/kingyue737">Yue JIN</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Chore] Fix example description for the <code>each</code> method of <code>SeriesData</code>. <a href="https://github.com/apache/echarts/pull/21294">#21294</a> (<a href="https://github.com/Yurunsoft">Yurun</a>, <a href="https://github.com/plainheart">plainheart</a>)</li>
+<li>[Chore] Fix the <code>test/webkit-dep.htm</code> test case. <a href="https://github.com/apache/echarts/pull/21508">#21508</a> (<a href="https://github.com/diysimon">zuming</a>, <a href="https://github.com/Ovilia">Ovilia</a>)</li>
 <li>[Break] Breaking changes against <code>v6.0.0</code>:<ul>
 <li><a href="https://echarts.apache.org/option.html#tooltip.valueFormatter">tooltip.valueFormatter</a>: The 2nd parameter of <code>tooltip.valueFormatter</code> callback is changed from <code>dataIndex</code> (i.e., the index after <code>series</code> data filtered by <code>dataZoom</code>) to <code>rawDataIndex</code> (i.e., the index of the original input <code>series</code> data).</li>
 <li><a href="https://echarts.apache.org/option.html#yAxis.startValue">axis.startValue</a>: Previously <code>startValue</code> was also used as <code>axis.min</code> if <a href="https://echarts.apache.org/option.html#yAxis.min">axis.min</a> was not provided. The new version decouples them - explicitly setting them both (e.g., <code>startValue: 111, min: 111</code>) is equivalent to the previous behavior (<code>startValue: 111</code> and <code>min</code> is not specified).</li>
@@ -92,7 +92,7 @@
 <ul>
 <li>[Feature] [theme] New theme for ECharts 6.0. <a href="https://github.com/apache/echarts/issues/20865">#20865</a> <a href="https://github.com/apache/echarts/issues/21097">#21097</a> <a href="https://github.com/apache/echarts/issues/21114">#21114</a> (<a href="https://github.com/Ovilia">Ovilia</a>)</li>
 <li>[Feature] [chord] New chord series. <a href="https://github.com/apache/echarts/issues/20522">#20522</a> (<a href="https://github.com/Ovilia">Ovilia</a>)</li>
-<li>[Feature] [matrix&amp;calendar] New matrix coordinate system. And all series and components (including other coordinate systems, such as <code>grid</code>(Cartesian), <code>geo</code>, <code>polar</code>, etc.) are supported to be declaratively laid out in the cells of matrix and calendar coordinate system. <a href="https://github.com/apache/echarts/issues/19807">#19807</a> <a href="https://github.com/apache/echarts/pull/21093">#21093</a> (<a href="https://github.com/Ovilia">Ovilia</ [...]
+<li>[Feature] [matrix] [calendar] New matrix coordinate system. And all series and components (including other coordinate systems, such as <code>grid</code>(Cartesian), <code>geo</code>, <code>polar</code>, etc.) are supported to be declaratively laid out in the cells of matrix and calendar coordinate system. <a href="https://github.com/apache/echarts/issues/19807">#19807</a> <a href="https://github.com/apache/echarts/pull/21093">#21093</a> (<a href="https://github.com/Ovilia">Ovilia</a> [...]
 <li>[Feature] [custom] Support reusable custom series. <a href="https://github.com/apache/echarts/issues/20226">#20226</a> (<a href="https://github.com/Ovilia">Ovilia</a>)</li>
 <li>[Feature] [cartesian] Introduce new layout mechanism to avoid Cartesian (i.e., <code>grid</code> component) axis labels and axis names overflowing the canvas, prevent axis names from overlapping with axis labels, and make them the default. <a href="https://github.com/apache/echarts/pull/21059">#21059</a> (<a href="https://github.com/100pah">100pah</a>) <a href="https://github.com/apache/echarts/pull/19534">#19534</a> (<a href="https://github.com/robin-gerling">robin-gerling</a>) <a h [...]
 <li>[Feature] [scatter] Support jittering for scatter series. <a href="https://github.com/apache/echarts/issues/19941">#19941</a> <a href="https://github.com/apache/echarts/pull/21067">#21067</a> (<a href="https://github.com/Ovilia">Ovilia</a>)</li>
diff --git a/en/index.html b/en/index.html
index d8d7f252d..830f0a9f5 100644
--- a/en/index.html
+++ b/en/index.html
@@ -7,7 +7,7 @@
     document.head.insertBefore(el, document.getElementById('font-hack'));
 }
 </script><title>Apache ECharts</title><script src="https://echarts.apache.org/en/./js/vendors/scrollReveal.js@4.0.7/scrollreveal.min.js"></script><script src="https://echarts.apache.org/en/./js/vendors/lottie-web@5.7.6/lottie.min.js"></script><script type="text/javascript" src="https://echarts.apache.org/en/./js/vendors/jquery@3.7.1/dist/jquery.min.js"></script></head><!--[if lte IE 8]><body class="lower-ie"><div id="lowie-main"><img src="https://echarts.apache.org/en/images/forie.png?_v [...]
-<!--[if (gt IE 8)|!(IE)]><body></body><![endif]--><noscript><div class="no-script"><strong>We're sorry, but Apache ECharts website doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></div></noscript><div id="apache-banner"><div class="txt"><p>Please visit the official Apache ECharts Website at</p><a id="a2" href="https://echarts.apache.org/en/index.html">https://echarts.apache.org</a></div><a href="https://echarts.apache.org" target="_blank" onclick=" [...]
+<!--[if (gt IE 8)|!(IE)]><body></body><![endif]--><noscript><div class="no-script"><strong>We're sorry, but Apache ECharts website doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></div></noscript><div id="apache-banner"><div class="txt"><p>Please visit the official Apache ECharts Website at</p><a id="a2" href="https://echarts.apache.org/en/index.html">https://echarts.apache.org</a></div><a href="https://echarts.apache.org" target="_blank" onclick=" [...]
 <rect width="510" height="510" x="0" y="0" id="0" fill="none" fill-opacity="1"></rect>
 <path d="M255 25.9A20 20 0 0 1 276.7 5.9A250 250 0 0 1 496.5 190.3A20 20 0 0 1 480.6 215.2L308.9 245.5A5 5 0 0 1 303.2 241.9A50 50 0 0 0 259.5 205.2A5 5 0 0 1 255 200.2Z" fill="#5070dd" stroke="white" stroke-width="4" stroke-linejoin="round" transform-origin="255px 255px" class="zr0-cls-0"></path>
 <path d="M443.3 221.8A18 18 0 0 1 464.3 238.1A210 210 0 0 1 393.8 412.6A18 18 0 0 1 367.4 409.6L287.2 299.3A5 5 0 0 1 287.9 292.6A50 50 0 0 0 304.8 250.8A5 5 0 0 1 308.9 245.5Z" fill="#b6d634" stroke="white" stroke-width="4" stroke-linejoin="round" transform-origin="255px 255px" class="zr0-cls-1"></path>
@@ -128,4 +128,4 @@ transform:scale(0,0);
 </svg></div></div></div></div></section><section id="feature-section"><div class="container"><div class="index-features"><h2 class="reveal">Features</h2><hr class="reveal"><a href="https://echarts.apache.org/en/feature.html" class="more reveal">View More</a></div><div class="row"><div class="col-md-6"><div id="index-feature-1" class="index-feature"><div class="index-feature-left reveal"><div id="bg-icon-1" class="index-feature-icon-bg"></div><div id="icon-1" class="index-feature-icon"></ [...]
 </script><script type="text/javascript">window.lazyLoadOptions = {
     elements_selector: ".lazy"
-};</script><script src="https://echarts.apache.org/en/./js/vendors/vanilla-lazyload@12.0.3/lazyload.min.js"></script><script src="https://echarts.apache.org/en/js/index.js?_v_=1779725039701"></script></html>
\ No newline at end of file
+};</script><script src="https://echarts.apache.org/en/./js/vendors/vanilla-lazyload@12.0.3/lazyload.min.js"></script><script src="https://echarts.apache.org/en/js/index.js?_v_=1779949681837"></script></html>
\ No newline at end of file
diff --git a/en/js/vendors/echarts-gl/README.md b/en/js/vendors/echarts-gl/README.md
index 7694dd4ae..f57178d57 100644
--- a/en/js/vendors/echarts-gl/README.md
+++ b/en/js/vendors/echarts-gl/README.md
@@ -67,3 +67,7 @@ chart.setOption({
 ## License
 
 ECharts-GL is available under the BSD license.
+
+## Notice
+
+The Apache Software Foundation [Apache ECharts, ECharts](https://echarts.apache.org/), Apache, the Apache feather, and the Apache ECharts project logo are either registered trademarks or trademarks of the [Apache Software Foundation](https://www.apache.org/).
diff --git a/en/js/vendors/echarts-gl/dist/echarts-gl.js b/en/js/vendors/echarts-gl/dist/echarts-gl.js
index bbd083317..b60635404 100644
--- a/en/js/vendors/echarts-gl/dist/echarts-gl.js
+++ b/en/js/vendors/echarts-gl/dist/echarts-gl.js
@@ -14,7 +14,7 @@ return /******/ (() => { // webpackBootstrap
 
 /***/ "./src/export/all.js":
 /*!*****************************************!*\
-  !*** ./src/export/all.js + 360 modules ***!
+  !*** ./src/export/all.js + 362 modules ***!
   \*****************************************/
 /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
 
@@ -569,2513 +569,2180 @@ core_util.extend(Base.prototype, mixin_notifier);
 
 /* harmony default export */ const core_Base = (Base);
 
-;// CONCATENATED MODULE: ./node_modules/claygl/src/core/GLInfo.js
-var EXTENSION_LIST = [
-    'OES_texture_float',
-    'OES_texture_half_float',
-    'OES_texture_float_linear',
-    'OES_texture_half_float_linear',
-    'OES_standard_derivatives',
-    'OES_vertex_array_object',
-    'OES_element_index_uint',
-    'WEBGL_compressed_texture_s3tc',
-    'WEBGL_depth_texture',
-    'EXT_texture_filter_anisotropic',
-    'EXT_shader_texture_lod',
-    'WEBGL_draw_buffers',
-    'EXT_frag_depth',
-    'EXT_sRGB',
-    'ANGLE_instanced_arrays'
-];
+;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/common.js
 
-var PARAMETER_NAMES = [
-    'MAX_TEXTURE_SIZE',
-    'MAX_CUBE_MAP_TEXTURE_SIZE'
-];
+var GLMAT_EPSILON = 0.000001;
 
-function GLInfo(_gl) {
-    var extensions = {};
-    var parameters = {};
+// Use Array instead of Float32Array. It seems to be much faster and higher precision.
+var GLMAT_ARRAY_TYPE = Array;
+// if(!GLMAT_ARRAY_TYPE) {
+//     GLMAT_ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;
+// }
 
-    // Get webgl extension
-    for (var i = 0; i < EXTENSION_LIST.length; i++) {
-        var extName = EXTENSION_LIST[i];
-        createExtension(extName);
-    }
-    // Get parameters
-    for (var i = 0; i < PARAMETER_NAMES.length; i++) {
-        var name = PARAMETER_NAMES[i];
-        parameters[name] = _gl.getParameter(_gl[name]);
-    }
+var common_GLMAT_RANDOM = Math.random;
 
-    this.getExtension = function (name) {
-        if (!(name in extensions)) {
-            createExtension(name);
-        }
-        return extensions[name];
-    };
+;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/vec3.js
 
-    this.getParameter = function (name) {
-        return parameters[name];
-    };
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
 
-    function createExtension(name) {
-        if (_gl.getExtension) {
-            var ext = _gl.getExtension(name);
-            if (!ext) {
-                ext = _gl.getExtension('MOZ_' + name);
-            }
-            if (!ext) {
-                ext = _gl.getExtension('WEBKIT_' + name);
-            }
-            extensions[name] = ext;
-        }
-    }
-}
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
 
-/* harmony default export */ const core_GLInfo = (GLInfo);
+  * 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.
 
-;// CONCATENATED MODULE: ./node_modules/claygl/src/core/glenum.js
-/**
- * @namespace clay.core.glenum
- * @see http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14
- */
-/* harmony default export */ const glenum = ({
-    /* ClearBufferMask */
-    DEPTH_BUFFER_BIT               : 0x00000100,
-    STENCIL_BUFFER_BIT             : 0x00000400,
-    COLOR_BUFFER_BIT               : 0x00004000,
+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. */
 
-    /* BeginMode */
-    POINTS                         : 0x0000,
-    LINES                          : 0x0001,
-    LINE_LOOP                      : 0x0002,
-    LINE_STRIP                     : 0x0003,
-    TRIANGLES                      : 0x0004,
-    TRIANGLE_STRIP                 : 0x0005,
-    TRIANGLE_FAN                   : 0x0006,
 
-    /* AlphaFunction (not supported in ES20) */
-    /*      NEVER */
-    /*      LESS */
-    /*      EQUAL */
-    /*      LEQUAL */
-    /*      GREATER */
-    /*      NOTEQUAL */
-    /*      GEQUAL */
-    /*      ALWAYS */
 
-    /* BlendingFactorDest */
-    ZERO                           : 0,
-    ONE                            : 1,
-    SRC_COLOR                      : 0x0300,
-    ONE_MINUS_SRC_COLOR            : 0x0301,
-    SRC_ALPHA                      : 0x0302,
-    ONE_MINUS_SRC_ALPHA            : 0x0303,
-    DST_ALPHA                      : 0x0304,
-    ONE_MINUS_DST_ALPHA            : 0x0305,
+/**
+ * @class 3 Dimensional Vector
+ * @name vec3
+ */
 
-    /* BlendingFactorSrc */
-    /*      ZERO */
-    /*      ONE */
-    DST_COLOR                      : 0x0306,
-    ONE_MINUS_DST_COLOR            : 0x0307,
-    SRC_ALPHA_SATURATE             : 0x0308,
-    /*      SRC_ALPHA */
-    /*      ONE_MINUS_SRC_ALPHA */
-    /*      DST_ALPHA */
-    /*      ONE_MINUS_DST_ALPHA */
+var vec3 = {};
 
-    /* BlendEquationSeparate */
-    FUNC_ADD                       : 0x8006,
-    BLEND_EQUATION                 : 0x8009,
-    BLEND_EQUATION_RGB             : 0x8009, /* same as BLEND_EQUATION */
-    BLEND_EQUATION_ALPHA           : 0x883D,
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+vec3.create = function() {
+    var out = new GLMAT_ARRAY_TYPE(3);
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    return out;
+};
 
-    /* BlendSubtract */
-    FUNC_SUBTRACT                  : 0x800A,
-    FUNC_REVERSE_SUBTRACT          : 0x800B,
+/**
+ * Creates a new vec3 initialized with values from an existing vector
+ *
+ * @param {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+vec3.clone = function(a) {
+    var out = new GLMAT_ARRAY_TYPE(3);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+};
 
-    /* Separate Blend Functions */
-    BLEND_DST_RGB                  : 0x80C8,
-    BLEND_SRC_RGB                  : 0x80C9,
-    BLEND_DST_ALPHA                : 0x80CA,
-    BLEND_SRC_ALPHA                : 0x80CB,
-    CONSTANT_COLOR                 : 0x8001,
-    ONE_MINUS_CONSTANT_COLOR       : 0x8002,
-    CONSTANT_ALPHA                 : 0x8003,
-    ONE_MINUS_CONSTANT_ALPHA       : 0x8004,
-    BLEND_COLOR                    : 0x8005,
+/**
+ * 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
+ */
+vec3.fromValues = function(x, y, z) {
+    var out = new GLMAT_ARRAY_TYPE(3);
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+};
 
-    /* Buffer Objects */
-    ARRAY_BUFFER                   : 0x8892,
-    ELEMENT_ARRAY_BUFFER           : 0x8893,
-    ARRAY_BUFFER_BINDING           : 0x8894,
-    ELEMENT_ARRAY_BUFFER_BINDING   : 0x8895,
+/**
+ * Copy the values from one vec3 to another
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the source vector
+ * @returns {vec3} out
+ */
+vec3.copy = function(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    return out;
+};
 
-    STREAM_DRAW                    : 0x88E0,
-    STATIC_DRAW                    : 0x88E4,
-    DYNAMIC_DRAW                   : 0x88E8,
+/**
+ * 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
+ */
+vec3.set = function(out, x, y, z) {
+    out[0] = x;
+    out[1] = y;
+    out[2] = z;
+    return out;
+};
 
-    BUFFER_SIZE                    : 0x8764,
-    BUFFER_USAGE                   : 0x8765,
+/**
+ * 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
+ */
+vec3.add = function(out, a, b) {
+    out[0] = a[0] + b[0];
+    out[1] = a[1] + b[1];
+    out[2] = a[2] + b[2];
+    return out;
+};
 
-    CURRENT_VERTEX_ATTRIB          : 0x8626,
+/**
+ * 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
+ */
+vec3.subtract = function(out, a, b) {
+    out[0] = a[0] - b[0];
+    out[1] = a[1] - b[1];
+    out[2] = a[2] - b[2];
+    return out;
+};
 
-    /* CullFaceMode */
-    FRONT                          : 0x0404,
-    BACK                           : 0x0405,
-    FRONT_AND_BACK                 : 0x0408,
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+vec3.sub = vec3.subtract;
 
-    /* DepthFunction */
-    /*      NEVER */
-    /*      LESS */
-    /*      EQUAL */
-    /*      LEQUAL */
-    /*      GREATER */
-    /*      NOTEQUAL */
-    /*      GEQUAL */
-    /*      ALWAYS */
+/**
+ * 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
+ */
+vec3.multiply = function(out, a, b) {
+    out[0] = a[0] * b[0];
+    out[1] = a[1] * b[1];
+    out[2] = a[2] * b[2];
+    return out;
+};
 
-    /* EnableCap */
-    /* TEXTURE_2D */
-    CULL_FACE                      : 0x0B44,
-    BLEND                          : 0x0BE2,
-    DITHER                         : 0x0BD0,
-    STENCIL_TEST                   : 0x0B90,
-    DEPTH_TEST                     : 0x0B71,
-    SCISSOR_TEST                   : 0x0C11,
-    POLYGON_OFFSET_FILL            : 0x8037,
-    SAMPLE_ALPHA_TO_COVERAGE       : 0x809E,
-    SAMPLE_COVERAGE                : 0x80A0,
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+vec3.mul = vec3.multiply;
 
-    /* ErrorCode */
-    NO_ERROR                       : 0,
-    INVALID_ENUM                   : 0x0500,
-    INVALID_VALUE                  : 0x0501,
-    INVALID_OPERATION              : 0x0502,
-    OUT_OF_MEMORY                  : 0x0505,
+/**
+ * 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
+ */
+vec3.divide = function(out, a, b) {
+    out[0] = a[0] / b[0];
+    out[1] = a[1] / b[1];
+    out[2] = a[2] / b[2];
+    return out;
+};
 
-    /* FrontFaceDirection */
-    CW                             : 0x0900,
-    CCW                            : 0x0901,
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+vec3.div = vec3.divide;
 
-    /* GetPName */
-    LINE_WIDTH                     : 0x0B21,
-    ALIASED_POINT_SIZE_RANGE       : 0x846D,
-    ALIASED_LINE_WIDTH_RANGE       : 0x846E,
-    CULL_FACE_MODE                 : 0x0B45,
-    FRONT_FACE                     : 0x0B46,
-    DEPTH_RANGE                    : 0x0B70,
-    DEPTH_WRITEMASK                : 0x0B72,
-    DEPTH_CLEAR_VALUE              : 0x0B73,
-    DEPTH_FUNC                     : 0x0B74,
-    STENCIL_CLEAR_VALUE            : 0x0B91,
-    STENCIL_FUNC                   : 0x0B92,
-    STENCIL_FAIL                   : 0x0B94,
-    STENCIL_PASS_DEPTH_FAIL        : 0x0B95,
-    STENCIL_PASS_DEPTH_PASS        : 0x0B96,
-    STENCIL_REF                    : 0x0B97,
-    STENCIL_VALUE_MASK             : 0x0B93,
-    STENCIL_WRITEMASK              : 0x0B98,
-    STENCIL_BACK_FUNC              : 0x8800,
-    STENCIL_BACK_FAIL              : 0x8801,
-    STENCIL_BACK_PASS_DEPTH_FAIL   : 0x8802,
-    STENCIL_BACK_PASS_DEPTH_PASS   : 0x8803,
-    STENCIL_BACK_REF               : 0x8CA3,
-    STENCIL_BACK_VALUE_MASK        : 0x8CA4,
-    STENCIL_BACK_WRITEMASK         : 0x8CA5,
-    VIEWPORT                       : 0x0BA2,
-    SCISSOR_BOX                    : 0x0C10,
-    /*      SCISSOR_TEST */
-    COLOR_CLEAR_VALUE              : 0x0C22,
-    COLOR_WRITEMASK                : 0x0C23,
-    UNPACK_ALIGNMENT               : 0x0CF5,
-    PACK_ALIGNMENT                 : 0x0D05,
-    MAX_TEXTURE_SIZE               : 0x0D33,
-    MAX_VIEWPORT_DIMS              : 0x0D3A,
-    SUBPIXEL_BITS                  : 0x0D50,
-    RED_BITS                       : 0x0D52,
-    GREEN_BITS                     : 0x0D53,
-    BLUE_BITS                      : 0x0D54,
-    ALPHA_BITS                     : 0x0D55,
-    DEPTH_BITS                     : 0x0D56,
-    STENCIL_BITS                   : 0x0D57,
-    POLYGON_OFFSET_UNITS           : 0x2A00,
-    /*      POLYGON_OFFSET_FILL */
-    POLYGON_OFFSET_FACTOR          : 0x8038,
-    TEXTURE_BINDING_2D             : 0x8069,
-    SAMPLE_BUFFERS                 : 0x80A8,
-    SAMPLES                        : 0x80A9,
-    SAMPLE_COVERAGE_VALUE          : 0x80AA,
-    SAMPLE_COVERAGE_INVERT         : 0x80AB,
+/**
+ * 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
+ */
+vec3.min = function(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;
+};
 
-    /* GetTextureParameter */
-    /*      TEXTURE_MAG_FILTER */
-    /*      TEXTURE_MIN_FILTER */
-    /*      TEXTURE_WRAP_S */
-    /*      TEXTURE_WRAP_T */
+/**
+ * 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
+ */
+vec3.max = function(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;
+};
 
-    COMPRESSED_TEXTURE_FORMATS     : 0x86A3,
+/**
+ * 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
+ */
+vec3.scale = function(out, a, b) {
+    out[0] = a[0] * b;
+    out[1] = a[1] * b;
+    out[2] = a[2] * b;
+    return out;
+};
 
-    /* HintMode */
-    DONT_CARE                      : 0x1100,
-    FASTEST                        : 0x1101,
-    NICEST                         : 0x1102,
+/**
+ * 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
+ */
+vec3.scaleAndAdd = function(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;
+};
 
-    /* HintTarget */
-    GENERATE_MIPMAP_HINT            : 0x8192,
+/**
+ * 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
+ */
+vec3.distance = function(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1],
+        z = b[2] - a[2];
+    return Math.sqrt(x*x + y*y + z*z);
+};
 
-    /* DataType */
-    BYTE                           : 0x1400,
-    UNSIGNED_BYTE                  : 0x1401,
-    SHORT                          : 0x1402,
-    UNSIGNED_SHORT                 : 0x1403,
-    INT                            : 0x1404,
-    UNSIGNED_INT                   : 0x1405,
-    FLOAT                          : 0x1406,
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+vec3.dist = vec3.distance;
 
-    /* PixelFormat */
-    DEPTH_COMPONENT                : 0x1902,
-    ALPHA                          : 0x1906,
-    RGB                            : 0x1907,
-    RGBA                           : 0x1908,
-    LUMINANCE                      : 0x1909,
-    LUMINANCE_ALPHA                : 0x190A,
+/**
+ * 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
+ */
+vec3.squaredDistance = function(a, b) {
+    var x = b[0] - a[0],
+        y = b[1] - a[1],
+        z = b[2] - a[2];
+    return x*x + y*y + z*z;
+};
 
-    /* PixelType */
-    /*      UNSIGNED_BYTE */
-    UNSIGNED_SHORT_4_4_4_4         : 0x8033,
-    UNSIGNED_SHORT_5_5_5_1         : 0x8034,
-    UNSIGNED_SHORT_5_6_5           : 0x8363,
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+vec3.sqrDist = vec3.squaredDistance;
 
-    /* Shaders */
-    FRAGMENT_SHADER                  : 0x8B30,
-    VERTEX_SHADER                    : 0x8B31,
-    MAX_VERTEX_ATTRIBS               : 0x8869,
-    MAX_VERTEX_UNIFORM_VECTORS       : 0x8DFB,
-    MAX_VARYING_VECTORS              : 0x8DFC,
-    MAX_COMBINED_TEXTURE_IMAGE_UNITS : 0x8B4D,
-    MAX_VERTEX_TEXTURE_IMAGE_UNITS   : 0x8B4C,
-    MAX_TEXTURE_IMAGE_UNITS          : 0x8872,
-    MAX_FRAGMENT_UNIFORM_VECTORS     : 0x8DFD,
-    SHADER_TYPE                      : 0x8B4F,
-    DELETE_STATUS                    : 0x8B80,
-    LINK_STATUS                      : 0x8B82,
-    VALIDATE_STATUS                  : 0x8B83,
-    ATTACHED_SHADERS                 : 0x8B85,
-    ACTIVE_UNIFORMS                  : 0x8B86,
-    ACTIVE_ATTRIBUTES                : 0x8B89,
-    SHADING_LANGUAGE_VERSION         : 0x8B8C,
-    CURRENT_PROGRAM                  : 0x8B8D,
-
-    /* StencilFunction */
-    NEVER                          : 0x0200,
-    LESS                           : 0x0201,
-    EQUAL                          : 0x0202,
-    LEQUAL                         : 0x0203,
-    GREATER                        : 0x0204,
-    NOTEQUAL                       : 0x0205,
-    GEQUAL                         : 0x0206,
-    ALWAYS                         : 0x0207,
-
-    /* StencilOp */
-    /*      ZERO */
-    KEEP                           : 0x1E00,
-    REPLACE                        : 0x1E01,
-    INCR                           : 0x1E02,
-    DECR                           : 0x1E03,
-    INVERT                         : 0x150A,
-    INCR_WRAP                      : 0x8507,
-    DECR_WRAP                      : 0x8508,
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec3.length = function (a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    return Math.sqrt(x*x + y*y + z*z);
+};
 
-    /* StringName */
-    VENDOR                         : 0x1F00,
-    RENDERER                       : 0x1F01,
-    VERSION                        : 0x1F02,
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+vec3.len = vec3.length;
 
-    /* TextureMagFilter */
-    NEAREST                        : 0x2600,
-    LINEAR                         : 0x2601,
+/**
+ * Calculates the squared length of a vec3
+ *
+ * @param {vec3} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec3.squaredLength = function (a) {
+    var x = a[0],
+        y = a[1],
+        z = a[2];
+    return x*x + y*y + z*z;
+};
 
-    /* TextureMinFilter */
-    /*      NEAREST */
-    /*      LINEAR */
-    NEAREST_MIPMAP_NEAREST         : 0x2700,
-    LINEAR_MIPMAP_NEAREST          : 0x2701,
-    NEAREST_MIPMAP_LINEAR          : 0x2702,
-    LINEAR_MIPMAP_LINEAR           : 0x2703,
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+vec3.sqrLen = vec3.squaredLength;
 
-    /* TextureParameterName */
-    TEXTURE_MAG_FILTER             : 0x2800,
-    TEXTURE_MIN_FILTER             : 0x2801,
-    TEXTURE_WRAP_S                 : 0x2802,
-    TEXTURE_WRAP_T                 : 0x2803,
+/**
+ * Negates the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to negate
+ * @returns {vec3} out
+ */
+vec3.negate = function(out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    return out;
+};
 
-    /* TextureTarget */
-    TEXTURE_2D                     : 0x0DE1,
-    TEXTURE                        : 0x1702,
+/**
+ * Returns the inverse of the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to invert
+ * @returns {vec3} out
+ */
+vec3.inverse = function(out, a) {
+  out[0] = 1.0 / a[0];
+  out[1] = 1.0 / a[1];
+  out[2] = 1.0 / a[2];
+  return out;
+};
 
-    TEXTURE_CUBE_MAP               : 0x8513,
-    TEXTURE_BINDING_CUBE_MAP       : 0x8514,
-    TEXTURE_CUBE_MAP_POSITIVE_X    : 0x8515,
-    TEXTURE_CUBE_MAP_NEGATIVE_X    : 0x8516,
-    TEXTURE_CUBE_MAP_POSITIVE_Y    : 0x8517,
-    TEXTURE_CUBE_MAP_NEGATIVE_Y    : 0x8518,
-    TEXTURE_CUBE_MAP_POSITIVE_Z    : 0x8519,
-    TEXTURE_CUBE_MAP_NEGATIVE_Z    : 0x851A,
-    MAX_CUBE_MAP_TEXTURE_SIZE      : 0x851C,
+/**
+ * Normalize a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to normalize
+ * @returns {vec3} out
+ */
+vec3.normalize = function(out, a) {
+    var x = a[0],
+        y = a[1],
+        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;
+};
 
-    /* TextureUnit */
-    TEXTURE0                       : 0x84C0,
-    TEXTURE1                       : 0x84C1,
-    TEXTURE2                       : 0x84C2,
-    TEXTURE3                       : 0x84C3,
-    TEXTURE4                       : 0x84C4,
-    TEXTURE5                       : 0x84C5,
-    TEXTURE6                       : 0x84C6,
-    TEXTURE7                       : 0x84C7,
-    TEXTURE8                       : 0x84C8,
-    TEXTURE9                       : 0x84C9,
-    TEXTURE10                      : 0x84CA,
-    TEXTURE11                      : 0x84CB,
-    TEXTURE12                      : 0x84CC,
-    TEXTURE13                      : 0x84CD,
-    TEXTURE14                      : 0x84CE,
-    TEXTURE15                      : 0x84CF,
-    TEXTURE16                      : 0x84D0,
-    TEXTURE17                      : 0x84D1,
-    TEXTURE18                      : 0x84D2,
-    TEXTURE19                      : 0x84D3,
-    TEXTURE20                      : 0x84D4,
-    TEXTURE21                      : 0x84D5,
-    TEXTURE22                      : 0x84D6,
-    TEXTURE23                      : 0x84D7,
-    TEXTURE24                      : 0x84D8,
-    TEXTURE25                      : 0x84D9,
-    TEXTURE26                      : 0x84DA,
-    TEXTURE27                      : 0x84DB,
-    TEXTURE28                      : 0x84DC,
-    TEXTURE29                      : 0x84DD,
-    TEXTURE30                      : 0x84DE,
-    TEXTURE31                      : 0x84DF,
-    ACTIVE_TEXTURE                 : 0x84E0,
+/**
+ * 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
+ */
+vec3.dot = function (a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+};
 
-    /* TextureWrapMode */
-    REPEAT                         : 0x2901,
-    CLAMP_TO_EDGE                  : 0x812F,
-    MIRRORED_REPEAT                : 0x8370,
+/**
+ * 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
+ */
+vec3.cross = function(out, a, b) {
+    var ax = a[0], ay = a[1], az = a[2],
+        bx = b[0], by = b[1], bz = b[2];
 
-    /* Uniform Types */
-    FLOAT_VEC2                     : 0x8B50,
-    FLOAT_VEC3                     : 0x8B51,
-    FLOAT_VEC4                     : 0x8B52,
-    INT_VEC2                       : 0x8B53,
-    INT_VEC3                       : 0x8B54,
-    INT_VEC4                       : 0x8B55,
-    BOOL                           : 0x8B56,
-    BOOL_VEC2                      : 0x8B57,
-    BOOL_VEC3                      : 0x8B58,
-    BOOL_VEC4                      : 0x8B59,
-    FLOAT_MAT2                     : 0x8B5A,
-    FLOAT_MAT3                     : 0x8B5B,
-    FLOAT_MAT4                     : 0x8B5C,
-    SAMPLER_2D                     : 0x8B5E,
-    SAMPLER_CUBE                   : 0x8B60,
+    out[0] = ay * bz - az * by;
+    out[1] = az * bx - ax * bz;
+    out[2] = ax * by - ay * bx;
+    return out;
+};
 
-    /* Vertex Arrays */
-    VERTEX_ATTRIB_ARRAY_ENABLED        : 0x8622,
-    VERTEX_ATTRIB_ARRAY_SIZE           : 0x8623,
-    VERTEX_ATTRIB_ARRAY_STRIDE         : 0x8624,
-    VERTEX_ATTRIB_ARRAY_TYPE           : 0x8625,
-    VERTEX_ATTRIB_ARRAY_NORMALIZED     : 0x886A,
-    VERTEX_ATTRIB_ARRAY_POINTER        : 0x8645,
-    VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : 0x889F,
+/**
+ * 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
+ */
+vec3.lerp = function (out, a, b, t) {
+    var ax = a[0],
+        ay = a[1],
+        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;
+};
 
-    /* Shader Source */
-    COMPILE_STATUS                 : 0x8B81,
+/**
+ * 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
+ */
+vec3.random = function (out, scale) {
+    scale = scale || 1.0;
 
-    /* Shader Precision-Specified Types */
-    LOW_FLOAT                      : 0x8DF0,
-    MEDIUM_FLOAT                   : 0x8DF1,
-    HIGH_FLOAT                     : 0x8DF2,
-    LOW_INT                        : 0x8DF3,
-    MEDIUM_INT                     : 0x8DF4,
-    HIGH_INT                       : 0x8DF5,
+    var r = common_GLMAT_RANDOM() * 2.0 * Math.PI;
+    var z = (common_GLMAT_RANDOM() * 2.0) - 1.0;
+    var zScale = Math.sqrt(1.0-z*z) * scale;
 
-    /* Framebuffer Object. */
-    FRAMEBUFFER                    : 0x8D40,
-    RENDERBUFFER                   : 0x8D41,
+    out[0] = Math.cos(r) * zScale;
+    out[1] = Math.sin(r) * zScale;
+    out[2] = z * scale;
+    return out;
+};
 
-    RGBA4                          : 0x8056,
-    RGB5_A1                        : 0x8057,
-    RGB565                         : 0x8D62,
-    DEPTH_COMPONENT16              : 0x81A5,
-    STENCIL_INDEX                  : 0x1901,
-    STENCIL_INDEX8                 : 0x8D48,
-    DEPTH_STENCIL                  : 0x84F9,
+/**
+ * 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
+ */
+vec3.transformMat4 = function(out, a, m) {
+    var x = a[0], y = a[1], z = a[2],
+        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;
+};
 
-    RENDERBUFFER_WIDTH             : 0x8D42,
-    RENDERBUFFER_HEIGHT            : 0x8D43,
-    RENDERBUFFER_INTERNAL_FORMAT   : 0x8D44,
-    RENDERBUFFER_RED_SIZE          : 0x8D50,
-    RENDERBUFFER_GREEN_SIZE        : 0x8D51,
-    RENDERBUFFER_BLUE_SIZE         : 0x8D52,
-    RENDERBUFFER_ALPHA_SIZE        : 0x8D53,
-    RENDERBUFFER_DEPTH_SIZE        : 0x8D54,
-    RENDERBUFFER_STENCIL_SIZE      : 0x8D55,
+/**
+ * Transforms the vec3 with a mat3.
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m the 3x3 matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat3 = function(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;
+};
 
-    FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE           : 0x8CD0,
-    FRAMEBUFFER_ATTACHMENT_OBJECT_NAME           : 0x8CD1,
-    FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL         : 0x8CD2,
-    FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE : 0x8CD3,
+/**
+ * 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
+ */
+vec3.transformQuat = function(out, a, q) {
+    // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
 
-    COLOR_ATTACHMENT0              : 0x8CE0,
-    DEPTH_ATTACHMENT               : 0x8D00,
-    STENCIL_ATTACHMENT             : 0x8D20,
-    DEPTH_STENCIL_ATTACHMENT       : 0x821A,
+    var x = a[0], y = a[1], z = a[2],
+        qx = q[0], qy = q[1], qz = q[2], qw = q[3],
 
-    NONE                           : 0,
+        // calculate quat * vec
+        ix = qw * x + qy * z - qz * y,
+        iy = qw * y + qz * x - qx * z,
+        iz = qw * z + qx * y - qy * x,
+        iw = -qx * x - qy * y - qz * z;
 
-    FRAMEBUFFER_COMPLETE                      : 0x8CD5,
-    FRAMEBUFFER_INCOMPLETE_ATTACHMENT         : 0x8CD6,
-    FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : 0x8CD7,
-    FRAMEBUFFER_INCOMPLETE_DIMENSIONS         : 0x8CD9,
-    FRAMEBUFFER_UNSUPPORTED                   : 0x8CDD,
+    // 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;
+};
 
-    FRAMEBUFFER_BINDING            : 0x8CA6,
-    RENDERBUFFER_BINDING           : 0x8CA7,
-    MAX_RENDERBUFFER_SIZE          : 0x84E8,
+/**
+ * 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
+ */
+vec3.rotateX = function(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];
 
-    INVALID_FRAMEBUFFER_OPERATION  : 0x0506,
+      //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);
 
-    /* WebGL-specific enums */
-    UNPACK_FLIP_Y_WEBGL            : 0x9240,
-    UNPACK_PREMULTIPLY_ALPHA_WEBGL : 0x9241,
-    CONTEXT_LOST_WEBGL             : 0x9242,
-    UNPACK_COLORSPACE_CONVERSION_WEBGL : 0x9243,
-    BROWSER_DEFAULT_WEBGL          : 0x9244,
-});
+      //translate to correct position
+      out[0] = r[0] + b[0];
+      out[1] = r[1] + b[1];
+      out[2] = r[2] + b[2];
 
-;// CONCATENATED MODULE: ./node_modules/claygl/src/core/request.js
-function get(options) {
+    return out;
+};
 
-    var xhr = new XMLHttpRequest();
+/**
+ * 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
+ */
+vec3.rotateY = function(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];
 
-    xhr.open('get', options.url);
-    // With response type set browser can get and put binary data
-    // https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Sending_and_Receiving_Binary_Data
-    // Default is text, and it can be set
-    // arraybuffer, blob, document, json, text
-    xhr.responseType = options.responseType || 'text';
+    //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);
 
-    if (options.onprogress) {
-        //https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest
-        xhr.onprogress = function(e) {
-            if (e.lengthComputable) {
-                var percent = e.loaded / e.total;
-                options.onprogress(percent, e.loaded, e.total);
-            }
-            else {
-                options.onprogress(null);
-            }
-        };
-    }
-    xhr.onload = function(e) {
-        if (xhr.status >= 400) {
-            options.onerror && options.onerror();
-        }
-        else {
-            options.onload && options.onload(xhr.response);
-        }
-    };
-    if (options.onerror) {
-        xhr.onerror = options.onerror;
-    }
-    xhr.send(null);
-}
+    //translate to correct position
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
 
-/* harmony default export */ const request = ({
-    get: get
-});
+    return out;
+};
 
-;// CONCATENATED MODULE: ./node_modules/claygl/src/core/vendor.js
+/**
+ * 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
+ */
+vec3.rotateZ = function(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];
 
-var supportWebGL;
+    //translate to correct position
+    out[0] = r[0] + b[0];
+    out[1] = r[1] + b[1];
+    out[2] = r[2] + b[2];
 
-var vendor = {};
+    return out;
+};
 
 /**
- * If support WebGL
- * @return {boolean}
+ * 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
  */
-vendor.supportWebGL = function () {
-    if (supportWebGL == null) {
-        try {
-            var canvas = document.createElement('canvas');
-            var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
-            if (!gl) {
-                throw new Error();
-            }
-        }
-        catch (e) {
-            supportWebGL = false;
-        }
-
-    }
-    return supportWebGL;
-};
-
-vendor.Int8Array = typeof Int8Array === 'undefined' ? Array : Int8Array;
-
-vendor.Uint8Array = typeof Uint8Array === 'undefined' ? Array : Uint8Array;
-
-vendor.Uint16Array = typeof Uint16Array === 'undefined' ? Array : Uint16Array;
-
-vendor.Uint32Array = typeof Uint32Array === 'undefined' ? Array : Uint32Array;
+vec3.forEach = (function() {
+    var vec = vec3.create();
 
-vendor.Int16Array = typeof Int16Array === 'undefined' ? Array : Int16Array;
+    return function(a, stride, offset, count, fn, arg) {
+        var i, l;
+        if(!stride) {
+            stride = 3;
+        }
 
-vendor.Float32Array = typeof Float32Array === 'undefined' ? Array : Float32Array;
+        if(!offset) {
+            offset = 0;
+        }
 
-vendor.Float64Array = typeof Float64Array === 'undefined' ? Array : Float64Array;
+        if(count) {
+            l = Math.min((count * stride) + offset, a.length);
+        } else {
+            l = a.length;
+        }
 
-var g = {};
-if (typeof window !== 'undefined') {
-    g = window;
-}
-else if (typeof __webpack_require__.g !== 'undefined') {
-    g = __webpack_require__.g;
-}
+        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;
+    };
+})();
 
-vendor.requestAnimationFrame = g.requestAnimationFrame
-    || g.msRequestAnimationFrame
-    || g.mozRequestAnimationFrame
-    || g.webkitRequestAnimationFrame
-    || function (func){ setTimeout(func, 16); };
+/**
+ * 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
+ */
+vec3.angle = function(a, b) {
 
-vendor.createCanvas = function () {
-    return document.createElement('canvas');
-};
+    var tempA = vec3.fromValues(a[0], a[1], a[2]);
+    var tempB = vec3.fromValues(b[0], b[1], b[2]);
 
-vendor.createImage = function () {
-    return new g.Image();
-};
+    vec3.normalize(tempA, tempA);
+    vec3.normalize(tempB, tempB);
 
-vendor.request = {
-    get: request.get
-};
+    var cosine = vec3.dot(tempA, tempB);
 
-vendor.addEventListener = function (dom, type, func, useCapture) {
-    dom.addEventListener(type, func, useCapture);
+    if(cosine > 1.0){
+        return 0;
+    } else {
+        return Math.acos(cosine);
+    }
 };
 
-vendor.removeEventListener = function (dom, type, func) {
-    dom.removeEventListener(type, func);
-};
+/* harmony default export */ const glmatrix_vec3 = (vec3);
+;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Vector3.js
 
-/* harmony default export */ const core_vendor = (vendor);
 
-;// CONCATENATED MODULE: ./node_modules/claygl/src/core/LinkedList.js
 /**
- * Simple double linked list. Compared with array, it has O(1) remove operation.
  * @constructor
- * @alias clay.core.LinkedList
+ * @alias clay.Vector3
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
  */
-var LinkedList = function () {
+var Vector3 = function(x, y, z) {
+
+    x = x || 0;
+    y = y || 0;
+    z = z || 0;
 
     /**
-     * @type {clay.core.LinkedList.Entry}
+     * Storage of Vector3, read and write of x, y, z will change the values in array
+     * All methods also operate on the array instead of x, y, z components
+     * @name array
+     * @type {Float32Array}
+     * @memberOf clay.Vector3#
      */
-    this.head = null;
+    this.array = glmatrix_vec3.fromValues(x, y, z);
 
     /**
-     * @type {clay.core.LinkedList.Entry}
+     * Dirty flag is used by the Node to determine
+     * if the matrix is updated to latest
+     * @name _dirty
+     * @type {boolean}
+     * @memberOf clay.Vector3#
      */
-    this.tail = null;
-
-    this._length = 0;
-};
-
-/**
- * Insert a new value at the tail
- * @param  {} val
- * @return {clay.core.LinkedList.Entry}
- */
-LinkedList.prototype.insert = function (val) {
-    var entry = new LinkedList.Entry(val);
-    this.insertEntry(entry);
-    return entry;
-};
-
-/**
- * Insert a new value at idx
- * @param {number} idx
- * @param  {} val
- * @return {clay.core.LinkedList.Entry}
- */
-LinkedList.prototype.insertAt = function (idx, val) {
-    if (idx < 0) {
-        return;
-    }
-    var next = this.head;
-    var cursor = 0;
-    while (next && cursor != idx) {
-        next = next.next;
-        cursor++;
-    }
-    if (next) {
-        var entry = new LinkedList.Entry(val);
-        var prev = next.prev;
-        if (!prev) { //next is head
-            this.head = entry;
-        }
-        else {
-            prev.next = entry;
-            entry.prev = prev;
-        }
-        entry.next = next;
-        next.prev = entry;
-    }
-    else {
-        this.insert(val);
-    }
+    this._dirty = true;
 };
 
-LinkedList.prototype.insertBeforeEntry = function (val, next) {
-    var entry = new LinkedList.Entry(val);
-    var prev = next.prev;
-    if (!prev) { //next is head
-        this.head = entry;
-    }
-    else {
-        prev.next = entry;
-        entry.prev = prev;
-    }
-    entry.next = next;
-    next.prev = entry;
-
-    this._length++;
-};
+Vector3.prototype = {
 
-/**
- * Insert an entry at the tail
- * @param  {clay.core.LinkedList.Entry} entry
- */
-LinkedList.prototype.insertEntry = function (entry) {
-    if (!this.head) {
-        this.head = this.tail = entry;
-    }
-    else {
-        this.tail.next = entry;
-        entry.prev = this.tail;
-        this.tail = entry;
-    }
-    this._length++;
-};
+    constructor: Vector3,
 
-/**
- * Remove entry.
- * @param  {clay.core.LinkedList.Entry} entry
- */
-LinkedList.prototype.remove = function (entry) {
-    var prev = entry.prev;
-    var next = entry.next;
-    if (prev) {
-        prev.next = next;
-    }
-    else {
-        // Is head
-        this.head = next;
-    }
-    if (next) {
-        next.prev = prev;
-    }
-    else {
-        // Is tail
-        this.tail = prev;
-    }
-    entry.next = entry.prev = null;
-    this._length--;
-};
+    /**
+     * Add b to self
+     * @param  {clay.Vector3} b
+     * @return {clay.Vector3}
+     */
+    add: function (b) {
+        glmatrix_vec3.add(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * Remove entry at index.
- * @param  {number} idx
- * @return {}
- */
-LinkedList.prototype.removeAt = function (idx) {
-    if (idx < 0) {
-        return;
-    }
-    var curr = this.head;
-    var cursor = 0;
-    while (curr && cursor != idx) {
-        curr = curr.next;
-        cursor++;
-    }
-    if (curr) {
-        this.remove(curr);
-        return curr.value;
-    }
-};
-/**
- * Get head value
- * @return {}
- */
-LinkedList.prototype.getHead = function () {
-    if (this.head) {
-        return this.head.value;
-    }
-};
-/**
- * Get tail value
- * @return {}
- */
-LinkedList.prototype.getTail = function () {
-    if (this.tail) {
-        return this.tail.value;
-    }
-};
-/**
- * Get value at idx
- * @param {number} idx
- * @return {}
- */
-LinkedList.prototype.getAt = function (idx) {
-    if (idx < 0) {
-        return;
-    }
-    var curr = this.head;
-    var cursor = 0;
-    while (curr && cursor != idx) {
-        curr = curr.next;
-        cursor++;
-    }
-    return curr.value;
-};
+    /**
+     * Set x, y and z components
+     * @param  {number}  x
+     * @param  {number}  y
+     * @param  {number}  z
+     * @return {clay.Vector3}
+     */
+    set: function (x, y, z) {
+        this.array[0] = x;
+        this.array[1] = y;
+        this.array[2] = z;
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * @param  {} value
- * @return {number}
- */
-LinkedList.prototype.indexOf = function (value) {
-    var curr = this.head;
-    var cursor = 0;
-    while (curr) {
-        if (curr.value === value) {
-            return cursor;
-        }
-        curr = curr.next;
-        cursor++;
-    }
-};
+    /**
+     * Set x, y and z components from array
+     * @param  {Float32Array|number[]} arr
+     * @return {clay.Vector3}
+     */
+    setArray: function (arr) {
+        this.array[0] = arr[0];
+        this.array[1] = arr[1];
+        this.array[2] = arr[2];
 
-/**
- * @return {number}
- */
-LinkedList.prototype.length = function () {
-    return this._length;
-};
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * If list is empty
- */
-LinkedList.prototype.isEmpty = function () {
-    return this._length === 0;
-};
+    /**
+     * Clone a new Vector3
+     * @return {clay.Vector3}
+     */
+    clone: function () {
+        return new Vector3(this.x, this.y, this.z);
+    },
 
-/**
- * @param  {Function} cb
- * @param  {} context
- */
-LinkedList.prototype.forEach = function (cb, context) {
-    var curr = this.head;
-    var idx = 0;
-    var haveContext = typeof(context) != 'undefined';
-    while (curr) {
-        if (haveContext) {
-            cb.call(context, curr.value, idx);
-        }
-        else {
-            cb(curr.value, idx);
-        }
-        curr = curr.next;
-        idx++;
-    }
-};
+    /**
+     * Copy from b
+     * @param  {clay.Vector3} b
+     * @return {clay.Vector3}
+     */
+    copy: function (b) {
+        glmatrix_vec3.copy(this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * Clear the list
- */
-LinkedList.prototype.clear = function () {
-    this.tail = this.head = null;
-    this._length = 0;
-};
+    /**
+     * Cross product of self and b, written to a Vector3 out
+     * @param  {clay.Vector3} a
+     * @param  {clay.Vector3} b
+     * @return {clay.Vector3}
+     */
+    cross: function (a, b) {
+        glmatrix_vec3.cross(this.array, a.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * @constructor
- * @param {} val
- */
-LinkedList.Entry = function (val) {
     /**
-     * @type {}
+     * Alias for distance
+     * @param  {clay.Vector3} b
+     * @return {number}
      */
-    this.value = val;
+    dist: function (b) {
+        return glmatrix_vec3.dist(this.array, b.array);
+    },
 
     /**
-     * @type {clay.core.LinkedList.Entry}
+     * Distance between self and b
+     * @param  {clay.Vector3} b
+     * @return {number}
      */
-    this.next = null;
+    distance: function (b) {
+        return glmatrix_vec3.distance(this.array, b.array);
+    },
 
     /**
-     * @type {clay.core.LinkedList.Entry}
+     * Alias for divide
+     * @param  {clay.Vector3} b
+     * @return {clay.Vector3}
      */
-    this.prev = null;
-};
+    div: function (b) {
+        glmatrix_vec3.div(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-/* harmony default export */ const core_LinkedList = (LinkedList);
+    /**
+     * Divide self by b
+     * @param  {clay.Vector3} b
+     * @return {clay.Vector3}
+     */
+    divide: function (b) {
+        glmatrix_vec3.divide(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-;// CONCATENATED MODULE: ./node_modules/claygl/src/core/LRU.js
+    /**
+     * Dot product of self and b
+     * @param  {clay.Vector3} b
+     * @return {number}
+     */
+    dot: function (b) {
+        return glmatrix_vec3.dot(this.array, b.array);
+    },
 
+    /**
+     * Alias of length
+     * @return {number}
+     */
+    len: function () {
+        return glmatrix_vec3.len(this.array);
+    },
 
-/**
- * LRU Cache
- * @constructor
- * @alias clay.core.LRU
- */
-var LRU = function (maxSize) {
+    /**
+     * Calculate the length
+     * @return {number}
+     */
+    length: function () {
+        return glmatrix_vec3.length(this.array);
+    },
+    /**
+     * Linear interpolation between a and b
+     * @param  {clay.Vector3} a
+     * @param  {clay.Vector3} b
+     * @param  {number}  t
+     * @return {clay.Vector3}
+     */
+    lerp: function (a, b, t) {
+        glmatrix_vec3.lerp(this.array, a.array, b.array, t);
+        this._dirty = true;
+        return this;
+    },
 
-    this._list = new core_LinkedList();
+    /**
+     * Minimum of self and b
+     * @param  {clay.Vector3} b
+     * @return {clay.Vector3}
+     */
+    min: function (b) {
+        glmatrix_vec3.min(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-    this._map = {};
+    /**
+     * Maximum of self and b
+     * @param  {clay.Vector3} b
+     * @return {clay.Vector3}
+     */
+    max: function (b) {
+        glmatrix_vec3.max(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-    this._maxSize = maxSize || 10;
-};
+    /**
+     * Alias for multiply
+     * @param  {clay.Vector3} b
+     * @return {clay.Vector3}
+     */
+    mul: function (b) {
+        glmatrix_vec3.mul(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * Set cache max size
- * @param {number} size
- */
-LRU.prototype.setMaxSize = function (size) {
-    this._maxSize = size;
-};
+    /**
+     * Mutiply self and b
+     * @param  {clay.Vector3} b
+     * @return {clay.Vector3}
+     */
+    multiply: function (b) {
+        glmatrix_vec3.multiply(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * @param  {string} key
- * @param  {} value
- */
-LRU.prototype.put = function (key, value) {
-    if (!this._map.hasOwnProperty(key)) {
-        var len = this._list.length();
-        if (len >= this._maxSize && len > 0) {
-            // Remove the least recently used
-            var leastUsedEntry = this._list.head;
-            this._list.remove(leastUsedEntry);
-            delete this._map[leastUsedEntry.key];
-        }
+    /**
+     * Negate self
+     * @return {clay.Vector3}
+     */
+    negate: function () {
+        glmatrix_vec3.negate(this.array, this.array);
+        this._dirty = true;
+        return this;
+    },
 
-        var entry = this._list.insert(value);
-        entry.key = key;
-        this._map[key] = entry;
-    }
-};
+    /**
+     * Normalize self
+     * @return {clay.Vector3}
+     */
+    normalize: function () {
+        glmatrix_vec3.normalize(this.array, this.array);
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * @param  {string} key
- * @return {}
- */
-LRU.prototype.get = function (key) {
-    var entry = this._map[key];
-    if (this._map.hasOwnProperty(key)) {
-        // Put the latest used entry in the tail
-        if (entry !== this._list.tail) {
-            this._list.remove(entry);
-            this._list.insertEntry(entry);
-        }
+    /**
+     * Generate random x, y, z components with a given scale
+     * @param  {number} scale
+     * @return {clay.Vector3}
+     */
+    random: function (scale) {
+        glmatrix_vec3.random(this.array, scale);
+        this._dirty = true;
+        return this;
+    },
 
-        return entry.value;
-    }
-};
+    /**
+     * Scale self
+     * @param  {number}  scale
+     * @return {clay.Vector3}
+     */
+    scale: function (s) {
+        glmatrix_vec3.scale(this.array, this.array, s);
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * @param {string} key
- */
-LRU.prototype.remove = function (key) {
-    var entry = this._map[key];
-    if (typeof(entry) !== 'undefined') {
-        delete this._map[key];
-        this._list.remove(entry);
-    }
-};
+    /**
+     * Scale b and add to self
+     * @param  {clay.Vector3} b
+     * @param  {number}  scale
+     * @return {clay.Vector3}
+     */
+    scaleAndAdd: function (b, s) {
+        glmatrix_vec3.scaleAndAdd(this.array, this.array, b.array, s);
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * Clear the cache
- */
-LRU.prototype.clear = function () {
-    this._list.clear();
-    this._map = {};
-};
+    /**
+     * Alias for squaredDistance
+     * @param  {clay.Vector3} b
+     * @return {number}
+     */
+    sqrDist: function (b) {
+        return glmatrix_vec3.sqrDist(this.array, b.array);
+    },
 
-/* harmony default export */ const core_LRU = (LRU);
+    /**
+     * Squared distance between self and b
+     * @param  {clay.Vector3} b
+     * @return {number}
+     */
+    squaredDistance: function (b) {
+        return glmatrix_vec3.squaredDistance(this.array, b.array);
+    },
 
-;// CONCATENATED MODULE: ./node_modules/claygl/src/core/color.js
-/**
- * @namespace clay.core.color
- */
+    /**
+     * Alias for squaredLength
+     * @return {number}
+     */
+    sqrLen: function () {
+        return glmatrix_vec3.sqrLen(this.array);
+    },
 
+    /**
+     * Squared length of self
+     * @return {number}
+     */
+    squaredLength: function () {
+        return glmatrix_vec3.squaredLength(this.array);
+    },
 
-var colorUtil = {};
+    /**
+     * Alias for subtract
+     * @param  {clay.Vector3} b
+     * @return {clay.Vector3}
+     */
+    sub: function (b) {
+        glmatrix_vec3.sub(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-var kCSSColorTable = {
-    'transparent': [0,0,0,0], 'aliceblue': [240,248,255,1],
-    'antiquewhite': [250,235,215,1], 'aqua': [0,255,255,1],
-    'aquamarine': [127,255,212,1], 'azure': [240,255,255,1],
-    'beige': [245,245,220,1], 'bisque': [255,228,196,1],
-    'black': [0,0,0,1], 'blanchedalmond': [255,235,205,1],
-    'blue': [0,0,255,1], 'blueviolet': [138,43,226,1],
-    'brown': [165,42,42,1], 'burlywood': [222,184,135,1],
-    'cadetblue': [95,158,160,1], 'chartreuse': [127,255,0,1],
-    'chocolate': [210,105,30,1], 'coral': [255,127,80,1],
-    'cornflowerblue': [100,149,237,1], 'cornsilk': [255,248,220,1],
-    'crimson': [220,20,60,1], 'cyan': [0,255,255,1],
-    'darkblue': [0,0,139,1], 'darkcyan': [0,139,139,1],
-    'darkgoldenrod': [184,134,11,1], 'darkgray': [169,169,169,1],
-    'darkgreen': [0,100,0,1], 'darkgrey': [169,169,169,1],
-    'darkkhaki': [189,183,107,1], 'darkmagenta': [139,0,139,1],
-    'darkolivegreen': [85,107,47,1], 'darkorange': [255,140,0,1],
-    'darkorchid': [153,50,204,1], 'darkred': [139,0,0,1],
-    'darksalmon': [233,150,122,1], 'darkseagreen': [143,188,143,1],
-    'darkslateblue': [72,61,139,1], 'darkslategray': [47,79,79,1],
-    'darkslategrey': [47,79,79,1], 'darkturquoise': [0,206,209,1],
-    'darkviolet': [148,0,211,1], 'deeppink': [255,20,147,1],
-    'deepskyblue': [0,191,255,1], 'dimgray': [105,105,105,1],
-    'dimgrey': [105,105,105,1], 'dodgerblue': [30,144,255,1],
-    'firebrick': [178,34,34,1], 'floralwhite': [255,250,240,1],
-    'forestgreen': [34,139,34,1], 'fuchsia': [255,0,255,1],
-    'gainsboro': [220,220,220,1], 'ghostwhite': [248,248,255,1],
-    'gold': [255,215,0,1], 'goldenrod': [218,165,32,1],
-    'gray': [128,128,128,1], 'green': [0,128,0,1],
-    'greenyellow': [173,255,47,1], 'grey': [128,128,128,1],
-    'honeydew': [240,255,240,1], 'hotpink': [255,105,180,1],
-    'indianred': [205,92,92,1], 'indigo': [75,0,130,1],
-    'ivory': [255,255,240,1], 'khaki': [240,230,140,1],
-    'lavender': [230,230,250,1], 'lavenderblush': [255,240,245,1],
-    'lawngreen': [124,252,0,1], 'lemonchiffon': [255,250,205,1],
-    'lightblue': [173,216,230,1], 'lightcoral': [240,128,128,1],
-    'lightcyan': [224,255,255,1], 'lightgoldenrodyellow': [250,250,210,1],
-    'lightgray': [211,211,211,1], 'lightgreen': [144,238,144,1],
-    'lightgrey': [211,211,211,1], 'lightpink': [255,182,193,1],
-    'lightsalmon': [255,160,122,1], 'lightseagreen': [32,178,170,1],
-    'lightskyblue': [135,206,250,1], 'lightslategray': [119,136,153,1],
-    'lightslategrey': [119,136,153,1], 'lightsteelblue': [176,196,222,1],
-    'lightyellow': [255,255,224,1], 'lime': [0,255,0,1],
-    'limegreen': [50,205,50,1], 'linen': [250,240,230,1],
-    'magenta': [255,0,255,1], 'maroon': [128,0,0,1],
-    'mediumaquamarine': [102,205,170,1], 'mediumblue': [0,0,205,1],
-    'mediumorchid': [186,85,211,1], 'mediumpurple': [147,112,219,1],
-    'mediumseagreen': [60,179,113,1], 'mediumslateblue': [123,104,238,1],
-    'mediumspringgreen': [0,250,154,1], 'mediumturquoise': [72,209,204,1],
-    'mediumvioletred': [199,21,133,1], 'midnightblue': [25,25,112,1],
-    'mintcream': [245,255,250,1], 'mistyrose': [255,228,225,1],
-    'moccasin': [255,228,181,1], 'navajowhite': [255,222,173,1],
-    'navy': [0,0,128,1], 'oldlace': [253,245,230,1],
-    'olive': [128,128,0,1], 'olivedrab': [107,142,35,1],
-    'orange': [255,165,0,1], 'orangered': [255,69,0,1],
-    'orchid': [218,112,214,1], 'palegoldenrod': [238,232,170,1],
-    'palegreen': [152,251,152,1], 'paleturquoise': [175,238,238,1],
-    'palevioletred': [219,112,147,1], 'papayawhip': [255,239,213,1],
-    'peachpuff': [255,218,185,1], 'peru': [205,133,63,1],
-    'pink': [255,192,203,1], 'plum': [221,160,221,1],
-    'powderblue': [176,224,230,1], 'purple': [128,0,128,1],
-    'red': [255,0,0,1], 'rosybrown': [188,143,143,1],
-    'royalblue': [65,105,225,1], 'saddlebrown': [139,69,19,1],
-    'salmon': [250,128,114,1], 'sandybrown': [244,164,96,1],
-    'seagreen': [46,139,87,1], 'seashell': [255,245,238,1],
-    'sienna': [160,82,45,1], 'silver': [192,192,192,1],
-    'skyblue': [135,206,235,1], 'slateblue': [106,90,205,1],
-    'slategray': [112,128,144,1], 'slategrey': [112,128,144,1],
-    'snow': [255,250,250,1], 'springgreen': [0,255,127,1],
-    'steelblue': [70,130,180,1], 'tan': [210,180,140,1],
-    'teal': [0,128,128,1], 'thistle': [216,191,216,1],
-    'tomato': [255,99,71,1], 'turquoise': [64,224,208,1],
-    'violet': [238,130,238,1], 'wheat': [245,222,179,1],
-    'white': [255,255,255,1], 'whitesmoke': [245,245,245,1],
-    'yellow': [255,255,0,1], 'yellowgreen': [154,205,50,1]
-};
+    /**
+     * Subtract b from self
+     * @param  {clay.Vector3} b
+     * @return {clay.Vector3}
+     */
+    subtract: function (b) {
+        glmatrix_vec3.subtract(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-function clampCssByte(i) {  // Clamp to integer 0 .. 255.
-    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).
-    return i < 0 ? 0 : i > 255 ? 255 : i;
-}
+    /**
+     * Transform self with a Matrix3 m
+     * @param  {clay.Matrix3} m
+     * @return {clay.Vector3}
+     */
+    transformMat3: function (m) {
+        glmatrix_vec3.transformMat3(this.array, this.array, m.array);
+        this._dirty = true;
+        return this;
+    },
 
-function clampCssAngle(i) {  // Clamp to integer 0 .. 360.
-    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).
-    return i < 0 ? 0 : i > 360 ? 360 : i;
-}
+    /**
+     * Transform self with a Matrix4 m
+     * @param  {clay.Matrix4} m
+     * @return {clay.Vector3}
+     */
+    transformMat4: function (m) {
+        glmatrix_vec3.transformMat4(this.array, this.array, m.array);
+        this._dirty = true;
+        return this;
+    },
+    /**
+     * Transform self with a Quaternion q
+     * @param  {clay.Quaternion} q
+     * @return {clay.Vector3}
+     */
+    transformQuat: function (q) {
+        glmatrix_vec3.transformQuat(this.array, this.array, q.array);
+        this._dirty = true;
+        return this;
+    },
 
-function clampCssFloat(f) {  // Clamp to float 0.0 .. 1.0.
-    return f < 0 ? 0 : f > 1 ? 1 : f;
-}
+    /**
+     * Trasnform self into projection space with m
+     * @param  {clay.Matrix4} m
+     * @return {clay.Vector3}
+     */
+    applyProjection: function (m) {
+        var v = this.array;
+        m = m.array;
 
-function parseCssInt(str) {  // int or percentage.
-    if (str.length && str.charAt(str.length - 1) === '%') {
-        return clampCssByte(parseFloat(str) / 100 * 255);
-    }
-    return clampCssByte(parseInt(str, 10));
-}
+        // Perspective projection
+        if (m[15] === 0) {
+            var w = -1 / v[2];
+            v[0] = m[0] * v[0] * w;
+            v[1] = m[5] * v[1] * w;
+            v[2] = (m[10] * v[2] + m[14]) * w;
+        }
+        else {
+            v[0] = m[0] * v[0] + m[12];
+            v[1] = m[5] * v[1] + m[13];
+            v[2] = m[10] * v[2] + m[14];
+        }
+        this._dirty = true;
 
-function parseCssFloat(str) {  // float or percentage.
-    if (str.length && str.charAt(str.length - 1) === '%') {
-        return clampCssFloat(parseFloat(str) / 100);
-    }
-    return clampCssFloat(parseFloat(str));
-}
+        return this;
+    },
 
-function cssHueToRgb(m1, m2, h) {
-    if (h < 0) {
-        h += 1;
-    }
-    else if (h > 1) {
-        h -= 1;
-    }
+    eulerFromQuat: function(q, order) {
+        Vector3.eulerFromQuat(this, q, order);
+    },
 
-    if (h * 6 < 1) {
-        return m1 + (m2 - m1) * h * 6;
-    }
-    if (h * 2 < 1) {
-        return m2;
-    }
-    if (h * 3 < 2) {
-        return m1 + (m2 - m1) * (2/3 - h) * 6;
+    eulerFromMat3: function (m, order) {
+        Vector3.eulerFromMat3(this, m, order);
+    },
+
+    toString: function() {
+        return '[' + Array.prototype.join.call(this.array, ',') + ']';
+    },
+
+    toArray: function () {
+        return Array.prototype.slice.call(this.array);
     }
-    return m1;
-}
+};
 
-function lerpNumber(a, b, p) {
-    return a + (b - a) * p;
-}
+var defineProperty = Object.defineProperty;
+// Getter and Setter
+if (defineProperty) {
 
-function setRgba(out, r, g, b, a) {
-    out[0] = r; out[1] = g; out[2] = b; out[3] = a;
-    return out;
-}
-function copyRgba(out, a) {
-    out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];
-    return out;
-}
+    var proto = Vector3.prototype;
+    /**
+     * @name x
+     * @type {number}
+     * @memberOf clay.Vector3
+     * @instance
+     */
+    defineProperty(proto, 'x', {
+        get: function () {
+            return this.array[0];
+        },
+        set: function (value) {
+            this.array[0] = value;
+            this._dirty = true;
+        }
+    });
 
-var colorCache = new core_LRU(20);
-var lastRemovedArr = null;
+    /**
+     * @name y
+     * @type {number}
+     * @memberOf clay.Vector3
+     * @instance
+     */
+    defineProperty(proto, 'y', {
+        get: function () {
+            return this.array[1];
+        },
+        set: function (value) {
+            this.array[1] = value;
+            this._dirty = true;
+        }
+    });
 
-function putToCache(colorStr, rgbaArr) {
-    // Reuse removed array
-    if (lastRemovedArr) {
-        copyRgba(lastRemovedArr, rgbaArr);
-    }
-    lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice()));
+    /**
+     * @name z
+     * @type {number}
+     * @memberOf clay.Vector3
+     * @instance
+     */
+    defineProperty(proto, 'z', {
+        get: function () {
+            return this.array[2];
+        },
+        set: function (value) {
+            this.array[2] = value;
+            this._dirty = true;
+        }
+    });
 }
 
+
+// Supply methods that are not in place
+
 /**
- * @name clay.core.color.parse
- * @param {string} colorStr
- * @param {Array.<number>} out
- * @return {Array.<number>}
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {clay.Vector3}
  */
-colorUtil.parse = function (colorStr, rgbaArr) {
-    if (!colorStr) {
-        return;
-    }
-    rgbaArr = rgbaArr || [];
+Vector3.add = function(out, a, b) {
+    glmatrix_vec3.add(out.array, a.array, b.array);
+    out._dirty = true;
+    return out;
+};
 
-    var cached = colorCache.get(colorStr);
-    if (cached) {
-        return copyRgba(rgbaArr, cached);
-    }
+/**
+ * @param  {clay.Vector3} out
+ * @param  {number}  x
+ * @param  {number}  y
+ * @param  {number}  z
+ * @return {clay.Vector3}
+ */
+Vector3.set = function(out, x, y, z) {
+    glmatrix_vec3.set(out.array, x, y, z);
+    out._dirty = true;
+};
 
-    // colorStr may be not string
-    colorStr = colorStr + '';
-    // Remove all whitespace, not compliant, but should just be more accepting.
-    var str = colorStr.replace(/ /g, '').toLowerCase();
+/**
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} b
+ * @return {clay.Vector3}
+ */
+Vector3.copy = function(out, b) {
+    glmatrix_vec3.copy(out.array, b.array);
+    out._dirty = true;
+    return out;
+};
 
-    // Color keywords (and transparent) lookup.
-    if (str in kCSSColorTable) {
-        copyRgba(rgbaArr, kCSSColorTable[str]);
-        putToCache(colorStr, rgbaArr);
-        return rgbaArr;
-    }
+/**
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {clay.Vector3}
+ */
+Vector3.cross = function(out, a, b) {
+    glmatrix_vec3.cross(out.array, a.array, b.array);
+    out._dirty = true;
+    return out;
+};
 
-    // #abc and #abc123 syntax.
-    if (str.charAt(0) === '#') {
-        if (str.length === 4) {
-            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.
-            if (!(iv >= 0 && iv <= 0xfff)) {
-                setRgba(rgbaArr, 0, 0, 0, 1);
-                return;  // Covers NaN.
-            }
-            setRgba(rgbaArr,
-                ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),
-                (iv & 0xf0) | ((iv & 0xf0) >> 4),
-                (iv & 0xf) | ((iv & 0xf) << 4),
-                1
-            );
-            putToCache(colorStr, rgbaArr);
-            return rgbaArr;
-        }
-        else if (str.length === 7) {
-            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.
-            if (!(iv >= 0 && iv <= 0xffffff)) {
-                setRgba(rgbaArr, 0, 0, 0, 1);
-                return;  // Covers NaN.
-            }
-            setRgba(rgbaArr,
-                (iv & 0xff0000) >> 16,
-                (iv & 0xff00) >> 8,
-                iv & 0xff,
-                1
-            );
-            putToCache(colorStr, rgbaArr);
-            return rgbaArr;
-        }
-
-        return;
-    }
-    var op = str.indexOf('('), ep = str.indexOf(')');
-    if (op !== -1 && ep + 1 === str.length) {
-        var fname = str.substr(0, op);
-        var params = str.substr(op + 1, ep - (op + 1)).split(',');
-        var alpha = 1;  // To allow case fallthrough.
-        switch (fname) {
-            case 'rgba':
-                if (params.length !== 4) {
-                    setRgba(rgbaArr, 0, 0, 0, 1);
-                    return;
-                }
-                alpha = parseCssFloat(params.pop()); // jshint ignore:line
-            // Fall through.
-            case 'rgb':
-                if (params.length !== 3) {
-                    setRgba(rgbaArr, 0, 0, 0, 1);
-                    return;
-                }
-                setRgba(rgbaArr,
-                    parseCssInt(params[0]),
-                    parseCssInt(params[1]),
-                    parseCssInt(params[2]),
-                    alpha
-                );
-                putToCache(colorStr, rgbaArr);
-                return rgbaArr;
-            case 'hsla':
-                if (params.length !== 4) {
-                    setRgba(rgbaArr, 0, 0, 0, 1);
-                    return;
-                }
-                params[3] = parseCssFloat(params[3]);
-                hsla2rgba(params, rgbaArr);
-                putToCache(colorStr, rgbaArr);
-                return rgbaArr;
-            case 'hsl':
-                if (params.length !== 3) {
-                    setRgba(rgbaArr, 0, 0, 0, 1);
-                    return;
-                }
-                hsla2rgba(params, rgbaArr);
-                putToCache(colorStr, rgbaArr);
-                return rgbaArr;
-            default:
-                return;
-        }
-    }
-
-    setRgba(rgbaArr, 0, 0, 0, 1);
-    return;
+/**
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {number}
+ */
+Vector3.dist = function(a, b) {
+    return glmatrix_vec3.distance(a.array, b.array);
 };
 
-colorUtil.parseToFloat = function (colorStr, rgbaArr) {
-    rgbaArr = colorUtil.parse(colorStr, rgbaArr);
-    if (!rgbaArr) {
-        return;
-    }
-    rgbaArr[0] /= 255;
-    rgbaArr[1] /= 255;
-    rgbaArr[2] /= 255;
-    return rgbaArr;
-}
-
 /**
- * @name clay.core.color.hsla2rgba
- * @param {Array.<number>} hsla
- * @param {Array.<number>} rgba
- * @return {Array.<number>} rgba
+ * @function
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {number}
  */
-function hsla2rgba(hsla, rgba) {
-    var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360;  // 0 .. 1
-    // NOTE(deanm): According to the CSS spec s/l should only be
-    // percentages, but we don't bother and let float or percentage.
-    var s = parseCssFloat(hsla[1]);
-    var l = parseCssFloat(hsla[2]);
-    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
-    var m1 = l * 2 - m2;
-
-    rgba = rgba || [];
-    setRgba(rgba,
-        clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255),
-        clampCssByte(cssHueToRgb(m1, m2, h) * 255),
-        clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255),
-        1
-    );
-
-    if (hsla.length === 4) {
-        rgba[3] = hsla[3];
-    }
-
-    return rgba;
-}
+Vector3.distance = Vector3.dist;
 
 /**
- * @name clay.core.color.rgba2hsla
- * @param {Array.<number>} rgba
- * @return {Array.<number>} hsla
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {clay.Vector3}
  */
-function rgba2hsla(rgba) {
-    if (!rgba) {
-        return;
-    }
-
-    // RGB from 0 to 255
-    var R = rgba[0] / 255;
-    var G = rgba[1] / 255;
-    var B = rgba[2] / 255;
-
-    var vMin = Math.min(R, G, B); // Min. value of RGB
-    var vMax = Math.max(R, G, B); // Max. value of RGB
-    var delta = vMax - vMin; // Delta RGB value
-
-    var L = (vMax + vMin) / 2;
-    var H;
-    var S;
-    // HSL results from 0 to 1
-    if (delta === 0) {
-        H = 0;
-        S = 0;
-    }
-    else {
-        if (L < 0.5) {
-            S = delta / (vMax + vMin);
-        }
-        else {
-            S = delta / (2 - vMax - vMin);
-        }
-
-        var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta;
-        var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta;
-        var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta;
-
-        if (R === vMax) {
-            H = deltaB - deltaG;
-        }
-        else if (G === vMax) {
-            H = (1 / 3) + deltaR - deltaB;
-        }
-        else if (B === vMax) {
-            H = (2 / 3) + deltaG - deltaR;
-        }
-
-        if (H < 0) {
-            H += 1;
-        }
-
-        if (H > 1) {
-            H -= 1;
-        }
-    }
-
-    var hsla = [H * 360, S, L];
-
-    if (rgba[3] != null) {
-        hsla.push(rgba[3]);
-    }
-
-    return hsla;
-}
+Vector3.div = function(out, a, b) {
+    glmatrix_vec3.divide(out.array, a.array, b.array);
+    out._dirty = true;
+    return out;
+};
 
 /**
- * @name clay.core.color.lift
- * @param {string} color
- * @param {number} level
- * @return {string}
+ * @function
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {clay.Vector3}
  */
-colorUtil.lift = function (color, level) {
-    var colorArr = colorUtil.parse(color);
-    if (colorArr) {
-        for (var i = 0; i < 3; i++) {
-            if (level < 0) {
-                colorArr[i] = colorArr[i] * (1 - level) | 0;
-            }
-            else {
-                colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;
-            }
-        }
-        return colorUtil.stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');
-    }
-}
+Vector3.divide = Vector3.div;
 
 /**
- * @name clay.core.color.toHex
- * @param {string} color
- * @return {string}
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {number}
  */
-colorUtil.toHex = function (color) {
-    var colorArr = colorUtil.parse(color);
-    if (colorArr) {
-        return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1);
-    }
+Vector3.dot = function(a, b) {
+    return glmatrix_vec3.dot(a.array, b.array);
 };
 
 /**
- * Map value to color. Faster than lerp methods because color is represented by rgba array.
- * @name clay.core.color
- * @param {number} normalizedValue A float between 0 and 1.
- * @param {Array.<Array.<number>>} colors List of rgba color array
- * @param {Array.<number>} [out] Mapped gba color array
- * @return {Array.<number>} will be null/undefined if input illegal.
+ * @param  {clay.Vector3} a
+ * @return {number}
  */
-colorUtil.fastLerp = function (normalizedValue, colors, out) {
-    if (!(colors && colors.length)
-        || !(normalizedValue >= 0 && normalizedValue <= 1)
-    ) {
-        return;
-    }
-
-    out = out || [];
+Vector3.len = function(b) {
+    return glmatrix_vec3.length(b.array);
+};
 
-    var value = normalizedValue * (colors.length - 1);
-    var leftIndex = Math.floor(value);
-    var rightIndex = Math.ceil(value);
-    var leftColor = colors[leftIndex];
-    var rightColor = colors[rightIndex];
-    var dv = value - leftIndex;
-    out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv));
-    out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv));
-    out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv));
-    out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv));
+// Vector3.length = Vector3.len;
 
+/**
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @param  {number}  t
+ * @return {clay.Vector3}
+ */
+Vector3.lerp = function(out, a, b, t) {
+    glmatrix_vec3.lerp(out.array, a.array, b.array, t);
+    out._dirty = true;
     return out;
-}
-
-colorUtil.fastMapToColor = colorUtil.fastLerp;
-
+};
 /**
- * @param {number} normalizedValue A float between 0 and 1.
- * @param {Array.<string>} colors Color list.
- * @param {boolean=} fullOutput Default false.
- * @return {(string|Object)} Result color. If fullOutput,
- *                           return {color: ..., leftIndex: ..., rightIndex: ..., value: ...},
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {clay.Vector3}
  */
-colorUtil.lerp = function (normalizedValue, colors, fullOutput) {
-    if (!(colors && colors.length)
-        || !(normalizedValue >= 0 && normalizedValue <= 1)
-    ) {
-        return;
-    }
-
-    var value = normalizedValue * (colors.length - 1);
-    var leftIndex = Math.floor(value);
-    var rightIndex = Math.ceil(value);
-    var leftColor = colorUtil.parse(colors[leftIndex]);
-    var rightColor = colorUtil.parse(colors[rightIndex]);
-    var dv = value - leftIndex;
-
-    var color = colorUtil.stringify(
-        [
-            clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)),
-            clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)),
-            clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)),
-            clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv))
-        ],
-        'rgba'
-    );
-
-    return fullOutput
-        ? {
-            color: color,
-            leftIndex: leftIndex,
-            rightIndex: rightIndex,
-            value: value
-        }
-        : color;
-}
+Vector3.min = function(out, a, b) {
+    glmatrix_vec3.min(out.array, a.array, b.array);
+    out._dirty = true;
+    return out;
+};
 
 /**
- * @deprecated
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {clay.Vector3}
  */
-colorUtil.mapToColor = colorUtil.lerp;
-
+Vector3.max = function(out, a, b) {
+    glmatrix_vec3.max(out.array, a.array, b.array);
+    out._dirty = true;
+    return out;
+};
 /**
- * @name clay.core.color
- * @param {string} color
- * @param {number=} h 0 ~ 360, ignore when null.
- * @param {number=} s 0 ~ 1, ignore when null.
- * @param {number=} l 0 ~ 1, ignore when null.
- * @return {string} Color string in rgba format.
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {clay.Vector3}
  */
-colorUtil.modifyHSL = function (color, h, s, l) {
-    color = colorUtil.parse(color);
-
-    if (color) {
-        color = rgba2hsla(color);
-        h != null && (color[0] = clampCssAngle(h));
-        s != null && (color[1] = parseCssFloat(s));
-        l != null && (color[2] = parseCssFloat(l));
-
-        return colorUtil.stringify(hsla2rgba(color), 'rgba');
-    }
-}
-
+Vector3.mul = function(out, a, b) {
+    glmatrix_vec3.multiply(out.array, a.array, b.array);
+    out._dirty = true;
+    return out;
+};
 /**
- * @param {string} color
- * @param {number=} alpha 0 ~ 1
- * @return {string} Color string in rgba format.
+ * @function
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {clay.Vector3}
  */
-colorUtil.modifyAlpha = function (color, alpha) {
-    color = colorUtil.parse(color);
-
-    if (color && alpha != null) {
-        color[3] = clampCssFloat(alpha);
-        return colorUtil.stringify(color, 'rgba');
-    }
-}
+Vector3.multiply = Vector3.mul;
+/**
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @return {clay.Vector3}
+ */
+Vector3.negate = function(out, a) {
+    glmatrix_vec3.negate(out.array, a.array);
+    out._dirty = true;
+    return out;
+};
+/**
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @return {clay.Vector3}
+ */
+Vector3.normalize = function(out, a) {
+    glmatrix_vec3.normalize(out.array, a.array);
+    out._dirty = true;
+    return out;
+};
+/**
+ * @param  {clay.Vector3} out
+ * @param  {number}  scale
+ * @return {clay.Vector3}
+ */
+Vector3.random = function(out, scale) {
+    glmatrix_vec3.random(out.array, scale);
+    out._dirty = true;
+    return out;
+};
+/**
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {number}  scale
+ * @return {clay.Vector3}
+ */
+Vector3.scale = function(out, a, scale) {
+    glmatrix_vec3.scale(out.array, a.array, scale);
+    out._dirty = true;
+    return out;
+};
+/**
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @param  {number}  scale
+ * @return {clay.Vector3}
+ */
+Vector3.scaleAndAdd = function(out, a, b, scale) {
+    glmatrix_vec3.scaleAndAdd(out.array, a.array, b.array, scale);
+    out._dirty = true;
+    return out;
+};
+/**
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {number}
+ */
+Vector3.sqrDist = function(a, b) {
+    return glmatrix_vec3.sqrDist(a.array, b.array);
+};
+/**
+ * @function
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {number}
+ */
+Vector3.squaredDistance = Vector3.sqrDist;
+/**
+ * @param  {clay.Vector3} a
+ * @return {number}
+ */
+Vector3.sqrLen = function(a) {
+    return glmatrix_vec3.sqrLen(a.array);
+};
+/**
+ * @function
+ * @param  {clay.Vector3} a
+ * @return {number}
+ */
+Vector3.squaredLength = Vector3.sqrLen;
 
 /**
- * @param {Array.<number>} arrColor like [12,33,44,0.4]
- * @param {string} type 'rgba', 'hsva', ...
- * @return {string} Result color. (If input illegal, return undefined).
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {clay.Vector3}
  */
-colorUtil.stringify = function (arrColor, type) {
-    if (!arrColor || !arrColor.length) {
-        return;
-    }
-    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];
-    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {
-        colorStr += ',' + arrColor[3];
-    }
-    return type + '(' + colorStr + ')';
+Vector3.sub = function(out, a, b) {
+    glmatrix_vec3.subtract(out.array, a.array, b.array);
+    out._dirty = true;
+    return out;
 };
+/**
+ * @function
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Vector3} b
+ * @return {clay.Vector3}
+ */
+Vector3.subtract = Vector3.sub;
 
+/**
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {Matrix3} m
+ * @return {clay.Vector3}
+ */
+Vector3.transformMat3 = function(out, a, m) {
+    glmatrix_vec3.transformMat3(out.array, a.array, m.array);
+    out._dirty = true;
+    return out;
+};
 
+/**
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Matrix4} m
+ * @return {clay.Vector3}
+ */
+Vector3.transformMat4 = function(out, a, m) {
+    glmatrix_vec3.transformMat4(out.array, a.array, m.array);
+    out._dirty = true;
+    return out;
+};
+/**
+ * @param  {clay.Vector3} out
+ * @param  {clay.Vector3} a
+ * @param  {clay.Quaternion} q
+ * @return {clay.Vector3}
+ */
+Vector3.transformQuat = function(out, a, q) {
+    glmatrix_vec3.transformQuat(out.array, a.array, q.array);
+    out._dirty = true;
+    return out;
+};
 
-/* harmony default export */ const color = (colorUtil);
-;// CONCATENATED MODULE: ./node_modules/claygl/src/Material.js
-
-
-
-var parseColor = color.parseToFloat;
-
-var programKeyCache = {};
-
-function getDefineCode(defines) {
-    var defineKeys = Object.keys(defines);
-    defineKeys.sort();
-    var defineStr = [];
-    // Custom Defines
-    for (var i = 0; i < defineKeys.length; i++) {
-        var key = defineKeys[i];
-        var value = defines[key];
-        if (value === null) {
-            defineStr.push(key);
-        }
-        else{
-            defineStr.push(key + ' ' + value.toString());
-        }
-    }
-    return defineStr.join('\n');
-}
-
-function getProgramKey(vertexDefines, fragmentDefines, enabledTextures) {
-    enabledTextures.sort();
-    var defineStr = [];
-    for (var i = 0; i < enabledTextures.length; i++) {
-        var symbol = enabledTextures[i];
-        defineStr.push(symbol);
-    }
-    var key = getDefineCode(vertexDefines) + '\n'
-        + getDefineCode(fragmentDefines) + '\n'
-        + defineStr.join('\n');
-
-    if (programKeyCache[key]) {
-        return programKeyCache[key];
-    }
-
-    var id = core_util.genGUID();
-    programKeyCache[key] = id;
-    return id;
+function clamp(val, min, max) {
+    return val < min ? min : (val > max ? max : val);
 }
-
+var atan2 = Math.atan2;
+var asin = Math.asin;
+var abs = Math.abs;
 /**
- * Material defines the appearance of mesh surface, like `color`, `roughness`, `metalness`, etc.
- * It contains a {@link clay.Shader} and corresponding uniforms.
- *
- * Here is a basic example to create a standard material
-```js
-var material = new clay.Material({
-    shader: new clay.Shader(
-        clay.Shader.source('clay.vertex'),
-        clay.Shader.source('clay.fragment')
-    )
-});
-```
- * @constructor clay.Material
- * @extends clay.core.Base
+ * Convert quaternion to euler angle
+ * Quaternion must be normalized
+ * From three.js
  */
-var Material = core_Base.extend(function () {
-    return /** @lends clay.Material# */ {
-        /**
-         * @type {string}
-         */
-        name: '',
-
-        /**
-         * @type {Object}
-         */
-        // uniforms: null,
-
-        /**
-         * @type {clay.Shader}
-         */
-        // shader: null,
-
-        /**
-         * @type {boolean}
-         */
-        depthTest: true,
+Vector3.eulerFromQuat = function (out, q, order) {
+    out._dirty = true;
+    q = q.array;
 
-        /**
-         * @type {boolean}
-         */
-        depthMask: true,
+    var target = out.array;
+    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 w2 = w * w;
 
-        /**
-         * @type {boolean}
-         */
-        transparent: false,
-        /**
-         * Blend func is a callback function when the material
-         * have custom blending
-         * The gl context will be the only argument passed in tho the
-         * blend function
-         * Detail of blend function in WebGL:
-         * http://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf
-         *
-         * Example :
-         * function(_gl) {
-         *  _gl.blendEquation(_gl.FUNC_ADD);
-         *  _gl.blendFunc(_gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA);
-         * }
-         */
-        blend: null,
+    var order = (order || 'XYZ').toUpperCase();
 
-        /**
-         * If update texture status automatically.
-         */
-        autoUpdateTextureStatus: true,
+    switch (order) {
+        case 'XYZ':
+            target[0] = atan2(2 * (x * w - y * z), (w2 - x2 - y2 + z2));
+            target[1] = asin(clamp(2 * (x * z + y * w), - 1, 1));
+            target[2] = atan2(2 * (z * w - x * y), (w2 + x2 - y2 - z2));
+            break;
+        case 'YXZ':
+            target[0] = asin(clamp(2 * (x * w - y * z), - 1, 1));
+            target[1] = atan2(2 * (x * z + y * w), (w2 - x2 - y2 + z2));
+            target[2] = atan2(2 * (x * y + z * w), (w2 - x2 + y2 - z2));
+            break;
+        case 'ZXY':
+            target[0] = asin(clamp(2 * (x * w + y * z), - 1, 1));
+            target[1] = atan2(2 * (y * w - z * x), (w2 - x2 - y2 + z2));
+            target[2] = atan2(2 * (z * w - x * y), (w2 - x2 + y2 - z2));
+            break;
+        case 'ZYX':
+            target[0] = atan2(2 * (x * w + z * y), (w2 - x2 - y2 + z2));
+            target[1] = asin(clamp(2 * (y * w - x * z), - 1, 1));
+            target[2] = atan2(2 * (x * y + z * w), (w2 + x2 - y2 - z2));
+            break;
+        case 'YZX':
+            target[0] = atan2(2 * (x * w - z * y), (w2 - x2 + y2 - z2));
+            target[1] = atan2(2 * (y * w - x * z), (w2 + x2 - y2 - z2));
+            target[2] = asin(clamp(2 * (x * y + z * w), - 1, 1));
+            break;
+        case 'XZY':
+            target[0] = atan2(2 * (x * w + y * z), (w2 - x2 + y2 - z2));
+            target[1] = atan2(2 * (x * z + y * w), (w2 + x2 - y2 - z2));
+            target[2] = asin(clamp(2 * (z * w - x * y), - 1, 1));
+            break;
+        default:
+            console.warn('Unkown order: ' + order);
+    }
+    return out;
+};
 
-        uniforms: {},
-        vertexDefines: {},
-        fragmentDefines: {},
-        _textureStatus: {},
+/**
+ * Convert rotation matrix to euler angle
+ * from three.js
+ */
+Vector3.eulerFromMat3 = function (out, m, order) {
+    // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
+    var te = m.array;
+    var m11 = te[0], m12 = te[3], m13 = te[6];
+    var m21 = te[1], m22 = te[4], m23 = te[7];
+    var m31 = te[2], m32 = te[5], m33 = te[8];
+    var target = out.array;
 
-        // shadowTransparentMap : null
+    var order = (order || 'XYZ').toUpperCase();
 
-        // PENDING enable the uniform that only used in shader.
-        _enabledUniforms: null,
-    };
-}, function () {
-    if (!this.name) {
-        this.name = 'MATERIAL_' + this.__uid__;
+    switch (order) {
+        case 'XYZ':
+            target[1] = asin(clamp(m13, -1, 1));
+            if (abs(m13) < 0.99999) {
+                target[0] = atan2(-m23, m33);
+                target[2] = atan2(-m12, m11);
+            }
+            else {
+                target[0] = atan2(m32, m22);
+                target[2] = 0;
+            }
+            break;
+        case 'YXZ':
+            target[0] = asin(-clamp(m23, -1, 1));
+            if (abs(m23) < 0.99999) {
+                target[1] = atan2(m13, m33);
+                target[2] = atan2(m21, m22);
+            }
+            else {
+                target[1] = atan2(-m31, m11);
+                target[2] = 0;
+            }
+            break;
+        case 'ZXY':
+            target[0] = asin(clamp(m32, -1, 1));
+            if (abs(m32) < 0.99999) {
+                target[1] = atan2(-m31, m33);
+                target[2] = atan2(-m12, m22);
+            }
+            else {
+                target[1] = 0;
+                target[2] = atan2(m21, m11);
+            }
+            break;
+        case 'ZYX':
+            target[1] = asin(-clamp(m31, -1, 1));
+            if (abs(m31) < 0.99999) {
+                target[0] = atan2(m32, m33);
+                target[2] = atan2(m21, m11);
+            }
+            else {
+                target[0] = 0;
+                target[2] = atan2(-m12, m22);
+            }
+            break;
+        case 'YZX':
+            target[2] = asin(clamp(m21, -1, 1));
+            if (abs(m21) < 0.99999) {
+                target[0] = atan2(-m23, m22);
+                target[1] = atan2(-m31, m11);
+            }
+            else {
+                target[0] = 0;
+                target[1] = atan2(m13, m33);
+            }
+            break;
+        case 'XZY':
+            target[2] = asin(-clamp(m12, -1, 1));
+            if (abs(m12) < 0.99999) {
+                target[0] = atan2(m32, m22);
+                target[1] = atan2(m13, m11);
+            }
+            else {
+                target[0] = atan2(-m23, m33);
+                target[1] = 0;
+            }
+            break;
+        default:
+            console.warn('Unkown order: ' + order);
     }
+    out._dirty = true;
 
-    if (this.shader) {
-        // Keep status, mainly preset uniforms, vertexDefines and fragmentDefines
-        this.attachShader(this.shader, true);
-    }
-},
-/** @lends clay.Material.prototype */
-{
-    precision: 'highp',
+    return out;
+};
 
+Object.defineProperties(Vector3, {
     /**
-     * Set material uniform
-     * @example
-     *  mat.setUniform('color', [1, 1, 1, 1]);
-     * @param {string} symbol
-     * @param {number|array|clay.Texture|ArrayBufferView} value
+     * @type {clay.Vector3}
+     * @readOnly
+     * @memberOf clay.Vector3
      */
-    setUniform: function (symbol, value) {
-        if (value === undefined) {
-            console.warn('Uniform value "' + symbol + '" is undefined');
-        }
-        var uniform = this.uniforms[symbol];
-        if (uniform) {
-
-            if (typeof value === 'string') {
-                // Try to parse as a color. Invalid color string will return null.
-                value = parseColor(value) || value;
-            }
-
-            uniform.value = value;
-
-            if (this.autoUpdateTextureStatus && uniform.type === 't') {
-                if (value) {
-                    this.enableTexture(symbol);
-                }
-                else {
-                    this.disableTexture(symbol);
-                }
-            }
+    POSITIVE_X: {
+        get: function () {
+            return new Vector3(1, 0, 0);
         }
     },
-
     /**
-     * @param {Object} obj
+     * @type {clay.Vector3}
+     * @readOnly
+     * @memberOf clay.Vector3
      */
-    setUniforms: function(obj) {
-        for (var key in obj) {
-            var val = obj[key];
-            this.setUniform(key, val);
+    NEGATIVE_X: {
+        get: function () {
+            return new Vector3(-1, 0, 0);
         }
     },
-
     /**
-     * @param  {string}  symbol
-     * @return {boolean}
+     * @type {clay.Vector3}
+     * @readOnly
+     * @memberOf clay.Vector3
      */
-    isUniformEnabled: function (symbol) {
-        return this._enabledUniforms.indexOf(symbol) >= 0;
-    },
-
-    getEnabledUniforms: function () {
-        return this._enabledUniforms;
+    POSITIVE_Y: {
+        get: function () {
+            return new Vector3(0, 1, 0);
+        }
     },
-    getTextureUniforms: function () {
-        return this._textureUniforms;
+    /**
+     * @type {clay.Vector3}
+     * @readOnly
+     * @memberOf clay.Vector3
+     */
+    NEGATIVE_Y: {
+        get: function () {
+            return new Vector3(0, -1, 0);
+        }
     },
-
     /**
-     * Alias of setUniform and setUniforms
-     * @param {object|string} symbol
-     * @param {number|array|clay.Texture|ArrayBufferView} [value]
+     * @type {clay.Vector3}
+     * @readOnly
+     * @memberOf clay.Vector3
      */
-    set: function (symbol, value) {
-        if (typeof(symbol) === 'object') {
-            for (var key in symbol) {
-                var val = symbol[key];
-                this.setUniform(key, val);
-            }
+    POSITIVE_Z: {
+        get: function () {
+            return new Vector3(0, 0, 1);
         }
-        else {
-            this.setUniform(symbol, value);
+    },
+    /**
+     * @type {clay.Vector3}
+     * @readOnly
+     */
+    NEGATIVE_Z: {
+        get: function () {
+            return new Vector3(0, 0, -1);
         }
     },
     /**
-     * Get uniform value
-     * @param  {string} symbol
-     * @return {number|array|clay.Texture|ArrayBufferView}
+     * @type {clay.Vector3}
+     * @readOnly
+     * @memberOf clay.Vector3
      */
-    get: function (symbol) {
-        var uniform = this.uniforms[symbol];
-        if (uniform) {
-            return uniform.value;
+    UP: {
+        get: function () {
+            return new Vector3(0, 1, 0);
         }
     },
     /**
-     * Attach a shader instance
-     * @param  {clay.Shader} shader
-     * @param  {boolean} keepStatus If try to keep uniform and texture
+     * @type {clay.Vector3}
+     * @readOnly
+     * @memberOf clay.Vector3
      */
-    attachShader: function(shader, keepStatus) {
-        var originalUniforms = this.uniforms;
+    ZERO: {
+        get: function () {
+            return new Vector3();
+        }
+    }
+});
 
-        // Ignore if uniform can use in shader.
-        this.uniforms = shader.createUniforms();
-        this.shader = shader;
+/* harmony default export */ const math_Vector3 = (Vector3);
 
-        var uniforms = this.uniforms;
-        this._enabledUniforms = Object.keys(uniforms);
-        // Make sure uniforms are set in same order to avoid texture slot wrong
-        this._enabledUniforms.sort();
-        this._textureUniforms = this._enabledUniforms.filter(function (uniformName) {
-            var type = this.uniforms[uniformName].type;
-            return type === 't' || type === 'tv';
-        }, this);
+;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/vec4.js
 
-        var originalVertexDefines = this.vertexDefines;
-        var originalFragmentDefines = this.fragmentDefines;
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
 
-        this.vertexDefines = core_util.clone(shader.vertexDefines);
-        this.fragmentDefines = core_util.clone(shader.fragmentDefines);
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
 
-        if (keepStatus) {
-            for (var symbol in originalUniforms) {
-                if (uniforms[symbol]) {
-                    uniforms[symbol].value = originalUniforms[symbol].value;
-                }
-            }
+  * 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.
 
-            core_util.defaults(this.vertexDefines, originalVertexDefines);
-            core_util.defaults(this.fragmentDefines, originalFragmentDefines);
-        }
+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. */
 
-        var textureStatus = {};
-        for (var key in shader.textures) {
-            textureStatus[key] = {
-                shaderType: shader.textures[key].shaderType,
-                type: shader.textures[key].type,
-                enabled: (keepStatus && this._textureStatus[key]) ? this._textureStatus[key].enabled : false
-            };
-        }
 
-        this._textureStatus = textureStatus;
 
-        this._programKey = '';
-    },
+/**
+ * @class 4 Dimensional Vector
+ * @name vec4
+ */
 
-    /**
-     * Clone a new material and keep uniforms, shader will not be cloned
-     * @return {clay.Material}
-     */
-    clone: function () {
-        var material = new this.constructor({
-            name: this.name,
-            shader: this.shader
-        });
-        for (var symbol in this.uniforms) {
-            material.uniforms[symbol].value = this.uniforms[symbol].value;
-        }
-        material.depthTest = this.depthTest;
-        material.depthMask = this.depthMask;
-        material.transparent = this.transparent;
-        material.blend = this.blend;
+var vec4 = {};
 
-        material.vertexDefines = core_util.clone(this.vertexDefines);
-        material.fragmentDefines = core_util.clone(this.fragmentDefines);
-        material.enableTexture(this.getEnabledTextures());
-        material.precision = this.precision;
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+vec4.create = function() {
+    var out = new GLMAT_ARRAY_TYPE(4);
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 0;
+    return out;
+};
 
-        return material;
-    },
-
-    /**
-     * Add a #define macro in shader code
-     * @param  {string} shaderType Can be vertex, fragment or both
-     * @param  {string} symbol
-     * @param  {number} [val]
-     */
-    define: function (shaderType, symbol, val) {
-        var vertexDefines = this.vertexDefines;
-        var fragmentDefines = this.fragmentDefines;
-        if (shaderType !== 'vertex' && shaderType !== 'fragment' && shaderType !== 'both'
-            && arguments.length < 3
-        ) {
-            // shaderType default to be 'both'
-            val = symbol;
-            symbol = shaderType;
-            shaderType = 'both';
-        }
-        val = val != null ? val : null;
-        if (shaderType === 'vertex' || shaderType === 'both') {
-            if (vertexDefines[symbol] !== val) {
-                vertexDefines[symbol] = val;
-                // Mark as dirty
-                this._programKey = '';
-            }
-        }
-        if (shaderType === 'fragment' || shaderType === 'both') {
-            if (fragmentDefines[symbol] !== val) {
-                fragmentDefines[symbol] = val;
-                if (shaderType !== 'both') {
-                    this._programKey = '';
-                }
-            }
-        }
-    },
-
-    /**
-     * Remove a #define macro in shader code
-     * @param  {string} shaderType Can be vertex, fragment or both
-     * @param  {string} symbol
-     */
-    undefine: function (shaderType, symbol) {
-        if (shaderType !== 'vertex' && shaderType !== 'fragment' && shaderType !== 'both'
-            && arguments.length < 2
-        ) {
-            // shaderType default to be 'both'
-            symbol = shaderType;
-            shaderType = 'both';
-        }
-        if (shaderType === 'vertex' || shaderType === 'both') {
-            if (this.isDefined('vertex', symbol)) {
-                delete this.vertexDefines[symbol];
-                // Mark as dirty
-                this._programKey = '';
-            }
-        }
-        if (shaderType === 'fragment' || shaderType === 'both') {
-            if (this.isDefined('fragment', symbol)) {
-                delete this.fragmentDefines[symbol];
-                if (shaderType !== 'both') {
-                    this._programKey = '';
-                }
-            }
-        }
-    },
-
-    /**
-     * If macro is defined in shader.
-     * @param  {string} shaderType Can be vertex, fragment or both
-     * @param  {string} symbol
-     */
-    isDefined: function (shaderType, symbol) {
-        // PENDING hasOwnProperty ?
-        switch (shaderType) {
-            case 'vertex':
-                return this.vertexDefines[symbol] !== undefined;
-            case 'fragment':
-                return this.fragmentDefines[symbol] !== undefined;
-        }
-    },
-    /**
-     * Get macro value defined in shader.
-     * @param  {string} shaderType Can be vertex, fragment or both
-     * @param  {string} symbol
-     */
-    getDefine: function (shaderType, symbol) {
-        switch(shaderType) {
-            case 'vertex':
-                return this.vertexDefines[symbol];
-            case 'fragment':
-                return this.fragmentDefines[symbol];
-        }
-    },
-    /**
-     * Enable a texture, actually it will add a #define macro in the shader code
-     * For example, if texture symbol is diffuseMap, it will add a line `#define DIFFUSEMAP_ENABLED` in the shader code
-     * @param  {string} symbol
-     */
-    enableTexture: function (symbol) {
-        if (Array.isArray(symbol)) {
-            for (var i = 0; i < symbol.length; i++) {
-                this.enableTexture(symbol[i]);
-            }
-            return;
-        }
-
-        var status = this._textureStatus[symbol];
-        if (status) {
-            var isEnabled = status.enabled;
-            if (!isEnabled) {
-                status.enabled = true;
-                this._programKey = '';
-            }
-        }
-    },
-    /**
-     * Enable all textures used in the shader
-     */
-    enableTexturesAll: function () {
-        var textureStatus = this._textureStatus;
-        for (var symbol in textureStatus) {
-            textureStatus[symbol].enabled = true;
-        }
-
-        this._programKey = '';
-    },
-    /**
-     * Disable a texture, it remove a #define macro in the shader
-     * @param  {string} symbol
-     */
-    disableTexture: function (symbol) {
-        if (Array.isArray(symbol)) {
-            for (var i = 0; i < symbol.length; i++) {
-                this.disableTexture(symbol[i]);
-            }
-            return;
-        }
-
-        var status = this._textureStatus[symbol];
-        if (status) {
-            var isDisabled = ! status.enabled;
-            if (!isDisabled) {
-                status.enabled = false;
-                this._programKey = '';
-            }
-        }
-    },
-    /**
-     * Disable all textures used in the shader
-     */
-    disableTexturesAll: function () {
-        var textureStatus = this._textureStatus;
-        for (var symbol in textureStatus) {
-            textureStatus[symbol].enabled = false;
-        }
-
-        this._programKey = '';
-    },
-    /**
-     * If texture of given type is enabled.
-     * @param  {string}  symbol
-     * @return {boolean}
-     */
-    isTextureEnabled: function (symbol) {
-        var textureStatus = this._textureStatus;
-        return !!textureStatus[symbol]
-            && textureStatus[symbol].enabled;
-    },
-
-    /**
-     * Get all enabled textures
-     * @return {string[]}
-     */
-    getEnabledTextures: function () {
-        var enabledTextures = [];
-        var textureStatus = this._textureStatus;
-        for (var symbol in textureStatus) {
-            if (textureStatus[symbol].enabled) {
-                enabledTextures.push(symbol);
-            }
-        }
-        return enabledTextures;
-    },
-
-    /**
-     * Mark defines are updated.
-     */
-    dirtyDefines: function () {
-        this._programKey = '';
-    },
-
-    getProgramKey: function () {
-        if (!this._programKey) {
-            this._programKey = getProgramKey(
-                this.vertexDefines, this.fragmentDefines, this.getEnabledTextures()
-            );
-        }
-        return this._programKey;
-    }
-});
-
-/* harmony default export */ const src_Material = (Material);
-
-;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/common.js
-
-var GLMAT_EPSILON = 0.000001;
-
-// Use Array instead of Float32Array. It seems to be much faster and higher precision.
-var GLMAT_ARRAY_TYPE = Array;
-// if(!GLMAT_ARRAY_TYPE) {
-//     GLMAT_ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;
-// }
-
-var common_GLMAT_RANDOM = Math.random;
-
-;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/vec2.js
-
-/* 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. */
-
-
-
-/**
- * @class 2 Dimensional Vector
- * @name vec2
- */
-
-var vec2 = {};
-
-/**
- * Creates a new, empty vec2
- *
- * @returns {vec2} a new 2D vector
- */
-vec2.create = function() {
-    var out = new GLMAT_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
- */
-vec2.clone = function(a) {
-    var out = new GLMAT_ARRAY_TYPE(2);
-    out[0] = a[0];
-    out[1] = a[1];
-    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
+ */
+vec4.clone = function(a) {
+    var out = new GLMAT_ARRAY_TYPE(4);
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+};
 
 /**
- * Creates a new vec2 initialized with the given values
+ * Creates a new vec4 initialized with the given values
  *
  * @param {Number} x X component
  * @param {Number} y Y component
- * @returns {vec2} a new 2D vector
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
  */
-vec2.fromValues = function(x, y) {
-    var out = new GLMAT_ARRAY_TYPE(2);
+vec4.fromValues = function(x, y, z, w) {
+    var out = new GLMAT_ARRAY_TYPE(4);
     out[0] = x;
     out[1] = y;
+    out[2] = z;
+    out[3] = w;
     return out;
 };
 
 /**
- * Copy the values from one vec2 to another
+ * Copy the values from one vec4 to another
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the source vector
- * @returns {vec2} out
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the source vector
+ * @returns {vec4} out
  */
-vec2.copy = function(out, a) {
+vec4.copy = function(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 vec2 to the given values
+ * Set the components of a vec4 to the given values
  *
- * @param {vec2} out the receiving vector
+ * @param {vec4} out the receiving vector
  * @param {Number} x X component
  * @param {Number} y Y component
- * @returns {vec2} out
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} out
  */
-vec2.set = function(out, x, y) {
+vec4.set = function(out, x, y, z, w) {
     out[0] = x;
     out[1] = y;
+    out[2] = z;
+    out[3] = w;
     return out;
 };
 
 /**
- * Adds two vec2's
+ * Adds two vec4's
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
  */
-vec2.add = function(out, a, b) {
+vec4.add = function(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 {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
  */
-vec2.subtract = function(out, a, b) {
+vec4.subtract = function(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;
 };
 
 /**
- * Alias for {@link vec2.subtract}
+ * Alias for {@link vec4.subtract}
  * @function
  */
-vec2.sub = vec2.subtract;
+vec4.sub = vec4.subtract;
 
 /**
- * Multiplies two vec2's
+ * Multiplies two vec4's
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
  */
-vec2.multiply = function(out, a, b) {
+vec4.multiply = function(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;
 };
 
 /**
- * Alias for {@link vec2.multiply}
+ * Alias for {@link vec4.multiply}
  * @function
  */
-vec2.mul = vec2.multiply;
+vec4.mul = vec4.multiply;
 
 /**
- * Divides two vec2's
+ * Divides two vec4's
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
  */
-vec2.divide = function(out, a, b) {
+vec4.divide = function(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;
 };
 
 /**
- * Alias for {@link vec2.divide}
+ * Alias for {@link vec4.divide}
  * @function
  */
-vec2.div = vec2.divide;
+vec4.div = vec4.divide;
 
 /**
- * Returns the minimum of two vec2's
+ * Returns the minimum of two vec4's
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
  */
-vec2.min = function(out, a, b) {
+vec4.min = function(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 vec2's
+ * Returns the maximum of two vec4's
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
- * @returns {vec2} out
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
  */
-vec2.max = function(out, a, b) {
+vec4.max = function(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;
 };
 
 /**
- * Scales a vec2 by a scalar number
+ * Scales a vec4 by a scalar number
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to scale
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to scale
  * @param {Number} b amount to scale the vector by
- * @returns {vec2} out
+ * @returns {vec4} out
  */
-vec2.scale = function(out, a, b) {
+vec4.scale = function(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 vec2's after scaling the second operand by a scalar value
+ * Adds two vec4'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 {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 {vec2} out
+ * @returns {vec4} out
  */
-vec2.scaleAndAdd = function(out, a, b, scale) {
+vec4.scaleAndAdd = function(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 vec2's
+ * Calculates the euclidian distance between two vec4's
  *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
  * @returns {Number} distance between a and b
  */
-vec2.distance = function(a, b) {
+vec4.distance = function(a, b) {
     var x = b[0] - a[0],
-        y = b[1] - a[1];
-    return Math.sqrt(x*x + y*y);
+        y = b[1] - a[1],
+        z = b[2] - a[2],
+        w = b[3] - a[3];
+    return Math.sqrt(x*x + y*y + z*z + w*w);
 };
 
 /**
- * Alias for {@link vec2.distance}
+ * Alias for {@link vec4.distance}
  * @function
  */
-vec2.dist = vec2.distance;
+vec4.dist = vec4.distance;
 
 /**
- * Calculates the squared euclidian distance between two vec2's
+ * Calculates the squared euclidian distance between two vec4's
  *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
  * @returns {Number} squared distance between a and b
  */
-vec2.squaredDistance = function(a, b) {
+vec4.squaredDistance = function(a, b) {
     var x = b[0] - a[0],
-        y = b[1] - a[1];
-    return x*x + y*y;
+        y = b[1] - a[1],
+        z = b[2] - a[2],
+        w = b[3] - a[3];
+    return x*x + y*y + z*z + w*w;
 };
 
 /**
- * Alias for {@link vec2.squaredDistance}
+ * Alias for {@link vec4.squaredDistance}
  * @function
  */
-vec2.sqrDist = vec2.squaredDistance;
+vec4.sqrDist = vec4.squaredDistance;
 
 /**
- * Calculates the length of a vec2
+ * Calculates the length of a vec4
  *
- * @param {vec2} a vector to calculate length of
+ * @param {vec4} a vector to calculate length of
  * @returns {Number} length of a
  */
-vec2.length = function (a) {
+vec4.length = function (a) {
     var x = a[0],
-        y = a[1];
-    return Math.sqrt(x*x + y*y);
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    return Math.sqrt(x*x + y*y + z*z + w*w);
 };
 
 /**
- * Alias for {@link vec2.length}
+ * Alias for {@link vec4.length}
  * @function
  */
-vec2.len = vec2.length;
+vec4.len = vec4.length;
 
 /**
- * Calculates the squared length of a vec2
+ * Calculates the squared length of a vec4
  *
- * @param {vec2} a vector to calculate squared length of
+ * @param {vec4} a vector to calculate squared length of
  * @returns {Number} squared length of a
  */
-vec2.squaredLength = function (a) {
+vec4.squaredLength = function (a) {
     var x = a[0],
-        y = a[1];
-    return x*x + y*y;
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    return x*x + y*y + z*z + w*w;
 };
 
 /**
- * Alias for {@link vec2.squaredLength}
+ * Alias for {@link vec4.squaredLength}
  * @function
  */
-vec2.sqrLen = vec2.squaredLength;
+vec4.sqrLen = vec4.squaredLength;
 
 /**
- * Negates the components of a vec2
+ * Negates the components of a vec4
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to negate
- * @returns {vec2} out
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to negate
+ * @returns {vec4} out
  */
-vec2.negate = function(out, a) {
+vec4.negate = function(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 vec2
+ * Returns the inverse of the components of a vec4
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to invert
- * @returns {vec2} out
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to invert
+ * @returns {vec4} out
  */
-vec2.inverse = function(out, a) {
+vec4.inverse = function(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 vec2
+ * Normalize a vec4
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a vector to normalize
- * @returns {vec2} out
- */
-vec2.normalize = function(out, a) {
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+vec4.normalize = function(out, a) {
     var x = a[0],
-        y = a[1];
-    var len = x*x + y*y;
+        y = a[1],
+        z = a[2],
+        w = a[3];
+    var len = x*x + y*y + z*z + w*w;
     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;
+        out[3] = a[3] * len;
     }
     return out;
 };
 
 /**
- * Calculates the dot product of two vec2's
+ * Calculates the dot product of two vec4's
  *
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
  * @returns {Number} dot product of a and b
  */
-vec2.dot = function (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
- */
-vec2.cross = function(out, a, b) {
-    var z = a[0] * b[1] - a[1] * b[0];
-    out[0] = out[1] = 0;
-    out[2] = z;
-    return out;
+vec4.dot = function (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 vec2's
+ * Performs a linear interpolation between two vec4's
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the first operand
- * @param {vec2} b the second operand
+ * @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 {vec2} out
+ * @returns {vec4} out
  */
-vec2.lerp = function (out, a, b, t) {
+vec4.lerp = function (out, a, b, t) {
     var ax = a[0],
-        ay = a[1];
+        ay = a[1],
+        az = a[2],
+        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 {vec2} out the receiving vector
+ * @param {vec4} out the receiving vector
  * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
- * @returns {vec2} out
+ * @returns {vec4} out
  */
-vec2.random = function (out, scale) {
+vec4.random = function (out, scale) {
     scale = scale || 1.0;
-    var r = GLMAT_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
- */
-vec2.transformMat2 = function(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;
+    //TODO: This is a pretty awful way of doing this. Find something better.
+    out[0] = common_GLMAT_RANDOM();
+    out[1] = common_GLMAT_RANDOM();
+    out[2] = common_GLMAT_RANDOM();
+    out[3] = common_GLMAT_RANDOM();
+    vec4.normalize(out, out);
+    vec4.scale(out, out, scale);
     return out;
 };
 
 /**
- * Transforms the vec2 with a mat2d
+ * Transforms the vec4 with a mat4.
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat2d} m matrix to transform with
- * @returns {vec2} out
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
  */
-vec2.transformMat2d = function(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];
+vec4.transformMat4 = function(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 vec2 with a mat3
- * 3rd vector component is implicitly '1'
+ * Transforms the vec4 with a quat
  *
- * @param {vec2} out the receiving vector
- * @param {vec2} a the vector to transform
- * @param {mat3} m matrix to transform with
- * @returns {vec2} out
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
  */
-vec2.transformMat3 = function(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;
-};
+vec4.transformQuat = function(out, a, q) {
+    var x = a[0], y = a[1], z = a[2],
+        qx = q[0], qy = q[1], qz = q[2], qw = q[3],
 
-/**
- * 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
- */
-vec2.transformMat4 = function(out, a, m) {
-    var x = a[0],
-        y = a[1];
-    out[0] = m[0] * x + m[4] * y + m[12];
-    out[1] = m[1] * x + m[5] * y + m[13];
+        // calculate quat * vec
+        ix = qw * x + qy * z - qz * y,
+        iy = qw * y + qz * x - qx * z,
+        iz = qw * z + qx * y - qy * x,
+        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;
 };
 
 /**
- * Perform some operation over an array of vec2s.
+ * 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 vec2. If 0 assumes tightly packed
+ * @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 vec2s to iterate over. If 0 iterates over entire 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
  */
-vec2.forEach = (function() {
-    var vec = vec2.create();
+vec4.forEach = (function() {
+    var vec = vec4.create();
 
     return function(a, stride, offset, count, fn, arg) {
         var i, l;
         if(!stride) {
-            stride = 2;
+            stride = 4;
         }
 
         if(!offset) {
@@ -3089,7302 +2756,6723 @@ vec2.forEach = (function() {
         }
 
         for(i = offset; i < l; i += stride) {
-            vec[0] = a[i]; vec[1] = a[i+1];
+            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] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
         }
 
         return a;
     };
 })();
 
-/* harmony default export */ const glmatrix_vec2 = (vec2);
-;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Vector2.js
+/* harmony default export */ const glmatrix_vec4 = (vec4);
+;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/mat3.js
 
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
 
-/**
- * @constructor
- * @alias clay.Vector2
- * @param {number} x
- * @param {number} y
- */
-var Vector2 = function(x, y) {
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
 
-    x = x || 0;
-    y = y || 0;
+  * 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.
 
-    /**
-     * Storage of Vector2, read and write of x, y will change the values in array
-     * All methods also operate on the array instead of x, y components
-     * @name array
-     * @type {Float32Array}
-     * @memberOf clay.Vector2#
-     */
-    this.array = glmatrix_vec2.fromValues(x, y);
+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. */
 
-    /**
-     * Dirty flag is used by the Node to determine
-     * if the matrix is updated to latest
-     * @name _dirty
-     * @type {boolean}
-     * @memberOf clay.Vector2#
-     */
-    this._dirty = true;
-};
 
-Vector2.prototype = {
 
-    constructor: Vector2,
+/**
+ * @class 3x3 Matrix
+ * @name mat3
+ */
 
-    /**
-     * Add b to self
-     * @param  {clay.Vector2} b
-     * @return {clay.Vector2}
-     */
-    add: function(b) {
-        glmatrix_vec2.add(this.array, this.array, b.array);
-        this._dirty = true;
-        return this;
-    },
+var mat3 = {};
 
-    /**
-     * Set x and y components
-     * @param  {number}  x
-     * @param  {number}  y
-     * @return {clay.Vector2}
-     */
-    set: function(x, y) {
-        this.array[0] = x;
-        this.array[1] = y;
-        this._dirty = true;
-        return this;
-    },
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.create = function() {
+    var out = new GLMAT_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;
+};
 
-    /**
-     * Set x and y components from array
-     * @param  {Float32Array|number[]} arr
-     * @return {clay.Vector2}
-     */
-    setArray: function(arr) {
-        this.array[0] = arr[0];
-        this.array[1] = arr[1];
+/**
+ * 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
+ */
+mat3.fromMat4 = function(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;
+};
 
-        this._dirty = true;
-        return this;
-    },
+/**
+ * Creates a new mat3 initialized with values from an existing matrix
+ *
+ * @param {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.clone = function(a) {
+    var out = new GLMAT_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;
+};
 
-    /**
-     * Clone a new Vector2
-     * @return {clay.Vector2}
-     */
-    clone: function() {
-        return new Vector2(this.x, this.y);
-    },
+/**
+ * Copy the values from one mat3 to another
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.copy = function(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;
+};
 
-    /**
-     * Copy x, y from b
-     * @param  {clay.Vector2} b
-     * @return {clay.Vector2}
-     */
-    copy: function(b) {
-        glmatrix_vec2.copy(this.array, b.array);
-        this._dirty = true;
-        return this;
-    },
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+mat3.identity = function(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;
+};
 
-    /**
-     * Cross product of self and b, written to a Vector3 out
-     * @param  {clay.Vector3} out
-     * @param  {clay.Vector2} b
-     * @return {clay.Vector2}
-     */
-    cross: function(out, b) {
-        glmatrix_vec2.cross(out.array, this.array, b.array);
-        out._dirty = true;
-        return this;
-    },
+/**
+ * Transpose the values of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.transpose = function(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];
+    }
 
-    /**
-     * Alias for distance
-     * @param  {clay.Vector2} b
-     * @return {number}
-     */
-    dist: function(b) {
-        return glmatrix_vec2.dist(this.array, b.array);
-    },
+    return out;
+};
 
-    /**
-     * Distance between self and b
-     * @param  {clay.Vector2} b
-     * @return {number}
-     */
-    distance: function(b) {
-        return glmatrix_vec2.distance(this.array, b.array);
-    },
+/**
+ * Inverts a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.invert = function(out, a) {
+    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],
 
-    /**
-     * Alias for divide
-     * @param  {clay.Vector2} b
-     * @return {clay.Vector2}
-     */
-    div: function(b) {
-        glmatrix_vec2.div(this.array, this.array, b.array);
-        this._dirty = true;
-        return this;
-    },
+        b01 = a22 * a11 - a12 * a21,
+        b11 = -a22 * a10 + a12 * a20,
+        b21 = a21 * a10 - a11 * a20,
 
-    /**
-     * Divide self by b
-     * @param  {clay.Vector2} b
-     * @return {clay.Vector2}
-     */
-    divide: function(b) {
-        glmatrix_vec2.divide(this.array, this.array, b.array);
-        this._dirty = true;
-        return this;
-    },
+        // Calculate the determinant
+        det = a00 * b01 + a01 * b11 + a02 * b21;
 
-    /**
-     * Dot product of self and b
-     * @param  {clay.Vector2} b
-     * @return {number}
-     */
-    dot: function(b) {
-        return glmatrix_vec2.dot(this.array, b.array);
-    },
+    if (!det) {
+        return null;
+    }
+    det = 1.0 / det;
 
-    /**
-     * Alias of length
-     * @return {number}
-     */
-    len: function() {
-        return glmatrix_vec2.len(this.array);
-    },
+    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;
+};
 
-    /**
-     * Calculate the length
-     * @return {number}
-     */
-    length: function() {
-        return glmatrix_vec2.length(this.array);
-    },
+/**
+ * Calculates the adjugate of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.adjoint = function(out, a) {
+    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];
 
-    /**
-     * Linear interpolation between a and b
-     * @param  {clay.Vector2} a
-     * @param  {clay.Vector2} b
-     * @param  {number}  t
-     * @return {clay.Vector2}
-     */
-    lerp: function(a, b, t) {
-        glmatrix_vec2.lerp(this.array, a.array, b.array, t);
-        this._dirty = true;
-        return this;
-    },
-
-    /**
-     * Minimum of self and b
-     * @param  {clay.Vector2} b
-     * @return {clay.Vector2}
-     */
-    min: function(b) {
-        glmatrix_vec2.min(this.array, this.array, b.array);
-        this._dirty = true;
-        return this;
-    },
-
-    /**
-     * Maximum of self and b
-     * @param  {clay.Vector2} b
-     * @return {clay.Vector2}
-     */
-    max: function(b) {
-        glmatrix_vec2.max(this.array, this.array, b.array);
-        this._dirty = true;
-        return this;
-    },
-
-    /**
-     * Alias for multiply
-     * @param  {clay.Vector2} b
-     * @return {clay.Vector2}
-     */
-    mul: function(b) {
-        glmatrix_vec2.mul(this.array, this.array, b.array);
-        this._dirty = true;
-        return this;
-    },
-
-    /**
-     * Mutiply self and b
-     * @param  {clay.Vector2} b
-     * @return {clay.Vector2}
-     */
-    multiply: function(b) {
-        glmatrix_vec2.multiply(this.array, this.array, b.array);
-        this._dirty = true;
-        return this;
-    },
+    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;
+};
 
-    /**
-     * Negate self
-     * @return {clay.Vector2}
-     */
-    negate: function() {
-        glmatrix_vec2.negate(this.array, this.array);
-        this._dirty = true;
-        return this;
-    },
+/**
+ * Calculates the determinant of a mat3
+ *
+ * @param {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat3.determinant = function (a) {
+    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];
 
-    /**
-     * Normalize self
-     * @return {clay.Vector2}
-     */
-    normalize: function() {
-        glmatrix_vec2.normalize(this.array, this.array);
-        this._dirty = true;
-        return this;
-    },
+    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+};
 
-    /**
-     * Generate random x, y components with a given scale
-     * @param  {number} scale
-     * @return {clay.Vector2}
-     */
-    random: function(scale) {
-        glmatrix_vec2.random(this.array, scale);
-        this._dirty = true;
-        return this;
-    },
+/**
+ * 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
+ */
+mat3.multiply = function (out, a, b) {
+    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],
 
-    /**
-     * Scale self
-     * @param  {number}  scale
-     * @return {clay.Vector2}
-     */
-    scale: function(s) {
-        glmatrix_vec2.scale(this.array, this.array, s);
-        this._dirty = true;
-        return this;
-    },
+        b00 = b[0], b01 = b[1], b02 = b[2],
+        b10 = b[3], b11 = b[4], b12 = b[5],
+        b20 = b[6], b21 = b[7], b22 = b[8];
 
-    /**
-     * Scale b and add to self
-     * @param  {clay.Vector2} b
-     * @param  {number}  scale
-     * @return {clay.Vector2}
-     */
-    scaleAndAdd: function(b, s) {
-        glmatrix_vec2.scaleAndAdd(this.array, this.array, b.array, s);
-        this._dirty = true;
-        return this;
-    },
+    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
 
-    /**
-     * Alias for squaredDistance
-     * @param  {clay.Vector2} b
-     * @return {number}
-     */
-    sqrDist: function(b) {
-        return glmatrix_vec2.sqrDist(this.array, b.array);
-    },
+    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
 
-    /**
-     * Squared distance between self and b
-     * @param  {clay.Vector2} b
-     * @return {number}
-     */
-    squaredDistance: function(b) {
-        return glmatrix_vec2.squaredDistance(this.array, b.array);
-    },
+    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;
+};
 
-    /**
-     * Alias for squaredLength
-     * @return {number}
-     */
-    sqrLen: function() {
-        return glmatrix_vec2.sqrLen(this.array);
-    },
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+mat3.mul = mat3.multiply;
 
-    /**
-     * Squared length of self
-     * @return {number}
-     */
-    squaredLength: function() {
-        return glmatrix_vec2.squaredLength(this.array);
-    },
+/**
+ * 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
+ */
+mat3.translate = function(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];
 
-    /**
-     * Alias for subtract
-     * @param  {clay.Vector2} b
-     * @return {clay.Vector2}
-     */
-    sub: function(b) {
-        glmatrix_vec2.sub(this.array, this.array, b.array);
-        this._dirty = true;
-        return this;
-    },
+    out[0] = a00;
+    out[1] = a01;
+    out[2] = a02;
 
-    /**
-     * Subtract b from self
-     * @param  {clay.Vector2} b
-     * @return {clay.Vector2}
-     */
-    subtract: function(b) {
-        glmatrix_vec2.subtract(this.array, this.array, b.array);
-        this._dirty = true;
-        return this;
-    },
+    out[3] = a10;
+    out[4] = a11;
+    out[5] = a12;
 
-    /**
-     * Transform self with a Matrix2 m
-     * @param  {clay.Matrix2} m
-     * @return {clay.Vector2}
-     */
-    transformMat2: function(m) {
-        glmatrix_vec2.transformMat2(this.array, this.array, m.array);
-        this._dirty = true;
-        return this;
-    },
+    out[6] = x * a00 + y * a10 + a20;
+    out[7] = x * a01 + y * a11 + a21;
+    out[8] = x * a02 + y * a12 + a22;
+    return out;
+};
 
-    /**
-     * Transform self with a Matrix2d m
-     * @param  {clay.Matrix2d} m
-     * @return {clay.Vector2}
-     */
-    transformMat2d: function(m) {
-        glmatrix_vec2.transformMat2d(this.array, this.array, m.array);
-        this._dirty = true;
-        return this;
-    },
+/**
+ * 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
+ */
+mat3.rotate = function (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],
 
-    /**
-     * Transform self with a Matrix3 m
-     * @param  {clay.Matrix3} m
-     * @return {clay.Vector2}
-     */
-    transformMat3: function(m) {
-        glmatrix_vec2.transformMat3(this.array, this.array, m.array);
-        this._dirty = true;
-        return this;
-    },
+        s = Math.sin(rad),
+        c = Math.cos(rad);
 
-    /**
-     * Transform self with a Matrix4 m
-     * @param  {clay.Matrix4} m
-     * @return {clay.Vector2}
-     */
-    transformMat4: function(m) {
-        glmatrix_vec2.transformMat4(this.array, this.array, m.array);
-        this._dirty = true;
-        return this;
-    },
+    out[0] = c * a00 + s * a10;
+    out[1] = c * a01 + s * a11;
+    out[2] = c * a02 + s * a12;
 
-    toString: function() {
-        return '[' + Array.prototype.join.call(this.array, ',') + ']';
-    },
+    out[3] = c * a10 - s * a00;
+    out[4] = c * a11 - s * a01;
+    out[5] = c * a12 - s * a02;
 
-    toArray: function () {
-        return Array.prototype.slice.call(this.array);
-    }
+    out[6] = a20;
+    out[7] = a21;
+    out[8] = a22;
+    return out;
 };
 
-// Getter and Setter
-if (Object.defineProperty) {
-
-    var proto = Vector2.prototype;
-    /**
-     * @name x
-     * @type {number}
-     * @memberOf clay.Vector2
-     * @instance
-     */
-    Object.defineProperty(proto, 'x', {
-        get: function () {
-            return this.array[0];
-        },
-        set: function (value) {
-            this.array[0] = value;
-            this._dirty = true;
-        }
-    });
+/**
+ * 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
+ **/
+mat3.scale = function(out, a, v) {
+    var x = v[0], y = v[1];
 
-    /**
-     * @name y
-     * @type {number}
-     * @memberOf clay.Vector2
-     * @instance
-     */
-    Object.defineProperty(proto, 'y', {
-        get: function () {
-            return this.array[1];
-        },
-        set: function (value) {
-            this.array[1] = value;
-            this._dirty = true;
-        }
-    });
-}
+    out[0] = x * a[0];
+    out[1] = x * a[1];
+    out[2] = x * a[2];
 
-// Supply methods that are not in place
+    out[3] = y * a[3];
+    out[4] = y * a[4];
+    out[5] = y * a[5];
 
-/**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {clay.Vector2}
- */
-Vector2.add = function(out, a, b) {
-    glmatrix_vec2.add(out.array, a.array, b.array);
-    out._dirty = true;
+    out[6] = a[6];
+    out[7] = a[7];
+    out[8] = a[8];
     return out;
 };
 
 /**
- * @param  {clay.Vector2} out
- * @param  {number}  x
- * @param  {number}  y
- * @return {clay.Vector2}
- */
-Vector2.set = function(out, x, y) {
-    glmatrix_vec2.set(out.array, x, y);
-    out._dirty = true;
+ * 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
+ **/
+mat3.fromMat2d = function(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;
 };
 
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} b
- * @return {clay.Vector2}
- */
-Vector2.copy = function(out, b) {
-    glmatrix_vec2.copy(out.array, b.array);
-    out._dirty = true;
+* 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
+*/
+mat3.fromQuat = function (out, q) {
+    var x = q[0], y = q[1], z = q[2], w = q[3],
+        x2 = x + x,
+        y2 = y + y,
+        z2 = z + z,
+
+        xx = x * x2,
+        yx = y * x2,
+        yy = y * y2,
+        zx = z * x2,
+        zy = z * y2,
+        zz = z * z2,
+        wx = w * x2,
+        wy = w * y2,
+        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;
 };
 
 /**
- * @param  {clay.Vector3} out
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {clay.Vector2}
- */
-Vector2.cross = function(out, a, b) {
-    glmatrix_vec2.cross(out.array, a.array, b.array);
-    out._dirty = true;
+* 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
+*/
+mat3.normalFromMat4 = function (out, a) {
+    var 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],
+        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+        b00 = a00 * a11 - a01 * a10,
+        b01 = a00 * a12 - a02 * a10,
+        b02 = a00 * a13 - a03 * a10,
+        b03 = a01 * a12 - a02 * a11,
+        b04 = a01 * a13 - a03 * a11,
+        b05 = a02 * a13 - a03 * a12,
+        b06 = a20 * a31 - a21 * a30,
+        b07 = a20 * a32 - a22 * a30,
+        b08 = a20 * a33 - a23 * a30,
+        b09 = a21 * a32 - a22 * a31,
+        b10 = a21 * a33 - a23 * a31,
+        b11 = a22 * a33 - a23 * a32,
+
+        // Calculate the determinant
+        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;
 };
+
 /**
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {number}
+ * Returns Frobenius norm of a mat3
+ *
+ * @param {mat3} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
  */
-Vector2.dist = function(a, b) {
-    return glmatrix_vec2.distance(a.array, b.array);
+mat3.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)))
 };
-/**
- * @function
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {number}
- */
-Vector2.distance = Vector2.dist;
-/**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {clay.Vector2}
- */
-Vector2.div = function(out, a, b) {
-    glmatrix_vec2.divide(out.array, a.array, b.array);
-    out._dirty = true;
+
+
+/* harmony default export */ const glmatrix_mat3 = (mat3);
+;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/quat.js
+
+
+/* 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. */
+
+
+
+
+
+
+
+/**
+ * @class Quaternion
+ * @name quat
+ */
+
+var quat = {};
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+quat.create = function() {
+    var out = new GLMAT_ARRAY_TYPE(4);
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
     return out;
 };
+
+/**
+ * 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
+ */
+quat.rotationTo = (function() {
+    var tmpvec3 = glmatrix_vec3.create();
+    var xUnitVec3 = glmatrix_vec3.fromValues(1,0,0);
+    var yUnitVec3 = glmatrix_vec3.fromValues(0,1,0);
+
+    return function(out, a, b) {
+        var dot = glmatrix_vec3.dot(a, b);
+        if (dot < -0.999999) {
+            glmatrix_vec3.cross(tmpvec3, xUnitVec3, a);
+            if (glmatrix_vec3.length(tmpvec3) < 0.000001)
+                glmatrix_vec3.cross(tmpvec3, yUnitVec3, a);
+            glmatrix_vec3.normalize(tmpvec3, tmpvec3);
+            quat.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 {
+            glmatrix_vec3.cross(tmpvec3, a, b);
+            out[0] = tmpvec3[0];
+            out[1] = tmpvec3[1];
+            out[2] = tmpvec3[2];
+            out[3] = 1 + dot;
+            return quat.normalize(out, 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
+ */
+quat.setAxes = (function() {
+    var matr = glmatrix_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 quat.normalize(out, quat.fromMat3(out, matr));
+    };
+})();
+
 /**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
  * @function
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {clay.Vector2}
  */
-Vector2.divide = Vector2.div;
+quat.clone = glmatrix_vec4.clone;
+
 /**
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {number}
+ * 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
  */
-Vector2.dot = function(a, b) {
-    return glmatrix_vec2.dot(a.array, b.array);
-};
+quat.fromValues = glmatrix_vec4.fromValues;
 
 /**
- * @param  {clay.Vector2} a
- * @return {number}
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
  */
-Vector2.len = function(b) {
-    return glmatrix_vec2.length(b.array);
-};
+quat.copy = glmatrix_vec4.copy;
 
-// Vector2.length = Vector2.len;
+/**
+ * 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
+ */
+quat.set = glmatrix_vec4.set;
 
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @param  {number}  t
- * @return {clay.Vector2}
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
  */
-Vector2.lerp = function(out, a, b, t) {
-    glmatrix_vec2.lerp(out.array, a.array, b.array, t);
-    out._dirty = true;
+quat.identity = function(out) {
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
     return out;
 };
+
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {clay.Vector2}
- */
-Vector2.min = function(out, a, b) {
-    glmatrix_vec2.min(out.array, a.array, b.array);
-    out._dirty = true;
+ * 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
+ **/
+quat.setAxisAngle = function(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;
 };
 
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {clay.Vector2}
+ * 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
  */
-Vector2.max = function(out, a, b) {
-    glmatrix_vec2.max(out.array, a.array, b.array);
-    out._dirty = true;
-    return out;
-};
+quat.add = glmatrix_vec4.add;
+
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {clay.Vector2}
+ * 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
  */
-Vector2.mul = function(out, a, b) {
-    glmatrix_vec2.multiply(out.array, a.array, b.array);
-    out._dirty = true;
+quat.multiply = function(out, a, b) {
+    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+        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;
 };
+
 /**
+ * Alias for {@link quat.multiply}
  * @function
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {clay.Vector2}
  */
-Vector2.multiply = Vector2.mul;
+quat.mul = quat.multiply;
+
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @return {clay.Vector2}
+ * 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
  */
-Vector2.negate = function(out, a) {
-    glmatrix_vec2.negate(out.array, a.array);
-    out._dirty = true;
-    return out;
-};
+quat.scale = glmatrix_vec4.scale;
+
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @return {clay.Vector2}
+ * 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
  */
-Vector2.normalize = function(out, a) {
-    glmatrix_vec2.normalize(out.array, a.array);
-    out._dirty = true;
+quat.rotateX = function (out, a, rad) {
+    rad *= 0.5;
+
+    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+        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;
 };
+
 /**
- * @param  {clay.Vector2} out
- * @param  {number}  scale
- * @return {clay.Vector2}
+ * 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
  */
-Vector2.random = function(out, scale) {
-    glmatrix_vec2.random(out.array, scale);
-    out._dirty = true;
+quat.rotateY = function (out, a, rad) {
+    rad *= 0.5;
+
+    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+        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;
 };
+
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {number}  scale
- * @return {clay.Vector2}
+ * 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
  */
-Vector2.scale = function(out, a, scale) {
-    glmatrix_vec2.scale(out.array, a.array, scale);
-    out._dirty = true;
+quat.rotateZ = function (out, a, rad) {
+    rad *= 0.5;
+
+    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+        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;
 };
+
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @param  {number}  scale
- * @return {clay.Vector2}
+ * 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
  */
-Vector2.scaleAndAdd = function(out, a, b, scale) {
-    glmatrix_vec2.scaleAndAdd(out.array, a.array, b.array, scale);
-    out._dirty = true;
+quat.calculateW = function (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;
 };
+
 /**
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {number}
+ * 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
  */
-Vector2.sqrDist = function(a, b) {
-    return glmatrix_vec2.sqrDist(a.array, b.array);
-};
+quat.dot = glmatrix_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
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {number}
  */
-Vector2.squaredDistance = Vector2.sqrDist;
+quat.lerp = glmatrix_vec4.lerp;
 
 /**
- * @param  {clay.Vector2} a
- * @return {number}
+ * 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
  */
-Vector2.sqrLen = function(a) {
-    return glmatrix_vec2.sqrLen(a.array);
+quat.slerp = function (out, a, b, t) {
+    // benchmarks:
+    //    http://jsperf.com/quaternion-slerp-implementations
+
+    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+        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) > 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;
 };
+
 /**
- * @function
- * @param  {clay.Vector2} a
- * @return {number}
+ * Calculates the inverse of a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate inverse of
+ * @returns {quat} out
  */
-Vector2.squaredLength = Vector2.sqrLen;
+quat.invert = function(out, a) {
+    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+        dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
+        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;
+};
 
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {clay.Vector2}
+ * 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
  */
-Vector2.sub = function(out, a, b) {
-    glmatrix_vec2.subtract(out.array, a.array, b.array);
-    out._dirty = true;
+quat.conjugate = function (out, a) {
+    out[0] = -a[0];
+    out[1] = -a[1];
+    out[2] = -a[2];
+    out[3] = a[3];
     return out;
 };
+
 /**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
  * @function
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Vector2} b
- * @return {clay.Vector2}
  */
-Vector2.subtract = Vector2.sub;
+quat.length = glmatrix_vec4.length;
+
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Matrix2} m
- * @return {clay.Vector2}
+ * Alias for {@link quat.length}
+ * @function
  */
-Vector2.transformMat2 = function(out, a, m) {
-    glmatrix_vec2.transformMat2(out.array, a.array, m.array);
-    out._dirty = true;
-    return out;
-};
+quat.len = quat.length;
+
 /**
- * @param  {clay.Vector2}  out
- * @param  {clay.Vector2}  a
- * @param  {clay.Matrix2d} m
- * @return {clay.Vector2}
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
  */
-Vector2.transformMat2d = function(out, a, m) {
-    glmatrix_vec2.transformMat2d(out.array, a.array, m.array);
-    out._dirty = true;
-    return out;
-};
+quat.squaredLength = glmatrix_vec4.squaredLength;
+
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {Matrix3} m
- * @return {clay.Vector2}
+ * Alias for {@link quat.squaredLength}
+ * @function
  */
-Vector2.transformMat3 = function(out, a, m) {
-    glmatrix_vec2.transformMat3(out.array, a.array, m.array);
-    out._dirty = true;
-    return out;
-};
+quat.sqrLen = quat.squaredLength;
+
 /**
- * @param  {clay.Vector2} out
- * @param  {clay.Vector2} a
- * @param  {clay.Matrix4} m
- * @return {clay.Vector2}
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
  */
-Vector2.transformMat4 = function(out, a, m) {
-    glmatrix_vec2.transformMat4(out.array, a.array, m.array);
-    out._dirty = true;
+quat.normalize = glmatrix_vec4.normalize;
+
+/**
+ * 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
+ */
+quat.fromMat3 = function(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;
 };
 
-/* harmony default export */ const math_Vector2 = (Vector2);
+/* harmony default export */ const glmatrix_quat = (quat);
+;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Quaternion.js
 
-;// CONCATENATED MODULE: ./node_modules/claygl/src/gpu/GLProgram.js
 
 
+/**
+ * @constructor
+ * @alias clay.Quaternion
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @param {number} w
+ */
+var Quaternion = function (x, y, z, w) {
 
-var SHADER_STATE_TO_ENABLE = 1;
-var SHADER_STATE_KEEP_ENABLE = 2;
-var SHADER_STATE_PENDING = 3;
+    x = x || 0;
+    y = y || 0;
+    z = z || 0;
+    w = w === undefined ? 1 : w;
 
-// Enable attribute operation is global to all programs
-// Here saved the list of all enabled attribute index
-// http://www.mjbshaw.com/2013/03/webgl-fixing-invalidoperation.html
-var enabledAttributeList = {};
+    /**
+     * Storage of Quaternion, read and write of x, y, z, w will change the values in array
+     * All methods also operate on the array instead of x, y, z, w components
+     * @name array
+     * @type {Float32Array}
+     * @memberOf clay.Quaternion#
+     */
+    this.array = glmatrix_quat.fromValues(x, y, z, w);
 
-// some util functions
-function addLineNumbers(string) {
-    var chunks = string.split('\n');
-    for (var i = 0, il = chunks.length; i < il; i ++) {
-        // Chrome reports shader errors on lines
-        // starting counting from 1
-        chunks[i] = (i + 1) + ': ' + chunks[i];
-    }
-    return chunks.join('\n');
-}
+    /**
+     * Dirty flag is used by the Node to determine
+     * if the matrix is updated to latest
+     * @name _dirty
+     * @type {boolean}
+     * @memberOf clay.Quaternion#
+     */
+    this._dirty = true;
+};
 
-// Return true or error msg if error happened
-function checkShaderErrorMsg(_gl, shader, shaderString) {
-    if (!_gl.getShaderParameter(shader, _gl.COMPILE_STATUS)) {
-        return [_gl.getShaderInfoLog(shader), addLineNumbers(shaderString)].join('\n');
-    }
-}
+Quaternion.prototype = {
 
-var tmpFloat32Array16 = new core_vendor.Float32Array(16);
+    constructor: Quaternion,
 
-var GLProgram = core_Base.extend({
+    /**
+     * Add b to self
+     * @param  {clay.Quaternion} b
+     * @return {clay.Quaternion}
+     */
+    add: function (b) {
+        glmatrix_quat.add(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-    uniformSemantics: {},
-    attributes: {}
+    /**
+     * Calculate the w component from x, y, z component
+     * @return {clay.Quaternion}
+     */
+    calculateW: function () {
+        glmatrix_quat.calculateW(this.array, this.array);
+        this._dirty = true;
+        return this;
+    },
 
-}, function () {
-    this._locations = {};
+    /**
+     * Set x, y and z components
+     * @param  {number}  x
+     * @param  {number}  y
+     * @param  {number}  z
+     * @param  {number}  w
+     * @return {clay.Quaternion}
+     */
+    set: function (x, y, z, w) {
+        this.array[0] = x;
+        this.array[1] = y;
+        this.array[2] = z;
+        this.array[3] = w;
+        this._dirty = true;
+        return this;
+    },
 
-    this._textureSlot = 0;
+    /**
+     * Set x, y, z and w components from array
+     * @param  {Float32Array|number[]} arr
+     * @return {clay.Quaternion}
+     */
+    setArray: function (arr) {
+        this.array[0] = arr[0];
+        this.array[1] = arr[1];
+        this.array[2] = arr[2];
+        this.array[3] = arr[3];
 
-    this._program = null;
-}, {
+        this._dirty = true;
+        return this;
+    },
 
-    bind: function (renderer) {
-        this._textureSlot = 0;
-        renderer.gl.useProgram(this._program);
+    /**
+     * Clone a new Quaternion
+     * @return {clay.Quaternion}
+     */
+    clone: function () {
+        return new Quaternion(this.x, this.y, this.z, this.w);
     },
 
-    hasUniform: function (symbol) {
-        var location = this._locations[symbol];
-        return location !== null && location !== undefined;
+    /**
+     * Calculates the conjugate of self If the quaternion is normalized,
+     * this function is faster than invert and produces the same result.
+     *
+     * @return {clay.Quaternion}
+     */
+    conjugate: function () {
+        glmatrix_quat.conjugate(this.array, this.array);
+        this._dirty = true;
+        return this;
     },
 
-    useTextureSlot: function (renderer, texture, slot) {
-        if (texture) {
-            renderer.gl.activeTexture(renderer.gl.TEXTURE0 + slot);
-            // Maybe texture is not loaded yet;
-            if (texture.isRenderable()) {
-                texture.bind(renderer);
-            }
-            else {
-                // Bind texture to null
-                texture.unbind(renderer);
-            }
-        }
+    /**
+     * Copy from b
+     * @param  {clay.Quaternion} b
+     * @return {clay.Quaternion}
+     */
+    copy: function (b) {
+        glmatrix_quat.copy(this.array, b.array);
+        this._dirty = true;
+        return this;
     },
 
-    currentTextureSlot: function () {
-        return this._textureSlot;
+    /**
+     * Dot product of self and b
+     * @param  {clay.Quaternion} b
+     * @return {number}
+     */
+    dot: function (b) {
+        return glmatrix_quat.dot(this.array, b.array);
     },
 
-    resetTextureSlot: function (slot) {
-        this._textureSlot = slot || 0;
+    /**
+     * Set from the given 3x3 rotation matrix
+     * @param  {clay.Matrix3} m
+     * @return {clay.Quaternion}
+     */
+    fromMat3: function (m) {
+        glmatrix_quat.fromMat3(this.array, m.array);
+        this._dirty = true;
+        return this;
     },
 
-    takeCurrentTextureSlot: function (renderer, texture) {
-        var textureSlot = this._textureSlot;
+    /**
+     * Set from the given 4x4 rotation matrix
+     * The 4th column and 4th row will be droped
+     * @param  {clay.Matrix4} m
+     * @return {clay.Quaternion}
+     */
+    fromMat4: (function () {
+        var m3 = glmatrix_mat3.create();
+        return function (m) {
+            glmatrix_mat3.fromMat4(m3, m.array);
+            // TODO Not like mat4, mat3 in glmatrix seems to be row-based
+            glmatrix_mat3.transpose(m3, m3);
+            glmatrix_quat.fromMat3(this.array, m3);
+            this._dirty = true;
+            return this;
+        };
+    })(),
 
-        this.useTextureSlot(renderer, texture, textureSlot);
+    /**
+     * Set to identity quaternion
+     * @return {clay.Quaternion}
+     */
+    identity: function () {
+        glmatrix_quat.identity(this.array);
+        this._dirty = true;
+        return this;
+    },
+    /**
+     * Invert self
+     * @return {clay.Quaternion}
+     */
+    invert: function () {
+        glmatrix_quat.invert(this.array, this.array);
+        this._dirty = true;
+        return this;
+    },
+    /**
+     * Alias of length
+     * @return {number}
+     */
+    len: function () {
+        return glmatrix_quat.len(this.array);
+    },
 
-        this._textureSlot++;
+    /**
+     * Calculate the length
+     * @return {number}
+     */
+    length: function () {
+        return glmatrix_quat.length(this.array);
+    },
 
-        return textureSlot;
+    /**
+     * Linear interpolation between a and b
+     * @param  {clay.Quaternion} a
+     * @param  {clay.Quaternion} b
+     * @param  {number}  t
+     * @return {clay.Quaternion}
+     */
+    lerp: function (a, b, t) {
+        glmatrix_quat.lerp(this.array, a.array, b.array, t);
+        this._dirty = true;
+        return this;
     },
 
-    setUniform: function (_gl, type, symbol, value) {
-        var locationMap = this._locations;
-        var location = locationMap[symbol];
-        // Uniform is not existed in the shader
-        if (location === null || location === undefined) {
-            return false;
-        }
+    /**
+     * Alias for multiply
+     * @param  {clay.Quaternion} b
+     * @return {clay.Quaternion}
+     */
+    mul: function (b) {
+        glmatrix_quat.mul(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-        switch (type) {
-            case 'm4':
-                if (!(value instanceof Float32Array)) {
-                    // Use Float32Array is much faster than array when uniformMatrix4fv.
-                    for (var i = 0; i < value.length; i++) {
-                        tmpFloat32Array16[i] = value[i];
-                    }
-                    value = tmpFloat32Array16;
-                }
-                _gl.uniformMatrix4fv(location, false, value);
-                break;
-            case '2i':
-                _gl.uniform2i(location, value[0], value[1]);
-                break;
-            case '2f':
-                _gl.uniform2f(location, value[0], value[1]);
-                break;
-            case '3i':
-                _gl.uniform3i(location, value[0], value[1], value[2]);
-                break;
-            case '3f':
-                _gl.uniform3f(location, value[0], value[1], value[2]);
-                break;
-            case '4i':
-                _gl.uniform4i(location, value[0], value[1], value[2], value[3]);
-                break;
-            case '4f':
-                _gl.uniform4f(location, value[0], value[1], value[2], value[3]);
-                break;
-            case '1i':
-                _gl.uniform1i(location, value);
-                break;
-            case '1f':
-                _gl.uniform1f(location, value);
-                break;
-            case '1fv':
-                _gl.uniform1fv(location, value);
-                break;
-            case '1iv':
-                _gl.uniform1iv(location, value);
-                break;
-            case '2iv':
-                _gl.uniform2iv(location, value);
-                break;
-            case '2fv':
-                _gl.uniform2fv(location, value);
-                break;
-            case '3iv':
-                _gl.uniform3iv(location, value);
-                break;
-            case '3fv':
-                _gl.uniform3fv(location, value);
-                break;
-            case '4iv':
-                _gl.uniform4iv(location, value);
-                break;
-            case '4fv':
-                _gl.uniform4fv(location, value);
-                break;
-            case 'm2':
-            case 'm2v':
-                _gl.uniformMatrix2fv(location, false, value);
-                break;
-            case 'm3':
-            case 'm3v':
-                _gl.uniformMatrix3fv(location, false, value);
-                break;
-            case 'm4v':
-                // Raw value
-                if (Array.isArray(value) && Array.isArray(value[0])) {
-                    var array = new core_vendor.Float32Array(value.length * 16);
-                    var cursor = 0;
-                    for (var i = 0; i < value.length; i++) {
-                        var item = value[i];
-                        for (var j = 0; j < 16; j++) {
-                            array[cursor++] = item[j];
-                        }
-                    }
-                    _gl.uniformMatrix4fv(location, false, array);
-                }
-                else {   // ArrayBufferView
-                    _gl.uniformMatrix4fv(location, false, value);
-                }
-                break;
-        }
-        return true;
+    /**
+     * Alias for multiplyLeft
+     * @param  {clay.Quaternion} a
+     * @return {clay.Quaternion}
+     */
+    mulLeft: function (a) {
+        glmatrix_quat.multiply(this.array, a.array, this.array);
+        this._dirty = true;
+        return this;
     },
 
-    setUniformOfSemantic: function (_gl, semantic, val) {
-        var semanticInfo = this.uniformSemantics[semantic];
-        if (semanticInfo) {
-            return this.setUniform(_gl, semanticInfo.type, semanticInfo.symbol, val);
-        }
-        return false;
+    /**
+     * Mutiply self and b
+     * @param  {clay.Quaternion} b
+     * @return {clay.Quaternion}
+     */
+    multiply: function (b) {
+        glmatrix_quat.multiply(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
     },
 
-    // Used for creating VAO
-    // Enable the attributes passed in and disable the rest
-    // Example Usage:
-    // enableAttributes(renderer, ["position", "texcoords"])
-    enableAttributes: function (renderer, attribList, vao) {
-        var _gl = renderer.gl;
-        var program = this._program;
+    /**
+     * Mutiply a and self
+     * Quaternion mutiply is not commutative, so the result of mutiplyLeft is different with multiply.
+     * @param  {clay.Quaternion} a
+     * @return {clay.Quaternion}
+     */
+    multiplyLeft: function (a) {
+        glmatrix_quat.multiply(this.array, a.array, this.array);
+        this._dirty = true;
+        return this;
+    },
 
-        var locationMap = this._locations;
+    /**
+     * Normalize self
+     * @return {clay.Quaternion}
+     */
+    normalize: function () {
+        glmatrix_quat.normalize(this.array, this.array);
+        this._dirty = true;
+        return this;
+    },
 
-        var enabledAttributeListInContext;
-        if (vao) {
-            enabledAttributeListInContext = vao.__enabledAttributeList;
-        }
-        else {
-            enabledAttributeListInContext = enabledAttributeList[renderer.__uid__];
-        }
-        if (!enabledAttributeListInContext) {
-            // In vertex array object context
-            // PENDING Each vao object needs to enable attributes again?
-            if (vao) {
-                enabledAttributeListInContext
-                    = vao.__enabledAttributeList
-                    = [];
-            }
-            else {
-                enabledAttributeListInContext
-                    = enabledAttributeList[renderer.__uid__]
-                    = [];
-            }
-        }
-        var locationList = [];
-        for (var i = 0; i < attribList.length; i++) {
-            var symbol = attribList[i];
-            if (!this.attributes[symbol]) {
-                locationList[i] = -1;
-                continue;
-            }
-            var location = locationMap[symbol];
-            if (location == null) {
-                location = _gl.getAttribLocation(program, symbol);
-                // Attrib location is a number from 0 to ...
-                if (location === -1) {
-                    locationList[i] = -1;
-                    continue;
-                }
-                locationMap[symbol] = location;
-            }
-            locationList[i] = location;
+    /**
+     * Rotate self by a given radian about X axis
+     * @param {number} rad
+     * @return {clay.Quaternion}
+     */
+    rotateX: function (rad) {
+        glmatrix_quat.rotateX(this.array, this.array, rad);
+        this._dirty = true;
+        return this;
+    },
 
-            if (!enabledAttributeListInContext[location]) {
-                enabledAttributeListInContext[location] = SHADER_STATE_TO_ENABLE;
-            }
-            else {
-                enabledAttributeListInContext[location] = SHADER_STATE_KEEP_ENABLE;
-            }
-        }
+    /**
+     * Rotate self by a given radian about Y axis
+     * @param {number} rad
+     * @return {clay.Quaternion}
+     */
+    rotateY: function (rad) {
+        glmatrix_quat.rotateY(this.array, this.array, rad);
+        this._dirty = true;
+        return this;
+    },
 
-        for (var i = 0; i < enabledAttributeListInContext.length; i++) {
-            switch(enabledAttributeListInContext[i]){
-                case SHADER_STATE_TO_ENABLE:
-                    _gl.enableVertexAttribArray(i);
-                    enabledAttributeListInContext[i] = SHADER_STATE_PENDING;
-                    break;
-                case SHADER_STATE_KEEP_ENABLE:
-                    enabledAttributeListInContext[i] = SHADER_STATE_PENDING;
-                    break;
-                // Expired
-                case SHADER_STATE_PENDING:
-                    _gl.disableVertexAttribArray(i);
-                    enabledAttributeListInContext[i] = 0;
-                    break;
-            }
-        }
+    /**
+     * Rotate self by a given radian about Z axis
+     * @param {number} rad
+     * @return {clay.Quaternion}
+     */
+    rotateZ: function (rad) {
+        glmatrix_quat.rotateZ(this.array, this.array, rad);
+        this._dirty = true;
+        return this;
+    },
 
-        return locationList;
+    /**
+     * Sets self to represent the shortest rotation from Vector3 a to Vector3 b.
+     * a and b needs to be normalized
+     * @param  {clay.Vector3} a
+     * @param  {clay.Vector3} b
+     * @return {clay.Quaternion}
+     */
+    rotationTo: function (a, b) {
+        glmatrix_quat.rotationTo(this.array, a.array, b.array);
+        this._dirty = true;
+        return this;
+    },
+    /**
+     * Sets self with values corresponding to the given axes
+     * @param {clay.Vector3} view
+     * @param {clay.Vector3} right
+     * @param {clay.Vector3} up
+     * @return {clay.Quaternion}
+     */
+    setAxes: function (view, right, up) {
+        glmatrix_quat.setAxes(this.array, view.array, right.array, up.array);
+        this._dirty = true;
+        return this;
     },
 
-    getAttribLocation: function (_gl, symbol) {
-        var locationMap = this._locations;
+    /**
+     * Sets self with a rotation axis and rotation angle
+     * @param {clay.Vector3} axis
+     * @param {number} rad
+     * @return {clay.Quaternion}
+     */
+    setAxisAngle: function (axis, rad) {
+        glmatrix_quat.setAxisAngle(this.array, axis.array, rad);
+        this._dirty = true;
+        return this;
+    },
+    /**
+     * Perform spherical linear interpolation between a and b
+     * @param  {clay.Quaternion} a
+     * @param  {clay.Quaternion} b
+     * @param  {number} t
+     * @return {clay.Quaternion}
+     */
+    slerp: function (a, b, t) {
+        glmatrix_quat.slerp(this.array, a.array, b.array, t);
+        this._dirty = true;
+        return this;
+    },
 
-        var location = locationMap[symbol];
-        if (location == null) {
-            location = _gl.getAttribLocation(this._program, symbol);
-            locationMap[symbol] = location;
-        }
+    /**
+     * Alias for squaredLength
+     * @return {number}
+     */
+    sqrLen: function () {
+        return glmatrix_quat.sqrLen(this.array);
+    },
 
-        return location;
+    /**
+     * Squared length of self
+     * @return {number}
+     */
+    squaredLength: function () {
+        return glmatrix_quat.squaredLength(this.array);
     },
 
-    buildProgram: function (_gl, shader, vertexShaderCode, fragmentShaderCode) {
-        var vertexShader = _gl.createShader(_gl.VERTEX_SHADER);
-        var program = _gl.createProgram();
+    /**
+     * Set from euler
+     * @param {clay.Vector3} v
+     * @param {String} order
+     */
+    fromEuler: function (v, order) {
+        return Quaternion.fromEuler(this, v, order);
+    },
 
-        _gl.shaderSource(vertexShader, vertexShaderCode);
-        _gl.compileShader(vertexShader);
+    toString: function () {
+        return '[' + Array.prototype.join.call(this.array, ',') + ']';
+    },
 
-        var fragmentShader = _gl.createShader(_gl.FRAGMENT_SHADER);
-        _gl.shaderSource(fragmentShader, fragmentShaderCode);
-        _gl.compileShader(fragmentShader);
+    toArray: function () {
+        return Array.prototype.slice.call(this.array);
+    }
+};
 
-        var msg = checkShaderErrorMsg(_gl, vertexShader, vertexShaderCode);
-        if (msg) {
-            return msg;
-        }
-        msg = checkShaderErrorMsg(_gl, fragmentShader, fragmentShaderCode);
-        if (msg) {
-            return msg;
-        }
+var Quaternion_defineProperty = Object.defineProperty;
+// Getter and Setter
+if (Quaternion_defineProperty) {
 
-        _gl.attachShader(program, vertexShader);
-        _gl.attachShader(program, fragmentShader);
-        // Force the position bind to location 0;
-        if (shader.attributeSemantics['POSITION']) {
-            _gl.bindAttribLocation(program, 0, shader.attributeSemantics['POSITION'].symbol);
-        }
-        else {
-            // Else choose an attribute and bind to location 0;
-            var keys = Object.keys(this.attributes);
-            _gl.bindAttribLocation(program, 0, keys[0]);
+    var Quaternion_proto = Quaternion.prototype;
+    /**
+     * @name x
+     * @type {number}
+     * @memberOf clay.Quaternion
+     * @instance
+     */
+    Quaternion_defineProperty(Quaternion_proto, 'x', {
+        get: function () {
+            return this.array[0];
+        },
+        set: function (value) {
+            this.array[0] = value;
+            this._dirty = true;
         }
+    });
 
-        _gl.linkProgram(program);
-
-        _gl.deleteShader(vertexShader);
-        _gl.deleteShader(fragmentShader);
-
-        this._program = program;
-
-        // Save code.
-        this.vertexCode = vertexShaderCode;
-        this.fragmentCode = fragmentShaderCode;
-
-        if (!_gl.getProgramParameter(program, _gl.LINK_STATUS)) {
-            return 'Could not link program\n' + _gl.getProgramInfoLog(program);
+    /**
+     * @name y
+     * @type {number}
+     * @memberOf clay.Quaternion
+     * @instance
+     */
+    Quaternion_defineProperty(Quaternion_proto, 'y', {
+        get: function () {
+            return this.array[1];
+        },
+        set: function (value) {
+            this.array[1] = value;
+            this._dirty = true;
         }
+    });
 
-        // Cache uniform locations
-        for (var i = 0; i < shader.uniforms.length; i++) {
-            var uniformSymbol = shader.uniforms[i];
-            this._locations[uniformSymbol] = _gl.getUniformLocation(program, uniformSymbol);
+    /**
+     * @name z
+     * @type {number}
+     * @memberOf clay.Quaternion
+     * @instance
+     */
+    Quaternion_defineProperty(Quaternion_proto, 'z', {
+        get: function () {
+            return this.array[2];
+        },
+        set: function (value) {
+            this.array[2] = value;
+            this._dirty = true;
         }
+    });
 
-    }
-});
+    /**
+     * @name w
+     * @type {number}
+     * @memberOf clay.Quaternion
+     * @instance
+     */
+    Quaternion_defineProperty(Quaternion_proto, 'w', {
+        get: function () {
+            return this.array[3];
+        },
+        set: function (value) {
+            this.array[3] = value;
+            this._dirty = true;
+        }
+    });
+}
 
-/* harmony default export */ const gpu_GLProgram = (GLProgram);
-;// CONCATENATED MODULE: ./node_modules/claygl/src/gpu/ProgramManager.js
+// Supply methods that are not in place
 
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} a
+ * @param  {clay.Quaternion} b
+ * @return {clay.Quaternion}
+ */
+Quaternion.add = function (out, a, b) {
+    glmatrix_quat.add(out.array, a.array, b.array);
+    out._dirty = true;
+    return out;
+};
 
-var loopRegex = /for\s*?\(int\s*?_idx_\s*\=\s*([\w-]+)\;\s*_idx_\s*<\s*([\w-]+);\s*_idx_\s*\+\+\s*\)\s*\{\{([\s\S]+?)(?=\}\})\}\}/g;
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {number}     x
+ * @param  {number}     y
+ * @param  {number}     z
+ * @param  {number}     w
+ * @return {clay.Quaternion}
+ */
+Quaternion.set = function (out, x, y, z, w) {
+    glmatrix_quat.set(out.array, x, y, z, w);
+    out._dirty = true;
+};
 
-function unrollLoop(shaderStr, defines, lightsNumbers) {
-    // Loop unroll from three.js, https://github.com/mrdoob/three.js/blob/master/src/renderers/webgl/WebGLProgram.js#L175
-    // In some case like shadowMap in loop use 'i' to index value much slower.
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} b
+ * @return {clay.Quaternion}
+ */
+Quaternion.copy = function (out, b) {
+    glmatrix_quat.copy(out.array, b.array);
+    out._dirty = true;
+    return out;
+};
 
-    // Loop use _idx_ and increased with _idx_++ will be unrolled
-    // Use {{ }} to match the pair so the if statement will not be affected
-    // Write like following
-    // for (int _idx_ = 0; _idx_ < 4; _idx_++) {{
-    //     vec3 color = texture2D(textures[_idx_], uv).rgb;
-    // }}
-    function replace(match, start, end, snippet) {
-        var unroll = '';
-        // Try to treat as define
-        if (isNaN(start)) {
-            if (start in defines) {
-                start = defines[start];
-            }
-            else {
-                start = lightNumberDefines[start];
-            }
-        }
-        if (isNaN(end)) {
-            if (end in defines) {
-                end = defines[end];
-            }
-            else {
-                end = lightNumberDefines[end];
-            }
-        }
-        // TODO Error checking
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} a
+ * @return {clay.Quaternion}
+ */
+Quaternion.calculateW = function (out, a) {
+    glmatrix_quat.calculateW(out.array, a.array);
+    out._dirty = true;
+    return out;
+};
 
-        for (var idx = parseInt(start); idx < parseInt(end); idx++) {
-            // PENDING Add scope?
-            unroll += '{'
-                + snippet
-                    .replace(/float\s*\(\s*_idx_\s*\)/g, idx.toFixed(1))
-                    .replace(/_idx_/g, idx)
-            + '}';
-        }
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} a
+ * @return {clay.Quaternion}
+ */
+Quaternion.conjugate = function (out, a) {
+    glmatrix_quat.conjugate(out.array, a.array);
+    out._dirty = true;
+    return out;
+};
 
-        return unroll;
-    }
+/**
+ * @param  {clay.Quaternion} out
+ * @return {clay.Quaternion}
+ */
+Quaternion.identity = function (out) {
+    glmatrix_quat.identity(out.array);
+    out._dirty = true;
+    return out;
+};
 
-    var lightNumberDefines = {};
-    for (var lightType in lightsNumbers) {
-        lightNumberDefines[lightType + '_COUNT'] = lightsNumbers[lightType];
-    }
-    return shaderStr.replace(loopRegex, replace);
-}
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} a
+ * @return {clay.Quaternion}
+ */
+Quaternion.invert = function (out, a) {
+    glmatrix_quat.invert(out.array, a.array);
+    out._dirty = true;
+    return out;
+};
 
-function ProgramManager_getDefineCode(defines, lightsNumbers, enabledTextures) {
-    var defineStr = [];
-    if (lightsNumbers) {
-        for (var lightType in lightsNumbers) {
-            var count = lightsNumbers[lightType];
-            if (count > 0) {
-                defineStr.push('#define ' + lightType.toUpperCase() + '_COUNT ' + count);
-            }
-        }
-    }
-    if (enabledTextures) {
-        for (var i = 0; i < enabledTextures.length; i++) {
-            var symbol = enabledTextures[i];
-            defineStr.push('#define ' + symbol.toUpperCase() + '_ENABLED');
-        }
-    }
-    // Custom Defines
-    for (var symbol in defines) {
-        var value = defines[symbol];
-        if (value === null) {
-            defineStr.push('#define ' + symbol);
-        }
-        else{
-            defineStr.push('#define ' + symbol + ' ' + value.toString());
-        }
-    }
-    return defineStr.join('\n');
-}
+/**
+ * @param  {clay.Quaternion} a
+ * @param  {clay.Quaternion} b
+ * @return {number}
+ */
+Quaternion.dot = function (a, b) {
+    return glmatrix_quat.dot(a.array, b.array);
+};
 
-function getExtensionCode(exts) {
-    // Extension declaration must before all non-preprocessor codes
-    // TODO vertex ? extension enum ?
-    var extensionStr = [];
-    for (var i = 0; i < exts.length; i++) {
-        extensionStr.push('#extension GL_' + exts[i] + ' : enable');
-    }
-    return extensionStr.join('\n');
-}
+/**
+ * @param  {clay.Quaternion} a
+ * @return {number}
+ */
+Quaternion.len = function (a) {
+    return glmatrix_quat.length(a.array);
+};
 
-function getPrecisionCode(precision) {
-    return ['precision', precision, 'float'].join(' ') + ';\n'
-        + ['precision', precision, 'int'].join(' ') + ';\n'
-        // depth texture may have precision problem on iOS device.
-        + ['precision', precision, 'sampler2D'].join(' ') + ';\n';
-}
+// Quaternion.length = Quaternion.len;
 
-function ProgramManager(renderer) {
-    this._renderer = renderer;
-    this._cache = {};
-}
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} a
+ * @param  {clay.Quaternion} b
+ * @param  {number}     t
+ * @return {clay.Quaternion}
+ */
+Quaternion.lerp = function (out, a, b, t) {
+    glmatrix_quat.lerp(out.array, a.array, b.array, t);
+    out._dirty = true;
+    return out;
+};
 
-ProgramManager.prototype.getProgram = function (renderable, material, scene) {
-    var cache = this._cache;
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} a
+ * @param  {clay.Quaternion} b
+ * @param  {number}     t
+ * @return {clay.Quaternion}
+ */
+Quaternion.slerp = function (out, a, b, t) {
+    glmatrix_quat.slerp(out.array, a.array, b.array, t);
+    out._dirty = true;
+    return out;
+};
 
-    var isSkinnedMesh = renderable.isSkinnedMesh && renderable.isSkinnedMesh();
-    var isInstancedMesh = renderable.isInstancedMesh && renderable.isInstancedMesh();
-    var key = 's' + material.shader.shaderID + 'm' + material.getProgramKey();
-    if (scene) {
-        key += 'se' + scene.getProgramKey(renderable.lightGroup);
-    }
-    if (isSkinnedMesh) {
-        key += ',sk' + renderable.joints.length;
-    }
-    if (isInstancedMesh) {
-        key += ',is';
-    }
-    var program = cache[key];
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} a
+ * @param  {clay.Quaternion} b
+ * @return {clay.Quaternion}
+ */
+Quaternion.mul = function (out, a, b) {
+    glmatrix_quat.multiply(out.array, a.array, b.array);
+    out._dirty = true;
+    return out;
+};
 
-    if (program) {
-        return program;
-    }
+/**
+ * @function
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} a
+ * @param  {clay.Quaternion} b
+ * @return {clay.Quaternion}
+ */
+Quaternion.multiply = Quaternion.mul;
 
-    var lightsNumbers = scene ? scene.getLightsNumbers(renderable.lightGroup) : {};
-    var renderer = this._renderer;
-    var _gl = renderer.gl;
-    var enabledTextures = material.getEnabledTextures();
-    var extraDefineCode = '';
-    if (isSkinnedMesh) {
-        var skinDefines = {
-            SKINNING: null,
-            JOINT_COUNT: renderable.joints.length
-        };
-        if (renderable.joints.length > renderer.getMaxJointNumber()) {
-            skinDefines.USE_SKIN_MATRICES_TEXTURE = null;
-        }
-        // TODO Add skinning code?
-        extraDefineCode += '\n' + ProgramManager_getDefineCode(skinDefines) + '\n';
-    }
-    if (isInstancedMesh) {
-        extraDefineCode += '\n#define INSTANCING\n';
-    }
-    // TODO Optimize key generation
-    // VERTEX
-    var vertexDefineStr = extraDefineCode + ProgramManager_getDefineCode(material.vertexDefines, lightsNumbers, enabledTextures);
-    // FRAGMENT
-    var fragmentDefineStr = extraDefineCode + ProgramManager_getDefineCode(material.fragmentDefines, lightsNumbers, enabledTextures);
-
-    var vertexCode = vertexDefineStr + '\n' + material.shader.vertex;
-
-    var extensions = [
-        'OES_standard_derivatives',
-        'EXT_shader_texture_lod'
-    ].filter(function (ext) {
-        return renderer.getGLExtension(ext) != null;
-    });
-
-    if (extensions.indexOf('EXT_shader_texture_lod') >= 0) {
-        fragmentDefineStr += '\n#define SUPPORT_TEXTURE_LOD';
-    }
-    if (extensions.indexOf('OES_standard_derivatives') >= 0) {
-        fragmentDefineStr += '\n#define SUPPORT_STANDARD_DERIVATIVES';
-    }
-
-    var fragmentCode = getExtensionCode(extensions) + '\n'
-        + getPrecisionCode(material.precision) + '\n'
-        + fragmentDefineStr + '\n'
-        + material.shader.fragment;
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} a
+ * @param  {number}     rad
+ * @return {clay.Quaternion}
+ */
+Quaternion.rotateX = function (out, a, rad) {
+    glmatrix_quat.rotateX(out.array, a.array, rad);
+    out._dirty = true;
+    return out;
+};
 
-    var finalVertexCode = unrollLoop(vertexCode, material.vertexDefines, lightsNumbers);
-    var finalFragmentCode = unrollLoop(fragmentCode, material.fragmentDefines, lightsNumbers);
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} a
+ * @param  {number}     rad
+ * @return {clay.Quaternion}
+ */
+Quaternion.rotateY = function (out, a, rad) {
+    glmatrix_quat.rotateY(out.array, a.array, rad);
+    out._dirty = true;
+    return out;
+};
 
-    var program = new gpu_GLProgram();
-    program.uniformSemantics = material.shader.uniformSemantics;
-    program.attributes = material.shader.attributes;
-    var errorMsg = program.buildProgram(_gl, material.shader, finalVertexCode, finalFragmentCode);
-    program.__error = errorMsg;
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} a
+ * @param  {number}     rad
+ * @return {clay.Quaternion}
+ */
+Quaternion.rotateZ = function (out, a, rad) {
+    glmatrix_quat.rotateZ(out.array, a.array, rad);
+    out._dirty = true;
+    return out;
+};
 
-    cache[key] = program;
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Vector3}    axis
+ * @param  {number}     rad
+ * @return {clay.Quaternion}
+ */
+Quaternion.setAxisAngle = function (out, axis, rad) {
+    glmatrix_quat.setAxisAngle(out.array, axis.array, rad);
+    out._dirty = true;
+    return out;
+};
 
-    return program;
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Quaternion} a
+ * @return {clay.Quaternion}
+ */
+Quaternion.normalize = function (out, a) {
+    glmatrix_quat.normalize(out.array, a.array);
+    out._dirty = true;
+    return out;
 };
 
-/* harmony default export */ const gpu_ProgramManager = (ProgramManager);
-;// CONCATENATED MODULE: ./node_modules/claygl/src/Shader.js
 /**
- * Mainly do the parse and compile of shader string
- * Support shader code chunk import and export
- * Support shader semantics
- * http://www.nvidia.com/object/using_sas.html
- * https://github.com/KhronosGroup/collada2json/issues/45
+ * @param  {clay.Quaternion} a
+ * @return {number}
  */
+Quaternion.sqrLen = function (a) {
+    return glmatrix_quat.sqrLen(a.array);
+};
 
+/**
+ * @function
+ * @param  {clay.Quaternion} a
+ * @return {number}
+ */
+Quaternion.squaredLength = Quaternion.sqrLen;
 
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Matrix3}    m
+ * @return {clay.Quaternion}
+ */
+Quaternion.fromMat3 = function (out, m) {
+    glmatrix_quat.fromMat3(out.array, m.array);
+    out._dirty = true;
+    return out;
+};
 
-var uniformRegex = /uniform\s+(bool|float|int|vec2|vec3|vec4|ivec2|ivec3|ivec4|mat2|mat3|mat4|sampler2D|samplerCube)\s+([\s\S]*?);/g;
-var attributeRegex = /attribute\s+(float|int|vec2|vec3|vec4)\s+([\s\S]*?);/g;
-// Only parse number define.
-var defineRegex = /#define\s+(\w+)?(\s+[\d-.]+)?\s*;?\s*\n/g;
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Vector3}    view
+ * @param  {clay.Vector3}    right
+ * @param  {clay.Vector3}    up
+ * @return {clay.Quaternion}
+ */
+Quaternion.setAxes = function (out, view, right, up) {
+    glmatrix_quat.setAxes(out.array, view.array, right.array, up.array);
+    out._dirty = true;
+    return out;
+};
 
-var uniformTypeMap = {
-    'bool': '1i',
-    'int': '1i',
-    'sampler2D': 't',
-    'samplerCube': 't',
-    'float': '1f',
-    'vec2': '2f',
-    'vec3': '3f',
-    'vec4': '4f',
-    'ivec2': '2i',
-    'ivec3': '3i',
-    'ivec4': '4i',
-    'mat2': 'm2',
-    'mat3': 'm3',
-    'mat4': 'm4'
+/**
+ * @param  {clay.Quaternion} out
+ * @param  {clay.Vector3}    a
+ * @param  {clay.Vector3}    b
+ * @return {clay.Quaternion}
+ */
+Quaternion.rotationTo = function (out, a, b) {
+    glmatrix_quat.rotationTo(out.array, a.array, b.array);
+    out._dirty = true;
+    return out;
 };
 
-function createZeroArray(len) {
-    var arr = [];
-    for (var i = 0; i < len; i++) {
-        arr[i] = 0;
-    }
-    return arr;
-}
+/**
+ * Set quaternion from euler
+ * @param {clay.Quaternion} out
+ * @param {clay.Vector3} v
+ * @param {String} order
+ */
+Quaternion.fromEuler = function (out, v, order) {
 
-var uniformValueConstructor = {
-    'bool': function () { return true; },
-    'int': function () { return 0; },
-    'float': function () { return 0; },
-    'sampler2D': function () { return null; },
-    'samplerCube': function () { return null; },
+    out._dirty = true;
 
-    'vec2': function () { return createZeroArray(2); },
-    'vec3': function () { return createZeroArray(3); },
-    'vec4': function () { return createZeroArray(4); },
+    v = v.array;
+    var target = out.array;
+    var c1 = Math.cos(v[0] / 2);
+    var c2 = Math.cos(v[1] / 2);
+    var c3 = Math.cos(v[2] / 2);
+    var s1 = Math.sin(v[0] / 2);
+    var s2 = Math.sin(v[1] / 2);
+    var s3 = Math.sin(v[2] / 2);
 
-    'ivec2': function () { return createZeroArray(2); },
-    'ivec3': function () { return createZeroArray(3); },
-    'ivec4': function () { return createZeroArray(4); },
+    var order = (order || 'XYZ').toUpperCase();
 
-    'mat2': function () { return createZeroArray(4); },
-    'mat3': function () { return createZeroArray(9); },
-    'mat4': function () { return createZeroArray(16); },
+    // http://www.mathworks.com/matlabcentral/fileexchange/
+    //  20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
+    //  content/SpinCalc.m
 
-    'array': function () { return []; }
+    switch (order) {
+        case 'XYZ':
+            target[0] = s1 * c2 * c3 + c1 * s2 * s3;
+            target[1] = c1 * s2 * c3 - s1 * c2 * s3;
+            target[2] = c1 * c2 * s3 + s1 * s2 * c3;
+            target[3] = c1 * c2 * c3 - s1 * s2 * s3;
+            break;
+        case 'YXZ':
+            target[0] = s1 * c2 * c3 + c1 * s2 * s3;
+            target[1] = c1 * s2 * c3 - s1 * c2 * s3;
+            target[2] = c1 * c2 * s3 - s1 * s2 * c3;
+            target[3] = c1 * c2 * c3 + s1 * s2 * s3;
+            break;
+        case 'ZXY':
+            target[0] = s1 * c2 * c3 - c1 * s2 * s3;
+            target[1] = c1 * s2 * c3 + s1 * c2 * s3;
+            target[2] = c1 * c2 * s3 + s1 * s2 * c3;
+            target[3] = c1 * c2 * c3 - s1 * s2 * s3;
+            break;
+        case 'ZYX':
+            target[0] = s1 * c2 * c3 - c1 * s2 * s3;
+            target[1] = c1 * s2 * c3 + s1 * c2 * s3;
+            target[2] = c1 * c2 * s3 - s1 * s2 * c3;
+            target[3] = c1 * c2 * c3 + s1 * s2 * s3;
+            break;
+        case 'YZX':
+            target[0] = s1 * c2 * c3 + c1 * s2 * s3;
+            target[1] = c1 * s2 * c3 + s1 * c2 * s3;
+            target[2] = c1 * c2 * s3 - s1 * s2 * c3;
+            target[3] = c1 * c2 * c3 - s1 * s2 * s3;
+            break;
+        case 'XZY':
+            target[0] = s1 * c2 * c3 - c1 * s2 * s3;
+            target[1] = c1 * s2 * c3 - s1 * c2 * s3;
+            target[2] = c1 * c2 * s3 + s1 * s2 * c3;
+            target[3] = c1 * c2 * c3 + s1 * s2 * s3;
+            break;
+    }
 };
 
-var attributeSemantics = [
-    'POSITION',
-    'NORMAL',
-    'BINORMAL',
-    'TANGENT',
-    'TEXCOORD',
-    'TEXCOORD_0',
-    'TEXCOORD_1',
-    'COLOR',
-    // Skinning
-    // https://github.com/KhronosGroup/glTF/blob/master/specification/README.md#semantics
-    'JOINT',
-    'WEIGHT'
-];
-var uniformSemantics = [
-    'SKIN_MATRIX',
-    // Information about viewport
-    'VIEWPORT_SIZE',
-    'VIEWPORT',
-    'DEVICEPIXELRATIO',
-    // Window size for window relative coordinate
-    // https://www.opengl.org/sdk/docs/man/html/gl_FragCoord.xhtml
-    'WINDOW_SIZE',
-    // Infomation about camera
-    'NEAR',
-    'FAR',
-    // Time
-    'TIME'
-];
-var matrixSemantics = [
-    'WORLD',
-    'VIEW',
-    'PROJECTION',
-    'WORLDVIEW',
-    'VIEWPROJECTION',
-    'WORLDVIEWPROJECTION',
-    'WORLDINVERSE',
-    'VIEWINVERSE',
-    'PROJECTIONINVERSE',
-    'WORLDVIEWINVERSE',
-    'VIEWPROJECTIONINVERSE',
-    'WORLDVIEWPROJECTIONINVERSE',
-    'WORLDTRANSPOSE',
-    'VIEWTRANSPOSE',
-    'PROJECTIONTRANSPOSE',
-    'WORLDVIEWTRANSPOSE',
-    'VIEWPROJECTIONTRANSPOSE',
-    'WORLDVIEWPROJECTIONTRANSPOSE',
-    'WORLDINVERSETRANSPOSE',
-    'VIEWINVERSETRANSPOSE',
-    'PROJECTIONINVERSETRANSPOSE',
-    'WORLDVIEWINVERSETRANSPOSE',
-    'VIEWPROJECTIONINVERSETRANSPOSE',
-    'WORLDVIEWPROJECTIONINVERSETRANSPOSE'
-];
-
-var attributeSizeMap = {
-    // WebGL does not support integer attributes
-    'vec4': 4,
-    'vec3': 3,
-    'vec2': 2,
-    'float': 1
-};
+/* harmony default export */ const math_Quaternion = (Quaternion);
 
+;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/mat4.js
 
-var shaderIDCache = {};
-var shaderCodeCache = {};
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
 
-function getShaderID(vertex, fragment) {
-    var key = 'vertex:' + vertex + 'fragment:' + fragment;
-    if (shaderIDCache[key]) {
-        return shaderIDCache[key];
-    }
-    var id = core_util.genGUID();
-    shaderIDCache[key] = id;
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
 
-    shaderCodeCache[id] = {
-        vertex: vertex,
-        fragment: fragment
-    };
+  * 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.
 
-    return id;
-}
+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 removeComment(code) {
-    return code.replace(/[ \t]*\/\/.*\n/g, '' )   // remove //
-        .replace(/[ \t]*\/\*[\s\S]*?\*\//g, '' ); // remove /* */
-}
 
-function logSyntaxError() {
-    console.error('Wrong uniform/attributes syntax');
-}
 
-function parseDeclarations(type, line) {
-    var speratorsRegexp = /[,=\(\):]/;
-    var tokens = line
-        // Convert `symbol: [1,2,3]` to `symbol: vec3(1,2,3)`
-        .replace(/:\s*\[\s*(.*)\s*\]/g, '=' + type + '($1)')
-        .replace(/\s+/g, '')
-        .split(/(?=[,=\(\):])/g);
+/**
+ * @class 4x4 Matrix
+ * @name mat4
+ */
 
-    var newTokens = [];
-    for (var i = 0; i < tokens.length; i++) {
-        if (tokens[i].match(speratorsRegexp)) {
-            newTokens.push(
-                tokens[i].charAt(0),
-                tokens[i].slice(1)
-            );
-        }
-        else {
-            newTokens.push(tokens[i]);
-        }
-    }
-    tokens = newTokens;
+var mat4 = {};
 
-    var TYPE_SYMBOL = 0;
-    var TYPE_ASSIGN = 1;
-    var TYPE_VEC = 2;
-    var TYPE_ARR = 3;
-    var TYPE_SEMANTIC = 4;
-    var TYPE_NORMAL = 5;
+/**
+ * Creates a new identity mat4
+ *
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.create = function() {
+    var out = new GLMAT_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;
+};
 
-    var opType = TYPE_SYMBOL;
-    var declarations = {};
-    var declarationValue = null;
-    var currentDeclaration;
+/**
+ * Creates a new mat4 initialized with values from an existing matrix
+ *
+ * @param {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.clone = function(a) {
+    var out = new GLMAT_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;
+};
 
-    addSymbol(tokens[0]);
+/**
+ * Copy the values from one mat4 to another
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.copy = function(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;
+};
 
-    function addSymbol(symbol) {
-        if (!symbol) {
-            logSyntaxError();
-        }
-        var arrResult = symbol.match(/\[(.*?)\]/);
-        currentDeclaration = symbol.replace(/\[(.*?)\]/, '');
-        declarations[currentDeclaration] = {};
-        if (arrResult) {
-            declarations[currentDeclaration].isArray = true;
-            declarations[currentDeclaration].arraySize = arrResult[1];
-        }
-    }
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+ */
+mat4.identity = function(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;
+};
 
-    for (var i = 1; i < tokens.length; i++) {
-        var token = tokens[i];
-        if (!token) {   // Empty token;
-            continue;
-        }
-        if (token === '=') {
-            if (opType !== TYPE_SYMBOL
-            && opType !== TYPE_ARR) {
-                logSyntaxError();
-                break;
-            }
-            opType = TYPE_ASSIGN;
+/**
+ * Transpose the values of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.transpose = function(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],
+            a12 = a[6], a13 = a[7],
+            a23 = a[11];
 
-            continue;
-        }
-        else if (token === ':') {
-            opType = TYPE_SEMANTIC;
+        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];
+    }
 
-            continue;
-        }
-        else if (token === ',') {
-            if (opType === TYPE_VEC) {
-                if (!(declarationValue instanceof Array)) {
-                    logSyntaxError();
-                    break;
-                }
-                declarationValue.push(+tokens[++i]);
-            }
-            else {
-                opType = TYPE_NORMAL;
-            }
+    return out;
+};
 
-            continue;
-        }
-        else if (token === ')') {
-            declarations[currentDeclaration].value = new core_vendor.Float32Array(declarationValue);
-            declarationValue = null;
-            opType = TYPE_NORMAL;
-            continue;
-        }
-        else if (token === '(') {
-            if (opType !== TYPE_VEC) {
-                logSyntaxError();
-                break;
-            }
-            if (!(declarationValue instanceof Array)) {
-                logSyntaxError();
-                break;
-            }
-            declarationValue.push(+tokens[++i]);
-            continue;
-        }
-        else if (token.indexOf('vec') >= 0) {
-            if (opType !== TYPE_ASSIGN
-            // Compatitable with old syntax `symbol: [1,2,3]`
-            && opType !== TYPE_SEMANTIC) {
-                logSyntaxError();
-                break;
-            }
-            opType = TYPE_VEC;
-            declarationValue = [];
-            continue;
-        }
-        else if (opType === TYPE_ASSIGN) {
-            if (type === 'bool') {
-                declarations[currentDeclaration].value = token === 'true';
-            }
-            else {
-                declarations[currentDeclaration].value = parseFloat(token);
-            }
-            declarationValue = null;
-            continue;
-        }
-        else if (opType === TYPE_SEMANTIC) {
-            var semantic = token;
-            if (attributeSemantics.indexOf(semantic) >= 0
-                || uniformSemantics.indexOf(semantic) >= 0
-                || matrixSemantics.indexOf(semantic) >= 0
-            ) {
-                declarations[currentDeclaration].semantic = semantic;
-            }
-            else if (semantic === 'ignore' || semantic === 'unconfigurable') {
-                declarations[currentDeclaration].ignore = true;
-            }
-            else {
-                // Try to parse as a default tvalue.
-                if (type === 'bool') {
-                    declarations[currentDeclaration].value = semantic === 'true';
-                }
-                else {
-                    declarations[currentDeclaration].value = parseFloat(semantic);
-                }
-            }
-            continue;
-        }
+/**
+ * Inverts a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.invert = function(out, a) {
+    var 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],
+        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
 
-        // treat as symbol.
-        addSymbol(token);
-        opType = TYPE_SYMBOL;
+        b00 = a00 * a11 - a01 * a10,
+        b01 = a00 * a12 - a02 * a10,
+        b02 = a00 * a13 - a03 * a10,
+        b03 = a01 * a12 - a02 * a11,
+        b04 = a01 * a13 - a03 * a11,
+        b05 = a02 * a13 - a03 * a12,
+        b06 = a20 * a31 - a21 * a30,
+        b07 = a20 * a32 - a22 * a30,
+        b08 = a20 * a33 - a23 * a30,
+        b09 = a21 * a32 - a22 * a31,
+        b10 = a21 * a33 - a23 * a31,
+        b11 = a22 * a33 - a23 * a32,
+
+        // Calculate the determinant
+        det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+    if (!det) {
+        return null;
     }
+    det = 1.0 / det;
 
-    return declarations;
-}
+    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;
+};
 
 /**
- * @constructor
- * @extends clay.core.Base
- * @alias clay.Shader
- * @param {string} vertex
- * @param {string} fragment
- * @example
- * // Create a phong shader
- * var shader = new clay.Shader(
- *      clay.Shader.source('clay.standard.vertex'),
- *      clay.Shader.source('clay.standard.fragment')
- * );
+ * Calculates the adjugate of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
  */
-function Shader(vertex, fragment) {
-    // First argument can be { vertex, fragment }
-    if (typeof vertex === 'object') {
-        fragment = vertex.fragment;
-        vertex = vertex.vertex;
-    }
+mat4.adjoint = function(out, a) {
+    var 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],
+        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
 
-    vertex = removeComment(vertex);
-    fragment = removeComment(fragment);
+    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;
+};
 
-    this._shaderID = getShaderID(vertex, fragment);
+/**
+ * Calculates the determinant of a mat4
+ *
+ * @param {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat4.determinant = function (a) {
+    var 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],
+        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
 
-    this._vertexCode = Shader.parseImport(vertex);
-    this._fragmentCode = Shader.parseImport(fragment);
+        b00 = a00 * a11 - a01 * a10,
+        b01 = a00 * a12 - a02 * a10,
+        b02 = a00 * a13 - a03 * a10,
+        b03 = a01 * a12 - a02 * a11,
+        b04 = a01 * a13 - a03 * a11,
+        b05 = a02 * a13 - a03 * a12,
+        b06 = a20 * a31 - a21 * a30,
+        b07 = a20 * a32 - a22 * a30,
+        b08 = a20 * a33 - a23 * a30,
+        b09 = a21 * a32 - a22 * a31,
+        b10 = a21 * a33 - a23 * a31,
+        b11 = a22 * a33 - a23 * a32;
 
-    /**
-     * @readOnly
-     */
-    this.attributeSemantics = {};
-    /**
-     * @readOnly
-     */
-    this.matrixSemantics = {};
-    /**
-     * @readOnly
-     */
-    this.uniformSemantics = {};
-    /**
-     * @readOnly
-     */
-    this.matrixSemanticKeys = [];
-    /**
-     * @readOnly
-     */
-    this.uniformTemplates = {};
-    /**
-     * @readOnly
-     */
-    this.attributes = {};
-    /**
-     * @readOnly
-     */
-    this.textures = {};
-    /**
-     * @readOnly
-     */
-    this.vertexDefines = {};
-    /**
-     * @readOnly
-     */
-    this.fragmentDefines = {};
+    // Calculate the determinant
+    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+};
 
-    this._parseAttributes();
-    this._parseUniforms();
-    this._parseDefines();
-}
+/**
+ * Multiplies two mat4's
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+mat4.multiply = function (out, a, b) {
+    var 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],
+        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
 
-Shader.prototype = {
+    // 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;
 
-    constructor: Shader,
+    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;
 
-    // Create a new uniform instance for material
-    createUniforms: function () {
-        var uniforms = {};
+    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;
 
-        for (var symbol in this.uniformTemplates){
-            var uniformTpl = this.uniformTemplates[symbol];
-            uniforms[symbol] = {
-                type: uniformTpl.type,
-                value: uniformTpl.value()
-            };
-        }
+    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;
+};
 
-        return uniforms;
-    },
+/**
+ * Multiplies two affine mat4's
+ * Add by https://github.com/pissang
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+mat4.multiplyAffine = function (out, a, b) {
+    var a00 = a[0], a01 = a[1], a02 = a[2],
+        a10 = a[4], a11 = a[5], a12 = a[6],
+        a20 = a[8], a21 = a[9], a22 = a[10],
+        a30 = a[12], a31 = a[13], a32 = a[14];
 
-    _parseImport: function () {
-        this._vertexCode = Shader.parseImport(this.vertex);
-        this._fragmentCode = Shader.parseImport(this.fragment);
-    },
+    // Cache only the current line of the second matrix
+    var b0  = b[0], b1 = b[1], b2 = b[2];
+    out[0] = b0*a00 + b1*a10 + b2*a20;
+    out[1] = b0*a01 + b1*a11 + b2*a21;
+    out[2] = b0*a02 + b1*a12 + b2*a22;
+    // out[3] = 0;
 
-    _addSemanticUniform: function (symbol, uniformType, semantic) {
-        // This case is only for SKIN_MATRIX
-        // TODO
-        if (attributeSemantics.indexOf(semantic) >= 0) {
-            this.attributeSemantics[semantic] = {
-                symbol: symbol,
-                type: uniformType
-            };
-        }
-        else if (matrixSemantics.indexOf(semantic) >= 0) {
-            var isTranspose = false;
-            var semanticNoTranspose = semantic;
-            if (semantic.match(/TRANSPOSE$/)) {
-                isTranspose = true;
-                semanticNoTranspose = semantic.slice(0, -9);
-            }
-            this.matrixSemantics[semantic] = {
-                symbol: symbol,
-                type: uniformType,
-                isTranspose: isTranspose,
-                semanticNoTranspose: semanticNoTranspose
-            };
-        }
-        else if (uniformSemantics.indexOf(semantic) >= 0) {
-            this.uniformSemantics[semantic] = {
-                symbol: symbol,
-                type: uniformType
-            };
-        }
-    },
+    b0 = b[4]; b1 = b[5]; b2 = b[6];
+    out[4] = b0*a00 + b1*a10 + b2*a20;
+    out[5] = b0*a01 + b1*a11 + b2*a21;
+    out[6] = b0*a02 + b1*a12 + b2*a22;
+    // out[7] = 0;
 
-    _addMaterialUniform: function (symbol, type, uniformType, defaultValueFunc, isArray, materialUniforms) {
-        materialUniforms[symbol] = {
-            type: uniformType,
-            value: isArray ? uniformValueConstructor['array'] : (defaultValueFunc || uniformValueConstructor[type]),
-            semantic: null
-        };
-    },
+    b0 = b[8]; b1 = b[9]; b2 = b[10];
+    out[8] = b0*a00 + b1*a10 + b2*a20;
+    out[9] = b0*a01 + b1*a11 + b2*a21;
+    out[10] = b0*a02 + b1*a12 + b2*a22;
+    // out[11] = 0;
 
-    _parseUniforms: function () {
-        var uniforms = {};
-        var self = this;
-        var shaderType = 'vertex';
-        this._uniformList = [];
+    b0 = b[12]; b1 = b[13]; b2 = b[14];
+    out[12] = b0*a00 + b1*a10 + b2*a20 + a30;
+    out[13] = b0*a01 + b1*a11 + b2*a21 + a31;
+    out[14] = b0*a02 + b1*a12 + b2*a22 + a32;
+    // out[15] = 1;
+    return out;
+};
 
-        this._vertexCode = this._vertexCode.replace(uniformRegex, _uniformParser);
-        shaderType = 'fragment';
-        this._fragmentCode = this._fragmentCode.replace(uniformRegex, _uniformParser);
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+mat4.mul = mat4.multiply;
 
-        self.matrixSemanticKeys = Object.keys(this.matrixSemantics);
+/**
+ * Alias for {@link mat4.multiplyAffine}
+ * @function
+ */
+mat4.mulAffine = mat4.multiplyAffine;
+/**
+ * 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
+ */
+mat4.translate = function (out, a, v) {
+    var x = v[0], y = v[1], z = v[2],
+        a00, a01, a02, a03,
+        a10, a11, a12, a13,
+        a20, a21, a22, a23;
 
-        function makeDefaultValueFunc(value) {
-            return value != null ? function () { return value; } : null;
-        }
+    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];
 
-        function _uniformParser(str, type, content) {
-            var declaredUniforms = parseDeclarations(type, content);
-            var uniformMainStr = [];
-            for (var symbol in declaredUniforms) {
+        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;
 
-                var uniformInfo = declaredUniforms[symbol];
-                var semantic = uniformInfo.semantic;
-                var tmpStr = symbol;
-                var uniformType = uniformTypeMap[type];
-                var defaultValueFunc = makeDefaultValueFunc(declaredUniforms[symbol].value);
-                if (declaredUniforms[symbol].isArray) {
-                    tmpStr += '[' + declaredUniforms[symbol].arraySize + ']';
-                    uniformType += 'v';
-                }
+        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];
+    }
 
-                uniformMainStr.push(tmpStr);
+    return out;
+};
 
-                self._uniformList.push(symbol);
+/**
+ * Scales the mat4 by the dimensions in the given vec3
+ *
+ * @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
+ **/
+mat4.scale = function(out, a, v) {
+    var x = v[0], y = v[1], z = v[2];
 
-                if (!uniformInfo.ignore) {
-                    if (type === 'sampler2D' || type === 'samplerCube') {
-                        // Texture is default disabled
-                        self.textures[symbol] = {
-                            shaderType: shaderType,
-                            type: type
-                        };
-                    }
-
-                    if (semantic) {
-                        // TODO Should not declare multiple symbols if have semantic.
-                        self._addSemanticUniform(symbol, uniformType, semantic);
-                    }
-                    else {
-                        self._addMaterialUniform(
-                            symbol, type, uniformType, defaultValueFunc,
-                            declaredUniforms[symbol].isArray, uniforms
-                        );
-                    }
-                }
-            }
-            return uniformMainStr.length > 0
-                ? 'uniform ' + type + ' ' + uniformMainStr.join(',') + ';\n' : '';
-        }
-
-        this.uniformTemplates = uniforms;
-    },
+    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;
+};
 
-    _parseAttributes: function () {
-        var attributes = {};
-        var self = this;
-        this._vertexCode = this._vertexCode.replace(attributeRegex, _attributeParser);
+/**
+ * Rotates a mat4 by the given angle
+ *
+ * @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
+ */
+mat4.rotate = function (out, a, rad, axis) {
+    var x = axis[0], y = axis[1], z = axis[2],
+        len = Math.sqrt(x * x + y * y + z * z),
+        s, c, t,
+        a00, a01, a02, a03,
+        a10, a11, a12, a13,
+        a20, a21, a22, a23,
+        b00, b01, b02,
+        b10, b11, b12,
+        b20, b21, b22;
 
-        function _attributeParser(str, type, content) {
-            var declaredAttributes = parseDeclarations(type, content);
+    if (Math.abs(len) < GLMAT_EPSILON) { return null; }
 
-            var size = attributeSizeMap[type] || 1;
-            var attributeMainStr = [];
-            for (var symbol in declaredAttributes) {
-                var semantic = declaredAttributes[symbol].semantic;
-                attributes[symbol] = {
-                    // TODO Can only be float
-                    type: 'float',
-                    size: size,
-                    semantic: semantic || null
-                };
-                // TODO Should not declare multiple symbols if have semantic.
-                if (semantic) {
-                    if (attributeSemantics.indexOf(semantic) < 0) {
-                        throw new Error('Unkown semantic "' + semantic + '"');
-                    }
-                    else {
-                        self.attributeSemantics[semantic] = {
-                            symbol: symbol,
-                            type: type
-                        };
-                    }
-                }
-                attributeMainStr.push(symbol);
-            }
+    len = 1 / len;
+    x *= len;
+    y *= len;
+    z *= len;
 
-            return 'attribute ' + type + ' ' + attributeMainStr.join(',') + ';\n';
-        }
+    s = Math.sin(rad);
+    c = Math.cos(rad);
+    t = 1 - c;
 
-        this.attributes = attributes;
-    },
+    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];
 
-    _parseDefines: function () {
-        var self = this;
-        var shaderType = 'vertex';
-        this._vertexCode = this._vertexCode.replace(defineRegex, _defineParser);
-        shaderType = 'fragment';
-        this._fragmentCode = this._fragmentCode.replace(defineRegex, _defineParser);
+    // 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;
 
-        function _defineParser(str, symbol, value) {
-            var defines = shaderType === 'vertex' ? self.vertexDefines : self.fragmentDefines;
-            if (!defines[symbol]) { // Haven't been defined by user
-                if (value === 'false') {
-                    defines[symbol] = false;
-                }
-                else if (value === 'true') {
-                    defines[symbol] = true;
-                }
-                else {
-                    defines[symbol] = value
-                        // If can parse to float
-                        ? (isNaN(parseFloat(value)) ? value.trim() : parseFloat(value))
-                        : null;
-                }
-            }
-            return '';
-        }
-    },
+    // 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;
 
-    /**
-     * Clone a new shader
-     * @return {clay.Shader}
-     */
-    clone: function () {
-        var code = shaderCodeCache[this._shaderID];
-        var shader = new Shader(code.vertex, code.fragment);
-        return shader;
+    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;
 };
 
-if (Object.defineProperty) {
-    Object.defineProperty(Shader.prototype, 'shaderID', {
-        get: function () {
-            return this._shaderID;
-        }
-    });
-    Object.defineProperty(Shader.prototype, 'vertex', {
-        get: function () {
-            return this._vertexCode;
-        }
-    });
-    Object.defineProperty(Shader.prototype, 'fragment', {
-        get: function () {
-            return this._fragmentCode;
-        }
-    });
-    Object.defineProperty(Shader.prototype, 'uniforms', {
-        get: function () {
-            return this._uniformList;
-        }
-    });
-}
+/**
+ * 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
+ */
+mat4.rotateX = function (out, a, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad),
+        a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7],
+        a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        a23 = a[11];
 
-var importRegex = /(@import)\s*([0-9a-zA-Z_\-\.]*)/g;
-Shader.parseImport = function (shaderStr) {
-    shaderStr = shaderStr.replace(importRegex, function (str, importSymbol, importName) {
-        var str = Shader.source(importName);
-        if (str) {
-            // Recursively parse
-            return Shader.parseImport(str);
-        }
-        else {
-            console.error('Shader chunk "' + importName + '" not existed in library');
-            return '';
-        }
-    });
-    return shaderStr;
-};
+    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];
+    }
 
-var exportRegex = /(@export)\s*([0-9a-zA-Z_\-\.]*)\s*\n([\s\S]*?)@end/g;
+    // 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;
+};
 
 /**
- * Import shader source
- * @param  {string} shaderStr
- * @memberOf clay.Shader
+ * 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
  */
-Shader['import'] = function (shaderStr) {
-    shaderStr.replace(exportRegex, function (str, exportSymbol, exportName, code) {
-        var code = code.replace(/(^[\s\t\xa0\u3000]+)|([\u3000\xa0\s\t]+\x24)/g, '');
-        if (code) {
-            var parts = exportName.split('.');
-            var obj = Shader.codes;
-            var i = 0;
-            var key;
-            while (i < parts.length - 1) {
-                key = parts[i++];
-                if (!obj[key]) {
-                    obj[key] = {};
-                }
-                obj = obj[key];
-            }
-            key = parts[i];
-            obj[key] = code;
-        }
-        return code;
-    });
+mat4.rotateY = function (out, a, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad),
+        a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3],
+        a20 = a[8],
+        a21 = a[9],
+        a22 = a[10],
+        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;
 };
 
 /**
- * Library to store all the loaded shader codes
- * @type {Object}
- * @readOnly
- * @memberOf clay.Shader
+ * 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
  */
-Shader.codes = {};
+mat4.rotateZ = function (out, a, rad) {
+    var s = Math.sin(rad),
+        c = Math.cos(rad),
+        a00 = a[0],
+        a01 = a[1],
+        a02 = a[2],
+        a03 = a[3],
+        a10 = a[4],
+        a11 = a[5],
+        a12 = a[6],
+        a13 = a[7];
 
-/**
- * Get shader source
- * @param  {string} name
- * @return {string}
- */
-Shader.source = function (name) {
-    var parts = name.split('.');
-    var obj = Shader.codes;
-    var i = 0;
-    while (obj && i < parts.length) {
-        var key = parts[i++];
-        obj = obj[key];
-    }
-    if (typeof obj !== 'string') {
-        // FIXME Use default instead
-        console.error('Shader "' + name + '" not existed in library');
-        return '';
+    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];
     }
-    return obj;
+
+    // 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;
 };
 
-/* harmony default export */ const src_Shader = (Shader);
+/**
+ * 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);
+ *     var 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
+ */
+mat4.fromRotationTranslation = function (out, q, v) {
+    // Quaternion math
+    var x = q[0], y = q[1], z = q[2], w = q[3],
+        x2 = x + x,
+        y2 = y + y,
+        z2 = z + z,
 
-;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/prez.glsl.js
-/* harmony default export */ const prez_glsl = ("@export clay.prez.vertex\nuniform mat4 WVP : WORLDVIEWPROJECTION;\nattribute vec3 pos : POSITION;\nattribute vec2 uv : TEXCOORD_0;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\n@import clay.chunk.skinning_header\n@import clay.chunk.instancing_header\nvarying vec2 v_Texcoord;\nvoid main()\n{\n vec4 P = vec4(pos, 1.0);\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n P = skinMatrixWS * P;\n#endif\n#ifdef INSTA [...]
+        xx = x * x2,
+        xy = x * y2,
+        xz = x * z2,
+        yy = y * y2,
+        yz = y * z2,
+        zz = z * z2,
+        wx = w * x2,
+        wy = w * y2,
+        wz = w * z2;
 
-;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/mat4.js
+    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;
 
-/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+    return out;
+};
 
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
+mat4.fromQuat = function (out, q) {
+    var x = q[0], y = q[1], z = q[2], w = q[3],
+        x2 = x + x,
+        y2 = y + y,
+        z2 = z + z,
 
-  * 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.
+        xx = x * x2,
+        yx = y * x2,
+        yy = y * y2,
+        zx = z * x2,
+        zy = z * y2,
+        zz = z * z2,
+        wx = w * x2,
+        wy = w * y2,
+        wz = w * z2;
 
-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. */
+    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;
 
-/**
- * @class 4x4 Matrix
- * @name mat4
- */
+    out[12] = 0;
+    out[13] = 0;
+    out[14] = 0;
+    out[15] = 1;
 
-var mat4 = {};
+    return out;
+};
 
 /**
- * Creates a new identity mat4
+ * Generates a frustum matrix with the given bounds
  *
- * @returns {mat4} a new 4x4 matrix
+ * @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
  */
-mat4.create = function() {
-    var out = new GLMAT_ARRAY_TYPE(16);
-    out[0] = 1;
+mat4.frustum = function (out, left, right, bottom, top, near, far) {
+    var rl = 1 / (right - left),
+        tb = 1 / (top - bottom),
+        nf = 1 / (near - far);
+    out[0] = (near * 2) * rl;
     out[1] = 0;
     out[2] = 0;
     out[3] = 0;
     out[4] = 0;
-    out[5] = 1;
+    out[5] = (near * 2) * tb;
     out[6] = 0;
     out[7] = 0;
-    out[8] = 0;
-    out[9] = 0;
-    out[10] = 1;
-    out[11] = 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] = 0;
-    out[15] = 1;
+    out[14] = (far * near * 2) * nf;
+    out[15] = 0;
     return out;
 };
 
 /**
- * Creates a new mat4 initialized with values from an existing matrix
+ * Generates a perspective projection matrix with the given bounds
  *
- * @param {mat4} a matrix to clone
- * @returns {mat4} a new 4x4 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
+ * @returns {mat4} out
  */
-mat4.clone = function(a) {
-    var out = new GLMAT_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
- */
-mat4.copy = function(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];
+mat4.perspective = function (out, fovy, aspect, near, far) {
+    var f = 1.0 / Math.tan(fovy / 2),
+        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;
 };
 
 /**
- * Set a mat4 to the identity matrix
+ * Generates a orthogonal projection matrix with the given bounds
  *
- * @param {mat4} out the receiving matrix
+ * @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
  */
-mat4.identity = function(out) {
-    out[0] = 1;
+mat4.ortho = function (out, left, right, bottom, top, near, far) {
+    var lr = 1 / (left - right),
+        bt = 1 / (bottom - top),
+        nf = 1 / (near - far);
+    out[0] = -2 * lr;
     out[1] = 0;
     out[2] = 0;
     out[3] = 0;
     out[4] = 0;
-    out[5] = 1;
+    out[5] = -2 * bt;
     out[6] = 0;
     out[7] = 0;
     out[8] = 0;
     out[9] = 0;
-    out[10] = 1;
+    out[10] = 2 * nf;
     out[11] = 0;
-    out[12] = 0;
-    out[13] = 0;
-    out[14] = 0;
+    out[12] = (left + right) * lr;
+    out[13] = (top + bottom) * bt;
+    out[14] = (far + near) * nf;
     out[15] = 1;
     return out;
 };
 
 /**
- * Transpose the values of a mat4
+ * Generates a look-at matrix with the given eye position, focal point, and up axis
  *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
+ * @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
  */
-mat4.transpose = function(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],
-            a12 = a[6], a13 = a[7],
-            a23 = a[11];
+mat4.lookAt = function (out, eye, center, up) {
+    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
+        eyex = eye[0],
+        eyey = eye[1],
+        eyez = eye[2],
+        upx = up[0],
+        upy = up[1],
+        upz = up[2],
+        centerx = center[0],
+        centery = center[1],
+        centerz = center[2];
 
-        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];
+    if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
+        Math.abs(eyey - centery) < GLMAT_EPSILON &&
+        Math.abs(eyez - centerz) < GLMAT_EPSILON) {
+        return mat4.identity(out);
     }
 
-    return out;
-};
+    z0 = eyex - centerx;
+    z1 = eyey - centery;
+    z2 = eyez - centerz;
 
-/**
- * Inverts a mat4
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
- */
-mat4.invert = function(out, a) {
-    var 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],
-        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+    len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
+    z0 *= len;
+    z1 *= len;
+    z2 *= len;
 
-        b00 = a00 * a11 - a01 * a10,
-        b01 = a00 * a12 - a02 * a10,
-        b02 = a00 * a13 - a03 * a10,
-        b03 = a01 * a12 - a02 * a11,
-        b04 = a01 * a13 - a03 * a11,
-        b05 = a02 * a13 - a03 * a12,
-        b06 = a20 * a31 - a21 * a30,
-        b07 = a20 * a32 - a22 * a30,
-        b08 = a20 * a33 - a23 * a30,
-        b09 = a21 * a32 - a22 * a31,
-        b10 = a21 * a33 - a23 * a31,
-        b11 = a22 * a33 - a23 * a32,
+    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;
+    }
 
-        // Calculate the determinant
-        det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+    y0 = z1 * x2 - z2 * x1;
+    y1 = z2 * x0 - z0 * x2;
+    y2 = z0 * x1 - z1 * x0;
 
-    if (!det) {
-        return null;
+    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;
     }
-    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;
+    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;
 };
 
 /**
- * Calculates the adjugate of a mat4
+ * Returns Frobenius norm of a mat4
  *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the source matrix
- * @returns {mat4} out
+ * @param {mat4} a the matrix to calculate Frobenius norm of
+ * @returns {Number} Frobenius norm
  */
-mat4.adjoint = function(out, a) {
-    var 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],
-        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;
+mat4.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) ))
 };
 
-/**
- * Calculates the determinant of a mat4
- *
- * @param {mat4} a the source matrix
- * @returns {Number} determinant of a
- */
-mat4.determinant = function (a) {
-    var 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],
-        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
-
-        b00 = a00 * a11 - a01 * a10,
-        b01 = a00 * a12 - a02 * a10,
-        b02 = a00 * a13 - a03 * a10,
-        b03 = a01 * a12 - a02 * a11,
-        b04 = a01 * a13 - a03 * a11,
-        b05 = a02 * a13 - a03 * a12,
-        b06 = a20 * a31 - a21 * a30,
-        b07 = a20 * a32 - a22 * a30,
-        b08 = a20 * a33 - a23 * a30,
-        b09 = a21 * a32 - a22 * a31,
-        b10 = a21 * a33 - a23 * a31,
-        b11 = a22 * a33 - a23 * a32;
-
-    // Calculate the determinant
-    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
-};
+/* harmony default export */ const glmatrix_mat4 = (mat4);
+;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Matrix4.js
 
-/**
- * Multiplies two mat4's
- *
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @returns {mat4} out
- */
-mat4.multiply = function (out, a, b) {
-    var 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],
-        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;
-};
 
 /**
- * Multiplies two affine mat4's
- * Add by https://github.com/pissang
- * @param {mat4} out the receiving matrix
- * @param {mat4} a the first operand
- * @param {mat4} b the second operand
- * @returns {mat4} out
+ * @constructor
+ * @alias clay.Matrix4
  */
-mat4.multiplyAffine = function (out, a, b) {
-    var a00 = a[0], a01 = a[1], a02 = a[2],
-        a10 = a[4], a11 = a[5], a12 = a[6],
-        a20 = a[8], a21 = a[9], a22 = a[10],
-        a30 = a[12], a31 = a[13], a32 = a[14];
-
-    // Cache only the current line of the second matrix
-    var b0  = b[0], b1 = b[1], b2 = b[2];
-    out[0] = b0*a00 + b1*a10 + b2*a20;
-    out[1] = b0*a01 + b1*a11 + b2*a21;
-    out[2] = b0*a02 + b1*a12 + b2*a22;
-    // out[3] = 0;
+var Matrix4 = function() {
 
-    b0 = b[4]; b1 = b[5]; b2 = b[6];
-    out[4] = b0*a00 + b1*a10 + b2*a20;
-    out[5] = b0*a01 + b1*a11 + b2*a21;
-    out[6] = b0*a02 + b1*a12 + b2*a22;
-    // out[7] = 0;
+    this._axisX = new math_Vector3();
+    this._axisY = new math_Vector3();
+    this._axisZ = new math_Vector3();
 
-    b0 = b[8]; b1 = b[9]; b2 = b[10];
-    out[8] = b0*a00 + b1*a10 + b2*a20;
-    out[9] = b0*a01 + b1*a11 + b2*a21;
-    out[10] = b0*a02 + b1*a12 + b2*a22;
-    // out[11] = 0;
+    /**
+     * Storage of Matrix4
+     * @name array
+     * @type {Float32Array}
+     * @memberOf clay.Matrix4#
+     */
+    this.array = glmatrix_mat4.create();
 
-    b0 = b[12]; b1 = b[13]; b2 = b[14];
-    out[12] = b0*a00 + b1*a10 + b2*a20 + a30;
-    out[13] = b0*a01 + b1*a11 + b2*a21 + a31;
-    out[14] = b0*a02 + b1*a12 + b2*a22 + a32;
-    // out[15] = 1;
-    return out;
+    /**
+     * @name _dirty
+     * @type {boolean}
+     * @memberOf clay.Matrix4#
+     */
+    this._dirty = true;
 };
 
-/**
- * Alias for {@link mat4.multiply}
- * @function
- */
-mat4.mul = mat4.multiply;
+Matrix4.prototype = {
 
-/**
- * Alias for {@link mat4.multiplyAffine}
- * @function
- */
-mat4.mulAffine = mat4.multiplyAffine;
-/**
- * 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
- */
-mat4.translate = function (out, a, v) {
-    var x = v[0], y = v[1], z = v[2],
-        a00, a01, a02, a03,
-        a10, a11, a12, a13,
-        a20, a21, a22, a23;
+    constructor: Matrix4,
 
-    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];
+    /**
+     * Set components from array
+     * @param  {Float32Array|number[]} arr
+     */
+    setArray: function (arr) {
+        for (var i = 0; i < this.array.length; i++) {
+            this.array[i] = arr[i];
+        }
+        this._dirty = true;
+        return this;
+    },
+    /**
+     * Calculate the adjugate of self, in-place
+     * @return {clay.Matrix4}
+     */
+    adjoint: function() {
+        glmatrix_mat4.adjoint(this.array, this.array);
+        this._dirty = true;
+        return this;
+    },
 
-        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;
+    /**
+     * Clone a new Matrix4
+     * @return {clay.Matrix4}
+     */
+    clone: function() {
+        return (new Matrix4()).copy(this);
+    },
 
-        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];
-    }
+    /**
+     * Copy from b
+     * @param  {clay.Matrix4} b
+     * @return {clay.Matrix4}
+     */
+    copy: function(a) {
+        glmatrix_mat4.copy(this.array, a.array);
+        this._dirty = true;
+        return this;
+    },
 
-    return out;
-};
+    /**
+     * Calculate matrix determinant
+     * @return {number}
+     */
+    determinant: function() {
+        return glmatrix_mat4.determinant(this.array);
+    },
 
-/**
- * Scales the mat4 by the dimensions in the given vec3
- *
- * @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
- **/
-mat4.scale = function(out, a, v) {
-    var x = v[0], y = v[1], z = v[2];
+    /**
+     * Set upper 3x3 part from quaternion
+     * @param  {clay.Quaternion} q
+     * @return {clay.Matrix4}
+     */
+    fromQuat: function(q) {
+        glmatrix_mat4.fromQuat(this.array, q.array);
+        this._dirty = true;
+        return this;
+    },
 
-    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
- *
- * @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
- */
-mat4.rotate = function (out, a, rad, axis) {
-    var x = axis[0], y = axis[1], z = axis[2],
-        len = Math.sqrt(x * x + y * y + z * z),
-        s, c, t,
-        a00, a01, a02, a03,
-        a10, a11, a12, a13,
-        a20, a21, a22, a23,
-        b00, b01, b02,
-        b10, b11, b12,
-        b20, b21, b22;
-
-    if (Math.abs(len) < GLMAT_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
- */
-mat4.rotateX = function (out, a, rad) {
-    var s = Math.sin(rad),
-        c = Math.cos(rad),
-        a10 = a[4],
-        a11 = a[5],
-        a12 = a[6],
-        a13 = a[7],
-        a20 = a[8],
-        a21 = a[9],
-        a22 = a[10],
-        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
- */
-mat4.rotateY = function (out, a, rad) {
-    var s = Math.sin(rad),
-        c = Math.cos(rad),
-        a00 = a[0],
-        a01 = a[1],
-        a02 = a[2],
-        a03 = a[3],
-        a20 = a[8],
-        a21 = a[9],
-        a22 = a[10],
-        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
- */
-mat4.rotateZ = function (out, a, rad) {
-    var s = Math.sin(rad),
-        c = Math.cos(rad),
-        a00 = a[0],
-        a01 = a[1],
-        a02 = a[2],
-        a03 = a[3],
-        a10 = a[4],
-        a11 = a[5],
-        a12 = a[6],
-        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 quaternion rotation and vector translation
- * This is equivalent to (but much faster than):
- *
- *     mat4.identity(dest);
- *     mat4.translate(dest, vec);
- *     var 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
- */
-mat4.fromRotationTranslation = function (out, q, v) {
-    // Quaternion math
-    var x = q[0], y = q[1], z = q[2], w = q[3],
-        x2 = x + x,
-        y2 = y + y,
-        z2 = z + z,
-
-        xx = x * x2,
-        xy = x * y2,
-        xz = x * z2,
-        yy = y * y2,
-        yz = y * z2,
-        zz = z * z2,
-        wx = w * x2,
-        wy = w * y2,
-        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;
+    /**
+     * Set from a quaternion rotation and a vector translation
+     * @param  {clay.Quaternion} q
+     * @param  {clay.Vector3} v
+     * @return {clay.Matrix4}
+     */
+    fromRotationTranslation: function(q, v) {
+        glmatrix_mat4.fromRotationTranslation(this.array, q.array, v.array);
+        this._dirty = true;
+        return this;
+    },
 
-    return out;
-};
+    /**
+     * Set from Matrix2d, it is used when converting a 2d shape to 3d space.
+     * In 3d space it is equivalent to ranslate on xy plane and rotate about z axis
+     * @param  {clay.Matrix2d} m2d
+     * @return {clay.Matrix4}
+     */
+    fromMat2d: function(m2d) {
+        Matrix4.fromMat2d(this, m2d);
+        return this;
+    },
 
-mat4.fromQuat = function (out, q) {
-    var x = q[0], y = q[1], z = q[2], w = q[3],
-        x2 = x + x,
-        y2 = y + y,
-        z2 = z + z,
+    /**
+     * Set from frustum bounds
+     * @param  {number} left
+     * @param  {number} right
+     * @param  {number} bottom
+     * @param  {number} top
+     * @param  {number} near
+     * @param  {number} far
+     * @return {clay.Matrix4}
+     */
+    frustum: function (left, right, bottom, top, near, far) {
+        glmatrix_mat4.frustum(this.array, left, right, bottom, top, near, far);
+        this._dirty = true;
+        return this;
+    },
 
-        xx = x * x2,
-        yx = y * x2,
-        yy = y * y2,
-        zx = z * x2,
-        zy = z * y2,
-        zz = z * z2,
-        wx = w * x2,
-        wy = w * y2,
-        wz = w * z2;
+    /**
+     * Set to a identity matrix
+     * @return {clay.Matrix4}
+     */
+    identity: function() {
+        glmatrix_mat4.identity(this.array);
+        this._dirty = true;
+        return this;
+    },
 
-    out[0] = 1 - yy - zz;
-    out[1] = yx + wz;
-    out[2] = zx - wy;
-    out[3] = 0;
+    /**
+     * Invert self
+     * @return {clay.Matrix4}
+     */
+    invert: function() {
+        glmatrix_mat4.invert(this.array, this.array);
+        this._dirty = true;
+        return this;
+    },
 
-    out[4] = yx - wz;
-    out[5] = 1 - xx - zz;
-    out[6] = zy + wx;
-    out[7] = 0;
+    /**
+     * Set as a matrix with the given eye position, focal point, and up axis
+     * @param  {clay.Vector3} eye
+     * @param  {clay.Vector3} center
+     * @param  {clay.Vector3} up
+     * @return {clay.Matrix4}
+     */
+    lookAt: function(eye, center, up) {
+        glmatrix_mat4.lookAt(this.array, eye.array, center.array, up.array);
+        this._dirty = true;
+        return this;
+    },
 
-    out[8] = zx + wy;
-    out[9] = zy - wx;
-    out[10] = 1 - xx - yy;
-    out[11] = 0;
+    /**
+     * Alias for mutiply
+     * @param  {clay.Matrix4} b
+     * @return {clay.Matrix4}
+     */
+    mul: function(b) {
+        glmatrix_mat4.mul(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-    out[12] = 0;
-    out[13] = 0;
-    out[14] = 0;
-    out[15] = 1;
+    /**
+     * Alias for multiplyLeft
+     * @param  {clay.Matrix4} a
+     * @return {clay.Matrix4}
+     */
+    mulLeft: function(a) {
+        glmatrix_mat4.mul(this.array, a.array, this.array);
+        this._dirty = true;
+        return this;
+    },
 
-    return out;
-};
+    /**
+     * Multiply self and b
+     * @param  {clay.Matrix4} b
+     * @return {clay.Matrix4}
+     */
+    multiply: function(b) {
+        glmatrix_mat4.multiply(this.array, this.array, b.array);
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * 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
- */
-mat4.frustum = function (out, left, right, bottom, top, near, far) {
-    var rl = 1 / (right - left),
-        tb = 1 / (top - bottom),
-        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;
-};
+    /**
+     * Multiply a and self, a is on the left
+     * @param  {clay.Matrix3} a
+     * @return {clay.Matrix3}
+     */
+    multiplyLeft: function(a) {
+        glmatrix_mat4.multiply(this.array, a.array, this.array);
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * 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
- */
-mat4.perspective = function (out, fovy, aspect, near, far) {
-    var f = 1.0 / Math.tan(fovy / 2),
-        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;
-};
+    /**
+     * Set as a orthographic projection matrix
+     * @param  {number} left
+     * @param  {number} right
+     * @param  {number} bottom
+     * @param  {number} top
+     * @param  {number} near
+     * @param  {number} far
+     * @return {clay.Matrix4}
+     */
+    ortho: function(left, right, bottom, top, near, far) {
+        glmatrix_mat4.ortho(this.array, left, right, bottom, top, near, far);
+        this._dirty = true;
+        return this;
+    },
+    /**
+     * Set as a perspective projection matrix
+     * @param  {number} fovy
+     * @param  {number} aspect
+     * @param  {number} near
+     * @param  {number} far
+     * @return {clay.Matrix4}
+     */
+    perspective: function(fovy, aspect, near, far) {
+        glmatrix_mat4.perspective(this.array, fovy, aspect, near, far);
+        this._dirty = true;
+        return this;
+    },
 
-/**
- * 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
- */
-mat4.ortho = function (out, left, right, bottom, top, near, far) {
-    var lr = 1 / (left - right),
-        bt = 1 / (bottom - top),
-        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;
... 45129 lines suppressed ...


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org