/home2/mshostin/public_html/main.js
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
    const copy = require('copy-to-clipboard');
    const createViewer = require('../../..');
    const { svgElementToSvgImageContent } = require('../../../util');
    
    document.addEventListener('keypress', function (event) {
      if (event.keyCode === 99) {
        // the c key
        const svg = document.getElementById('svg');
        const content = svgElementToSvgImageContent(svg);
        copy(content);
      }
    });
    
    createViewer({
      width: 0.4,
      height: 0.4,
      followMouse: true,
      followMotion: true,
    });
    
    },{"../../..":3,"../../../util":13,"copy-to-clipboard":4}],2:[function(require,module,exports){
    module.exports={
      "positions": [
        [111.024597, 52.604599, 46.225899],
        [114.025002, 87.673302, 58.9818],
        [66.192001, 80.898003, 55.394299],
        [72.113297, 35.491798, 30.871401],
        [97.804497, 116.560997, 73.978798],
        [16.7623, 58.010899, 58.078201],
        [52.608898, 30.3641, 42.556099],
        [106.881401, 31.945499, 46.9133],
        [113.484596, 38.6049, 49.121498],
        [108.6633, 43.2332, 46.315399],
        [101.216599, 15.9822, 46.308201],
        [16.6605, -16.2883, 93.618698],
        [40.775002, -10.2288, 85.276398],
        [23.926901, -2.5103, 86.736504],
        [11.1691, -7.0037, 99.377602],
        [9.5692, -34.393902, 141.671997],
        [12.596, 7.1655, 88.740997],
        [61.180901, 8.8142, 76.996803],
        [39.719501, -28.927099, 88.963799],
        [13.7962, -68.575699, 132.057007],
        [15.2674, -62.32, 129.688004],
        [14.8446, -52.6096, 140.113007],
        [12.8917, -49.771599, 144.740997],
        [35.604198, -71.758003, 81.063904],
        [47.462502, -68.606102, 63.369701],
        [38.2486, -64.730202, 38.909901],
        [-12.8917, -49.771599, 144.740997],
        [-13.7962, -68.575699, 132.057007],
        [17.802099, -71.758003, 81.063904],
        [19.1243, -69.0168, 49.420101],
        [38.2486, -66.275597, 17.776199],
        [12.8928, -36.703499, 141.671997],
        [109.283997, -93.589897, 27.824301],
        [122.117996, -36.8894, 35.025002],
        [67.7668, -30.197001, 78.417801],
        [33.180698, 101.851997, 25.3186],
        [9.4063, -35.589802, 150.722],
        [-9.5692, -34.393902, 141.671997],
        [-9.4063, -35.589802, 150.722],
        [11.4565, -37.899399, 150.722],
        [-12.596, 7.1655, 88.740997],
        [-11.1691, -7.0037, 99.377602],
        [70.236504, 62.836201, -3.9475],
        [47.263401, 54.293999, -27.414801],
        [28.7302, 91.731102, -24.972601],
        [69.167603, 6.5862, -12.7757],
        [28.7302, 49.1003, -48.3596],
        [31.903, 5.692, -47.821999],
        [35.075802, -34.432899, -16.280899],
        [115.284103, 48.681499, 48.684101],
        [110.842796, 28.4821, 49.176201],
        [-19.1243, -69.0168, 49.420101],
        [-38.2486, -66.275597, 17.776199],
        [-111.024597, 52.604599, 46.225899],
        [-72.113297, 35.491798, 30.871401],
        [-66.192001, 80.898003, 55.394299],
        [-114.025002, 87.673302, 58.9818],
        [-97.804497, 116.560997, 73.978798],
        [-52.608898, 30.3641, 42.556099],
        [-16.7623, 58.010899, 58.078201],
        [-106.881401, 31.945499, 46.9133],
        [-108.6633, 43.2332, 46.315399],
        [-113.484596, 38.6049, 49.121498],
        [-101.216599, 15.9822, 46.308201],
        [-16.6605, -16.2883, 93.618698],
        [-23.926901, -2.5103, 86.736504],
        [-40.775002, -10.2288, 85.276398],
        [-61.180901, 8.8142, 76.996803],
        [-39.719501, -28.927099, 88.963799],
        [-14.8446, -52.6096, 140.113007],
        [-15.2674, -62.32, 129.688004],
        [-47.462502, -68.606102, 63.369701],
        [-35.604198, -71.758003, 81.063904],
        [-38.2486, -64.730202, 38.909901],
        [-17.802099, -71.758003, 81.063904],
        [-12.8928, -36.703499, 141.671997],
        [-67.7668, -30.197001, 78.417801],
        [-122.117996, -36.8894, 35.025002],
        [-109.283997, -93.589897, 27.824301],
        [-33.180698, 101.851997, 25.3186],
        [-11.4565, -37.899399, 150.722],
        [-70.236504, 62.836201, -3.9475],
        [-28.7302, 91.731102, -24.972601],
        [-47.263401, 54.293999, -27.414801],
        [-69.167603, 6.5862, -12.7757],
        [-28.7302, 49.1003, -48.3596],
        [-31.903, 5.692, -47.821999],
        [-35.075802, -34.432899, -16.280899],
        [-115.284103, 48.681499, 48.684101],
        [-110.842796, 28.4821, 49.176201]
      ],
      "chunks": [
        {
          "color": [119, 57, 0],
          "faces": [
            [0, 1, 2],
            [2, 3, 0],
            [4, 5, 2],
            [6, 3, 2],
            [2, 5, 6],
            [7, 8, 9],
            [10, 3, 6],
            [10, 50, 7],
            [7, 3, 10],
            [7, 9, 3],
            [49, 0, 9],
            [3, 9, 0],
            [53, 54, 55],
            [55, 56, 53],
            [57, 56, 55],
            [58, 59, 55],
            [55, 54, 58],
            [60, 61, 62],
            [63, 58, 54],
            [63, 60, 89],
            [60, 63, 54],
            [60, 54, 61],
            [88, 61, 53],
            [54, 53, 61],
            [2, 1, 4],
            [55, 59, 57]
          ]
        },
        {
          "color": [36, 51, 67],
          "faces": [
            [11, 12, 13],
            [64, 65, 66]
          ]
        },
        {
          "color": [228, 116, 36],
          "faces": [
            [14, 15, 11],
            [11, 16, 14],
            [17, 12, 18],
            [41, 64, 37],
            [67, 68, 66]
          ]
        },
        {
          "color": [192, 172, 157],
          "faces": [
            [19, 20, 21],
            [21, 22, 19],
            [20, 19, 23],
            [23, 24, 20],
            [23, 25, 24],
            [19, 22, 26],
            [26, 27, 19],
            [23, 28, 29],
            [23, 29, 30],
            [25, 23, 30],
            [29, 51, 52],
            [52, 30, 29],
            [27, 26, 69],
            [69, 70, 27],
            [70, 71, 72],
            [72, 27, 70],
            [72, 71, 73],
            [51, 74, 72],
            [52, 51, 72],
            [73, 52, 72],
            [19, 27, 74],
            [74, 28, 19],
            [51, 29, 28],
            [28, 74, 51],
            [74, 27, 72],
            [28, 23, 19]
          ]
        },
        {
          "color": [214, 194, 178],
          "faces": [
            [21, 20, 24],
            [24, 31, 21],
            [69, 71, 70],
            [71, 69, 75]
          ]
        },
        {
          "color": [228, 119, 25],
          "faces": [
            [31, 24, 18],
            [6, 5, 16],
            [16, 17, 6],
            [24, 32, 33],
            [33, 34, 24],
            [5, 4, 35],
            [75, 68, 71],
            [58, 67, 40],
            [40, 59, 58],
            [71, 76, 77],
            [77, 78, 71]
          ]
        },
        {
          "color": [205, 98, 0],
          "faces": [
            [24, 34, 18],
            [16, 13, 12],
            [12, 17, 16],
            [13, 16, 11],
            [71, 68, 76],
            [40, 67, 66],
            [66, 65, 40],
            [65, 64, 40]
          ]
        },
        {
          "color": [0, 0, 0],
          "faces": [
            [36, 15, 37],
            [37, 38, 36],
            [31, 39, 22],
            [22, 21, 31],
            [31, 15, 36],
            [36, 39, 31],
            [75, 69, 26],
            [26, 80, 75],
            [75, 80, 38],
            [38, 37, 75],
            [38, 80, 39],
            [39, 36, 38],
            [39, 80, 26],
            [26, 22, 39]
          ]
        },
        {
          "color": [247, 132, 25],
          "faces": [
            [17, 33, 10],
            [17, 18, 34],
            [34, 33, 17],
            [10, 6, 17],
            [11, 15, 31],
            [31, 18, 11],
            [18, 12, 11],
            [14, 16, 40],
            [40, 41, 14],
            [59, 5, 35],
            [35, 79, 59],
            [67, 63, 77],
            [67, 77, 76],
            [76, 68, 67],
            [63, 67, 58],
            [64, 68, 75],
            [75, 37, 64],
            [68, 64, 66],
            [14, 41, 37],
            [37, 15, 14],
            [5, 59, 40],
            [40, 16, 5]
          ]
        },
        {
          "color": [225, 119, 25],
          "faces": [
            [35, 4, 42],
            [4, 1, 42],
            [42, 43, 44],
            [44, 35, 42],
            [45, 43, 42],
            [42, 10, 45],
            [30, 32, 24],
            [24, 25, 30],
            [30, 33, 32],
            [33, 30, 10],
            [44, 43, 46],
            [43, 45, 47],
            [47, 46, 43],
            [48, 47, 45],
            [45, 30, 48],
            [30, 45, 10],
            [49, 42, 0],
            [8, 7, 42],
            [50, 42, 7],
            [50, 10, 42],
            [1, 0, 42],
            [42, 9, 8],
            [42, 49, 9],
            [64, 41, 40],
            [57, 59, 79],
            [79, 81, 57],
            [57, 81, 56],
            [82, 79, 35],
            [35, 44, 82],
            [81, 79, 82],
            [82, 83, 81],
            [84, 63, 81],
            [81, 83, 84],
            [44, 46, 85],
            [85, 82, 44],
            [52, 73, 71],
            [71, 78, 52],
            [52, 78, 77],
            [77, 63, 52],
            [82, 85, 83],
            [83, 85, 86],
            [86, 84, 83],
            [87, 52, 84],
            [84, 86, 87],
            [52, 63, 84],
            [88, 53, 81],
            [62, 81, 60],
            [89, 60, 81],
            [89, 81, 63],
            [56, 81, 53],
            [81, 62, 61],
            [81, 61, 88],
            [48, 87, 86],
            [86, 47, 48],
            [47, 86, 85],
            [85, 46, 47],
            [48, 30, 52],
            [52, 87, 48]
          ]
        }
      ]
    }
    
    },{}],3:[function(require,module,exports){
    const foxJson = require('./fox.json');
    const {
      calculateSizingOptions,
      createLogoViewer,
      loadModelFromJson,
      createModelRenderer,
      createNode,
      setAttribute,
      setGradientDefinitions,
      setMaskDefinitions,
    } = require('./util');
    
    module.exports = createLogo;
    
    function createLogo(options = {}) {
      const cameraDistance = options.cameraDistance || 400;
      const { height, width } = calculateSizingOptions(options);
      const meshJson = options.meshJson || foxJson;
    
      const container = document.getElementById('svg');
      
    //   setAttribute(container, 'width', `${width}px`);
    //   setAttribute(container, 'height', `${height}px`);
    //   document.body.appendChild(container);
    
      setGradientDefinitions(container, meshJson.gradients);
      setMaskDefinitions({ container, masks: meshJson.masks, height, width });
    
      const modelObj = loadModelFromJson(meshJson);
      const renderFox = createModelRenderer(container, cameraDistance, modelObj);
      const renderScene = (lookCurrent, slowDrift) => {
        const rect = container.getBoundingClientRect();
        renderFox(rect, lookCurrent, slowDrift);
      };
    
      return createLogoViewer(
        container,
        renderScene,
        Object.assign({ cameraDistance }, options),
      );
    }
    
    },{"./fox.json":2,"./util":13}],4:[function(require,module,exports){
    'use strict';
    
    var deselectCurrent = require('toggle-selection');
    
    var defaultMessage = 'Copy to clipboard: #{key}, Enter';
    
    function format(message) {
      var copyKey = (/mac os x/i.test(navigator.userAgent) ? '⌘' : 'Ctrl') + '+C';
      return message.replace(/#{\s*key\s*}/g, copyKey);
    }
    
    function copy(text, options) {
      var debug, message, reselectPrevious, range, selection, mark, success = false;
      if (!options) { options = {}; }
      debug = options.debug || false;
      try {
        reselectPrevious = deselectCurrent();
    
        range = document.createRange();
        selection = document.getSelection();
    
        mark = document.createElement('span');
        mark.textContent = text;
        // reset user styles for span element
        mark.style.all = 'unset';
        // prevents scrolling to the end of the page
        mark.style.position = 'fixed';
        mark.style.top = 0;
        mark.style.clip = 'rect(0, 0, 0, 0)';
        // used to preserve spaces and line breaks
        mark.style.whiteSpace = 'pre';
        // do not inherit user-select (it may be `none`)
        mark.style.webkitUserSelect = 'text';
        mark.style.MozUserSelect = 'text';
        mark.style.msUserSelect = 'text';
        mark.style.userSelect = 'text';
    
        document.body.appendChild(mark);
    
        range.selectNode(mark);
        selection.addRange(range);
    
        var successful = document.execCommand('copy');
        if (!successful) {
          throw new Error('copy command was unsuccessful');
        }
        success = true;
      } catch (err) {
        debug && console.error('unable to copy using execCommand: ', err);
        debug && console.warn('trying IE specific stuff');
        try {
          window.clipboardData.setData('text', text);
          success = true;
        } catch (err) {
          debug && console.error('unable to copy using clipboardData: ', err);
          debug && console.error('falling back to prompt');
          message = format('message' in options ? options.message : defaultMessage);
          window.prompt(message, text);
        }
      } finally {
        if (selection) {
          if (typeof selection.removeRange == 'function') {
            selection.removeRange(range);
          } else {
            selection.removeAllRanges();
          }
        }
    
        if (mark) {
          document.body.removeChild(mark);
        }
        reselectPrevious();
      }
    
      return success;
    }
    
    module.exports = copy;
    
    },{"toggle-selection":12}],5:[function(require,module,exports){
    module.exports = identity;
    
    /**
     * Set a mat4 to the identity matrix
     *
     * @param {mat4} out the receiving matrix
     * @returns {mat4} out
     */
    function identity(out) {
        out[0] = 1;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = 1;
        out[6] = 0;
        out[7] = 0;
        out[8] = 0;
        out[9] = 0;
        out[10] = 1;
        out[11] = 0;
        out[12] = 0;
        out[13] = 0;
        out[14] = 0;
        out[15] = 1;
        return out;
    };
    },{}],6:[function(require,module,exports){
    module.exports = invert;
    
    /**
     * Inverts a mat4
     *
     * @param {mat4} out the receiving matrix
     * @param {mat4} a the source matrix
     * @returns {mat4} out
     */
    function invert(out, a) {
        var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
            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] = (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;
    };
    },{}],7:[function(require,module,exports){
    var identity = require('./identity');
    
    module.exports = lookAt;
    
    /**
     * Generates a look-at matrix with the given eye position, focal point, and up axis
     *
     * @param {mat4} out mat4 frustum matrix will be written into
     * @param {vec3} eye Position of the viewer
     * @param {vec3} center Point the viewer is looking at
     * @param {vec3} up vec3 pointing up
     * @returns {mat4} out
     */
    function lookAt(out, eye, center, up) {
        var x0, 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];
    
        if (Math.abs(eyex - centerx) < 0.000001 &&
            Math.abs(eyey - centery) < 0.000001 &&
            Math.abs(eyez - centerz) < 0.000001) {
            return identity(out);
        }
    
        z0 = eyex - centerx;
        z1 = eyey - centery;
        z2 = eyez - centerz;
    
        len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
        z0 *= len;
        z1 *= len;
        z2 *= len;
    
        x0 = upy * z2 - upz * z1;
        x1 = upz * z0 - upx * z2;
        x2 = upx * z1 - upy * z0;
        len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
        if (!len) {
            x0 = 0;
            x1 = 0;
            x2 = 0;
        } else {
            len = 1 / len;
            x0 *= len;
            x1 *= len;
            x2 *= len;
        }
    
        y0 = z1 * x2 - z2 * x1;
        y1 = z2 * x0 - z0 * x2;
        y2 = z0 * x1 - z1 * x0;
    
        len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
        if (!len) {
            y0 = 0;
            y1 = 0;
            y2 = 0;
        } else {
            len = 1 / len;
            y0 *= len;
            y1 *= len;
            y2 *= len;
        }
    
        out[0] = x0;
        out[1] = y0;
        out[2] = z0;
        out[3] = 0;
        out[4] = x1;
        out[5] = y1;
        out[6] = z1;
        out[7] = 0;
        out[8] = x2;
        out[9] = y2;
        out[10] = z2;
        out[11] = 0;
        out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
        out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
        out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
        out[15] = 1;
    
        return out;
    };
    },{"./identity":5}],8:[function(require,module,exports){
    module.exports = multiply;
    
    /**
     * 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
     */
    function multiply(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;
    };
    },{}],9:[function(require,module,exports){
    module.exports = perspective;
    
    /**
     * Generates a perspective projection matrix with the given bounds
     *
     * @param {mat4} out mat4 frustum matrix will be written into
     * @param {number} fovy Vertical field of view in radians
     * @param {number} aspect Aspect ratio. typically viewport width/height
     * @param {number} near Near bound of the frustum
     * @param {number} far Far bound of the frustum
     * @returns {mat4} out
     */
    function perspective(out, fovy, aspect, near, far) {
        var f = 1.0 / Math.tan(fovy / 2),
            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;
    };
    },{}],10:[function(require,module,exports){
    module.exports = rotate;
    
    /**
     * 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
     */
    function rotate(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) < 0.000001) { 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;
    };
    },{}],11:[function(require,module,exports){
    module.exports = transformMat4;
    
    /**
     * Transforms the vec3 with a mat4.
     * 4th vector component is implicitly '1'
     *
     * @param {vec3} out the receiving vector
     * @param {vec3} a the vector to transform
     * @param {mat4} m matrix to transform with
     * @returns {vec3} out
     */
    function transformMat4(out, a, m) {
        var x = a[0], y = a[1], z = a[2],
            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
    }
    },{}],12:[function(require,module,exports){
    
    module.exports = function () {
      var selection = document.getSelection();
      if (!selection.rangeCount) {
        return function () {};
      }
      var active = document.activeElement;
    
      var ranges = [];
      for (var i = 0; i < selection.rangeCount; i++) {
        ranges.push(selection.getRangeAt(i));
      }
    
      switch (active.tagName.toUpperCase()) { // .toUpperCase handles XHTML
        case 'INPUT':
        case 'TEXTAREA':
          active.blur();
          break;
    
        default:
          active = null;
          break;
      }
    
      selection.removeAllRanges();
      return function () {
        selection.type === 'Caret' &&
        selection.removeAllRanges();
    
        if (!selection.rangeCount) {
          ranges.forEach(function(range) {
            selection.addRange(range);
          });
        }
    
        active &&
        active.focus();
      };
    };
    
    },{}],13:[function(require,module,exports){
    const perspective = require('gl-mat4/perspective');
    const multiply = require('gl-mat4/multiply');
    const lookAt = require('gl-mat4/lookAt');
    const invert = require('gl-mat4/invert');
    const rotate = require('gl-mat4/rotate');
    const transform = require('gl-vec3/transformMat4');
    
    const SVG_NS = 'http://www.w3.org/2000/svg';
    
    // Taken from https://github.com/yuzhe-han/ParentNode-replaceChildren
    // This is to support browsers that do not yet support `replaceChildren`
    const replaceChildrenPonyfill = function (...addNodes) {
      while (this.lastChild) {
        this.removeChild(this.lastChild);
      }
    
      if (addNodes.length > 0) {
        this.append(...addNodes);
      }
    };
    
    module.exports = {
      calculateSizingOptions,
      createLogoViewer,
      createModelRenderer,
      loadModelFromJson,
      positionsFromModel,
      createPolygonsFromModelJson,
      createStandardModelPolygon,
      createMatrixComputer,
      compareZ,
      createFaceUpdater,
      createNode,
      setAttribute,
      setGradientDefinitions,
      setMaskDefinitions,
      svgElementToSvgImageContent,
      Polygon,
    };
    
    /**
     * A distance measurement used for SVG attributes. A length is specified as a number followed by a
     * unit identifier.
     *
     * See {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#length} for further
     * information.
     *
     * @typedef {`${number}${'em' | 'ex' | 'px' | 'in' | 'cm' | 'mm' | 'pt' | 'pc' | '%'}`} SvgLength
     */
    
    /**
     * A definition for a `<stop>` SVG element, which defines a color and the position for that color
     * on a gradient. This element is always a child of either a `<linearGradient>` or
     * `<radialGradient>` element.
     *
     * See {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Element/stop} for more information
     * about the `<stop>` element.
     *
     * @typedef {object} StopDefinition
     * @property {number | `${number}%`} [offset] - The location of the gradient stop along the
     * gradient vector.
     * @property {string} [stop-color] - The color of the gradient stop. See {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Element/stop}.
     * @property {number} [stop-opacity] - The opacity of the gradient stop. See {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stop-opacity}.
     */
    
    /**
     * A definition for a `<linearGradient>` SVG element. This definition includes all supported
     * `<linearGradient>` attributes, and it includes a `stops` property which is an array of
     * definitions for each `<stop>` child node.
     *
     * See {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient} for more
     * information about the `<linearGradient>` element.
     *
     * @typedef {object} LinearGradientDefinition
     * @property {string} [gradientTransform] - A transform from the gradient coordinate system to the
     * target coordinate system. See {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/gradientTransform}.
     * @property {'userSpaceOnUse' | 'objectBoundingBox'} [gradientUnits] - The coordinate system used.
     * for the coordinate attributes. See {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/gradientUnits}.
     * @property {'pad' | 'reflect' | 'repeat'} [spreadMethod] - The method used to fill a shape beyond
     * the defined edges of a gradient. See {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/spreadMethod}.
     * @property {StopDefinition[]} [stops] - The colors of the gradient, and the position of each
     * color along the gradient vector.
     * @property {'linear'} type - The type of the gradient.
     * @property {SvgLength} [x1] - The x coordinate of the starting point of the vector gradient.
     * @property {SvgLength} [x2] - The x coordinate of the ending point of the vector gradient.
     * @property {SvgLength} [y1] - The y coordinate of the starting point of the vector gradient.
     * @property {SvgLength} [y2] - The y coordinate of the ending point of the vector gradient.
     */
    
    /**
     * A definition for a `<radialGradient>` SVG element. This definition includes all supported
     * `<radialGradient>` attributes, and it includes a `stops` property which is an array of
     * definitions for each `<stop>` child node.
     *
     * See {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Element/radialGradient} for more
     * information about the `<radialGradient>` element.
     *
     * @typedef {object} RadialGradientDefinition
     * @property {SvgLength} [cx] - The x coordinate of the end circle of the radial gradiant.
     * @property {SvgLength} [cy] - The y coordinate of the end circle of the radial gradient.
     * @property {SvgLength} [fr] - The radius of the start circle of the radial gradient.
     * @property {SvgLength} [fx] - The x coordinate of the start circle of the radial gradient.
     * @property {SvgLength} [fy] - The y coordinate of the start circle of the radial gradient.
     * @property {string} [gradientTransform] - A transform from the gradient coordinate system to the
     * target coordinate system. See {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/gradientTransform}.
     * @property {'userSpaceOnUse' | 'objectBoundingBox'} [gradientUnits] - The coordinate system used
     * for the coordinate attributes. See {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/gradientUnits}.
     * @property {SvgLength} [r] - The radius of the end circle of the radial gradient.
     * @property {'pad' | 'reflect' | 'repeat'} [spreadMethod] - The method used to fill a shape beyond
     * the defined edges of a gradient. See {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/spreadMethod}.
     * @property {StopDefinition[]} [stops] - The colors of the gradient, and the position of each
     * color along the gradient vector.
     * @property {'radial'} type - The type of the gradient.
     */
    
    function createLogoViewer(
      container,
      renderScene,
      {
        followMouse = false,
        followMotion = false,
        slowDrift = false,
        lazyRender = true,
      } = {},
    ) {
      let shouldRender = true;
      const mouse = {
        x: 0,
        y: 0,
      };
      const lookCurrent = [0, 0];
      const lookRate = 0.3;
    
      // closes over scene state
      const renderCurrentScene = () => {
        updateLookCurrent();
        renderScene(lookCurrent, slowDrift);
      };
    
      function setLookAtTarget(target) {
        const bounds = container.getBoundingClientRect();
        mouse.x = 1.0 - (2.0 * (target.x - bounds.left)) / bounds.width;
        mouse.y = 1.0 - (2.0 * (target.y - bounds.top)) / bounds.height;
      }
    
      function stopAnimation() {
        shouldRender = false;
      }
    
      function startAnimation() {
        shouldRender = true;
      }
    
      function setFollowMouse(state) {
        // eslint-disable-next-line no-param-reassign
        followMouse = state;
      }
    
      function setFollowMotion(state) {
        // eslint-disable-next-line no-param-reassign
        followMotion = state;
      }
    
      window.addEventListener('mousemove', function (ev) {
        if (!shouldRender) {
          startAnimation();
        }
    
        if (followMouse) {
          setLookAtTarget({
            x: ev.clientX,
            y: ev.clientY,
          });
          renderCurrentScene();
        }
      });
    
      window.addEventListener('deviceorientation', function (event) {
        if (!shouldRender) {
          startAnimation();
        }
    
        if (followMotion) {
          // gamma: left to right
          const leftToRight = event.gamma;
          // beta: front back motion
          const frontToBack = event.beta;
          // x offset: needed to correct the intial position
          const xOffset = 200;
          // y offset: needed to correct the intial position
          const yOffset = -300;
          // acceleration
          const acceleration = 10;
    
          setLookAtTarget({
            x: xOffset + leftToRight * acceleration,
            y: yOffset + frontToBack * acceleration,
          });
          renderCurrentScene();
        }
      });
    
      function lookAtAndRender(target) {
        // update look target
        setLookAtTarget(target);
        // this should prolly just call updateLookCurrent or set lookCurrent values to eaxactly lookTarget
        // but im not really sure why its different, so im leaving it alone
        lookCurrent[0] = mouse.x;
        lookCurrent[1] = mouse.y + 0.085 / lookRate;
        renderCurrentScene();
      }
    
      function renderLoop() {
        if (!shouldRender) {
          return;
        }
        window.requestAnimationFrame(renderLoop);
        renderCurrentScene();
      }
    
      function updateLookCurrent() {
        const li = 1.0 - lookRate;
        lookCurrent[0] = li * lookCurrent[0] + lookRate * mouse.x;
        lookCurrent[1] = li * lookCurrent[1] + lookRate * mouse.y + 0.085;
      }
    
      if (lazyRender) {
        renderCurrentScene();
      } else {
        renderLoop();
      }
    
      return {
        container,
        lookAt: setLookAtTarget,
        setFollowMouse,
        setFollowMotion,
        stopAnimation,
        startAnimation,
        lookAtAndRender,
        renderCurrentScene,
      };
    }
    
    function loadModelFromJson(
      modelJson,
      createSvgPolygon = createStandardModelPolygon,
    ) {
      const vertCount = modelJson.positions.length;
      const positions = new Float32Array(3 * vertCount);
      const transformed = new Float32Array(3 * vertCount);
      const { polygons, polygonsByChunk } = createPolygonsFromModelJson(
        modelJson,
        createSvgPolygon,
      );
      positionsFromModel(positions, modelJson);
      const updatePositions = createPositionUpdater(
        positions,
        transformed,
        vertCount,
      );
      const modelObj = {
        updatePositions,
        positions,
        transformed,
        polygons,
        polygonsByChunk,
      };
      return modelObj;
    }
    
    function createModelRenderer(container, cameraDistance, modelObj) {
      const { updatePositions, transformed, polygons } = modelObj;
    
      for (const polygon of polygons) {
        container.appendChild(polygon.svg);
      }
    
      const computeMatrix = createMatrixComputer(cameraDistance);
      const updateFaces = createFaceUpdater(container, polygons, transformed);
    
      return (rect, lookPos, slowDrift) => {
        const matrix = computeMatrix(rect, lookPos, slowDrift);
        updatePositions(matrix);
        updateFaces(rect, container, polygons, transformed);
      };
    }
    
    function positionsFromModel(positions, modelJson) {
      const pp = modelJson.positions;
      let ptr = 0;
      for (let i = 0; i < pp.length; ++i) {
        const p = pp[i];
        for (let j = 0; j < 3; ++j) {
          positions[ptr] = p[j];
          ptr += 1;
        }
      }
    }
    
    function createPolygonsFromModelJson(modelJson, createSvgPolygon) {
      const polygons = [];
      const polygonsByChunk = modelJson.chunks.map((chunk, index) => {
        const { faces } = chunk;
        return faces.map((face) => {
          const svgPolygon = createSvgPolygon(chunk, {
            gradients: modelJson.gradients,
            index,
            masks: modelJson.masks,
          });
          const polygon = new Polygon(svgPolygon, face);
          polygons.push(polygon);
          return polygon;
        });
      });
      return { polygons, polygonsByChunk };
    }
    
    /**
     * Create an SVG `<polygon> element.
     *
     * This polygon is assigned the correct `fill` and `stroke` attributes, according to the chunk
     * definition provided. But the `points` attribute is always set to a dummy value, as it gets reset
     * later to the correct position during each render loop.
     *
     * @param {object} chunk - The definition for the chunk of the model this polygon is a part of.
     * This includes the color or gradient to apply to the polygon.
     * @param {object} options - Polygon options.
     * @param {(LinearGradientDefinition | RadialGradientDefinition)[]} [options.gradients] - The set of
     * all gradient definitions used in this model.
     * @param options.index - The index for the chunk this polygon is found in.
     * @returns {Element} The `<polygon>` SVG element.
     */
    function createStandardModelPolygon(chunk, { gradients = {}, index, masks }) {
      const svgPolygon = createNode('polygon');
    
      if (chunk.gradient && chunk.color) {
        throw new Error(
          `Both gradient and color for chunk '${index}'. These options are mutually exclusive.`,
        );
      } else if (chunk.gradient) {
        const gradientId = chunk.gradient;
        if (!gradients[gradientId]) {
          throw new Error(`Gradient ID not found: '${gradientId}'`);
        }
    
        setAttribute(svgPolygon, 'fill', `url('#${gradientId}')`);
        setAttribute(svgPolygon, 'stroke', `url('#${gradientId}')`);
      } else {
        const fill =
          typeof chunk.color === 'string' ? chunk.color : `rgb(${chunk.color})`;
        setAttribute(svgPolygon, 'fill', fill);
        setAttribute(svgPolygon, 'stroke', fill);
      }
    
      if (chunk.mask) {
        if (!masks[chunk.mask]) {
          throw new Error(`Mask ID not found: '${chunk.mask}'`);
        }
        setAttribute(svgPolygon, 'mask', `url('#${chunk.mask}')`);
      }
    
      setAttribute(svgPolygon, 'points', '0,0, 10,0, 0,10');
      return svgPolygon;
    }
    
    function createMatrixComputer(distance) {
      const objectCenter = new Float32Array(3);
      const up = new Float32Array([0, 1, 0]);
      const projection = new Float32Array(16);
      const model = new Float32Array(16);
      const view = lookAt(
        new Float32Array(16),
        new Float32Array([0, 0, distance]),
        objectCenter,
        up,
      );
      const invView = invert(new Float32Array(16), view);
      const invProjection = new Float32Array(16);
      const target = new Float32Array(3);
      const transformedMatrix = new Float32Array(16);
    
      const X = new Float32Array([1, 0, 0]);
      const Y = new Float32Array([0, 1, 0]);
      const Z = new Float32Array([0, 0, 1]);
    
      return (rect, lookPos, slowDrift) => {
        const viewportWidth = rect.width;
        const viewportHeight = rect.height;
        perspective(
          projection,
          Math.PI / 4.0,
          viewportWidth / viewportHeight,
          100.0,
          1000.0,
        );
        invert(invProjection, projection);
        target[0] = lookPos[0];
        target[1] = lookPos[1];
        target[2] = 1.2;
        transform(target, target, invProjection);
        transform(target, target, invView);
        lookAt(model, objectCenter, target, up);
    
        // this shouldnt operate directly on the matrix/model,
        // it should likely operate on the lookPos
        // if we do want to operate on the matrix/model, it shouldnt happen here
        if (slowDrift) {
          const time = Date.now() / 1000.0;
          rotate(model, model, 0.1 + Math.sin(time / 3) * 0.2, X);
          rotate(model, model, -0.1 + Math.sin(time / 2) * 0.03, Z);
          rotate(model, model, 0.5 + Math.sin(time / 3) * 0.2, Y);
        }
    
        multiply(transformedMatrix, projection, view);
        multiply(transformedMatrix, transformedMatrix, model);
    
        return transformedMatrix;
      };
    }
    
    function createPositionUpdater(positions, transformed, vertCount) {
      return (M) => {
        const m00 = M[0];
        const m01 = M[1];
        const m02 = M[2];
        const m03 = M[3];
        const m10 = M[4];
        const m11 = M[5];
        const m12 = M[6];
        const m13 = M[7];
        const m20 = M[8];
        const m21 = M[9];
        const m22 = M[10];
        const m23 = M[11];
        const m30 = M[12];
        const m31 = M[13];
        const m32 = M[14];
        const m33 = M[15];
    
        for (let i = 0; i < vertCount; ++i) {
          const x = positions[3 * i];
          const y = positions[3 * i + 1];
          const z = positions[3 * i + 2];
    
          const tw = x * m03 + y * m13 + z * m23 + m33;
          transformed[3 * i] = (x * m00 + y * m10 + z * m20 + m30) / tw;
          transformed[3 * i + 1] = (x * m01 + y * m11 + z * m21 + m31) / tw;
          transformed[3 * i + 2] = (x * m02 + y * m12 + z * m22 + m32) / tw;
        }
      };
    }
    
    function compareZ(a, b) {
      return b.zIndex - a.zIndex;
    }
    
    function createFaceUpdater(container, polygons, transformed) {
      const toDraw = [];
      return (rect) => {
        let i;
        const w = rect.width;
        const h = rect.height;
        toDraw.length = 0;
        for (i = 0; i < polygons.length; ++i) {
          const poly = polygons[i];
          const { indices } = poly;
    
          const i0 = indices[0];
          const i1 = indices[1];
          const i2 = indices[2];
          const ax = transformed[3 * i0];
          const ay = transformed[3 * i0 + 1];
          const bx = transformed[3 * i1];
          const by = transformed[3 * i1 + 1];
          const cx = transformed[3 * i2];
          const cy = transformed[3 * i2 + 1];
          const det = (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
          if (det < 0) {
            continue;
          }
    
          const points = [];
          let zmax = -Infinity;
          let zmin = Infinity;
          const element = poly.svg;
          for (let j = 0; j < 3; ++j) {
            const idx = indices[j];
            points.push(
              `${0.5 * w * (1.0 - transformed[3 * idx])},${
                0.5 * h * (1.0 - transformed[3 * idx + 1])
              }`,
            );
            const z = transformed[3 * idx + 2];
            zmax = Math.max(zmax, z);
            zmin = Math.min(zmin, z);
          }
          poly.zIndex = zmax + 0.25 * zmin;
          const joinedPoints = points.join(' ');
    
          if (joinedPoints.indexOf('NaN') === -1) {
            setAttribute(element, 'points', joinedPoints);
          }
    
          toDraw.push(poly);
        }
        toDraw.sort(compareZ);
    
        const newPolygons = toDraw.map((poly) => poly.svg);
        const defs = container.getElementsByTagName('defs');
        const maskChildren = container.getElementsByTagName('mask');
        if (container.replaceChildren) {
          container.replaceChildren(...defs, ...maskChildren, ...newPolygons);
        } else {
          replaceChildrenPonyfill.bind(container)(
            ...defs,
            ...maskChildren,
            ...newPolygons,
          );
        }
      };
    }
    
    function calculateSizingOptions(options = {}) {
      let width = options.width || 400;
      let height = options.height || 400;
    
      if (!options.pxNotRatio) {
        width = Math.floor(window.innerWidth * (options.width || 0.25));
        height = Math.floor(window.innerHeight * options.height || width);
    
        if ('minWidth' in options && width < options.minWidth) {
          width = options.minWidth;
          height = Math.floor((options.minWidth * options.height) / options.width);
        }
      }
      return { width, height };
    }
    
    function createNode(type) {
      return document.createElementNS(SVG_NS, type);
    }
    
    function setAttribute(node, attribute, value) {
      node.setAttributeNS(null, attribute, value);
    }
    
    function svgElementToSvgImageContent(svgElement) {
      const inner = svgElement.innerHTML;
      const head =
        `<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> ` +
        `<svg width="521px" height="521px" version="1.1" baseProfile="full" xmlns="${SVG_NS}" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events">`;
      const foot = '</svg>';
      const content = head + inner + foot;
      return content;
    }
    
    function Polygon(svg, indices) {
      this.svg = svg;
      this.indices = indices;
      this.zIndex = 0;
    }
    
    /**
     * Parse gradient definitions and construct them in the DOM.
     *
     * Both `<linearGradient>` and `<radialGradient>` are supported. All gradients get added to a
     * `<defs>` element that is added as a direct child of the container element.
     *
     * @param {Element} container - The `<svg>` HTML element that the definitions should be added to.
     * @param {(LinearGradientDefinition | RadialGradientDefinition)[]} [gradients] - The gradient definitions.
     */
    function setGradientDefinitions(container, gradients) {
      if (!gradients || Object.keys(gradients).length === 0) {
        return;
      }
    
      const defsContainer = createNode('defs');
    
      const linearCoordinateAttributes = ['x1', 'x2', 'y1', 'y2'];
      const radialCoordinateAttributes = ['cx', 'cy', 'fr', 'fx', 'fy', 'r'];
      const commonAttributes = [
        'gradientTransform',
        'gradientUnits',
        'spreadMethod',
        'stops',
        'type',
      ];
      const allLinearAttributes = [
        ...linearCoordinateAttributes,
        ...commonAttributes,
      ];
      const allRadialAttributes = [
        ...radialCoordinateAttributes,
        ...commonAttributes,
      ];
    
      for (const [gradientId, gradientDefinition] of Object.entries(gradients)) {
        let gradient;
        if (gradientDefinition.type === 'linear') {
          gradient = createNode('linearGradient');
    
          const unsupportedLinearAttribute = Object.keys(gradientDefinition).find(
            (attribute) => !allLinearAttributes.includes(attribute),
          );
          if (unsupportedLinearAttribute) {
            throw new Error(
              `Unsupported linear gradient attribute: '${unsupportedLinearAttribute}'`,
            );
          } else if (
            linearCoordinateAttributes.some(
              (attributeName) => gradientDefinition[attributeName] !== undefined,
            )
          ) {
            const missingAttributes = linearCoordinateAttributes.filter(
              (attributeName) => gradientDefinition[attributeName] === undefined,
            );
            if (missingAttributes.length > 0) {
              throw new Error(
                `Missing coordinate attributes: '${missingAttributes.join(', ')}'`,
              );
            }
    
            for (const attribute of linearCoordinateAttributes) {
              if (typeof gradientDefinition[attribute] !== 'string') {
                throw new Error(
                  `Type of '${attribute}' option expected to be 'string'. Instead received type '${typeof gradientDefinition[
                    attribute
                  ]}'`,
                );
              }
              setAttribute(gradient, attribute, gradientDefinition[attribute]);
            }
          }
        } else if (gradientDefinition.type === 'radial') {
          gradient = createNode('radialGradient');
    
          const presentCoordinateAttributes = radialCoordinateAttributes.filter(
            (attributeName) => gradientDefinition[attributeName] !== undefined,
          );
          const unsupportedRadialAttribute = Object.keys(gradientDefinition).find(
            (attribute) => !allRadialAttributes.includes(attribute),
          );
          if (unsupportedRadialAttribute) {
            throw new Error(
              `Unsupported radial gradient attribute: '${unsupportedRadialAttribute}'`,
            );
          } else if (presentCoordinateAttributes.length > 0) {
            for (const attribute of presentCoordinateAttributes) {
              if (typeof gradientDefinition[attribute] !== 'string') {
                throw new Error(
                  `Type of '${attribute}' option expected to be 'string'. Instead received type '${typeof gradientDefinition[
                    attribute
                  ]}'`,
                );
              }
              setAttribute(gradient, attribute, gradientDefinition[attribute]);
            }
          }
        } else {
          throw new Error(
            `Unsupported gradient type: '${gradientDefinition.type}'`,
          );
        }
    
        // Set common attributes
        setAttribute(gradient, 'id', gradientId);
        if (gradientDefinition.gradientUnits !== undefined) {
          if (
            !['userSpaceOnUse', 'objectBoundingBox'].includes(
              gradientDefinition.gradientUnits,
            )
          ) {
            throw new Error(
              `Unrecognized value for 'gradientUnits' attribute: '${gradientDefinition.gradientUnits}'`,
            );
          }
          setAttribute(gradient, 'gradientUnits', gradientDefinition.gradientUnits);
        }
    
        if (gradientDefinition.gradientTransform !== undefined) {
          if (typeof gradientDefinition.gradientTransform !== 'string') {
            throw new Error(
              `Type of 'gradientTransform' option expected to be 'string'. Instead received type '${typeof gradientDefinition.gradientTransform}'`,
            );
          }
    
          setAttribute(
            gradient,
            'gradientTransform',
            gradientDefinition.gradientTransform,
          );
        }
    
        if (gradientDefinition.spreadMethod !== undefined) {
          if (
            !['pad', 'reflect', 'repeat'].includes(gradientDefinition.spreadMethod)
          ) {
            throw new Error(
              `Unrecognized value for 'spreadMethod' attribute: '${gradientDefinition.spreadMethod}'`,
            );
          }
          setAttribute(gradient, 'spreadMethod', gradientDefinition.spreadMethod);
        }
    
        if (gradientDefinition.stops !== undefined) {
          if (!Array.isArray(gradientDefinition.stops)) {
            throw new Error(`The 'stop' attribute must be an array`);
          }
    
          for (const stopDefinition of gradientDefinition.stops) {
            if (typeof stopDefinition !== 'object') {
              throw new Error(
                `Each entry in the 'stop' attribute must be an object. Instead received type '${typeof stopDefinition}'`,
              );
            }
            const stop = createNode('stop');
    
            if (stopDefinition.offset !== undefined) {
              setAttribute(stop, 'offset', stopDefinition.offset);
            }
    
            if (stopDefinition['stop-color'] !== undefined) {
              setAttribute(stop, 'stop-color', stopDefinition['stop-color']);
            }
    
            if (stopDefinition['stop-opacity'] !== undefined) {
              setAttribute(stop, 'stop-opacity', stopDefinition['stop-opacity']);
            }
    
            gradient.appendChild(stop);
          }
        }
    
        defsContainer.appendChild(gradient);
      }
    
      container.appendChild(defsContainer);
    }
    
    /**
     * The properties of a single SVG mask.
     *
     * @typedef MaskDefinition
     * @property {string} color - The color or gradient to apply to the mask.
     */
    
    /**
     * Parse mask definitions and construct them in the DOM.
     *
     * The `<mask>` element contains a single rectangle that should cover the full extent of the SVG
     * model. The color of this rectangle can be set to single color or a gradient. Anything the mask
     * is applied to will be invisible if under a black pixel, visible if under a white pixel, and
     * partially translucent if under a pixel that is between white and black.
     *
     * Later this could be extended to include custom paths and other shapes, rather than just a single
     * rectangle.
     *
     * @param options - The mask options.
     * @param {Element} options.container - The `<svg>` HTML element that the mask should be added to.
     * @param {Record<string, MaskDefinition>} [options.masks] - The gradient definitions.
     * @param {number} options.height - The height of the SVG container.
     * @param {number} options.width - The width of the SVG container.
     */
    function setMaskDefinitions({ container, masks, height, width }) {
      if (!masks || Object.keys(masks).length === 0) {
        return;
      }
    
      for (const [maskId, maskDefinition] of Object.entries(masks)) {
        const mask = createNode('mask');
        setAttribute(mask, 'id', maskId);
    
        const maskedRect = createNode('rect');
    
        // Extend mask beyond container to ensure it completely covers the model.
        // The model can extend beyond the container as well.
        setAttribute(maskedRect, 'width', width * 1.5);
        setAttribute(maskedRect, 'height', height * 1.5);
        setAttribute(maskedRect, 'x', `-${Math.floor(width / 4)}`);
        setAttribute(maskedRect, 'y', `-${Math.floor(height / 4)}`);
    
        setAttribute(maskedRect, 'fill', maskDefinition.color);
        mask.appendChild(maskedRect);
    
        container.appendChild(mask);
      }
    }
    
    },{"gl-mat4/invert":6,"gl-mat4/lookAt":7,"gl-mat4/multiply":8,"gl-mat4/perspective":9,"gl-mat4/rotate":10,"gl-vec3/transformMat4":11}]},{},[1]);