diff --git a/vendor/triangulation/.gitignore b/vendor/triangulation/.gitignore
new file mode 100644
index 0000000..4baffb5
--- /dev/null
+++ b/vendor/triangulation/.gitignore
@@ -0,0 +1,5 @@
+.idea
+coverage
+node_modules
+dist
+*.log
diff --git a/vendor/triangulation/README.md b/vendor/triangulation/README.md
new file mode 100644
index 0000000..6e020a5
--- /dev/null
+++ b/vendor/triangulation/README.md
@@ -0,0 +1,49 @@
+three.js - triangulation
+========
+
+### Triangulation support ###
+
+The aim of the project is to add support for different triangulation/tessellation algorithms/libraries to **three.js**.
+Right now the library seamlessly supports the following triangulation libraries:
+
+— [original](https://github.com/mrdoob/three.js/blob/master/src/extras/ShapeUtils.js) - original algorithm from `THREE.ShapeUtils`<br>
+— [earcut](https://github.com/mapbox/earcut) - earcut triangulation library<br>
+— [poly2tri](https://github.com/r3mi/poly2tri.js) - poly2tri triangulation library<br>
+— [libtess](https://github.com/brendankenny/libtess.js/) - libtess tessellation library<br> 
+
+To be able to use the **libtess** library you will have to also load the file [tessy.js](tessy.js) into your project. 
+
+### Triangulation comparison ###
+
+The second aim of the project is to create compare the results of these different triangulation/tessellation algorithms/libraries in **three.js**.
+
+### Adapter ###
+
+The library comes with an adapter [triangulation.js](triangulation.js) which can make it easy to switch between the different triangulation libraries inside your project. The implementation is simple.
+The adapter is available through `THREE.Triangulation` and has two public methods:
+
+1. `setLibrary` - sets the library that you currently want to use.
+  * The available libraries are in an object called `libraries`. So to set earcut as your library: `THREE.Triangulation.setLibrary( THREE.Triangulation.libraries.earcut );` (or  simply use the string `'earcut'`).
+
+2. `setTimer` - sets the timer on/off.
+  * The timer will output the time that was needed to perform the triangulation operations inside the console giving you valuable feedback on the performance of the chosen library.
+  To turn the timer on simply call: `THREE.Triangulation.setTimer( true );`
+
+
+### Viewers ###
+
+For now there are two viewers.
+
+- One [single screen viewer](https://rawgit.com/Wilt/three.js_triangulation/master/viewers/single.html) where the triangulation result of a certain shape with a selected algorithm can be viewed.
+- And [multiple screen viewer](https://rawgit.com/Wilt/three.js_triangulation/master/viewers/multiple.html) where the triangulation result of a certain shape can be seen for all algorithms at the same time.
+
+
+### Benchmarking ###
+
+The next step will be to do some benchmarking of the different algorithms
+
+### Support for another (or your own) triangulation library ###
+
+Do you want support for another (or your own) triangulation library, then please make an issue or a pull-request where you explain what the added value of the 
+proposed library is compared to the ones that are already implemented. It would also be good to make a live example where you show that your code is working. 
+This will increase the chances of the library being implemented.
\ No newline at end of file
diff --git a/vendor/triangulation/tessy.js b/vendor/triangulation/tessy.js
new file mode 100644
index 0000000..5915353
--- /dev/null
+++ b/vendor/triangulation/tessy.js
@@ -0,0 +1,36 @@
+var tessy = (function initTesselator() {
+    // function called for each vertex of tesselator output
+    function vertexCallback(data, polyVertArray) {
+        // console.log(data[0], data[1]);
+        polyVertArray[polyVertArray.length] = data[0];
+        polyVertArray[polyVertArray.length] = data[1];
+    }
+    function begincallback(type) {
+        if (type !== libtess.primitiveType.GL_TRIANGLES) {
+            console.log('expected TRIANGLES but got type: ' + type);
+        }
+    }
+    function errorcallback(errno) {
+        console.log('error callback');
+        console.log('error number: ' + errno);
+    }
+    // callback for when segments intersect and must be split
+    function combinecallback(coords, data, weight) {
+        // console.log('combine callback');
+        return [coords[0], coords[1], coords[2]];
+    }
+    function edgeCallback(flag) {
+        // don't really care about the flag, but need no-strip/no-fan behavior
+        // console.log('edge flag: ' + flag);
+    }
+
+    var tessy = new libtess.GluTesselator();
+    // tessy.gluTessProperty(libtess.gluEnum.GLU_TESS_WINDING_RULE, libtess.windingRule.GLU_TESS_WINDING_POSITIVE);
+    tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_VERTEX_DATA, vertexCallback);
+    tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_BEGIN, begincallback);
+    tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_ERROR, errorcallback);
+    tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_COMBINE, combinecallback);
+    tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_EDGE_FLAG, edgeCallback);
+
+    return tessy;
+})();
\ No newline at end of file
diff --git a/vendor/triangulation/triangulation.js b/vendor/triangulation/triangulation.js
new file mode 100644
index 0000000..61b89b4
--- /dev/null
+++ b/vendor/triangulation/triangulation.js
@@ -0,0 +1,319 @@
+'use strict';
+
+if ( ! window.THREE ) throw new Error( 'ERROR: three.js not loaded' );
+
+THREE.Triangulation = ( function() {
+
+    var timer = false;
+
+    var library = 'original';
+
+    /**
+     * Names of the supported libraries
+     *
+     * @type {{original: string, earcut: string, poly2tri: string, libtess: string}}
+     */
+    var libraries = {
+        original: 'original',
+        earcut: 'earcut',
+        poly2tri: 'poly2tri',
+        libtess: 'libtess'
+    };
+
+    /**
+     * Container object for holding the different library adapters
+     *
+     * @type {{}}
+     */
+    var adapters = {};
+
+    adapters[ libraries.original ] = {
+
+        triangulate: THREE.ShapeUtils.triangulate,
+
+        triangulateShape: THREE.ShapeUtils.triangulateShape
+
+    };
+
+    adapters[ libraries.earcut ] = {
+
+        triangulateShape: function( contour, holes ) {
+
+            var i, il, dim = 2, array;
+            var holeIndices = [];
+            var points = [];
+
+            addPoints( contour );
+
+            for ( i = 0, il = holes.length; i < il; i ++ ) {
+
+                holeIndices.push( points.length / dim );
+
+                addPoints( holes[ i ] );
+
+            }
+
+            array = earcut( points, holeIndices, dim );
+
+            var result = [];
+
+            for ( i = 0, il = array.length; i < il; i += 3 ) {
+
+                result.push( array.slice( i, i + 3 ) );
+
+            }
+
+            return result;
+
+            function addPoints( a ) {
+
+                var i, il = a.length;
+
+                for ( i = 0; i < il; i ++ ) {
+
+                    points.push( a[ i ].x, a[ i ].y );
+
+                }
+
+            }
+
+        }
+
+    };
+
+    adapters[ libraries.poly2tri ] = {
+
+        triangulateShape: function( contour, holes ) {
+
+            var i, il, object, sweepContext, triangles;
+            var pointMap = {}, count = 0;
+
+            points = makePoints( contour );
+
+            sweepContext = new poly2tri.SweepContext( points );
+
+            for ( i = 0, il = holes.length; i < il; i ++ ) {
+
+                points = makePoints( holes[ i ] );
+
+                sweepContext.addHole( points );
+
+                points = points.concat( points );
+
+            }
+
+            object = sweepContext.triangulate();
+
+            triangles = object.triangles_;
+
+            var a, b, c, points, result = [];
+
+            for ( i = 0, il = triangles.length; i < il; i ++ ) {
+
+                points = triangles[ i ].points_;
+
+                a = pointMap[ points[ 0 ].x + ',' + points[ 0 ].y ];
+                b = pointMap[ points[ 1 ].x + ',' + points[ 1 ].y ];
+                c = pointMap[ points[ 2 ].x + ',' + points[ 2 ].y ];
+
+                result.push( [ a, b, c ] );
+
+            }
+
+            return result;
+
+            function makePoints( a ) {
+
+                var i, il = a.length,
+                    points = [];
+
+                for ( i = 0; i < il; i ++ ) {
+
+                    points.push( new poly2tri.Point( a[ i ].x, a[ i ].y ) );
+                    pointMap[ a[ i ].x + ',' + a[ i ].y ] = count;
+                    count ++;
+
+                }
+
+                return points;
+
+            }
+
+        }
+
+    };
+
+    adapters[ libraries.libtess ] = {
+
+        triangulateShape: function( contour, holes ) {
+
+            var i, il, triangles = [];
+            var pointMap = {}, count = 0;
+
+            // libtess will take 3d verts and flatten to a plane for tesselation
+            // since only doing 2d tesselation here, provide z=1 normal to skip
+            // iterating over verts only to get the same answer.
+            // comment out to test normal-generation code
+            tessy.gluTessNormal( 0, 0, 1 );
+
+            tessy.gluTessBeginPolygon( triangles );
+
+            points = makePoints( contour );
+
+            for ( i = 0, il = holes.length; i < il; i ++ ) {
+
+                points = makePoints( holes[ i ] );
+
+            }
+
+            tessy.gluTessEndPolygon();
+
+            var a, b, c, points, result = [];
+
+            for ( i = 0, il = triangles.length; i < il; i += 6 ) {
+
+                a = pointMap[ triangles[ i ] + ',' + triangles[ i + 1 ]];
+                b = pointMap[ triangles[ i + 2 ] + ',' + triangles[ i + 3 ]];
+                c = pointMap[ triangles[ i + 4 ] + ',' + triangles[ i + 5 ]];
+
+                result.push( [ a, b, c ] );
+
+            }
+
+            return result;
+
+            function makePoints( a ) {
+
+                var i, il = a.length,
+                    coordinates;
+
+                tessy.gluTessBeginContour();
+
+                for ( i = 0; i < il; i ++ ) {
+
+                    coordinates = [ a[ i ].x, a[ i ].y, 0 ];
+                    tessy.gluTessVertex( coordinates, coordinates );
+                    pointMap[ a[ i ].x + ',' + a[ i ].y ] = count;
+                    count ++;
+
+                }
+
+                tessy.gluTessEndContour();
+
+                return points;
+
+            }
+
+        }
+
+    };
+
+    /**
+     * Initialize the library by attaching the triangulation methods to the three.js API
+     */
+    function init() {
+
+        checkDependencies( library );
+
+        if ( timer ) {
+
+            THREE.ShapeUtils.triangulate = function() {
+
+                return adapters[ library ].triangulate.apply( this, arguments );
+
+            };
+
+            THREE.ShapeUtils.triangulateShape = function() {
+
+                console.time( library );
+
+                var result = adapters[ library ].triangulateShape.apply( this, arguments );
+
+                console.timeEnd( library );
+
+                return result;
+
+            };
+
+        } else {
+
+            THREE.ShapeUtils.triangulate = adapters[ library ].triangulate;
+
+            THREE.ShapeUtils.triangulateShape = adapters[ library ].triangulateShape;
+
+        }
+
+    }
+
+    /**
+     * Checks dependencies needed for the current library
+     *
+     * @param library
+     */
+    function checkDependencies( library ) {
+
+        switch ( library ) {
+
+            case libraries.earcut:
+
+                if ( ! window.earcut ) throw new Error( 'ERROR: earcut not loaded' );
+
+                break;
+
+            case libraries.poly2tri:
+
+                if ( ! window.poly2tri ) throw new Error( 'ERROR: poly2tri not loaded' );
+
+                break;
+
+            case libraries.libtess:
+
+                if ( ! window.tessy ) throw new Error( 'ERROR: libtess not loaded' );
+
+                break;
+
+        }
+
+    }
+
+    /**
+     * Set the current triangulation library
+     *
+     * @param name
+     */
+    function setLibrary( name ) {
+
+        if ( ! libraries.hasOwnProperty( name ) ) throw new Error( 'ERROR: unknown library ' + name );
+
+        library = name;
+
+        init();
+
+    }
+
+    /**
+     * Set timer for triangulation on/off
+     *
+     * @param boolean
+     */
+    function setTimer( boolean ) {
+
+        timer = boolean;
+
+        init();
+
+    }
+
+    init();
+
+    return {
+
+        libraries: libraries,
+
+        setTimer: setTimer,
+
+        setLibrary: setLibrary
+
+    };
+
+} )();
