text: // Voxel browser from https://raw.githubusercontent.com/maxogden/voxel/master/voxel-browser.js
  (function(){var require = function (file, cwd) {
    var resolved = require.resolve(file, cwd || '/');
    var mod = require.modules[resolved];
    if (!mod) throw new Error(
      'Failed to resolve module ' + file + ', tried ' + resolved
    );
    var cached = require.cache[resolved];
    var res = cached? cached.exports : mod();
    return res;
  };
  
    require.paths = [];
    require.modules = {};
    require.cache = {};
    require.extensions = [".js",".coffee",".json"];
  
    require._core = {
      'assert': true,
      'events': true,
      'fs': true,
      'path': true,
      'vm': true
    };
  
    require.resolve = (function () {
      return function (x, cwd) {
        if (!cwd) cwd = '/';
  
        if (require._core[x]) return x;
        var path = require.modules.path();
        cwd = path.resolve('/', cwd);
        var y = cwd || '/';
  
        if (x.match(/^(?:\.\.?\/|\/)/)) {
          var m = loadAsFileSync(path.resolve(y, x))
            || loadAsDirectorySync(path.resolve(y, x));
          if (m) return m;
        }
  
        var n = loadNodeModulesSync(x, y);
        if (n) return n;
  
        throw new Error("Cannot find module '" + x + "'");
  
        function loadAsFileSync (x) {
          x = path.normalize(x);
          if (require.modules[x]) {
            return x;
          }
  
          for (var i = 0; i < require.extensions.length; i++) {
            var ext = require.extensions[i];
            if (require.modules[x + ext]) return x + ext;
          }
        }
  
        function loadAsDirectorySync (x) {
          x = x.replace(/\/+$/, '');
          var pkgfile = path.normalize(x + '/package.json');
          if (require.modules[pkgfile]) {
            var pkg = require.modules[pkgfile]();
            var b = pkg.browserify;
            if (typeof b === 'object' && b.main) {
              var m = loadAsFileSync(path.resolve(x, b.main));
              if (m) return m;
            }
            else if (typeof b === 'string') {
              var m = loadAsFileSync(path.resolve(x, b));
              if (m) return m;
            }
            else if (pkg.main) {
              var m = loadAsFileSync(path.resolve(x, pkg.main));
              if (m) return m;
            }
          }
  
          return loadAsFileSync(x + '/index');
        }
  
        function loadNodeModulesSync (x, start) {
          var dirs = nodeModulesPathsSync(start);
          for (var i = 0; i < dirs.length; i++) {
            var dir = dirs[i];
            var m = loadAsFileSync(dir + '/' + x);
            if (m) return m;
            var n = loadAsDirectorySync(dir + '/' + x);
            if (n) return n;
          }
  
          var m = loadAsFileSync(x);
          if (m) return m;
        }
  
        function nodeModulesPathsSync (start) {
          var parts;
          if (start === '/') parts = [ '' ];
          else parts = path.normalize(start).split('/');
  
          var dirs = [];
          for (var i = parts.length - 1; i >= 0; i--) {
            if (parts[i] === 'node_modules') continue;
            var dir = parts.slice(0, i + 1).join('/') + '/node_modules';
            dirs.push(dir);
          }
  
          return dirs;
        }
      };
    })();
  
    require.alias = function (from, to) {
      var path = require.modules.path();
      var res = null;
      try {
        res = require.resolve(from + '/package.json', '/');
      }
      catch (err) {
        res = require.resolve(from, '/');
      }
      var basedir = path.dirname(res);
  
      var keys = (Object.keys || function (obj) {
        var res = [];
        for (var key in obj) res.push(key);
        return res;
      })(require.modules);
  
      for (var i = 0; i < keys.length; i++) {
        var key = keys[i];
        if (key.slice(0, basedir.length + 1) === basedir + '/') {
          var f = key.slice(basedir.length);
          require.modules[to + f] = require.modules[basedir + f];
        }
        else if (key === basedir) {
          require.modules[to] = require.modules[basedir];
        }
      }
    };
  
    (function () {
      var process = {};
      var global = typeof window !== 'undefined' ? window : {};
      var definedProcess = false;
  
      require.define = function (filename, fn) {
        if (!definedProcess && require.modules.__browserify_process) {
          process = require.modules.__browserify_process();
          definedProcess = true;
        }
  
        var dirname = require._core[filename]
            ? ''
            : require.modules.path().dirname(filename)
          ;
  
        var require_ = function (file) {
          var requiredModule = require(file, dirname);
          var cached = require.cache[require.resolve(file, dirname)];
  
          if (cached && cached.parent === null) {
            cached.parent = module_;
          }
  
          return requiredModule;
        };
        require_.resolve = function (name) {
          return require.resolve(name, dirname);
        };
        require_.modules = require.modules;
        require_.define = require.define;
        require_.cache = require.cache;
        var module_ = {
          id : filename,
          filename: filename,
          exports : {},
          loaded : false,
          parent: null
        };
  
        require.modules[filename] = function () {
          require.cache[filename] = module_;
          fn.call(
            module_.exports,
            require_,
            module_,
            module_.exports,
            dirname,
            filename,
            process,
            global
          );
          module_.loaded = true;
          return module_.exports;
        };
      };
    })();
  
  
    require.define("path",function(require,module,exports,__dirname,__filename,process,global){function filter (xs, fn) {
      var res = [];
      for (var i = 0; i < xs.length; i++) {
        if (fn(xs[i], i, xs)) res.push(xs[i]);
      }
      return res;
    }
  
  // resolves . and .. elements in a path array with directory names there
  // must be no slashes, empty elements, or device names (c:\) in the array
  // (so also no leading and trailing slashes - it does not distinguish
  // relative and absolute paths)
      function normalizeArray(parts, allowAboveRoot) {
        // if the path tries to go above the root, `up` ends up > 0
        var up = 0;
        for (var i = parts.length; i >= 0; i--) {
          var last = parts[i];
          if (last == '.') {
            parts.splice(i, 1);
          } else if (last === '..') {
            parts.splice(i, 1);
            up++;
          } else if (up) {
            parts.splice(i, 1);
            up--;
          }
        }
  
        // if the path is allowed to go above the root, restore leading ..s
        if (allowAboveRoot) {
          for (; up--; up) {
            parts.unshift('..');
          }
        }
  
        return parts;
      }
  
  // Regex to split a filename into [*, dir, basename, ext]
  // posix version
      var splitPathRe = /^(.+\/(?!$)|\/)?((?:.+?)?(\.[^.]*)?)$/;
  
  // path.resolve([from ...], to)
  // posix version
      exports.resolve = function() {
        var resolvedPath = '',
          resolvedAbsolute = false;
  
        for (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) {
          var path = (i >= 0)
            ? arguments[i]
            : process.cwd();
  
          // Skip empty and invalid entries
          if (typeof path !== 'string' || !path) {
            continue;
          }
  
          resolvedPath = path + '/' + resolvedPath;
          resolvedAbsolute = path.charAt(0) === '/';
        }
  
  // At this point the path should be resolved to a full absolute path, but
  // handle relative paths to be safe (might happen when process.cwd() fails)
  
  // Normalize the path
        resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
          return !!p;
        }), !resolvedAbsolute).join('/');
  
        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
      };
  
  // path.normalize(path)
  // posix version
      exports.normalize = function(path) {
        var isAbsolute = path.charAt(0) === '/',
          trailingSlash = path.slice(-1) === '/';
  
  // Normalize the path
        path = normalizeArray(filter(path.split('/'), function(p) {
          return !!p;
        }), !isAbsolute).join('/');
  
        if (!path && !isAbsolute) {
          path = '.';
        }
        if (path && trailingSlash) {
          path += '/';
        }
  
        return (isAbsolute ? '/' : '') + path;
      };
  
  
  // posix version
      exports.join = function() {
        var paths = Array.prototype.slice.call(arguments, 0);
        return exports.normalize(filter(paths, function(p, index) {
          return p && typeof p === 'string';
        }).join('/'));
      };
  
  
      exports.dirname = function(path) {
        var dir = splitPathRe.exec(path)[1] || '';
        var isWindows = false;
        if (!dir) {
          // No dirname
          return '.';
        } else if (dir.length === 1 ||
          (isWindows && dir.length <= 3 && dir.charAt(1) === ':')) {
          // It is just a slash or a drive letter with a slash
          return dir;
        } else {
          // It is a full dirname, strip trailing slash
          return dir.substring(0, dir.length - 1);
        }
      };
  
  
      exports.basename = function(path, ext) {
        var f = splitPathRe.exec(path)[2] || '';
        // TODO: make this comparison case-insensitive on windows?
        if (ext && f.substr(-1 * ext.length) === ext) {
          f = f.substr(0, f.length - ext.length);
        }
        return f;
      };
  
  
      exports.extname = function(path) {
        return splitPathRe.exec(path)[3] || '';
      };
  
    });
  
    require.define("__browserify_process",function(require,module,exports,__dirname,__filename,process,global){var process = module.exports = {};
  
      process.nextTick = (function () {
        var canSetImmediate = typeof window !== 'undefined'
          && window.setImmediate;
        var canPost = typeof window !== 'undefined'
            && window.postMessage && window.addEventListener
          ;
  
        if (canSetImmediate) {
          return function (f) { return window.setImmediate(f) };
        }
  
        if (canPost) {
          var queue = [];
          window.addEventListener('message', function (ev) {
            if (ev.source === window && ev.data === 'browserify-tick') {
              ev.stopPropagation();
              if (queue.length > 0) {
                var fn = queue.shift();
                fn();
              }
            }
          }, true);
  
          return function nextTick(fn) {
            queue.push(fn);
            window.postMessage('browserify-tick', '*');
          };
        }
  
        return function nextTick(fn) {
          setTimeout(fn, 0);
        };
      })();
  
      process.title = 'browser';
      process.browser = true;
      process.env = {};
      process.argv = [];
  
      process.binding = function (name) {
        if (name === 'evals') return (require)('vm');
        else throw new Error('No such module. (Possibly not yet loaded)')
      };
  
      (function () {
        var cwd = '/';
        var path;
        process.cwd = function () { return cwd };
        process.chdir = function (dir) {
          if (!path) path = require('path');
          cwd = path.resolve(dir, cwd);
        };
      })();
  
    });
  
    require.define("/package.json",function(require,module,exports,__dirname,__filename,process,global){module.exports = {"main":"index.js"}
    });
  
    require.define("/index.js",function(require,module,exports,__dirname,__filename,process,global){module.exports.meshers = {
      culled: require('./meshers/culled').mesher,
      greedy: require('./meshers/greedy').mesher,
      monotone: require('./meshers/monotone').mesher,
      stupid: require('./meshers/stupid').mesher
    };
  
      module.exports.geometry = {};
      module.exports.generator = {};
      module.exports.generate = generate;
  
  // from https://github.com/mikolalysenko/mikolalysenko.github.com/blob/master/MinecraftMeshes2/js/testdata.js#L4
      function generate(l, h, f) {
        var d = [ h[0]-l[0], h[1]-l[1], h[2]-l[2] ]
          , v = new Int32Array(d[0]*d[1]*d[2])
          , n = 0;
        for(var k=l[2]; k<h[2]; ++k)
          for(var j=l[1]; j<h[1]; ++j)
            for(var i=l[0]; i<h[0]; ++i, ++n) {
              v[n] = f(i,j,k);
            }
        return {voxels:v, dims:d};
      }
  
  // shape and terrain generator functions
      module.exports.generator['Sphere'] = function(i,j,k) {
        return i*i+j*j+k*k <= 16*16 ? 0x113344 : 0;
      };
  
      module.exports.generator['Noise'] = function(i,j,k) {
        return Math.random() < 0.1 ? Math.random() * 0xffffff : 0;
      };
  
      module.exports.generator['Dense Noise'] = function(i,j,k) {
        return Math.round(Math.random() * 0xffffff);
      };
  
      module.exports.generator['Checker'] = function(i,j,k) {
        return !!((i+j+k)&1) ? (((i^j^k)&2) ? 1 : 0xffffff) : 0;
      };
  
      module.exports.generator['Hill'] = function(i,j,k) {
        return j <= 16 * Math.exp(-(i*i + k*k) / 64) ? 0x118822 : 0;
      };
  
      module.exports.generator['Valley'] = function(i,j,k) {
        return j <= (i*i + k*k) * 31 / (32*32*2) + 1 ? 0x118822 : 0;
      };
  
      module.exports.generator['Hilly Terrain'] = function(i,j,k) {
        var h0 = 3.0 * Math.sin(Math.PI * i / 12.0 - Math.PI * k * 0.1) + 27;
        if(j > h0+1) {
          return 0;
        }
        if(h0 <= j) {
          return 0x23dd31;
        }
        var h1 = 2.0 * Math.sin(Math.PI * i * 0.25 - Math.PI * k * 0.3) + 20;
        if(h1 <= j) {
          return 0x964B00;
        }
        if(2 < j) {
          return Math.random() < 0.1 ? 0x222222 : 0xaaaaaa;
        }
        return 0xff0000;
      };
  
  // convenience function that uses the above functions to prebake some simple voxel geometries
      module.exports.generateExamples = function() {
        return {
          'Sphere': generate([-16,-16,-16], [16,16,16], module.exports.generator['Sphere']),
          'Noise': generate([0,0,0], [16,16,16], module.exports.generator['Noise']),
          'Dense Noise': generate([0,0,0], [16,16,16], module.exports.generator['Dense Noise']),
          'Checker': generate([0,0,0], [8,8,8], module.exports.generator['Checker']),
          'Hill': generate([-16, 0, -16], [16,16,16], module.exports.generator['Hill']),
          'Valley': generate([0,0,0], [32,32,32], module.exports.generator['Valley']),
          'Hilly Terrain': generate([0, 0, 0], [32,32,32], module.exports.generator['Hilly Terrain'])
        }
      }
  
  
    });
  
  
    // TODO (AXC): For more efficient memory usage, access volume using functions
  
    require.define("/meshers/culled.js",function(require,module,exports,__dirname,__filename,process,global){//Naive meshing (with face culling)
      function CulledMesh(volume, dims) {
        //Precalculate direction vectors for convenience
        var dir = new Array(3);
        for(var i=0; i<3; ++i) {
          dir[i] = [[0,0,0], [0,0,0]];
          dir[i][0][(i+1)%3] = 1;
          dir[i][1][(i+2)%3] = 1;
        }
        //March over the volume
        var vertices = []
          , faces = []
          , x = [0,0,0]
          , B = [[false,true]    //Incrementally update bounds (this is a bit ugly)
            ,[false,true]
            ,[false,true]]
          , n = -dims[0]*dims[1];
        for(           B[2]=[false,true],x[2]=-1; x[2]<dims[2]; B[2]=[true,(++x[2]<dims[2]-1)])
          for(n-=dims[0],B[1]=[false,true],x[1]=-1; x[1]<dims[1]; B[1]=[true,(++x[1]<dims[1]-1)])
            for(n-=1,      B[0]=[false,true],x[0]=-1; x[0]<dims[0]; B[0]=[true,(++x[0]<dims[0]-1)], ++n) {
              //Read current voxel and 3 neighboring voxels using bounds check results
              var p =   (B[0][0] && B[1][0] && B[2][0]) ? volume[n]                 : 0
                , b = [ (B[0][1] && B[1][0] && B[2][0]) ? volume[n+1]               : 0
                  , (B[0][0] && B[1][1] && B[2][0]) ? volume[n+dims[0]]         : 0
                  , (B[0][0] && B[1][0] && B[2][1]) ? volume[n+dims[0]*dims[1]] : 0
                ];
              //Generate faces
              for(var d=0; d<3; ++d)
                if((!!p) !== (!!b[d])) {
                  var s = !p ? 1 : 0;
                  var t = [x[0],x[1],x[2]]
                    , u = dir[d][s]
                    , v = dir[d][s^1];
                  ++t[d];
  
                  var vertex_count = vertices.length;
                  vertices.push([t[0],           t[1],           t[2]          ]);
                  vertices.push([t[0]+u[0],      t[1]+u[1],      t[2]+u[2]     ]);
                  vertices.push([t[0]+u[0]+v[0], t[1]+u[1]+v[1], t[2]+u[2]+v[2]]);
                  vertices.push([t[0]     +v[0], t[1]     +v[1], t[2]     +v[2]]);
                  faces.push([vertex_count, vertex_count+1, vertex_count+2, vertex_count+3, s ? b[d] : p]);
                }
            }
        return { vertices:vertices, faces:faces };
      }
  
  
      if(exports) {
        exports.mesher = CulledMesh;
      }
  
    });
  
    require.define("/meshers/greedy.js",function(require,module,exports,__dirname,__filename,process,global){var GreedyMesh = (function() {
  //Cache buffer internally
      var mask = new Int32Array(4096);
  
      return function(volume, dims) {
  
        var vertices = [], faces = []
          , dimsX = dims[0]
          , dimsY = dims[1]
          , dimsXY = dimsX * dimsY;
  
        //Sweep over 3-axes
        for(var d=0; d<3; ++d) {
          var i, j, k, l, w, W, h, n, c
            , u = (d+1)%3
            , v = (d+2)%3
            , x = [0,0,0]
            , q = [0,0,0]
            , du = [0,0,0]
            , dv = [0,0,0]
            , dimsD = dims[d]
            , dimsU = dims[u]
            , dimsV = dims[v]
            , qdimsX, qdimsXY
            , xd
  
          if (mask.length < dimsU * dimsV) {
            mask = new Int32Array(dimsU * dimsV);
          }
  
          q[d] =  1;
          x[d] = -1;
  
          qdimsX  = dimsX  * q[1]
          qdimsXY = dimsXY * q[2]
  
          // Compute mask
          while (x[d] < dimsD) {
            xd = x[d]
            n = 0;
  
            for(x[v] = 0; x[v] < dimsV; ++x[v]) {
              for(x[u] = 0; x[u] < dimsU; ++x[u], ++n) {
                var a = xd >= 0      && (volume[x[0]      + dimsX * x[1]          + dimsXY * x[2]          ] & 0xfffffff)
                  , b = xd < dimsD-1 && (volume[x[0]+q[0] + dimsX * x[1] + qdimsX + dimsXY * x[2] + qdimsXY] & 0xfffffff)
                if (a ? b : !b) {
                  mask[n] = 0; continue;
                }
                mask[n] = a ? a : -b;
              }
            }
  
            ++x[d];
  
            // Generate mesh for mask using lexicographic ordering
            n = 0;
            for (j=0; j < dimsV; ++j) {
              for (i=0; i < dimsU; ) {
                c = mask[n];
                if (!c) {
                  i++;  n++; continue;
                }
  
                //Compute width
                w = 1;
                while (c === mask[n+w] && i+w < dimsU) w++;
  
                //Compute height (this is slightly awkward)
                for (h=1; j+h < dimsV; ++h) {
                  k = 0;
                  while (k < w && c === mask[n+k+h*dimsU]) k++
                  if (k < w) break;
                }
  
                // Add quad
                // The du/dv arrays are reused/reset
                // for each iteration.
                du[d] = 0; dv[d] = 0;
                x[u]  = i;  x[v] = j;
  
                if (c > 0) {
                  dv[v] = h; dv[u] = 0;
                  du[u] = w; du[v] = 0;
                } else {
                  c = -c;
                  du[v] = h; du[u] = 0;
                  dv[u] = w; dv[v] = 0;
                }
                var vertex_count = vertices.length;
                vertices.push([x[0],             x[1],             x[2]            ]);
                vertices.push([x[0]+du[0],       x[1]+du[1],       x[2]+du[2]      ]);
                vertices.push([x[0]+du[0]+dv[0], x[1]+du[1]+dv[1], x[2]+du[2]+dv[2]]);
                vertices.push([x[0]      +dv[0], x[1]      +dv[1], x[2]      +dv[2]]);
                faces.push([vertex_count, vertex_count+1, vertex_count+2, vertex_count+3, c]);
  
                //Zero-out mask
                W = n + w;
                for(l=0; l<h; ++l) {
                  for(k=n; k<W; ++k) {
                    mask[k+l*dimsU] = 0;
                  }
                }
  
                //Increment counters and continue
                i += w; n += w;
              }
            }
          }
        }
        return { vertices:vertices, faces:faces };
      }
    })();
  
      if(exports) {
        exports.mesher = GreedyMesh;
      }
  
    });
  
    require.define("/meshers/monotone.js",function(require,module,exports,__dirname,__filename,process,global){"use strict";
  
      var MonotoneMesh = (function(){
  
        function MonotonePolygon(c, v, ul, ur) {
          this.color  = c;
          this.left   = [[ul, v]];
          this.right  = [[ur, v]];
        }
  
        MonotonePolygon.prototype.close_off = function(v) {
          this.left.push([ this.left[this.left.length-1][0], v ]);
          this.right.push([ this.right[this.right.length-1][0], v ]);
        };
  
        MonotonePolygon.prototype.merge_run = function(v, u_l, u_r) {
          var l = this.left[this.left.length-1][0]
            , r = this.right[this.right.length-1][0];
          if(l !== u_l) {
            this.left.push([ l, v ]);
            this.left.push([ u_l, v ]);
          }
          if(r !== u_r) {
            this.right.push([ r, v ]);
            this.right.push([ u_r, v ]);
          }
        };
  
  
        return function(volume, dims) {
          function f(i,j,k) {
            return volume[i + dims[0] * (j + dims[1] * k)] & 0xfffffff; // Keep first bit free for negation
          }
          //Sweep over 3-axes
          var vertices = [], faces = [];
          for(var d=0; d<3; ++d) {
            var i, j, k
              , u = (d+1)%3   //u and v are orthogonal directions to d
              , v = (d+2)%3
              , x = new Int32Array(3)
              , q = new Int32Array(3)
              , runs = new Int32Array(2 * (dims[u]+1))
              , frontier = new Int32Array(dims[u])  //Frontier is list of pointers to polygons
              , next_frontier = new Int32Array(dims[u])
              , left_index = new Int32Array(2 * dims[v])
              , right_index = new Int32Array(2 * dims[v])
              , stack = new Int32Array(24 * dims[v])
              , delta = [[0,0], [0,0]];
            //q points along d-direction
            q[d] = 1;
            //Initialize sentinel
            for(x[d]=-1; x[d]<dims[d]; ) {
              // --- Perform monotone polygon subdivision ---
              var n = 0
                , polygons = []
                , nf = 0;
              for(x[v]=0; x[v]<dims[v]; ++x[v]) {
                //Make one pass over the u-scan line of the volume to run-length encode polygon
                var nr = 0, p = 0, c = 0;
                for(x[u]=0; x[u]<dims[u]; ++x[u], p = c) {
                  //Compute the type for this face
                  var a = (0    <= x[d]      ? f(x[0],      x[1],      x[2])      : 0)
                    , b = (x[d] <  dims[d]-1 ? f(x[0]+q[0], x[1]+q[1], x[2]+q[2]) : 0);
                  c = a;
                  if((!a) === (!b)) {
                    c = 0;
                  } else if(!a) {
                    c = -b;
                  }
                  //If cell type doesn't match, start a new run
                  if(p !== c) {
                    runs[nr++] = x[u];
                    runs[nr++] = c;
                  }
                }
                //Add sentinel run
                runs[nr++] = dims[u];
                runs[nr++] = 0;
                //Update frontier by merging runs
                var fp = 0;
                for(var i=0, j=0; i<nf && j<nr-2; ) {
                  var p    = polygons[frontier[i]]
                    , p_l  = p.left[p.left.length-1][0]
                    , p_r  = p.right[p.right.length-1][0]
                    , p_c  = p.color
                    , r_l  = runs[j]    //Start of run
                    , r_r  = runs[j+2]  //End of run
                    , r_c  = runs[j+1]; //Color of run
                  //Check if we can merge run with polygon
                  if(r_r > p_l && p_r > r_l && r_c === p_c) {
                    //Merge run
                    p.merge_run(x[v], r_l, r_r);
                    //Insert polygon into frontier
                    next_frontier[fp++] = frontier[i];
                    ++i;
                    j += 2;
                  } else {
                    //Check if we need to advance the run pointer
                    if(r_r <= p_r) {
                      if(!!r_c) {
                        var n_poly = new MonotonePolygon(r_c, x[v], r_l, r_r);
                        next_frontier[fp++] = polygons.length;
                        polygons.push(n_poly);
                      }
                      j += 2;
                    }
                    //Check if we need to advance the frontier pointer
                    if(p_r <= r_r) {
                      p.close_off(x[v]);
                      ++i;
                    }
                  }
                }
                //Close off any residual polygons
                for(; i<nf; ++i) {
                  polygons[frontier[i]].close_off(x[v]);
                }
                //Add any extra runs to frontier
                for(; j<nr-2; j+=2) {
                  var r_l  = runs[j]
                    , r_r  = runs[j+2]
                    , r_c  = runs[j+1];
                  if(!!r_c) {
                    var n_poly = new MonotonePolygon(r_c, x[v], r_l, r_r);
                    next_frontier[fp++] = polygons.length;
                    polygons.push(n_poly);
                  }
                }
                //Swap frontiers
                var tmp = next_frontier;
                next_frontier = frontier;
                frontier = tmp;
                nf = fp;
              }
              //Close off frontier
              for(var i=0; i<nf; ++i) {
                var p = polygons[frontier[i]];
                p.close_off(dims[v]);
              }
              // --- Monotone subdivision of polygon is complete at this point ---
  
              x[d]++;
  
              //Now we just need to triangulate each monotone polygon
              for(var i=0; i<polygons.length; ++i) {
                var p = polygons[i]
                  , c = p.color
                  , flipped = false;
                if(c < 0) {
                  flipped = true;
                  c = -c;
                }
                for(var j=0; j<p.left.length; ++j) {
                  left_index[j] = vertices.length;
                  var y = [0.0,0.0,0.0]
                    , z = p.left[j];
                  y[d] = x[d];
                  y[u] = z[0];
                  y[v] = z[1];
                  vertices.push(y);
                }
                for(var j=0; j<p.right.length; ++j) {
                  right_index[j] = vertices.length;
                  var y = [0.0,0.0,0.0]
                    , z = p.right[j];
                  y[d] = x[d];
                  y[u] = z[0];
                  y[v] = z[1];
                  vertices.push(y);
                }
                //Triangulate the monotone polygon
                var bottom = 0
                  , top = 0
                  , l_i = 1
                  , r_i = 1
                  , side = true;  //true = right, false = left
  
                stack[top++] = left_index[0];
                stack[top++] = p.left[0][0];
                stack[top++] = p.left[0][1];
  
                stack[top++] = right_index[0];
                stack[top++] = p.right[0][0];
                stack[top++] = p.right[0][1];
  
                while(l_i < p.left.length || r_i < p.right.length) {
                  //Compute next side
                  var n_side = false;
                  if(l_i === p.left.length) {
                    n_side = true;
                  } else if(r_i !== p.right.length) {
                    var l = p.left[l_i]
                      , r = p.right[r_i];
                    n_side = l[1] > r[1];
                  }
                  var idx = n_side ? right_index[r_i] : left_index[l_i]
                    , vert = n_side ? p.right[r_i] : p.left[l_i];
                  if(n_side !== side) {
                    //Opposite side
                    while(bottom+3 < top) {
                      if(flipped === n_side) {
                        faces.push([ stack[bottom], stack[bottom+3], idx, c]);
                      } else {
                        faces.push([ stack[bottom+3], stack[bottom], idx, c]);
                      }
                      bottom += 3;
                    }
                  } else {
                    //Same side
                    while(bottom+3 < top) {
                      //Compute convexity
                      for(var j=0; j<2; ++j)
                        for(var k=0; k<2; ++k) {
                          delta[j][k] = stack[top-3*(j+1)+k+1] - vert[k];
                        }
                      var det = delta[0][0] * delta[1][1] - delta[1][0] * delta[0][1];
                      if(n_side === (det > 0)) {
                        break;
                      }
                      if(det !== 0) {
                        if(flipped === n_side) {
                          faces.push([ stack[top-3], stack[top-6], idx, c ]);
                        } else {
                          faces.push([ stack[top-6], stack[top-3], idx, c ]);
                        }
                      }
                      top -= 3;
                    }
                  }
                  //Push vertex
                  stack[top++] = idx;
                  stack[top++] = vert[0];
                  stack[top++] = vert[1];
                  //Update loop index
                  if(n_side) {
                    ++r_i;
                  } else {
                    ++l_i;
                  }
                  side = n_side;
                }
              }
            }
          }
          return { vertices:vertices, faces:faces };
        }
      })();
  
      if(exports) {
        exports.mesher = MonotoneMesh;
      }
  
    });
  
    require.define("/meshers/stupid.js",function(require,module,exports,__dirname,__filename,process,global){//The stupidest possible way to generate a Minecraft mesh (I think)
      function StupidMesh(volume, dims, opts) {
        opts = opts || {};
        var useAlphaForSize = opts.sizeBy === 'alpha';
        var size = opts.size || 1;
        var offset = (1 - size)/2;
        var vertices = [], faces = [], x = [0,0,0], n = 0;
        for(x[2]=0; x[2]<dims[2]; ++x[2])
          for(x[1]=0; x[1]<dims[1]; ++x[1])
            for(x[0]=0; x[0]<dims[0]; ++x[0], ++n) {
              var v = volume[n];
              if (!!v) {
                if (useAlphaForSize) {
                  size = ( v >>> 24 & 255 ) / 255;
                  offset = (1 - size) / 2;
                }
                for (var d = 0; d < 3; ++d) {
                  var t = [x[0] + offset, x[1] + offset, x[2] + offset]
                    , u = [0, 0, 0]
                    , v = [0, 0, 0];
                  u[(d + 1) % 3] = size;
                  v[(d + 2) % 3] = size;
                  for (var s = 0; s < 2; ++s) {
                    t[d] = x[d] + s * size + offset;
                    var tmp = u;
                    u = v;
                    v = tmp;
                    var vertex_count = vertices.length;
                    vertices.push([t[0], t[1], t[2]]);
                    vertices.push([t[0] + u[0], t[1] + u[1], t[2] + u[2]]);
                    vertices.push([t[0] + u[0] + v[0], t[1] + u[1] + v[1], t[2] + u[2] + v[2]]);
                    vertices.push([t[0] + v[0], t[1] + v[1], t[2] + v[2]]);
                    faces.push([vertex_count, vertex_count + 1, vertex_count + 2, vertex_count + 3, volume[n]]);
                  }
                }
              }
            }
        return { vertices:vertices, faces:faces };
      }
  
  
      if(exports) {
        exports.mesher = StupidMesh;
      }
  
    });
  
    require.define("/test.js",function(require,module,exports,__dirname,__filename,process,global){voxel = require('./')
    });
    require("/test.js");
  })();
  