diff --git a/lawsons-klein-bottle/bundle.js b/lawsons-klein-bottle/bundle.js new file mode 100644 index 0000000..3e8cf5b --- /dev/null +++ b/lawsons-klein-bottle/bundle.js @@ -0,0 +1 @@ +!function(){return function e(t,n,r){function i(a,u){if(!n[a]){if(!t[a]){var s="function"==typeof require&&require;if(!u&&s)return s(a,!0);if(o)return o(a,!0);var f=new Error("Cannot find module '"+a+"'");throw f.code="MODULE_NOT_FOUND",f}var c=n[a]={exports:{}};t[a][0].call(c.exports,function(e){return i(t[a][1][e]||e)},c,c.exports,e,t,n,r)}return n[a].exports}for(var o="function"==typeof require&&require,a=0;a=0;f--)if(c[f]!==l[f])return!1;for(f=c.length-1;f>=0;f--)if(u=c[f],!y(e[u],t[u],n,r))return!1;return!0}(e,t,n,r))}return n?e===t:e==t}function w(e){return"[object Arguments]"==Object.prototype.toString.call(e)}function x(e,t){if(!e||!t)return!1;if("[object RegExp]"==Object.prototype.toString.call(t))return t.test(e);try{if(e instanceof t)return!0}catch(e){}return!Error.isPrototypeOf(t)&&!0===t.call({},e)}function _(e,t,n,r){var i;if("function"!=typeof t)throw new TypeError('"block" argument must be a function');"string"==typeof n&&(r=n,n=null),i=function(e){var t;try{e()}catch(e){t=e}return t}(t),r=(n&&n.name?" ("+n.name+").":".")+(r?" "+r:"."),e&&!i&&v(i,n,"Missing expected exception"+r);var o="string"==typeof r,u=!e&&i&&!n;if((!e&&a.isError(i)&&o&&x(i,n)||u)&&v(i,n,"Got unwanted exception"+r),e&&i&&n&&!x(i,n)||!e&&i)throw i}p.AssertionError=function(e){var t;this.name="AssertionError",this.actual=e.actual,this.expected=e.expected,this.operator=e.operator,e.message?(this.message=e.message,this.generatedMessage=!1):(this.message=m(g((t=this).actual),128)+" "+t.operator+" "+m(g(t.expected),128),this.generatedMessage=!0);var n=e.stackStartFunction||v;if(Error.captureStackTrace)Error.captureStackTrace(this,n);else{var r=new Error;if(r.stack){var i=r.stack,o=d(n),a=i.indexOf("\n"+o);if(a>=0){var u=i.indexOf("\n",a+1);i=i.substring(u+1)}this.stack=i}}},a.inherits(p.AssertionError,Error),p.fail=v,p.ok=b,p.equal=function(e,t,n){e!=t&&v(e,t,n,"==",p.equal)},p.notEqual=function(e,t,n){e==t&&v(e,t,n,"!=",p.notEqual)},p.deepEqual=function(e,t,n){y(e,t,!1)||v(e,t,n,"deepEqual",p.deepEqual)},p.deepStrictEqual=function(e,t,n){y(e,t,!0)||v(e,t,n,"deepStrictEqual",p.deepStrictEqual)},p.notDeepEqual=function(e,t,n){y(e,t,!1)&&v(e,t,n,"notDeepEqual",p.notDeepEqual)},p.notDeepStrictEqual=function e(t,n,r){y(t,n,!0)&&v(t,n,r,"notDeepStrictEqual",e)},p.strictEqual=function(e,t,n){e!==t&&v(e,t,n,"===",p.strictEqual)},p.notStrictEqual=function(e,t,n){e===t&&v(e,t,n,"!==",p.notStrictEqual)},p.throws=function(e,t,n){_(!0,e,t,n)},p.doesNotThrow=function(e,t,n){_(!1,e,t,n)},p.ifError=function(e){if(e)throw e},p.strict=r(function e(t,n){t||v(t,!0,n,"==",e)},p,{equal:p.strictEqual,deepEqual:p.deepStrictEqual,notEqual:p.notStrictEqual,notDeepEqual:p.notDeepStrictEqual}),p.strict.strict=p.strict;var A=Object.keys||function(e){var t=[];for(var n in e)u.call(e,n)&&t.push(n);return t}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"object-assign":48,"util/":4}],2:[function(e,t,n){"function"==typeof Object.create?t.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(e,t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}},{}],3:[function(e,t,n){t.exports=function(e){return e&&"object"==typeof e&&"function"==typeof e.copy&&"function"==typeof e.fill&&"function"==typeof e.readUInt8}},{}],4:[function(e,t,n){(function(t,r){var i=/%[sdj%]/g;n.format=function(e){if(!v(e)){for(var t=[],n=0;n=o)return e;switch(e){case"%s":return String(r[n++]);case"%d":return Number(r[n++]);case"%j":try{return JSON.stringify(r[n++])}catch(e){return"[Circular]"}default:return e}}),s=r[n];n=3&&(r.depth=arguments[2]),arguments.length>=4&&(r.colors=arguments[3]),d(t)?r.showHidden=t:t&&n._extend(r,t),b(r.showHidden)&&(r.showHidden=!1),b(r.depth)&&(r.depth=2),b(r.colors)&&(r.colors=!1),b(r.customInspect)&&(r.customInspect=!0),r.colors&&(r.stylize=s),c(r,e,r.depth)}function s(e,t){var n=u.styles[t];return n?"["+u.colors[n][0]+"m"+e+"["+u.colors[n][1]+"m":e}function f(e,t){return e}function c(e,t,r){if(e.customInspect&&t&&A(t.inspect)&&t.inspect!==n.inspect&&(!t.constructor||t.constructor.prototype!==t)){var i=t.inspect(r,e);return v(i)||(i=c(e,i,r)),i}var o=function(e,t){if(b(t))return e.stylize("undefined","undefined");if(v(t)){var n="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(n,"string")}if(g(t))return e.stylize(""+t,"number");if(d(t))return e.stylize(""+t,"boolean");if(m(t))return e.stylize("null","null")}(e,t);if(o)return o;var a=Object.keys(t),u=function(e){var t={};return e.forEach(function(e,n){t[e]=!0}),t}(a);if(e.showHidden&&(a=Object.getOwnPropertyNames(t)),_(t)&&(a.indexOf("message")>=0||a.indexOf("description")>=0))return l(t);if(0===a.length){if(A(t)){var s=t.name?": "+t.name:"";return e.stylize("[Function"+s+"]","special")}if(y(t))return e.stylize(RegExp.prototype.toString.call(t),"regexp");if(x(t))return e.stylize(Date.prototype.toString.call(t),"date");if(_(t))return l(t)}var f,w="",E=!1,C=["{","}"];(h(t)&&(E=!0,C=["[","]"]),A(t))&&(w=" [Function"+(t.name?": "+t.name:"")+"]");return y(t)&&(w=" "+RegExp.prototype.toString.call(t)),x(t)&&(w=" "+Date.prototype.toUTCString.call(t)),_(t)&&(w=" "+l(t)),0!==a.length||E&&0!=t.length?r<0?y(t)?e.stylize(RegExp.prototype.toString.call(t),"regexp"):e.stylize("[Object]","special"):(e.seen.push(t),f=E?function(e,t,n,r,i){for(var o=[],a=0,u=t.length;a=0&&0,e+t.replace(/\u001b\[\d\d?m/g,"").length+1},0)>60)return n[0]+(""===t?"":t+"\n ")+" "+e.join(",\n ")+" "+n[1];return n[0]+t+" "+e.join(", ")+" "+n[1]}(f,w,C)):C[0]+w+C[1]}function l(e){return"["+Error.prototype.toString.call(e)+"]"}function p(e,t,n,r,i,o){var a,u,s;if((s=Object.getOwnPropertyDescriptor(t,i)||{value:t[i]}).get?u=s.set?e.stylize("[Getter/Setter]","special"):e.stylize("[Getter]","special"):s.set&&(u=e.stylize("[Setter]","special")),O(r,i)||(a="["+i+"]"),u||(e.seen.indexOf(s.value)<0?(u=m(n)?c(e,s.value,null):c(e,s.value,n-1)).indexOf("\n")>-1&&(u=o?u.split("\n").map(function(e){return" "+e}).join("\n").substr(2):"\n"+u.split("\n").map(function(e){return" "+e}).join("\n")):u=e.stylize("[Circular]","special")),b(a)){if(o&&i.match(/^\d+$/))return u;(a=JSON.stringify(""+i)).match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=e.stylize(a,"name")):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=e.stylize(a,"string"))}return a+": "+u}function h(e){return Array.isArray(e)}function d(e){return"boolean"==typeof e}function m(e){return null===e}function g(e){return"number"==typeof e}function v(e){return"string"==typeof e}function b(e){return void 0===e}function y(e){return w(e)&&"[object RegExp]"===E(e)}function w(e){return"object"==typeof e&&null!==e}function x(e){return w(e)&&"[object Date]"===E(e)}function _(e){return w(e)&&("[object Error]"===E(e)||e instanceof Error)}function A(e){return"function"==typeof e}function E(e){return Object.prototype.toString.call(e)}function C(e){return e<10?"0"+e.toString(10):e.toString(10)}n.debuglog=function(e){if(b(o)&&(o=t.env.NODE_DEBUG||""),e=e.toUpperCase(),!a[e])if(new RegExp("\\b"+e+"\\b","i").test(o)){var r=t.pid;a[e]=function(){var t=n.format.apply(n,arguments);console.error("%s %d: %s",e,r,t)}}else a[e]=function(){};return a[e]},n.inspect=u,u.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},u.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"},n.isArray=h,n.isBoolean=d,n.isNull=m,n.isNullOrUndefined=function(e){return null==e},n.isNumber=g,n.isString=v,n.isSymbol=function(e){return"symbol"==typeof e},n.isUndefined=b,n.isRegExp=y,n.isObject=w,n.isDate=x,n.isError=_,n.isFunction=A,n.isPrimitive=function(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e},n.isBuffer=e("./support/isBuffer");var k=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function O(e,t){return Object.prototype.hasOwnProperty.call(e,t)}n.log=function(){var e,t;console.log("%s - %s",(e=new Date,t=[C(e.getHours()),C(e.getMinutes()),C(e.getSeconds())].join(":"),[e.getDate(),k[e.getMonth()],t].join(" ")),n.format.apply(n,arguments))},n.inherits=e("inherits"),n._extend=function(e,t){if(!t||!w(t))return e;for(var n=Object.keys(t),r=n.length;r--;)e[n[r]]=t[n[r]];return e}}).call(this,e("_process"),"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./support/isBuffer":3,_process:49,inherits:2}],5:[function(e,t,n){"use strict";n.byteLength=function(e){var t=f(e),n=t[0],r=t[1];return 3*(n+r)/4-r},n.toByteArray=function(e){var t,n,r=f(e),a=r[0],u=r[1],s=new o(function(e,t,n){return 3*(t+n)/4-n}(0,a,u)),c=0,l=u>0?a-4:a;for(n=0;n>16&255,s[c++]=t>>8&255,s[c++]=255&t;2===u&&(t=i[e.charCodeAt(n)]<<2|i[e.charCodeAt(n+1)]>>4,s[c++]=255&t);1===u&&(t=i[e.charCodeAt(n)]<<10|i[e.charCodeAt(n+1)]<<4|i[e.charCodeAt(n+2)]>>2,s[c++]=t>>8&255,s[c++]=255&t);return s},n.fromByteArray=function(e){for(var t,n=e.length,i=n%3,o=[],a=0,u=n-i;au?u:a+16383));1===i?(t=e[n-1],o.push(r[t>>2]+r[t<<4&63]+"==")):2===i&&(t=(e[n-2]<<8)+e[n-1],o.push(r[t>>10]+r[t>>4&63]+r[t<<2&63]+"="));return o.join("")};for(var r=[],i=[],o="undefined"!=typeof Uint8Array?Uint8Array:Array,a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",u=0,s=a.length;u0)throw new Error("Invalid string. Length must be a multiple of 4");var n=e.indexOf("=");return-1===n&&(n=t),[n,n===t?0:4-n%4]}function c(e,t,n){for(var i,o,a=[],u=t;u>18&63]+r[o>>12&63]+r[o>>6&63]+r[63&o]);return a.join("")}i["-".charCodeAt(0)]=62,i["_".charCodeAt(0)]=63},{}],6:[function(e,t,n){(function(t){"use strict";var r=e("base64-js"),i=e("ieee754"),o="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):null;n.Buffer=t,n.SlowBuffer=function(e){+e!=e&&(e=0);return t.alloc(+e)},n.INSPECT_MAX_BYTES=50;var a=2147483647;function u(e){if(e>a)throw new RangeError('The value "'+e+'" is invalid for option "size"');var n=new Uint8Array(e);return Object.setPrototypeOf(n,t.prototype),n}function t(e,t,n){if("number"==typeof e){if("string"==typeof t)throw new TypeError('The "string" argument must be of type string. Received type number');return c(e)}return s(e,t,n)}function s(e,n,r){if("string"==typeof e)return function(e,n){"string"==typeof n&&""!==n||(n="utf8");if(!t.isEncoding(n))throw new TypeError("Unknown encoding: "+n);var r=0|d(e,n),i=u(r),o=i.write(e,n);o!==r&&(i=i.slice(0,o));return i}(e,n);if(ArrayBuffer.isView(e))return l(e);if(null==e)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e);if(I(e,ArrayBuffer)||e&&I(e.buffer,ArrayBuffer))return p(e,n,r);if("undefined"!=typeof SharedArrayBuffer&&(I(e,SharedArrayBuffer)||e&&I(e.buffer,SharedArrayBuffer)))return p(e,n,r);if("number"==typeof e)throw new TypeError('The "value" argument must not be of type number. Received type number');var i=e.valueOf&&e.valueOf();if(null!=i&&i!==e)return t.from(i,n,r);var o=function(e){if(t.isBuffer(e)){var n=0|h(e.length),r=u(n);return 0===r.length?r:(e.copy(r,0,0,n),r)}if(void 0!==e.length)return"number"!=typeof e.length||U(e.length)?u(0):l(e);if("Buffer"===e.type&&Array.isArray(e.data))return l(e.data)}(e);if(o)return o;if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof e[Symbol.toPrimitive])return t.from(e[Symbol.toPrimitive]("string"),n,r);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e)}function f(e){if("number"!=typeof e)throw new TypeError('"size" argument must be of type number');if(e<0)throw new RangeError('The value "'+e+'" is invalid for option "size"')}function c(e){return f(e),u(e<0?0:0|h(e))}function l(e){for(var t=e.length<0?0:0|h(e.length),n=u(t),r=0;r=a)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+a.toString(16)+" bytes");return 0|e}function d(e,n){if(t.isBuffer(e))return e.length;if(ArrayBuffer.isView(e)||I(e,ArrayBuffer))return e.byteLength;if("string"!=typeof e)throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof e);var r=e.length,i=arguments.length>2&&!0===arguments[2];if(!i&&0===r)return 0;for(var o=!1;;)switch(n){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":return L(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return N(e).length;default:if(o)return i?-1:L(e).length;n=(""+n).toLowerCase(),o=!0}}function m(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function g(e,n,r,i,o){if(0===e.length)return-1;if("string"==typeof r?(i=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),U(r=+r)&&(r=o?0:e.length-1),r<0&&(r=e.length+r),r>=e.length){if(o)return-1;r=e.length-1}else if(r<0){if(!o)return-1;r=0}if("string"==typeof n&&(n=t.from(n,i)),t.isBuffer(n))return 0===n.length?-1:v(e,n,r,i,o);if("number"==typeof n)return n&=255,"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,n,r):Uint8Array.prototype.lastIndexOf.call(e,n,r):v(e,[n],r,i,o);throw new TypeError("val must be string, number or Buffer")}function v(e,t,n,r,i){var o,a=1,u=e.length,s=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,u/=2,s/=2,n/=2}function f(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}if(i){var c=-1;for(o=n;ou&&(n=u-s),o=n;o>=0;o--){for(var l=!0,p=0;pi&&(r=i):r=i;var o=t.length;r>o/2&&(r=o/2);for(var a=0;a>8,i=n%256,o.push(i),o.push(r);return o}(t,e.length-n),e,n,r)}function E(e,t,n){return 0===t&&n===e.length?r.fromByteArray(e):r.fromByteArray(e.slice(t,n))}function C(e,t,n){n=Math.min(e.length,n);for(var r=[],i=t;i239?4:f>223?3:f>191?2:1;if(i+l<=n)switch(l){case 1:f<128&&(c=f);break;case 2:128==(192&(o=e[i+1]))&&(s=(31&f)<<6|63&o)>127&&(c=s);break;case 3:o=e[i+1],a=e[i+2],128==(192&o)&&128==(192&a)&&(s=(15&f)<<12|(63&o)<<6|63&a)>2047&&(s<55296||s>57343)&&(c=s);break;case 4:o=e[i+1],a=e[i+2],u=e[i+3],128==(192&o)&&128==(192&a)&&128==(192&u)&&(s=(15&f)<<18|(63&o)<<12|(63&a)<<6|63&u)>65535&&s<1114112&&(c=s)}null===c?(c=65533,l=1):c>65535&&(c-=65536,r.push(c>>>10&1023|55296),c=56320|1023&c),r.push(c),i+=l}return function(e){var t=e.length;if(t<=k)return String.fromCharCode.apply(String,e);var n="",r=0;for(;rthis.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if((n>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return j(this,t,n);case"utf8":case"utf-8":return C(this,t,n);case"ascii":return O(this,t,n);case"latin1":case"binary":return T(this,t,n);case"base64":return E(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return S(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}.apply(this,arguments)},t.prototype.toLocaleString=t.prototype.toString,t.prototype.equals=function(e){if(!t.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e||0===t.compare(this,e)},t.prototype.inspect=function(){var e="",t=n.INSPECT_MAX_BYTES;return e=this.toString("hex",0,t).replace(/(.{2})/g,"$1 ").trim(),this.length>t&&(e+=" ... "),""},o&&(t.prototype[o]=t.prototype.inspect),t.prototype.compare=function(e,n,r,i,o){if(I(e,Uint8Array)&&(e=t.from(e,e.offset,e.byteLength)),!t.isBuffer(e))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof e);if(void 0===n&&(n=0),void 0===r&&(r=e?e.length:0),void 0===i&&(i=0),void 0===o&&(o=this.length),n<0||r>e.length||i<0||o>this.length)throw new RangeError("out of range index");if(i>=o&&n>=r)return 0;if(i>=o)return-1;if(n>=r)return 1;if(this===e)return 0;for(var a=(o>>>=0)-(i>>>=0),u=(r>>>=0)-(n>>>=0),s=Math.min(a,u),f=this.slice(i,o),c=e.slice(n,r),l=0;l>>=0,isFinite(n)?(n>>>=0,void 0===r&&(r="utf8")):(r=n,n=void 0)}var i=this.length-t;if((void 0===n||n>i)&&(n=i),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var o=!1;;)switch(r){case"hex":return b(this,e,t,n);case"utf8":case"utf-8":return y(this,e,t,n);case"ascii":return w(this,e,t,n);case"latin1":case"binary":return x(this,e,t,n);case"base64":return _(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return A(this,e,t,n);default:if(o)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),o=!0}},t.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var k=4096;function O(e,t,n){var r="";n=Math.min(e.length,n);for(var i=t;ir)&&(n=r);for(var i="",o=t;on)throw new RangeError("Trying to access beyond buffer length")}function z(e,n,r,i,o,a){if(!t.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(n>o||ne.length)throw new RangeError("Index out of range")}function D(e,t,n,r,i,o){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function P(e,t,n,r,o){return t=+t,n>>>=0,o||D(e,0,n,4),i.write(e,t,n,r,23,4),n+4}function F(e,t,n,r,o){return t=+t,n>>>=0,o||D(e,0,n,8),i.write(e,t,n,r,52,8),n+8}t.prototype.slice=function(e,n){var r=this.length;(e=~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),(n=void 0===n?r:~~n)<0?(n+=r)<0&&(n=0):n>r&&(n=r),n>>=0,t>>>=0,n||B(e,t,this.length);for(var r=this[e],i=1,o=0;++o>>=0,t>>>=0,n||B(e,t,this.length);for(var r=this[e+--t],i=1;t>0&&(i*=256);)r+=this[e+--t]*i;return r},t.prototype.readUInt8=function(e,t){return e>>>=0,t||B(e,1,this.length),this[e]},t.prototype.readUInt16LE=function(e,t){return e>>>=0,t||B(e,2,this.length),this[e]|this[e+1]<<8},t.prototype.readUInt16BE=function(e,t){return e>>>=0,t||B(e,2,this.length),this[e]<<8|this[e+1]},t.prototype.readUInt32LE=function(e,t){return e>>>=0,t||B(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},t.prototype.readUInt32BE=function(e,t){return e>>>=0,t||B(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},t.prototype.readIntLE=function(e,t,n){e>>>=0,t>>>=0,n||B(e,t,this.length);for(var r=this[e],i=1,o=0;++o=(i*=128)&&(r-=Math.pow(2,8*t)),r},t.prototype.readIntBE=function(e,t,n){e>>>=0,t>>>=0,n||B(e,t,this.length);for(var r=t,i=1,o=this[e+--r];r>0&&(i*=256);)o+=this[e+--r]*i;return o>=(i*=128)&&(o-=Math.pow(2,8*t)),o},t.prototype.readInt8=function(e,t){return e>>>=0,t||B(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},t.prototype.readInt16LE=function(e,t){e>>>=0,t||B(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},t.prototype.readInt16BE=function(e,t){e>>>=0,t||B(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},t.prototype.readInt32LE=function(e,t){return e>>>=0,t||B(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},t.prototype.readInt32BE=function(e,t){return e>>>=0,t||B(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},t.prototype.readFloatLE=function(e,t){return e>>>=0,t||B(e,4,this.length),i.read(this,e,!0,23,4)},t.prototype.readFloatBE=function(e,t){return e>>>=0,t||B(e,4,this.length),i.read(this,e,!1,23,4)},t.prototype.readDoubleLE=function(e,t){return e>>>=0,t||B(e,8,this.length),i.read(this,e,!0,52,8)},t.prototype.readDoubleBE=function(e,t){return e>>>=0,t||B(e,8,this.length),i.read(this,e,!1,52,8)},t.prototype.writeUIntLE=function(e,t,n,r){(e=+e,t>>>=0,n>>>=0,r)||z(this,e,t,n,Math.pow(2,8*n)-1,0);var i=1,o=0;for(this[t]=255&e;++o>>=0,n>>>=0,r)||z(this,e,t,n,Math.pow(2,8*n)-1,0);var i=n-1,o=1;for(this[t+i]=255&e;--i>=0&&(o*=256);)this[t+i]=e/o&255;return t+n},t.prototype.writeUInt8=function(e,t,n){return e=+e,t>>>=0,n||z(this,e,t,1,255,0),this[t]=255&e,t+1},t.prototype.writeUInt16LE=function(e,t,n){return e=+e,t>>>=0,n||z(this,e,t,2,65535,0),this[t]=255&e,this[t+1]=e>>>8,t+2},t.prototype.writeUInt16BE=function(e,t,n){return e=+e,t>>>=0,n||z(this,e,t,2,65535,0),this[t]=e>>>8,this[t+1]=255&e,t+2},t.prototype.writeUInt32LE=function(e,t,n){return e=+e,t>>>=0,n||z(this,e,t,4,4294967295,0),this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e,t+4},t.prototype.writeUInt32BE=function(e,t,n){return e=+e,t>>>=0,n||z(this,e,t,4,4294967295,0),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},t.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t>>>=0,!r){var i=Math.pow(2,8*n-1);z(this,e,t,n,i-1,-i)}var o=0,a=1,u=0;for(this[t]=255&e;++o>0)-u&255;return t+n},t.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t>>>=0,!r){var i=Math.pow(2,8*n-1);z(this,e,t,n,i-1,-i)}var o=n-1,a=1,u=0;for(this[t+o]=255&e;--o>=0&&(a*=256);)e<0&&0===u&&0!==this[t+o+1]&&(u=1),this[t+o]=(e/a>>0)-u&255;return t+n},t.prototype.writeInt8=function(e,t,n){return e=+e,t>>>=0,n||z(this,e,t,1,127,-128),e<0&&(e=255+e+1),this[t]=255&e,t+1},t.prototype.writeInt16LE=function(e,t,n){return e=+e,t>>>=0,n||z(this,e,t,2,32767,-32768),this[t]=255&e,this[t+1]=e>>>8,t+2},t.prototype.writeInt16BE=function(e,t,n){return e=+e,t>>>=0,n||z(this,e,t,2,32767,-32768),this[t]=e>>>8,this[t+1]=255&e,t+2},t.prototype.writeInt32LE=function(e,t,n){return e=+e,t>>>=0,n||z(this,e,t,4,2147483647,-2147483648),this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24,t+4},t.prototype.writeInt32BE=function(e,t,n){return e=+e,t>>>=0,n||z(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},t.prototype.writeFloatLE=function(e,t,n){return P(this,e,t,!0,n)},t.prototype.writeFloatBE=function(e,t,n){return P(this,e,t,!1,n)},t.prototype.writeDoubleLE=function(e,t,n){return F(this,e,t,!0,n)},t.prototype.writeDoubleBE=function(e,t,n){return F(this,e,t,!1,n)},t.prototype.copy=function(e,n,r,i){if(!t.isBuffer(e))throw new TypeError("argument should be a Buffer");if(r||(r=0),i||0===i||(i=this.length),n>=e.length&&(n=e.length),n||(n=0),i>0&&i=this.length)throw new RangeError("Index out of range");if(i<0)throw new RangeError("sourceEnd out of bounds");i>this.length&&(i=this.length),e.length-n=0;--a)e[a+n]=this[a+r];else Uint8Array.prototype.set.call(e,this.subarray(r,i),n);return o},t.prototype.fill=function(e,n,r,i){if("string"==typeof e){if("string"==typeof n?(i=n,n=0,r=this.length):"string"==typeof r&&(i=r,r=this.length),void 0!==i&&"string"!=typeof i)throw new TypeError("encoding must be a string");if("string"==typeof i&&!t.isEncoding(i))throw new TypeError("Unknown encoding: "+i);if(1===e.length){var o=e.charCodeAt(0);("utf8"===i&&o<128||"latin1"===i)&&(e=o)}}else"number"==typeof e?e&=255:"boolean"==typeof e&&(e=Number(e));if(n<0||this.length>>=0,r=void 0===r?this.length:r>>>0,e||(e=0),"number"==typeof e)for(a=n;a55295&&n<57344){if(!i){if(n>56319){(t-=3)>-1&&o.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&o.push(239,191,189);continue}i=n;continue}if(n<56320){(t-=3)>-1&&o.push(239,191,189),i=n;continue}n=65536+(i-55296<<10|n-56320)}else i&&(t-=3)>-1&&o.push(239,191,189);if(i=null,n<128){if((t-=1)<0)break;o.push(n)}else if(n<2048){if((t-=2)<0)break;o.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;o.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;o.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return o}function N(e){return r.toByteArray(function(e){if((e=(e=e.split("=")[0]).trim().replace(M,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function R(e,t,n,r){for(var i=0;i=t.length||i>=e.length);++i)t[i+n]=e[i];return i}function I(e,t){return e instanceof t||null!=e&&null!=e.constructor&&null!=e.constructor.name&&e.constructor.name===t.name}function U(e){return e!=e}var H=function(){for(var e=new Array(256),t=0;t<16;++t)for(var n=16*t,r=0;r<16;++r)e[n+r]="0123456789abcdef"[t]+"0123456789abcdef"[r];return e}()}).call(this,e("buffer").Buffer)},{"base64-js":5,buffer:6,ieee754:42}],7:[function(e,t,n){(function(e){var r,i;r=this,i=function(){"use strict";var t=function(){},n={},r=[],i=[];function o(e,o){var a,u,s,f,c=i;for(f=arguments.length;2 ."+e+"__sectionFields {\n margin-left: 4px;\n }\n\n ."+e+"__sectionFields {\n box-sizing: border-box;\n }\n\n ."+e+"__sectionFields ."+e+"__field {\n border-bottom: 1px solid "+t.fieldBorderColor+";\n box-sizing: border-box;\n }\n\n ."+e+"__sectionFields ."+e+"__sectionFields {\n border-right: none;\n margin-right: 0;\n }\n\n ."+e+" > ."+e+"__section:first-child > ."+e+"__sectionHeading:first-child {\n border-right: 1px solid "+t.sectionHeadingBorderColor+";\n }\n\n ."+e+"__sectionHeading {\n padding: 0;\n font-family: inherit;\n user-select: none;\n -moz-user-select: -moz-none;\n text-indent: 5px;\n cursor: pointer;\n width: 100%;\n\n color: "+t.sectionHeadingColor+";\n background-color: "+t.sectionHeadingBgColor+";\n height: "+t.sectionHeadingHeight+";\n line-height: "+t.sectionHeadingHeight+";\n }\n\n ."+e+"__sectionHeading button:focus {\n background-color: "+t.sectionHeadingHoverColor+";\n }\n\n ."+e+"__sectionHeading > button {\n height: 100%;\n vertical-align: middle;\n font-size: 1.0em;\n cursor: pointer;\n text-align: left;\n outline: none;\n color: inherit;\n font-size: inherit;\n font-family: inherit;\n background: transparent;\n border: none;\n border-radius: 0;\n display: block;\n width: 100%;\n }\n\n ."+e+"__sectionHeading:hover {\n background-color: "+t.sectionHeadingHoverColor+";\n }\n\n ."+e+"__sectionHeading > button::before {\n transform: translate(0, -1px) rotate(90deg);\n }\n\n ."+e+"__sectionHeading > button::before {\n content: '▲';\n display: inline-block;\n transform-origin: 50% 50%;\n margin-right: 0.5em;\n font-size: 0.5em;\n vertical-align: middle;\n }\n\n ."+e+"__section--expanded > ."+e+"__sectionHeading > button::before {\n transform: none;\n content: '▼';\n }\n "}},re=$.h,ie={name:"tabs",component:X({init:function(){var e=this.props.field,t=Object.keys(e.value.$displayFields);this.state={activeTab:t[0]}},getRef:function(e){this.contentsEl=e},activateTab:function(e,t){this.setState({activeTab:e}),t.preventDefault()},preventDefault:function(e){},render:function(){var e=this,t=this.props.field,n=t.$config.label||t.name,r=this.props.className;t.parentField||""!==n||(n="Controls");for(var i=Object.keys(t.value.$displayFields),o={},a=0;a button:hover {\n background-color: "+t.fieldHoverColor+";\n }\n\n ."+e+"__field--button > button:active {\n background-color: "+t.fieldActiveColor+";\n }\n\n ."+e+"__field--button > button:focus {\n "+t.focusBorder+"\n }\n\n ."+e+"__field--button > button::before {\n content: '';\n width: 3px;\n display: inline-block;\n vertical-align: middle;\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n }\n "}},he=$.h,de={name:"color",component:X({render:function(){var e=this,t=this.props.field,n=t.$config,r=this.props.className;return he("div",{className:r+"__field "+r+"__field--color"},he("label",{className:r+"__label",htmlFor:r+"-"+t.path},he("span",{className:r+"__labelText"},n.label||t.name)," ",he("span",{className:r+"__container"},he("input",{id:r+"-"+t.path,name:t.path,type:"color",value:t.value,onInput:function(t){e.props.field.value=t.target.value}}))))}}),css:function(e,t){return"\n ."+e+"__field--color input[type=color] {\n margin: 0;\n border: 1px solid #aaa;\n width: 50px;\n height: "+t.sliderHeight+";\n border-radius: "+t.controlBorderRadius+";\n padding: 0;\n }\n\n ."+e+"__field--color input[type=color]::-webkit-color-swatch-wrapper {\n padding: 0px;\n background-color: #888;\n }\n\n ."+e+"__field--color input[type=color]:focus {\n "+t.focusBorder+"\n }\n "}},me=$.h,ge={name:"raw",component:X({getRef:function(e){this.el=e},getContent:function(e){return this.content=e.field.value,"function"==typeof this.content&&(this.content=this.content(me,{field:e.field,state:e.state})),this.content},render:function(){var e=this.props.className;return me("div",{className:e+"__field--raw "+e+"__field"},me("div",{ref:this.getRef,className:e+"__rawContent"},this.getContent(this.props)))}}),css:function(e,t){return"\n ."+e+"__field--raw {\n height: auto;\n padding: 0 7px 0 10px;\n overflow: hidden;\n }\n\n ."+e+"__rawContent {\n max-width: 100%;\n margin: 0;\n padding: 0;\n }\n\n ."+e+"__rawContent a {\n color: inherit;\n }\n\n ."+e+"__rawContent::before {\n background-color: #aaa;\n }\n\n ."+e+"__rawContent::before {\n content: '';\n width: 3px;\n display: inline-block;\n vertical-align: middle;\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n }\n\n ."+e+"__rawContent > p:first-child {\n margin-top: 5px;\n }\n\n ."+e+"__rawContent > p:last-child{\n margin-bottom: 5px;\n }\n\n ."+e+"__rawContent p {\n line-height: 1.8;\n }\n\n ."+e+"__rawContent pre {\n line-height: 1.3;\n font-size: 0.8em;\n margin: 0;\n }\n "}},ve=function(){var e={};function t(t,n){(n=Y(n||{},{containerCSS:"position:fixed;top:0;right:8px",style:!0,className:"controlPanel-"+Math.random().toString(36).substring(2,15)})).root=n.root||document.body;var r=n.className,i=X({render:function(){return $.h(function(t){var n=e[t];if(!n)throw new Error('Unrecognized component, "'+t+'"');return n}(this.props.field.type).component,{ControlComponent:i,className:r,field:this.props.field,state:t,h:$.h})}}),o=X({state:{dummy:0},componentDidMount:function(){var e=this;this.props.state.$field.onChanges(function(t){e.setState({dummy:e.state.dummy+1})})},getRef:function(e){for(var t=["mousedown","mouseup","mousemove","touchstart","touchmove","touchend","wheel"],r=0;r button::before { background-color: #8ff; }\n\n "+Object.keys(n).map(function(r){var i=n[r].css;return i?i(e,t):""}).join("\n")+"\n "}(r,n.theme,e)),$.render($.h(o,{state:t}),n.root),t}return t.registerComponent=function(n){return e[n.name]=n,t},t.registerComponents=function(e){for(var n=0;n-1}},{}],24:[function(e,t,n){"use strict";var r,i,o,a,u,s,f,c=e("d"),l=e("es5-ext/object/valid-callable"),p=Function.prototype.apply,h=Function.prototype.call,d=Object.create,m=Object.defineProperty,g=Object.defineProperties,v=Object.prototype.hasOwnProperty,b={configurable:!0,enumerable:!1,writable:!0};i=function(e,t){var n,i;return l(t),i=this,r.call(this,e,n=function(){o.call(i,e,n),p.call(t,this,arguments)}),n.__eeOnceListener__=t,this},u={on:r=function(e,t){var n;return l(t),v.call(this,"__ee__")?n=this.__ee__:(n=b.value=d(null),m(this,"__ee__",b),b.value=null),n[e]?"object"==typeof n[e]?n[e].push(t):n[e]=[n[e],t]:n[e]=t,this},once:i,off:o=function(e,t){var n,r,i,o;if(l(t),!v.call(this,"__ee__"))return this;if(!(n=this.__ee__)[e])return this;if("object"==typeof(r=n[e]))for(o=0;i=r[o];++o)i!==t&&i.__eeOnceListener__!==t||(2===r.length?n[e]=r[o?0:1]:r.splice(o,1));else r!==t&&r.__eeOnceListener__!==t||delete n[e];return this},emit:a=function(e){var t,n,r,i,o;if(v.call(this,"__ee__")&&(i=this.__ee__[e]))if("object"==typeof i){for(n=arguments.length,o=new Array(n-1),t=1;t0&&(o=1/Math.sqrt(o),e[0]=t[0]*o,e[1]=t[1]*o,e[2]=t[2]*o);return e}},{}],38:[function(e,t,n){t.exports=function(e,t,n,r){var i=n[1],o=n[2],a=t[1]-i,u=t[2]-o,s=Math.sin(r),f=Math.cos(r);return e[0]=t[0],e[1]=i+a*f-u*s,e[2]=o+a*s+u*f,e}},{}],39:[function(e,t,n){t.exports=function(e,t,n,r){var i=n[0],o=n[2],a=t[0]-i,u=t[2]-o,s=Math.sin(r),f=Math.cos(r);return e[0]=i+u*s+a*f,e[1]=t[1],e[2]=o+u*f-a*s,e}},{}],40:[function(e,t,n){t.exports=function(e,t,n,r){return e[0]=t[0]+n[0]*r,e[1]=t[1]+n[1]*r,e[2]=t[2]+n[2]*r,e}},{}],41:[function(e,t,n){t.exports=function(e,t,n){var r=t[0],i=t[1],o=t[2],a=n[3]*r+n[7]*i+n[11]*o+n[15];return a=a||1,e[0]=(n[0]*r+n[4]*i+n[8]*o+n[12])/a,e[1]=(n[1]*r+n[5]*i+n[9]*o+n[13])/a,e[2]=(n[2]*r+n[6]*i+n[10]*o+n[14])/a,e}},{}],42:[function(e,t,n){n.read=function(e,t,n,r,i){var o,a,u=8*i-r-1,s=(1<>1,c=-7,l=n?i-1:0,p=n?-1:1,h=e[t+l];for(l+=p,o=h&(1<<-c)-1,h>>=-c,c+=u;c>0;o=256*o+e[t+l],l+=p,c-=8);for(a=o&(1<<-c)-1,o>>=-c,c+=r;c>0;a=256*a+e[t+l],l+=p,c-=8);if(0===o)o=1-f;else{if(o===s)return a?NaN:1/0*(h?-1:1);a+=Math.pow(2,r),o-=f}return(h?-1:1)*a*Math.pow(2,o-r)},n.write=function(e,t,n,r,i,o){var a,u,s,f=8*o-i-1,c=(1<>1,p=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,h=r?0:o-1,d=r?1:-1,m=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(u=isNaN(t)?1:0,a=c):(a=Math.floor(Math.log(t)/Math.LN2),t*(s=Math.pow(2,-a))<1&&(a--,s*=2),(t+=a+l>=1?p/s:p*Math.pow(2,1-l))*s>=2&&(a++,s/=2),a+l>=c?(u=0,a=c):a+l>=1?(u=(t*s-1)*Math.pow(2,i),a+=l):(u=t*Math.pow(2,l-1)*Math.pow(2,i),a=0));i>=8;e[n+h]=255&u,h+=d,u/=256,i-=8);for(a=a<0;e[n+h]=255&a,h+=d,a/=256,f-=8);e[n+h-d]|=128*m}},{}],43:[function(e,t,n){"use strict";var r=e("gl-vec3/transformMat4"),i=e("gl-vec3/rotateY"),o=e("gl-vec3/rotateX"),a=e("gl-vec3/equals"),u=e("gl-vec3/add"),s=e("gl-vec3/scaleAndAdd"),f=e("gl-vec3/copy"),c=e("gl-vec3/normalize"),l=e("gl-mat4/identity"),p=e("gl-mat4/invert"),h=e("gl-mat4/translate"),d=e("gl-mat4/scale"),m=e("gl-mat4/lookAt"),g=e("gl-mat4/perspective"),v=.5*Math.PI-1e-4,b=.5*-Math.PI+1e-4;t.exports=function(e){var t=!0,n={aspectRatio:(e=e||{}).aspectRatio?e.aspectRatio:1,zoomAboutCursor:void 0===e.zoomAboutCursor||e.zoomAboutCursor,distance:void 0===e.distance?10:e.distance,phi:void 0===e.phi?0:e.phi,theta:void 0===e.theta?0:e.theta,fovY:void 0===e.fovY?Math.PI/4:e.fovY,near:void 0===e.near?.1:e.near,far:void 0===e.far?100:e.far,panDecayTime:e.panDecayTime||100,zoomDecayTime:e.zoomDecayTime||100,rotationDecayTime:e.rotationDecayTime||100,dirty:!0,up:e.up||new Float32Array([0,1,0]),center:e.center||new Float32Array(3),rotationCenter:e.rotationCenter||e.center&&e.center.slice()||new Float32Array(3),zoom:0,panX:0,panY:0,panZ:0,pitch:0,yaw:0,dTheta:0,dPhi:0,mouseX:0,mouseY:0},y=null,w={tick:function(e){if(P.zoom&&(n.zoom=P.zoom),P.dTheta&&(n.dTheta=P.dTheta),P.dPhi&&(n.dPhi=P.dPhi),P.panX&&(n.panX=P.panX),P.panY&&(n.panY=P.panY),P.panZ&&(n.panZ=P.panZ),P.yaw&&(n.yaw=P.yaw),P.pitch&&(n.pitch=P.pitch),D(P),e){var r=n.dPhi,i=n.dTheta,o=n.zoom,u=n.panX,s=n.panY,f=n.panZ,c=n.pitch,l=n.yaw;Object.assign(n,e),void 0!==e.dPhi&&(n.dPhi+=r),void 0!==e.dTheta&&(n.dTheta+=i),void 0!==e.zoom&&(n.zoom+=o),void 0!==e.panX&&(n.panX+=u),void 0!==e.panY&&(n.panY+=s),void 0!==e.panZ&&(n.panZ+=f),void 0!==e.pitch&&(n.pitch+=c),void 0!==e.yaw&&(n.yaw+=l)}a(n.up,O.up)&&a(n.center,O.center)&&n.near===O.near&&n.far===O.far&&n.phi===O.phi&&n.theta===O.theta&&n.distance===O.distance&&n.fovY===O.fovY||(j.dPhi=n.phi-O.phi,j.dTheta=n.theta-O.theta,j.zoom=n.distance/O.distance-1,n.theta=O.theta,n.distance=O.distance,n.phi=O.phi,j.yaw=0,j.pitch=0,j.panX=0,j.panY=0,j.panZ=0,j.mouseX=0,j.mouseY=0,F(j)),!function(){if(Math.abs(n.zoom)>1e-4)return!0;if(Math.abs(n.panX)>1e-4)return!0;if(Math.abs(n.panY)>1e-4)return!0;if(Math.abs(n.panZ)>1e-4)return!0;if(Math.abs(n.dTheta)>1e-4)return!0;if(Math.abs(n.dPhi)>1e-4)return!0;if(Math.abs(n.yaw)>1e-4)return!0;if(Math.abs(n.pitch)>1e-4)return!0}()?D(n):F(n);var p,h,d,m,g=Date.now();null!==y&&(p=g-y,h=n.panDecayTime?Math.exp(-p/n.panDecayTime/Math.LN2):0,d=n.zoomDecayTime?Math.exp(-p/n.zoomDecayTime/Math.LN2):0,m=n.rotationDecayTime?Math.exp(-p/n.rotationDecayTime/Math.LN2):0,n.zoom*=d,n.panX*=h,n.panY*=h,n.panZ*=h,n.dTheta*=m,n.dPhi*=m,n.yaw*=m,n.pitch*=m),y=g,w.state.dirty=t,t=!1,T()},taint:B,resize:z,params:n,rotate:function(e,t){P.dTheta+=e,P.dPhi+=t},pivot:function(e,t){var r=w.params.fovY;P.yaw+=e*r*n.aspectRatio,P.pitch+=t*r},pan:function(e,t){var r=w.params.distance*Math.tan(.5*w.params.fovY)*2;return P.panX+=e*n.aspectRatio*r,P.panY+=t*r,w},zoom:function(e,t,r){return P.zoom+=r,n.mouseX=e,n.mouseY=t,w},state:{}};w.state.projection=new Float32Array(16),w.state.viewInv=new Float32Array(16),w.state.view=new Float32Array(16),w.state.width=null,w.state.height=null,w.state.eye=new Float32Array(3);var x=new Float32Array(3),_=new Float32Array(3),A=new Float32Array(3),E=new Float32Array(3),C=new Float32Array(3),k=new Float32Array(16),O={up:new Float32Array(3),center:new Float32Array(3)};function T(){f(O.up,n.up),f(O.center,n.center),O.near=n.near,O.far=n.far,O.distance=n.distance,O.phi=n.phi,O.theta=n.theta,O.fovY=n.fovY}T();var j={};function S(){w.state.eye[0]=0,w.state.eye[1]=0,w.state.eye[2]=n.distance,o(w.state.eye,w.state.eye,C,-n.phi),i(w.state.eye,w.state.eye,C,n.theta),u(w.state.eye,w.state.eye,n.center),m(w.state.view,w.state.eye,n.center,n.up),g(w.state.projection,n.fovY,w.params.aspectRatio,n.near,n.far),p(w.state.viewInv,w.state.view)}function B(){t=!0}function z(e){w.params.aspectRatio=e,S(),B()}function D(e){e.zoom=0,e.dTheta=0,e.dPhi=0,e.panX=0,e.panY=0,e.panZ=0,e.yaw=0,e.pitch=0}var P={};function F(e){var t;l(k),n.zoomAboutCursor&&(t=n.distance*Math.tan(.5*n.fovY),x[0]=e.mouseX*n.aspectRatio*t,x[1]=e.mouseY*t,x[2]=0,h(k,k,x)),x[0]=1+e.zoom,x[1]=1+e.zoom,x[2]=1,d(k,k,x),n.zoomAboutCursor&&(t=n.distance*Math.tan(.5*n.fovY),x[0]=-e.mouseX*n.aspectRatio*t,x[1]=-e.mouseY*t,x[2]=0,h(k,k,x)),k[12]-=.5*e.panX,k[13]-=.5*e.panY,r(n.center,n.center,w.state.view),r(n.center,n.center,k),r(n.center,n.center,w.state.viewInv),n.rotateAboutCenter&&f(n.rotationCenter,n.center),n.distance*=1+e.zoom;var a=n.phi;n.phi+=e.dPhi,n.phi=Math.min(v,Math.max(b,n.phi));var u=n.phi-a,p=n.theta;n.theta+=e.dTheta;var m=n.theta-p;if(i(n.center,n.center,n.rotationCenter,m-n.theta),o(n.center,n.center,n.rotationCenter,-u),i(n.center,n.center,n.rotationCenter,n.theta),0!==e.yaw||0!==e.pitch){A[0]=w.state.view[0],A[1]=w.state.view[4],A[2]=w.state.view[8],c(A,A),_[0]=w.state.view[1],_[1]=w.state.view[5],_[2]=w.state.view[9],c(_,_),E[0]=w.state.view[2],E[1]=w.state.view[6],E[2]=w.state.view[10],c(E,E);var g=Math.min(v,Math.max(b,n.phi+.5*e.pitch)),y=g-n.phi;s(n.center,n.center,A,-Math.sin(.5*e.yaw)*n.distance),s(n.center,n.center,_,-Math.sin(y)*n.distance),s(n.center,n.center,E,(2-Math.cos(.5*e.yaw)-Math.cos(y))*n.distance),n.phi=g,n.theta+=.5*e.yaw}S(),B()}return D(P),z(w.params.aspectRatio),w}},{"gl-mat4/identity":26,"gl-mat4/invert":27,"gl-mat4/lookAt":28,"gl-mat4/perspective":30,"gl-mat4/scale":31,"gl-mat4/translate":32,"gl-vec3/add":33,"gl-vec3/copy":34,"gl-vec3/equals":36,"gl-vec3/normalize":37,"gl-vec3/rotateX":38,"gl-vec3/rotateY":39,"gl-vec3/scaleAndAdd":40,"gl-vec3/transformMat4":41}],44:[function(e,t,n){"use strict";t.exports=function(e,t){t||(t=e,e=window);var n=0,i=0,o=0,a={shift:!1,alt:!1,control:!1,meta:!1},u=!1;function s(e){var t=!1;return"altKey"in e&&(t=t||e.altKey!==a.alt,a.alt=!!e.altKey),"shiftKey"in e&&(t=t||e.shiftKey!==a.shift,a.shift=!!e.shiftKey),"ctrlKey"in e&&(t=t||e.ctrlKey!==a.control,a.control=!!e.ctrlKey),"metaKey"in e&&(t=t||e.metaKey!==a.meta,a.meta=!!e.metaKey),t}function f(e,u){var f=r.x(u),c=r.y(u);"buttons"in u&&(e=0|u.buttons),(e!==n||f!==i||c!==o||s(u))&&(n=0|e,i=f||0,o=c||0,t&&t(n,i,o,a))}function c(e){f(0,e)}function l(){(n||i||o||a.shift||a.alt||a.meta||a.control)&&(i=o=0,n=0,a.shift=a.alt=a.control=a.meta=!1,t&&t(0,0,0,a))}function p(e){s(e)&&t&&t(n,i,o,a)}function h(e){0===r.buttons(e)?f(0,e):f(n,e)}function d(e){f(n|r.buttons(e),e)}function m(e){f(n&~r.buttons(e),e)}function g(){u||(u=!0,e.addEventListener("mousemove",h),e.addEventListener("mousedown",d),e.addEventListener("mouseup",m),e.addEventListener("mouseleave",c),e.addEventListener("mouseenter",c),e.addEventListener("mouseout",c),e.addEventListener("mouseover",c),e.addEventListener("blur",l),e.addEventListener("keyup",p),e.addEventListener("keydown",p),e.addEventListener("keypress",p),e!==window&&(window.addEventListener("blur",l),window.addEventListener("keyup",p),window.addEventListener("keydown",p),window.addEventListener("keypress",p)))}g();var v={element:e};return Object.defineProperties(v,{enabled:{get:function(){return u},set:function(t){t?g():u&&(u=!1,e.removeEventListener("mousemove",h),e.removeEventListener("mousedown",d),e.removeEventListener("mouseup",m),e.removeEventListener("mouseleave",c),e.removeEventListener("mouseenter",c),e.removeEventListener("mouseout",c),e.removeEventListener("mouseover",c),e.removeEventListener("blur",l),e.removeEventListener("keyup",p),e.removeEventListener("keydown",p),e.removeEventListener("keypress",p),e!==window&&(window.removeEventListener("blur",l),window.removeEventListener("keyup",p),window.removeEventListener("keydown",p),window.removeEventListener("keypress",p)))},enumerable:!0},buttons:{get:function(){return n},enumerable:!0},x:{get:function(){return i},enumerable:!0},y:{get:function(){return o},enumerable:!0},mods:{get:function(){return a},enumerable:!0}}),v};var r=e("mouse-event")},{"mouse-event":46}],45:[function(e,t,n){var r={left:0,top:0};t.exports=function(e,t,n){t=t||e.currentTarget||e.srcElement,Array.isArray(n)||(n=[0,0]);var i=e.clientX||0,o=e.clientY||0,a=(u=t,u===window||u===document||u===document.body?r:u.getBoundingClientRect());var u;return n[0]=i-a.left,n[1]=o-a.top,n}},{}],46:[function(e,t,n){"use strict";function r(e){return e.target||e.srcElement||window}n.buttons=function(e){if("object"==typeof e){if("buttons"in e)return e.buttons;if("which"in e){if(2===(t=e.which))return 4;if(3===t)return 2;if(t>0)return 1<=0)return 1<0){if(d.theta=0,_>1){var A=p[1].position[0]-p[0].position[0],E=(p[0].position[1]-p[1].position[1])*t/n;d.theta=Math.atan2(E,A)}m(),d.buttons=0,d.mods={},d.active=h,w=b,x=y,d.x0=2*w/t-1,d.y0=1-2*x/n,d.x=2*b/t-1,d.y=1-2*y/n,d.x1=2*p[0].position[0]/t-1,d.y1=1-2*p[0].position[1]/n,h>1&&(d.x2=2*p[1].position[0]/t-1,d.y2=1-2*p[1].position[1]/n),d.active=h,d.dx=0,d.dy=0,d.dz=0,d.zoomx=1,d.zoomy=1,d.dtheta=0,d.originalEvent=r,s.emit(1===h?"touchstart":"pinchstart",d)}}function T(r){for(var o,a=!1,u=0;u1)for(var n=1;n>>=t))<<3,(t|=n=(15<(e>>>=n))<<2)|(n=(3<(e>>>=n))<<1)|e>>>n>>1}function u(){function e(e){e:{for(var t=16;268435456>=t;t*=16)if(e<=t){e=t;break e}e=0}return 0<(t=n[a(e)>>2]).length?t.pop():new ArrayBuffer(e)}function t(e){n[a(e.byteLength)>>2].push(e)}var n=o(8,function(){return[]});return{alloc:e,free:t,allocType:function(t,n){var r=null;switch(t){case 5120:r=new Int8Array(e(n),0,n);break;case 5121:r=new Uint8Array(e(n),0,n);break;case 5122:r=new Int16Array(e(2*n),0,n);break;case 5123:r=new Uint16Array(e(2*n),0,n);break;case 5124:r=new Int32Array(e(4*n),0,n);break;case 5125:r=new Uint32Array(e(4*n),0,n);break;case 5126:r=new Float32Array(e(4*n),0,n);break;default:return null}return r.length!==n?r.subarray(0,n):r},freeType:function(e){t(e.buffer)}}}function s(e){return!!e&&"object"==typeof e&&Array.isArray(e.shape)&&Array.isArray(e.stride)&&"number"==typeof e.offset&&e.shape.length===e.stride.length&&(Array.isArray(e.data)||X(e.data))}function f(e,t,n,r,i,o){for(var a=0;a(i=u)&&(i=r.buffer.byteLength,5123===l?i>>=1:5125===l&&(i>>=2)),r.vertCount=i,i=a,0>a&&(i=4,1===(a=r.buffer.dimension)&&(i=0),2===a&&(i=1),3===a&&(i=4)),r.primType=i}function a(e){r.elementsCount--,delete u[e.id],e.buffer.destroy(),e.buffer=null}var u={},f=0,c={uint8:5121,uint16:5123};t.oes_element_index_uint&&(c.uint32=5125),i.prototype.bind=function(){this.buffer.bind()};var l=[];return{create:function(e,t){function u(e){if(e)if("number"==typeof e)f(e),l.primType=4,l.vertCount=0|e,l.type=5121;else{var t=null,n=35044,r=-1,i=-1,a=0,p=0;Array.isArray(e)||X(e)||s(e)?t=e:("data"in e&&(t=e.data),"usage"in e&&(n=J[e.usage]),"primitive"in e&&(r=re[e.primitive]),"count"in e&&(i=0|e.count),"type"in e&&(p=c[e.type]),"length"in e?a=0|e.length:(a=i,5123===p||5122===p?a*=2:5125!==p&&5124!==p||(a*=4))),o(l,t,n,r,i,a,p)}else f(),l.primType=4,l.vertCount=0,l.type=5121;return u}var f=n.create(null,34963,!0),l=new i(f._buffer);return r.elementsCount++,u(e),u._reglType="elements",u._elements=l,u.subdata=function(e,t){return f.subdata(e,t),u},u.destroy=function(){a(l)},u},createStream:function(e){var t=l.pop();return t||(t=new i(n.create(null,34963,!0,!1)._buffer)),o(t,e,35040,-1,-1,0,0),t},destroyStream:function(e){l.push(e)},getElements:function(e){return"function"==typeof e&&e._elements instanceof i?e._elements:null},clear:function(){G(u).forEach(a)}}}function m(e){for(var t=Y.allocType(5123,e.length),n=0;n>>31<<15,i=(o<<1>>>24)-127,o=o>>13&1023;t[n]=-24>i?r:-14>i?r+(o+1024>>-14-i):15>=i,n.height>>=i,h(n,r[i]),e.mipmask|=1<t;++t)e.images[t]=null;return e}function S(e){for(var t=e.images,n=0;nt){for(var n=0;n=--this.refCount&&L(this)}}),a.profile&&(o.getTotalTextureSize=function(){var e=0;return Object.keys(be).forEach(function(t){e+=be[t].stats.size}),e}),{create2D:function(t,n){function r(e,t){var n=i.texInfo;B.call(n);var o=j();return"number"==typeof e?k(o,0|e,"number"==typeof t?0|t:0|e):e?(z(n,e),O(o,e)):k(o,1,1),n.genMipmaps&&(o.mipmask=(o.width<<1)-1),i.mipmask=o.mipmask,f(i,o),i.internalformat=o.internalformat,r.width=o.width,r.height=o.height,F(i),T(o,3553),D(n,3553),M(),S(o),a.profile&&(i.stats.size=A(i.internalformat,i.type,o.width,o.height,n.genMipmaps,!1)),r.format=ee[i.internalformat],r.type=te[i.type],r.mag=ne[n.magFilter],r.min=re[n.minFilter],r.wrapS=ie[n.wrapS],r.wrapT=ie[n.wrapT],r}var i=new P(3553);return be[i.id]=i,o.textureCount++,r(t,n),r.subimage=function(e,t,n,o){t|=0,n|=0,o|=0;var a=v();return f(a,i),a.width=0,a.height=0,h(a,e),a.width=a.width||(i.width>>o)-t,a.height=a.height||(i.height>>o)-n,F(i),d(a,3553,t,n,o),M(),E(a),r},r.resize=function(t,n){var o=0|t,u=0|n||o;if(o===i.width&&u===i.height)return r;r.width=i.width=o,r.height=i.height=u,F(i);for(var s=0;i.mipmask>>s;++s){var f=o>>s,c=u>>s;if(!f||!c)break;e.texImage2D(3553,s,i.format,f,c,0,i.format,i.type,null)}return M(),a.profile&&(i.stats.size=A(i.internalformat,i.type,o,u,!1,!1)),r},r._reglType="texture2d",r._texture=i,a.profile&&(r.stats=i.stats),r.destroy=function(){i.decRef()},r},createCube:function(t,n,r,i,u,s){function l(e,t,n,r,i,o){var u,s=p.texInfo;for(B.call(s),u=0;6>u;++u)m[u]=j();if("number"!=typeof e&&e){if("object"==typeof e)if(t)O(m[0],e),O(m[1],t),O(m[2],n),O(m[3],r),O(m[4],i),O(m[5],o);else if(z(s,e),c(p,e),"faces"in e)for(e=e.faces,u=0;6>u;++u)f(m[u],p),O(m[u],e[u]);else for(u=0;6>u;++u)O(m[u],e)}else for(e=0|e||1,u=0;6>u;++u)k(m[u],e,e);for(f(p,m[0]),p.mipmask=s.genMipmaps?(m[0].width<<1)-1:m[0].mipmask,p.internalformat=m[0].internalformat,l.width=m[0].width,l.height=m[0].height,F(p),u=0;6>u;++u)T(m[u],34069+u);for(D(s,34067),M(),a.profile&&(p.stats.size=A(p.internalformat,p.type,l.width,l.height,s.genMipmaps,!0)),l.format=ee[p.internalformat],l.type=te[p.type],l.mag=ne[s.magFilter],l.min=re[s.minFilter],l.wrapS=ie[s.wrapS],l.wrapT=ie[s.wrapT],u=0;6>u;++u)S(m[u]);return l}var p=new P(34067);be[p.id]=p,o.cubeCount++;var m=Array(6);return l(t,n,r,i,u,s),l.subimage=function(e,t,n,r,i){n|=0,r|=0,i|=0;var o=v();return f(o,p),o.width=0,o.height=0,h(o,t),o.width=o.width||(p.width>>i)-n,o.height=o.height||(p.height>>i)-r,F(p),d(o,34069+e,n,r,i),M(),E(o),l},l.resize=function(t){if((t|=0)!==p.width){l.width=p.width=t,l.height=p.height=t,F(p);for(var n=0;6>n;++n)for(var r=0;p.mipmask>>r;++r)e.texImage2D(34069+n,r,p.format,t>>r,t>>r,0,p.format,p.type,null);return M(),a.profile&&(p.stats.size=A(p.internalformat,p.type,l.width,l.height,!1,!0)),l}},l._reglType="textureCube",l._texture=p,a.profile&&(l.stats=p.stats),l.destroy=function(){p.decRef()},l},clear:function(){for(var t=0;tn;++n)if(0!=(t.mipmask&1<>n,t.height>>n,0,t.internalformat,t.type,null);else for(var r=0;6>r;++r)e.texImage2D(34069+r,n,t.internalformat,t.width>>n,t.height>>n,0,t.internalformat,t.type,null);D(t.texInfo,t.target)})}}}function C(e,t,n,r,i,o){function a(e,t,n){this.target=e,this.texture=t,this.renderbuffer=n;var r=e=0;t?(e=t.width,r=t.height):n&&(e=n.width,r=n.height),this.width=e,this.height=r}function u(e){e&&(e.texture&&e.texture._texture.decRef(),e.renderbuffer&&e.renderbuffer._renderbuffer.decRef())}function s(e,t,n){e&&(e.texture?e.texture._texture.refCount+=1:e.renderbuffer._renderbuffer.refCount+=1)}function f(t,n){n&&(n.texture?e.framebufferTexture2D(36160,t,n.target,n.texture._texture.texture,0):e.framebufferRenderbuffer(36160,t,36161,n.renderbuffer._renderbuffer.renderbuffer))}function c(e){var t=3553,n=null,r=null,i=e;return"object"==typeof e&&(i=e.data,"target"in e&&(t=0|e.target)),"texture2d"===(e=i._reglType)?n=i:"textureCube"===e?n=i:"renderbuffer"===e&&(r=i,t=36161),new a(t,n,r)}function l(e,t,n,o,u){return n?((e=r.create2D({width:e,height:t,format:o,type:u}))._texture.refCount=0,new a(3553,e,null)):((e=i.create({width:e,height:t,format:o}))._renderbuffer.refCount=0,new a(36161,null,e))}function p(e){return e&&(e.texture||e.renderbuffer)}function h(e,t,n){e&&(e.texture?e.texture.resize(t,n):e.renderbuffer&&e.renderbuffer.resize(t,n),e.width=t,e.height=n)}function d(){this.id=A++,E[this.id]=this,this.framebuffer=e.createFramebuffer(),this.height=this.width=0,this.colorAttachments=[],this.depthStencilAttachment=this.stencilAttachment=this.depthAttachment=null}function m(e){e.colorAttachments.forEach(u),u(e.depthAttachment),u(e.stencilAttachment),u(e.depthStencilAttachment)}function g(t){e.deleteFramebuffer(t.framebuffer),t.framebuffer=null,o.framebufferCount--,delete E[t.id]}function v(t){var r;e.bindFramebuffer(36160,t.framebuffer);var i=t.colorAttachments;for(r=0;ri;++i){for(f=0;fe;++e)n[e].resize(r);return t.width=t.height=r,t},_reglType:"framebufferCube",destroy:function(){n.forEach(function(e){e.destroy()})}})},clear:function(){G(E).forEach(g)},restore:function(){y.cur=null,y.next=null,y.dirty=!0,G(E).forEach(function(t){t.framebuffer=e.createFramebuffer(),v(t)})}})}function k(){this.w=this.z=this.y=this.x=this.state=0,this.buffer=null,this.size=0,this.normalized=!1,this.type=5126,this.divisor=this.stride=this.offset=0}function O(e,t,n,r,i){function o(){this.id=++f,this.attributes=[];var e=t.oes_vertex_array_object;this.vao=e?e.createVertexArrayOES():null,c[this.id]=this,this.buffers=[]}var a=n.maxAttributes,u=Array(a);for(n=0;ne&&(e=t.stats.uniformsCount)}),e},n.getMaxAttributesCount=function(){var e=0;return p.forEach(function(t){t.stats.attributesCount>e&&(e=t.stats.attributesCount)}),e}),{clear:function(){var t=e.deleteShader.bind(e);G(f).forEach(t),f={},G(c).forEach(t),c={},p.forEach(function(t){e.deleteProgram(t.program)}),p.length=0,l={},n.shaderCount=0},program:function(e,t,r,i){var o=l[t];o||(o=l[t]={});var a=o[e];return a&&!i?a:(t=new u(t,e),n.shaderCount++,s(t,r,i),a||(o[e]=t),p.push(t),t)},restore:function(){f={},c={};for(var e=0;e"+t+"?"+i+".constant["+t+"]:0;"}).join(""),"}}else{","if(",u,"(",i,".buffer)){",c,"=",o,".createStream(",34962,",",i,".buffer);","}else{",c,"=",o,".getBuffer(",i,".buffer);","}",l,'="type" in ',i,"?",a.glTypes,"[",i,".type]:",c,".dtype;",s.normalized,"=!!",i,".normalized;"),r("size"),r("offset"),r("stride"),r("divisor"),n("}}"),n.exit("if(",s.isStream,"){",o,".destroyStream(",c,");","}"),s})}),a}function C(e,t,r,i,a){function u(e){var t=f[e];t&&(p[e]=t)}var s=function(e,t){if("string"==typeof(n=e.static).frag&&"string"==typeof n.vert){if(0>1)",u],");")}function t(){n(s,".drawArraysInstancedANGLE(",[d,m,g,u],");")}h?b?e():(n("if(",h,"){"),e(),n("}else{"),t(),n("}")):t()}function a(){function e(){n(c+".drawElements("+[d,g,v,m+"<<(("+v+"-5121)>>1)"]+");")}function t(){n(c+".drawArrays("+[d,m,g]+");")}h?b?e():(n("if(",h,"){"),e(),n("}else{"),t(),n("}")):t()}var u,s,f=e.shared,c=f.gl,l=f.draw,p=r.draw,h=function(){var i=p.elements,o=t;return i?((i.contextDep&&r.contextDynamic||i.propDep)&&(o=n),i=i.append(e,o)):i=o.def(l,".","elements"),i&&o("if("+i+")"+c+".bindBuffer(34963,"+i+".buffer.buffer);"),i}(),d=i("primitive"),m=i("offset"),g=function(){var i=p.count,o=t;return i?((i.contextDep&&r.contextDynamic||i.propDep)&&(o=n),i=i.append(e,o)):i=o.def(l,".","count"),i}();if("number"==typeof g){if(0===g)return}else n("if(",g,"){"),n.exit("}");Z&&(u=i("instances"),s=e.instancing);var v=h+".type",b=p.elements&&M(p.elements);Z&&("number"!=typeof u||0<=u)?"string"==typeof u?(n("if(",u,">0){"),o(),n("}else if(",u,"<0){"),a(),n("}")):o():a()}function H(e,t,n,r,i){return i=(t=w()).proc("body",i),Z&&(t.instancing=i.def(t.shared.extensions,".angle_instanced_arrays")),e(t,i,n,r),t.compile().body}function q(e,t,n,r){S(e,t),n.useVAO?n.drawVAO?t(e.shared.vao,".setVAO(",n.drawVAO.append(e,t),");"):t(e.shared.vao,".setVAO(",e.shared.vao,".targetVAO);"):(t(e.shared.vao,".setVAO(null);"),R(e,t,n,r.attributes,function(){return!0})),I(e,t,n,r.uniforms,function(){return!0}),U(e,t,t,n)}function W(e,t,n,r){function i(){return!0}e.batchId="a1",S(e,t),R(e,t,n,r.attributes,i),I(e,t,n,r.uniforms,i),U(e,t,t,n)}function Y(e,t,n,r){function i(e){return e.contextDep&&a||e.propDep}function o(e){return!i(e)}S(e,t);var a=n.contextDep,u=t.def(),s=t.def();e.shared.props=s,e.batchId=u;var f=e.scope(),c=e.scope();t(f.entry,"for(",u,"=0;",u,"<","a1",";++",u,"){",s,"=","a0","[",u,"];",c,"}",f.exit),n.needsContext&&k(e,c,n.context),n.needsFramebuffer&&O(e,c,n.framebuffer),j(e,c,n.state,i),n.profile&&i(n.profile)&&B(e,c,n,!1,!0),r?(n.useVAO?n.drawVAO?i(n.drawVAO)?c(e.shared.vao,".setVAO(",n.drawVAO.append(e,c),");"):f(e.shared.vao,".setVAO(",n.drawVAO.append(e,f),");"):f(e.shared.vao,".setVAO(",e.shared.vao,".targetVAO);"):(f(e.shared.vao,".setVAO(null);"),R(e,f,n,r.attributes,o),R(e,c,n,r.attributes,i)),I(e,f,n,r.uniforms,o),I(e,c,n,r.uniforms,i),U(e,f,c,n)):(t=e.global.def("{}"),r=n.shader.progVar.append(e,c),s=c.def(r,".id"),f=c.def(t,"[",s,"]"),c(e.shared.gl,".useProgram(",r,".program);","if(!",f,"){",f,"=",t,"[",s,"]=",e.link(function(t){return H(W,e,n,t,2)}),"(",r,");}",f,".call(this,a0[",u,"],",u,");"))}function $(e,n){function r(t){var r=n.shader[t];r&&i.set(o.shader,"."+t,r.append(e,i))}var i=e.proc("scope",3);e.batchId="a2";var o=e.shared,a=o.current;k(e,i,n.context),n.framebuffer&&n.framebuffer.append(e,i),P(Object.keys(n.state)).forEach(function(t){var r=n.state[t].append(e,i);g(r)?r.forEach(function(n,r){i.set(e.next[t],"["+r+"]",n)}):i.set(o.next,"."+t,r)}),B(e,i,n,!0,!0),["elements","offset","count","instances","primitive"].forEach(function(t){var r=n.draw[t];r&&i.set(o.draw,"."+t,""+r.append(e,i))}),Object.keys(n.uniforms).forEach(function(r){i.set(o.uniforms,"["+t.id(r)+"]",n.uniforms[r].append(e,i))}),Object.keys(n.attributes).forEach(function(t){var r=n.attributes[t].append(e,i),o=e.scopeAttrib(t);Object.keys(new G).forEach(function(e){i.set(o,"."+e,r[e])})}),n.scopeVAO&&i.set(o.vao,".targetVAO",n.scopeVAO.append(e,i)),r("vert"),r("frag"),0=--this.refCount&&a(this)},i.profile&&(r.getTotalRenderbufferSize=function(){var e=0;return Object.keys(c).forEach(function(t){e+=c[t].stats.size}),e}),{create:function(t,n){function a(t,n){var r=0,o=0,c=32854;if("object"==typeof t&&t?("shape"in t?(r=0|(o=t.shape)[0],o=0|o[1]):("radius"in t&&(r=o=0|t.radius),"width"in t&&(r=0|t.width),"height"in t&&(o=0|t.height)),"format"in t&&(c=u[t.format])):"number"==typeof t?(r=0|t,o="number"==typeof n?0|n:r):t||(r=o=1),r!==f.width||o!==f.height||c!==f.format)return a.width=f.width=r,a.height=f.height=o,f.format=c,e.bindRenderbuffer(36161,f.renderbuffer),e.renderbufferStorage(36161,c,r,o),i.profile&&(f.stats.size=be[f.format]*f.width*f.height),a.format=s[f.format],a}var f=new o(e.createRenderbuffer());return c[f.id]=f,r.renderbufferCount++,a(t,n),a.resize=function(t,n){var r=0|t,o=0|n||r;return r===f.width&&o===f.height?a:(a.width=f.width=r,a.height=f.height=o,e.bindRenderbuffer(36161,f.renderbuffer),e.renderbufferStorage(36161,f.format,r,o),i.profile&&(f.stats.size=be[f.format]*f.width*f.height),a)},a._reglType="renderbuffer",a._renderbuffer=f,i.profile&&(a.stats=f.stats),a.destroy=function(){f.decRef()},a},clear:function(){G(c).forEach(a)},restore:function(){G(c).forEach(function(t){t.renderbuffer=e.createRenderbuffer(),e.bindRenderbuffer(36161,t.renderbuffer),e.renderbufferStorage(36161,t.format,t.width,t.height)}),e.bindRenderbuffer(36161,null)}}},we=[];we[6408]=4,we[6407]=3;var xe=[];xe[5121]=1,xe[5126]=4,xe[36193]=2;var _e=["x","y","z","w"],Ae="blend.func blend.equation stencil.func stencil.opFront stencil.opBack sample.coverage viewport scissor.box polygonOffset.offset".split(" "),Ee={0:0,1:1,zero:0,one:1,"src color":768,"one minus src color":769,"src alpha":770,"one minus src alpha":771,"dst color":774,"one minus dst color":775,"dst alpha":772,"one minus dst alpha":773,"constant color":32769,"one minus constant color":32770,"constant alpha":32771,"one minus constant alpha":32772,"src alpha saturate":776},Ce={never:512,less:513,"<":513,equal:514,"=":514,"==":514,"===":514,lequal:515,"<=":515,greater:516,">":516,notequal:517,"!=":517,"!==":517,gequal:518,">=":518,always:519},ke={0:0,zero:0,keep:7680,replace:7681,increment:7682,decrement:7683,"increment wrap":34055,"decrement wrap":34056,invert:5386},Oe={cw:2304,ccw:2305},Te=new F(!1,!1,!1,function(){});return function(e){function t(){if(0===Q.length)_&&_.update(),ee=null;else{ee=q.next(t),l();for(var e=Q.length-1;0<=e;--e){var n=Q[e];n&&n(B,null,0)}g.flush(),_&&_.update()}}function n(){!ee&&0=Q.length&&r()}}}}function c(){var e=X.viewport,t=X.scissor_box;e[0]=e[1]=t[0]=t[1]=0,B.viewportWidth=B.framebufferWidth=B.drawingBufferWidth=e[2]=t[2]=g.drawingBufferWidth,B.viewportHeight=B.framebufferHeight=B.drawingBufferHeight=e[3]=t[3]=g.drawingBufferHeight}function l(){B.tick+=1,B.time=m(),c(),Y.procs.poll()}function p(){c(),Y.procs.refresh(),_&&_.update()}function m(){return(W()-A)/1e3}if(!(e=i(e)))return null;var g=e.gl,v=g.getContextAttributes();g.isContextLost();var b=function(e,t){function n(t){var n;t=t.toLowerCase();try{n=r[t]=e.getExtension(t)}catch(e){}return!!n}for(var r={},i=0;it;++t)te(U({framebuffer:e.framebuffer.faces[t]},e),s);else te(e,s);else s(0,e)},prop:V.define.bind(null,1),context:V.define.bind(null,2),this:V.define.bind(null,3),draw:u({}),buffer:function(e){return D.create(e,34962,!1,!1)},elements:function(e){return F.create(e,!1)},texture:L.create2D,cube:L.createCube,renderbuffer:N.create,framebuffer:H.create,framebufferCube:H.createCube,vao:P.createVAO,attributes:v,frame:f,on:function(e,t){var n;switch(e){case"frame":return f(t);case"lost":n=Z;break;case"restore":n=K;break;case"destroy":n=J}return n.push(t),{cancel:function(){for(var e=0;e 400.0) vPosition /= 0.0;\n\n // Compute the normal via numerical differentiation\n const float dx = 5e-3;\n vNormal = normalize(cross(\n f(uvScaled + vec2(dx / uRange.x, 0), uTau) - vPosition,\n f(uvScaled + vec2(0, dx / uRange.y), uTau) - vPosition\n ));\n\n gl_Position = uProjectionView * vec4(vPosition, 1);\n }\n ",frag:"\n #extension GL_OES_standard_derivatives : enable\n precision highp float;\n varying vec3 vPosition, vNormal;\n uniform vec3 uEye;\n uniform bool uWire;\n varying vec2 vUV;\n varying float vRadius;\n uniform float pixelRatio;\n\n #define PI 3.141592653589\n\n // From https://github.com/rreusser/glsl-solid-wireframe\n float gridFactor (vec2 parameter, float width, float feather) {\n float w1 = width - feather * 0.5;\n vec2 d = fwidth(parameter);\n vec2 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);\n vec2 a2 = smoothstep(d * w1, d * (w1 + feather), looped);\n return min(a2.x, a2.y);\n }\n\n void main () {\n if (dot(vPosition, vPosition) > 100.0) discard;\n // Shading technique adapted/simplified/customized from: https://observablehq.com/@rreusser/faking-transparency-for-3d-surfaces\n vec3 normal = normalize(vNormal);\n float vDotN = abs(dot(normal, normalize(vPosition - uEye)));\n float vDotNGrad = fwidth(vDotN);\n float cartoonEdge = smoothstep(0.75, 1.25, vDotN / (vDotNGrad * 3.0 * pixelRatio));\n float sgn = gl_FrontFacing ? 1.0 : -1.0;\n float grid = gridFactor(vUV * vec2(2.0, 2.0) * 4.0 / PI, 0.25 * pixelRatio, 1.0);\n vec3 baseColor = gl_FrontFacing ? vec3(0.9, 0.2, 0.1) : vec3(0.1, 0.4, 0.8);\n float vDotN4 = vDotN * vDotN;\n vDotN *= vDotN4;\n vDotN *= vDotN4;\n float shade = mix(1.0, vDotN4, 0.6) + 0.2;\n\n if (uWire) {\n gl_FragColor.rgb = vec3(1);\n gl_FragColor.a = mix(0.15, (1.0 - grid) * 0.055, cartoonEdge);\n } else {\n gl_FragColor = vec4(pow(\n mix(baseColor, (0.5 + sgn * 0.5 * normal), 0.4) * cartoonEdge * mix(1.0, 0.6, 1.0 - grid) * shade,\n vec3(0.454)),\n 1.0);\n }\n }\n ",uniforms:{uRange:function(e,t){return[u.uRange,u.vRange]},uTau:e.prop("tau"),uWire:e.prop("wire"),pixelRatio:e.context("pixelRatio")},attributes:{uv:n.positions},depth:{enable:function(e,t){return!t.wire}},blend:{enable:function(e,t){return!!t.wire},func:{srcRGB:"src alpha",srcAlpha:1,dstRGB:1,dstAlpha:1},equation:{rgb:"reverse subtract",alpha:"add"}},elements:n.cells})}(s,200);u.$onChanges(f.taint);s.frame(function(e){e.tick,e.time;f({rotationCenter:f.params.center},function(e){e.dirty&&(s.clear({color:[1,1,1,1]}),c([{wire:!1,tau:u.tau},{wire:!0,tau:u.tau}]))})})},{"./mesh-surface-2d":58,"./regl-turntable-camera":59,"controls-gui":7,"controls-state":8,"gl-mat4/create":25,"gl-mat4/lookAt":28,"gl-mat4/multiply":29,regl:50}],57:[function(e,t,n){"use strict";var r=e("gl-vec3/transformMat4"),i=e("normalized-interaction-events"),o=e("assert");t.exports=function(e,t){t=t||{};var n=e.element,u=null,s=null,f=null,c={defaultPrevented:!1};function l(){c.defaultPrevented=!1}function p(e){return e.defaultPrevented=c.defaultPrevented,e.preventDefault=function(){e.defaultPrevented=!0,c.defaultPrevented=!0},e}var h=[0,0,0],d=[0,0];return i(n).on("wheel",function(t){t.originalEvent.preventDefault(),e.zoom(t.x0,t.y0,Math.exp(-t.dy)-1)}).on("mousedown",function(e){l(),e=p(e),u&&u(e),e.originalEvent.preventDefault()}).on("mousemove",function(t){t=p(t),f&&f(t),t.defaultPrevented||t.active&&1===t.buttons&&(t.mods.alt?(e.zoom(t.x0,t.y0,Math.exp(t.dy)-1),t.originalEvent.preventDefault()):t.mods.shift?(e.pan(t.dx,t.dy),t.originalEvent.preventDefault()):t.mods.meta?(e.pivot(t.dx,t.dy),t.originalEvent.preventDefault()):(e.rotate(-t.dx*a,-t.dy*a),t.originalEvent.preventDefault()))}).on("mouseup",function(e){e.originalEvent.preventDefault(),l(),e=p(e),s&&s(e)}).on("touchstart",function(e){e.originalEvent.preventDefault(),e=p(e),u&&u(e)}).on("touchmove",function(t){t=p(t),f&&f(t),t.defaultPrevented||t.active&&(e.rotate(-t.dx*a,-t.dy*a),t.originalEvent.preventDefault())}).on("touchend",function(e){e.originalEvent.preventDefault(),l(),e=p(e),s&&s(e)}).on("pinchmove",function(n){n.active&&(function(e){h[0]=e.x,h[1]=e.y,h[2]=0,t.invViewportShift&&r(h,h,invViewportShift),d[0]=h[0],d[1]=h[1]}(n),e.zoom(d[0],d[1],1-n.zoomx),e.pan(n.dx,n.dy),n.originalEvent.preventDefault())}).on("pinchstart",function(e){e.originalEvent.preventDefault()}),u=t.onStart,f=t.onMove,s=t.onEnd,{setInteractions:function(e){o(e),u=e.onStart,s=e.onEnd,f=e.onMove}}};var a=.75*Math.PI},{assert:1,"gl-vec3/transformMat4":41,"normalized-interaction-events":47}],58:[function(e,t,n){"use strict";function r(e,t){if(!e)throw new Error(t)}var i=[0,0,0];t.exports=function(e,t,n){var o,a,u,s,f,c=(n=n||{}).resolution||30,l=Array.isArray(n.resolution)?n.resolution[0]:c,p=Array.isArray(n.resolution)?n.resolution[1]:c,h=void 0===n.uDomain?[0,1]:n.uDomain,d=void 0===n.vDomain?[0,1]:n.vDomain;e=e||{};var m=l,g=p;n.uClosed||(m+=1),n.vClosed||(g+=1);var v=m*g,b=2*v,y=e.positions=e.positions||new Float32Array(b);r(y.length,b);var w=3*(l*p*2),x=e.cells=e.cells||new Int16Array(w);if(r(x.length,w),n.attributes){e.attributes={};var _={},A=Object.keys(n.attributes);for(o=0;oLawson's Klein Bottle + + + + + + + + + + + + \ No newline at end of file diff --git a/nav.bundle.js b/nav.bundle.js index eba23bf..3f7c65f 100644 --- a/nav.bundle.js +++ b/nav.bundle.js @@ -1,9 +1,9 @@ -(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 1; --i) { + code = path.charCodeAt(i); + if (code === 47 /*/*/) { + if (!matchedSlash) { + end = i; + break; + } + } else { + // We saw the first non-path separator + matchedSlash = false; + } } - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); + if (end === -1) return hasRoot ? '/' : '.'; + if (hasRoot && end === 1) { + // return '//'; + // Backwards-compat fix: + return '/'; } - - return root + dir; + return path.slice(0, end); }; +function basename(path) { + if (typeof path !== 'string') path = path + ''; -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? + var start = 0; + var end = -1; + var matchedSlash = true; + var i; + + for (i = path.length - 1; i >= 0; --i) { + if (path.charCodeAt(i) === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // path component + matchedSlash = false; + end = i + 1; + } + } + + if (end === -1) return ''; + return path.slice(start, end); +} + +// Uses a mixed approach for backwards-compatibility, as ext behavior changed +// in new Node.js versions, so only basename() above is backported here +exports.basename = function (path, ext) { + var f = basename(path); if (ext && f.substr(-1 * ext.length) === ext) { f = f.substr(0, f.length - ext.length); } return f; }; +exports.extname = function (path) { + if (typeof path !== 'string') path = path + ''; + var startDot = -1; + var startPart = 0; + var end = -1; + var matchedSlash = true; + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + var preDotState = 0; + for (var i = path.length - 1; i >= 0; --i) { + var code = path.charCodeAt(i); + if (code === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === 46 /*.*/) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) + startDot = i; + else if (preDotState !== 1) + preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } -exports.extname = function(path) { - return splitPath(path)[3]; + if (startDot === -1 || end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { + return ''; + } + return path.slice(startDot, end); }; function filter (xs, f) { diff --git a/sketches/static/lawsons-klein-bottle-thumbnail.jpg b/sketches/static/lawsons-klein-bottle-thumbnail.jpg new file mode 100644 index 0000000..f42f215 Binary files /dev/null and b/sketches/static/lawsons-klein-bottle-thumbnail.jpg differ diff --git a/src/bin/build.js b/src/bin/build.js index ea7a3ec..5aced66 100755 --- a/src/bin/build.js +++ b/src/bin/build.js @@ -47,7 +47,7 @@ switch (entryFile.type) { ssr: true, theme: 'none', layout: 'none', - transform: ['glslify'] + transform: [],//['glslify'] }); idyll.build(); @@ -56,7 +56,7 @@ switch (entryFile.type) { var cpInputDir = path.join(__dirname, '..', projectDir, dir); var cpOutputDir = path.join(__dirname, '..', outputDir, dir); - if (fs.existsSync(cpInputDir)) { + if (cpInputDir && fs.existsSync(cpInputDir)) { console.log('copying', dir); cpr(cpInputDir, cpOutputDir, {}); } @@ -130,7 +130,7 @@ switch (entryFile.type) { var cpInputDir = path.join(__dirname, '..', projectDir, dir); var cpOutputDir = path.join(__dirname, '..', outputDir, dir); - if (fs.existsSync(cpInputDir)) { + if (cpInputDir && fs.existsSync(cpInputDir)) { console.log('copying', dir); cpr(cpInputDir, cpOutputDir, {}); } diff --git a/src/src/lawsons-klein-bottle/README.md b/src/src/lawsons-klein-bottle/README.md new file mode 100644 index 0000000..f162b9b --- /dev/null +++ b/src/src/lawsons-klein-bottle/README.md @@ -0,0 +1,19 @@ +# WIP Lawson's Klein Bottle + +It uses the [regl](https://github.com/regl-project/regl) library for interfacing with WebGL and uses [this shader technique](https://observablehq.com/@rreusser/faking-transparency-for-3d-surfaces) for drawing the surface. + +There are some shared dependencies a couple directories up, so you'll need to run `npm install` both in the root project directory and in this directory: + +```sh +git clone https://github.com/rreusser/explorations.git +cd explorations +npm install +cd posts/lawsons-klein-bottle +npm install +npm start +``` + +## License + +© 2020 Ricky Reusser. MIT License. + diff --git a/src/src/lawsons-klein-bottle/index.js b/src/src/lawsons-klein-bottle/index.js new file mode 100644 index 0000000..c98aff9 --- /dev/null +++ b/src/src/lawsons-klein-bottle/index.js @@ -0,0 +1,176 @@ +const createREGL = require('regl'); +const createCamera = require('./regl-turntable-camera'); +const meshSurface = require('./mesh-surface-2d'); +const mat4create = require('gl-mat4/create'); +const mat4multiply = require('gl-mat4/multiply'); +const mat4lookAt = require('gl-mat4/lookAt'); + +const State = require('controls-state'); +const GUI = require('controls-gui'); + +const state = GUI(State({ + tau: State.Slider(1, {min: 0, max: 2.0, step: 0.01, label: 'τ'}), + uRange: State.Slider(1, {min: 0, max: 2.0, step: 0.01, label: 'uRange'}), + vRange: State.Slider(1, {min: 0, max: 2.0, step: 0.01, label: 'vRange'}), +}), { + containerCSS: "position:absolute; top:0; right:10px; width:350px; z-index: 1", +}); + +function createDrawThingy (regl, res) { + const mesh = meshSurface({}, (out, u, v) => { + out[0] = u * 0.999999; + out[1] = v * 0.999999; + }, { + resolution: [res, res], + uDomain: [-Math.PI, Math.PI], + vDomain: [-Math.PI * 0.5, Math.PI * 0.5], + }); + + return regl({ + vert: ` + precision highp float; + attribute vec2 uv; + uniform mat4 uProjectionView; + uniform float uTau; + uniform vec2 uRange; + varying vec3 vPosition, vNormal; + varying float vRadius; + varying vec2 vUV; + + /* + vec4 quatMult(vec4 q1, vec4 q2) { + return vec4( + (q1.w * q2.x) + (q1.x * q2.w) + (q1.y * q2.z) - (q1.z * q2.y), + (q1.w * q2.y) - (q1.x * q2.z) + (q1.y * q2.w) + (q1.z * q2.x), + (q1.w * q2.z) + (q1.x * q2.y) - (q1.y * q2.x) + (q1.z * q2.w), + (q1.w * q2.w) - (q1.x * q2.x) - (q1.y * q2.y) - (q1.z * q2.z) + ); + } + */ + + vec3 f(vec2 uv, float tau) { + float tx = tau * uv.x; + vec4 p = vec4( + cos(uv.y) * vec2(cos(uv.x), sin(uv.x)), + sin(uv.y) * vec2(cos(tx), sin(tx)) + ); + + //p.xyz = mat3(uView) * p.xzy; + + // Compute the stereographic projection + return p.yzx / (1.0 - p.w); + } + + void main () { + vUV = uv; + vec2 uvScaled = uv * uRange; + vUV *= uRange; + vPosition = f(uvScaled, uTau); + vRadius = dot(vPosition, vPosition); + + // Taint bad triangles to prevent them from passing through the origin as they cross from -Ininity to Infinity + if (vRadius > 400.0) vPosition /= 0.0; + + // Compute the normal via numerical differentiation + const float dx = 5e-3; + vNormal = normalize(cross( + f(uvScaled + vec2(dx / uRange.x, 0), uTau) - vPosition, + f(uvScaled + vec2(0, dx / uRange.y), uTau) - vPosition + )); + + gl_Position = uProjectionView * vec4(vPosition, 1); + } + `, + frag: ` + #extension GL_OES_standard_derivatives : enable + precision highp float; + varying vec3 vPosition, vNormal; + uniform vec3 uEye; + uniform bool uWire; + varying vec2 vUV; + varying float vRadius; + uniform float pixelRatio; + + #define PI 3.141592653589 + + // From https://github.com/rreusser/glsl-solid-wireframe + float gridFactor (vec2 parameter, float width, float feather) { + float w1 = width - feather * 0.5; + vec2 d = fwidth(parameter); + vec2 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5); + vec2 a2 = smoothstep(d * w1, d * (w1 + feather), looped); + return min(a2.x, a2.y); + } + + void main () { + if (dot(vPosition, vPosition) > 100.0) discard; + // Shading technique adapted/simplified/customized from: https://observablehq.com/@rreusser/faking-transparency-for-3d-surfaces + vec3 normal = normalize(vNormal); + float vDotN = abs(dot(normal, normalize(vPosition - uEye))); + float vDotNGrad = fwidth(vDotN); + float cartoonEdge = smoothstep(0.75, 1.25, vDotN / (vDotNGrad * 3.0 * pixelRatio)); + float sgn = gl_FrontFacing ? 1.0 : -1.0; + float grid = gridFactor(vUV * vec2(2.0, 2.0) * 4.0 / PI, 0.25 * pixelRatio, 1.0); + vec3 baseColor = gl_FrontFacing ? vec3(0.9, 0.2, 0.1) : vec3(0.1, 0.4, 0.8); + float vDotN4 = vDotN * vDotN; + vDotN *= vDotN4; + vDotN *= vDotN4; + float shade = mix(1.0, vDotN4, 0.6) + 0.2; + + if (uWire) { + gl_FragColor.rgb = vec3(1); + gl_FragColor.a = mix(0.15, (1.0 - grid) * 0.055, cartoonEdge); + } else { + gl_FragColor = vec4(pow( + mix(baseColor, (0.5 + sgn * 0.5 * normal), 0.4) * cartoonEdge * mix(1.0, 0.6, 1.0 - grid) * shade, + vec3(0.454)), + 1.0); + } + } + `, + uniforms: { + uRange: (ctx, props) => [state.uRange, state.vRange], + uTau: regl.prop('tau'), + uWire: regl.prop('wire'), + pixelRatio: regl.context('pixelRatio'), + }, + attributes: {uv: mesh.positions}, + depth: {enable: (ctx, props) => props.wire ? false : true}, + blend: { + enable: (ctx, props) => props.wire ? true : false, + func: {srcRGB: 'src alpha', srcAlpha: 1, dstRGB: 1, dstAlpha: 1}, + equation: {rgb: 'reverse subtract', alpha: 'add'} + }, + elements: mesh.cells + }); +} + +const regl = createREGL({extensions: ['OES_standard_derivatives']}); + +const camera = createCamera(regl, { + distance: 8, + theta: Math.PI * 1.1, + phi: Math.PI * 0.1, + far: 200, + rotateAbountCenter: true +}); + +const drawTorus = createDrawThingy(regl, 200); + +state.$onChanges(camera.taint); + +let frame = regl.frame(({tick, time}) => { + camera({ + rotationCenter: camera.params.center + }, ({dirty}) => { + if (!dirty) return; + regl.clear({color: [1, 1, 1, 1]}); + + // Perform two drawing passes, first for the solid surface, then for the wireframe overlayed on top + // to give a fake transparency effect + drawTorus([ + {wire: false, tau: state.tau}, + {wire: true, tau: state.tau} + ]); + }); +}); diff --git a/src/src/lawsons-klein-bottle/interactions.js b/src/src/lawsons-klein-bottle/interactions.js new file mode 100644 index 0000000..ba4f930 --- /dev/null +++ b/src/src/lawsons-klein-bottle/interactions.js @@ -0,0 +1,148 @@ +'use strict'; + +const vec3TransformMat4 = require('gl-vec3/transformMat4'); +const interactionEvents = require('normalized-interaction-events'); +const assert = require('assert'); + +module.exports = attachCameraControls; + +const RADIANS_PER_HALF_SCREEN_WIDTH = Math.PI * 0.75; + +function attachCameraControls (camera, opts) { + opts = opts || {}; + var element = camera.element; + + var onStart = null; + var onEnd = null; + var onMove = null; + + var singletonEventData = { + defaultPrevented: false + }; + + function localPreventDefault () { + singletonEventData.defaultPrevented = true; + } + + function resetLocalPreventDefault () { + singletonEventData.defaultPrevented = false; + } + + function providePreventDefault (ev) { + ev.defaultPrevented = singletonEventData.defaultPrevented; + ev.preventDefault = function () { + ev.defaultPrevented = true; + localPreventDefault(); + }; + return ev; + } + + var v = [0, 0, 0]; + var xy = [0, 0]; + function transformXY(ev) { + v[0] = ev.x; + v[1] = ev.y; + v[2] = 0; + if (opts.invViewportShift) { + vec3TransformMat4(v, v, invViewportShift); + } + xy[0] = v[0]; + xy[1] = v[1]; + return xy; + } + + interactionEvents(element) + .on('wheel', function (ev) { + ev.originalEvent.preventDefault(); + + camera.zoom(ev.x0, ev.y0, Math.exp(-ev.dy) - 1.0); + }) + .on('mousedown', function (ev) { + resetLocalPreventDefault(); + + ev = providePreventDefault(ev); + onStart && onStart(ev); + + ev.originalEvent.preventDefault(); + }) + .on('mousemove', function (ev) { + ev = providePreventDefault(ev); + onMove && onMove(ev); + + if (ev.defaultPrevented) return; + + if (!ev.active || ev.buttons !== 1) return; + + if (ev.mods.alt) { + camera.zoom(ev.x0, ev.y0, Math.exp(ev.dy) - 1.0); + ev.originalEvent.preventDefault(); + } else if (ev.mods.shift) { + camera.pan(ev.dx, ev.dy); + ev.originalEvent.preventDefault(); + } else if (ev.mods.meta) { + camera.pivot(ev.dx, ev.dy); + ev.originalEvent.preventDefault(); + } else { + camera.rotate( + -ev.dx * RADIANS_PER_HALF_SCREEN_WIDTH, + -ev.dy * RADIANS_PER_HALF_SCREEN_WIDTH + ); + ev.originalEvent.preventDefault(); + } + }) + .on('mouseup', function (ev) { + ev.originalEvent.preventDefault(); + resetLocalPreventDefault(); + ev = providePreventDefault(ev); + onEnd && onEnd(ev); + }) + .on('touchstart', function (ev) { + ev.originalEvent.preventDefault(); + + ev = providePreventDefault(ev); + onStart && onStart(ev); + }) + .on('touchmove', function (ev) { + ev = providePreventDefault(ev); + onMove && onMove(ev); + + if (ev.defaultPrevented) return; + + if (!ev.active) return; + camera.rotate( + -ev.dx * RADIANS_PER_HALF_SCREEN_WIDTH, + -ev.dy * RADIANS_PER_HALF_SCREEN_WIDTH + ); + ev.originalEvent.preventDefault(); + }) + .on('touchend', function (ev) { + ev.originalEvent.preventDefault(); + resetLocalPreventDefault(); + ev = providePreventDefault(ev); + onEnd && onEnd(ev); + }) + .on('pinchmove', function (ev) { + if (!ev.active) return; + transformXY(ev); + camera.zoom(xy[0], xy[1], 1 - ev.zoomx); + camera.pan(ev.dx, ev.dy); + + ev.originalEvent.preventDefault(); + }) + .on('pinchstart', function (ev) { + ev.originalEvent.preventDefault(); + }); + + onStart = opts.onStart; + onMove = opts.onMove; + onEnd = opts.onEnd; + + return { + setInteractions: function (interactions) { + assert(interactions); + onStart = interactions.onStart; + onEnd = interactions.onEnd; + onMove = interactions.onMove; + } + }; +} diff --git a/src/src/lawsons-klein-bottle/mesh-surface-2d.js b/src/src/lawsons-klein-bottle/mesh-surface-2d.js new file mode 100644 index 0000000..e21ef49 --- /dev/null +++ b/src/src/lawsons-klein-bottle/mesh-surface-2d.js @@ -0,0 +1,106 @@ +'use strict'; + +function assert (condition, message) { + if (!condition) throw new Error(message); +} + +var DEFAULT_RESOLUTION = 30; +var tmp1 = [0.0, 0.0, 0.0]; +var tmp2 = [0.0, 0.0, 0.0]; +var tmp3 = [0.0, 0.0, 0.0]; + +module.exports = function (meshData, surfaceFn, opts) { + var i, j, u, v, index, nbUFaces, nbVFaces; + + opts = opts || {}; + + var res = opts.resolution || DEFAULT_RESOLUTION; + var nbUFaces = Array.isArray(opts.resolution) ? opts.resolution[0] : res; + var nbVFaces = Array.isArray(opts.resolution) ? opts.resolution[1] : res; + + var uDomain = opts.uDomain === undefined ? [0, 1] : opts.uDomain; + var vDomain = opts.vDomain === undefined ? [0, 1] : opts.vDomain; + + meshData = meshData || {}; + + var nbBoundaryAdjustedUFaces = nbUFaces; + var nbBoundaryAdjustedVFaces = nbVFaces; + if (!opts.uClosed) nbBoundaryAdjustedUFaces += 1; + if (!opts.vClosed) nbBoundaryAdjustedVFaces += 1; + + var nbPositions = nbBoundaryAdjustedUFaces * nbBoundaryAdjustedVFaces; + var positionDataLength = nbPositions * 2; + var positions = meshData.positions = meshData.positions || new Float32Array(positionDataLength); + assert(positions.length, positionDataLength, 'Incorrect number of positions in pre-allocated array'); + + var nbFaces = nbUFaces * nbVFaces * 2; + var cellDataLength = nbFaces * 3; + var cells = meshData.cells = meshData.cells || new Int16Array(cellDataLength); + assert(cells.length, cellDataLength, 'Incorrect number of cells in pre-allocated array'); + + if (opts.attributes) { + meshData.attributes = {}; + var attrSize = {}; + var attributeKeys = Object.keys(opts.attributes); + + for (i = 0; i < attributeKeys.length; i++) { + var key = attributeKeys[i]; + var attrFn = opts.attributes[key]; + var test = []; + attrFn(test, uDomain[0], vDomain[0]); + attrSize[key] = test.length; + + var attrDataLength = nbPositions * attrSize[key]; + meshData.attributes[key] = meshData.attributes[key] || new Float32Array(attrDataLength); + assert(meshData.attributes[key].length, attrDataLength, 'Incorrect attr size in pre-allocated array for attr ' + key); + } + } + + for (i = 0; i < nbBoundaryAdjustedUFaces; i++) { + u = uDomain[0] + (uDomain[1] - uDomain[0]) * i / nbUFaces; + for (j = 0; j < nbBoundaryAdjustedVFaces; j++) { + v = vDomain[0] + (vDomain[1] - vDomain[0]) * j / nbVFaces; + + index = 2 * (i + nbBoundaryAdjustedUFaces * j); + + surfaceFn(tmp1, u, v); + + positions[index + 0] = tmp1[0]; + positions[index + 1] = tmp1[1]; + + if (attributeKeys) { + for (var k = 0; k < attributeKeys.length; k++) { + var key = attributeKeys[k]; + var attrFn = opts.attributes[key]; + attrFn(tmp1, u, v); + var attrIndex = (i + nbBoundaryAdjustedUFaces * j) * attrSize[key]; + var attrData = meshData.attributes[key]; + for (var l = 0; l < attrSize[key]; l++) { + attrData[attrIndex + l] = tmp1[l]; + } + } + } + + } + } + + var faceIndex = 0; + for (i = 0; i < nbUFaces; i++) { + var iPlusOne = i + 1; + if (opts.uClosed) iPlusOne = iPlusOne % nbUFaces; + for (j = 0; j < nbVFaces; j++) { + var jPlusOne = j + 1; + if (opts.vClosed) jPlusOne = jPlusOne % nbVFaces; + + cells[faceIndex++] = i + nbBoundaryAdjustedUFaces * j; + cells[faceIndex++] = iPlusOne + nbBoundaryAdjustedUFaces * j; + cells[faceIndex++] = iPlusOne + nbBoundaryAdjustedUFaces * jPlusOne; + + cells[faceIndex++] = i + nbBoundaryAdjustedUFaces * j; + cells[faceIndex++] = iPlusOne + nbBoundaryAdjustedUFaces * jPlusOne; + cells[faceIndex++] = i + nbBoundaryAdjustedUFaces * jPlusOne; + } + } + + return meshData; +}; diff --git a/src/src/lawsons-klein-bottle/metadata.json b/src/src/lawsons-klein-bottle/metadata.json new file mode 100644 index 0000000..1a3bc95 --- /dev/null +++ b/src/src/lawsons-klein-bottle/metadata.json @@ -0,0 +1,6 @@ +{ + "title": "Lawson's Klein Bottle", + "description": "3D sterographic projection of a 4D Klein bottle", + "order": 3200, + "image": "http://rreusser.github.io/src/src/lawsons-klein-bottle/thumbnail.jpg" +} diff --git a/src/src/lawsons-klein-bottle/regl-turntable-camera.js b/src/src/lawsons-klein-bottle/regl-turntable-camera.js new file mode 100644 index 0000000..76b858f --- /dev/null +++ b/src/src/lawsons-klein-bottle/regl-turntable-camera.js @@ -0,0 +1,83 @@ +'use strict'; + +var mat4create = require('gl-mat4/create'); +var mat4multiply = require('gl-mat4/multiply'); +var createCamera = require('inertial-turntable-camera'); +var createInteractions = require('./interactions'); + +var RADIANS_PER_HALF_SCREEN_WIDTH = Math.PI * 2 * 0.4; + +module.exports = function createReglCamera (regl, opts) { + var element = regl._gl.canvas; + element.addEventListener('wheel', event => event.preventDefault()); + + function getAspectRatio () { + return element.clientWidth / element.clientHeight; + } + + var camera = createCamera(Object.assign({}, { + aspectRatio: getAspectRatio(), + }, opts || {})); + + var mProjectionView = mat4create(); + var setCameraUniforms = regl({ + context: { + projection: () => camera.state.projection, + view: () => camera.state.view, + viewInv: () => camera.state.viewInv, + eye: () => camera.state.eye, + }, + uniforms: { + uProjectionView: ctx => mat4multiply(mProjectionView, ctx.projection, ctx.view), + uProjection: regl.context('projection'), + uView: regl.context('view'), + uEye: regl.context('eye'), + } + }); + + function invokeCamera (props, callback) { + if (!callback) { + callback = props; + props = {}; + } + + camera.tick(props); + + setCameraUniforms(function () { + callback(camera.state, camera.params); + }); + } + + invokeCamera.taint = camera.taint; + invokeCamera.resize = camera.resize; + invokeCamera.tick = camera.tick; + invokeCamera.setUniforms = setCameraUniforms; + + invokeCamera.rotate = camera.rotate; + invokeCamera.pan = camera.pan; + invokeCamera.pivot = camera.pivot; + invokeCamera.zoom = camera.zoom; + + Object.defineProperties(invokeCamera, { + state: { + get: function () { return camera.state; }, + set: function (value) { camera.state = value; } + }, + params: { + get: function () { return camera.params; }, + set: function (value) { camera.params = value; } + }, + element: { + get: function () { return element; } + }, + }); + + window.addEventListener('resize', function () { + camera.resize(getAspectRatio()); + }, false); + + camera.element = regl._gl.canvas; + createInteractions(camera); + + return invokeCamera; +}; diff --git a/src/src/lawsons-klein-bottle/thumbnail.jpg b/src/src/lawsons-klein-bottle/thumbnail.jpg new file mode 100644 index 0000000..f42f215 Binary files /dev/null and b/src/src/lawsons-klein-bottle/thumbnail.jpg differ diff --git a/src/src/sketches/index.json b/src/src/sketches/index.json index b7deeb2..9136e9e 100644 --- a/src/src/sketches/index.json +++ b/src/src/sketches/index.json @@ -1 +1 @@ -[{"id":"calabi-yau","path":"../calabi-yau/","title":"Calabi-Yau Manifolds","order":3200,"description":"A simple plot of Calabi-Yau manifolds; nothing more, nothing less","thumbnailPath":"static/calabi-yau-thumbnail.jpg"},{"id":"boys-surface","path":"../boys-surface/","title":"Boy's Surface","order":3100,"description":"An immersion of the real projective plane in 3D space","thumbnailPath":"static/boys-surface-thumbnail.jpg"},{"id":"clifford-torus","path":"../clifford-torus/","title":"Clifford Torus","order":3000,"description":"3D sterographic projection of a 4D Clifford torus","thumbnailPath":"static/clifford-torus-thumbnail.jpg"},{"id":"webcam-kmeans","path":"../webcam-kmeans/","title":"K-Means","order":2900,"description":"Live k-means on a video feed with Lloyd's algorithm","thumbnailPath":"static/webcam-kmeans-thumbnail.jpg"},{"id":"moire","path":"../moire/","title":"Moiré","order":2800,"description":"Just moiré","thumbnailPath":"static/moire-thumbnail.jpg"},{"id":"ikeda","path":"../ikeda/","title":"Ikeda Map","order":2700,"description":"A discrete chaotic attractor","thumbnailPath":"static/ikeda-thumbnail.jpg"},{"id":"hertzsprung-russell","path":"../hertzsprung-russell/","title":"Hertzsprung-Russell Diagram","order":2600,"description":"Star magnitudes and temperatures","thumbnailPath":"static/hertzsprung-russell-thumbnail.jpg"},{"id":"mandelbrot","path":"../mandelbrot/","title":"Mandelbrot","order":2500,"description":"Drawing the first iterations of the Mandelbrot set as a complex function","thumbnailPath":"static/mandelbrot-thumbnail.jpg"},{"id":"pulsar","path":"../pulsar/","title":"Pulsar","order":2400,"description":"Signals and noise (no physical significance)","thumbnailPath":"static/pulsar-thumbnail.png"},{"id":"multiscale-turing-patterns","path":"../multiscale-turing-patterns/","title":"Multiscale Turing Patterns","order":2300,"description":"Multiscale turing patterns, as described by Jonathan McCabe","thumbnailPath":"static/multiscale-turing-patterns-thumbnail.jpg"},{"id":"magnet","path":"../magnet/","title":"Magnet","order":2200,"description":"Just a magnetic field","thumbnailPath":"static/magnet-thumbnail.jpg"},{"id":"potential-flow","path":"../potential-flow/","title":"Potential Flow","order":2100,"description":"Procedural (almost) potential flow with curl noise","thumbnailPath":"static/potential-flow-thumbnail.jpg"},{"id":"ueda-attractor","path":"../ueda-attractor/","title":"Ueda Attractor","order":2000,"description":"Ueda's chaotic nonlinear oscillator","thumbnailPath":"static/ueda-attractor-thumbnail.jpg"},{"id":"path-integral-diffraction","path":"../path-integral-diffraction/","title":"Single-slit diffraction","order":1900,"description":"Diffraction of a 1D wavefunction through a slit using Feynman's path integral approach","thumbnailPath":"static/path-integral-diffraction-thumbnail.jpg"},{"id":"fibonacci-sphere","path":"../fibonacci-sphere/","title":"Fibonacci Sphere","order":1800,"description":"From Martin Roberts' article about evenly distributed points on a sphere","thumbnailPath":"static/fibonacci-sphere-thumbnail.jpg"},{"id":"gray-scott-reaction-diffusion","path":"../gray-scott-reaction-diffusion/","title":"Gray Scott Reaction Diffusion","order":1700,"description":"Reacting species diffusing at different rates","thumbnailPath":"static/gray-scott-reaction-diffusion-thumbnail.jpg"},{"id":"rule-30","path":"../rule-30/","title":"Rule 30","order":1600,"description":"Stephen Wolfram's 1D cellular automata","thumbnailPath":"static/rule-30-thumbnail.png"},{"id":"line-integral-convolution","path":"../line-integral-convolution/","title":"Line Integral Convolution","order":1500,"description":"Visualizing vector fields with Line Integral Convolution (LIC)","thumbnailPath":"static/line-integral-convolution-thumbnail.jpg"},{"id":"iterative-closest-point","path":"../iterative-closest-point/","title":"Rigid Point Cloud Alignment","order":1400,"description":"Aligning point clouds with the Iterative Closest Point method","thumbnailPath":"static/iterative-closest-point-thumbnail.png"},{"id":"spherical-harmonics","path":"../spherical-harmonics/","title":"Spherical Harmonics","order":1300,"description":"Just a plot of the first few spherical harmonics","thumbnailPath":"static/spherical-harmonics-thumbnail.jpg"},{"id":"domain-coloring-with-scaling","path":"../domain-coloring-with-scaling/","title":"Domain Coloring with Contour Scaling","order":1200,"description":"Using OES_standard_derivatives to scale contours to the local gradient of a function","thumbnailPath":"static/domain-coloring-with-scaling-thumbnail.jpg"},{"id":"flamms-paraboloid","path":"../flamms-paraboloid/","title":"Flamm's Paraboloid","order":1100,"description":"Scroll to build Flamm's Paraboloid","thumbnailPath":"static/flamms-paraboloid-thumbnail.jpg"},{"id":"continuum-gravity","path":"../continuum-gravity/","title":"Continuum Gravity","order":1000,"description":"One million particles interacting gravitationally via a Poisson equation solved on a 2D grid","thumbnailPath":"static/continuum-gravity-thumbnail.jpg"},{"id":"kuramoto-sivashinsky","path":"../kuramoto-sivashinsky/","title":"Kuramoto-Sivashinsky","order":900,"description":"Integrating the 2D Kuramoto-Sivashinsky Equation, ∂u/∂t + ∇⁴u + ∇²u + ½ |∇u|² = 0","thumbnailPath":"static/kuramoto-sivashinsky-thumbnail.jpg"},{"id":"karman-trefftz-airfoil","path":"../karman-trefftz-airfoil/","title":"Karman-Trefftz Airfoil","order":700,"description":"Flow over an airfoil, computed with the Karman-Trefftz conformal map and visualized on the GPU","thumbnailPath":"static/karman-trefftz-airfoil-thumbnail.jpg"},{"id":"periodic-three-body-orbits","path":"../periodic-three-body-orbits/","title":"Periodic Three-Body Orbits","order":600,"description":"Periodic solutions of three bodies interacting via Newtonian gravity","thumbnailPath":"static/periodic-three-body-orbits-thumbnail.jpg"},{"id":"hydrodynamic-instabilities","path":"../hydrodynamic-instabilities/","title":"Hydrodynamic Instabilities","order":500,"description":"The Kelvin-Helmholtz and Rayleigh-Taylor hydrodynamic instabilities","thumbnailPath":"static/hydrodynamic-instabilities-thumbnail.jpg"},{"id":"strange-attractors","path":"../strange-attractors/","title":"Strange Attractors","order":450,"description":"Strange attractors on the GPU","thumbnailPath":"static/strange-attractors-thumbnail.jpg"},{"id":"schwarzschild-spacetime","path":"../schwarzschild-spacetime/","title":"Schwarzschild Trajectories","order":350,"description":"Integrating particle geodesics in Schwarzschild spacetime (a black hole).","thumbnailPath":"static/schwarzschild-spacetime-thumbnail.jpg"},{"id":"random-polynomial-roots","path":"../random-polynomial-roots/","title":"Polynomial Roots","order":300,"description":"Roots of a polynomial with random coefficients, plotted in the complex plane","thumbnailPath":"static/random-polynomial-roots-thumbnail.jpg"},{"id":"umbilic-torus","path":"../umbilic-torus/","title":"Umbilic Torus","order":300,"description":"Umbilic Torus","thumbnailPath":"static/umbilic-torus-thumbnail.jpg"},{"id":"lamb-wave-dispersion","path":"../lamb-wave-dispersion/","title":"Lamb Wave Dispersion Relation","order":220,"description":"Plotting the the complex dispersion relation for elastodynamic plate waves; zeros represent valid modes","thumbnailPath":"static/lamb-wave-dispersion-thumbnail.jpg"},{"id":"fluid-simulation","path":"../fluid-simulation/","title":"Fluid Simluation","order":210,"description":"Classic semi-Lagrangian fluid simulation from Visual Simulation of Smoke","thumbnailPath":"static/fluid-simulation-thumbnail.jpg"},{"id":"erosion","path":"../erosion/","title":"Erosion","order":100,"description":"An ad-hoc particle-based terrain erosion algorithm, computed on the GPU","thumbnailPath":"static/erosion-thumbnail.jpg"},{"id":"centripetal-b-splines","path":"../centripetal-b-splines/","title":"Centripetal B-Splines","order":80,"description":"Experimenting with centripetal parameterization for B-splines","thumbnailPath":"static/centripetal-b-splines-thumbnail.png"},{"id":"smooth-life","path":"../smooth-life/","title":"Smooth Life","order":80,"description":"Conway's Game of Life, generalized to a continuum and solved on the GPU","thumbnailPath":"static/smooth-life-thumbnail.jpg"},{"id":"logistic-map","path":"../logistic-map/","title":"Logistic Map","order":20,"description":"The chaotic logistic map, computed and displayed on the GPU","thumbnailPath":"static/logistic-map-thumbnail.jpg"},{"id":"nose-hoover-attractor","path":"../nose-hoover-attractor/","title":"Nosé-Hoover Attractor","order":8,"description":"Plotting a strange attractor with 2D rectangles","thumbnailPath":"static/nose-hoover-attractor-thumbnail.jpg"},{"id":"vortex-sdf","path":"../vortex-sdf/","title":"Vortex","order":7,"description":"A vortex, rendered as a single signed distance function","thumbnailPath":"static/vortex-sdf-thumbnail.jpg"},{"id":"k-means","path":"../k-means/","title":"K-means clustering","order":5,"description":"WIP refactoring of the kmpp npm module","thumbnailPath":"static/k-means-thumbnail.jpg"},{"id":"double-pendulum","path":"../double-pendulum/","title":"Double Pendulum","order":3,"description":"Accumulating long-term patterns in a chaotic double-pendulum","thumbnailPath":"static/double-pendulum-thumbnail.jpg"}] \ No newline at end of file +[{"id":"calabi-yau","path":"../calabi-yau/","title":"Calabi-Yau Manifolds","order":3200,"description":"A simple plot of Calabi-Yau manifolds; nothing more, nothing less","thumbnailPath":"static/calabi-yau-thumbnail.jpg"},{"id":"lawsons-klein-bottle","path":"../lawsons-klein-bottle/","title":"Lawson's Klein Bottle","order":3200,"description":"3D sterographic projection of a 4D Klein bottle","thumbnailPath":"static/lawsons-klein-bottle-thumbnail.jpg"},{"id":"boys-surface","path":"../boys-surface/","title":"Boy's Surface","order":3100,"description":"An immersion of the real projective plane in 3D space","thumbnailPath":"static/boys-surface-thumbnail.jpg"},{"id":"clifford-torus","path":"../clifford-torus/","title":"Clifford Torus","order":3000,"description":"3D sterographic projection of a 4D Clifford torus","thumbnailPath":"static/clifford-torus-thumbnail.jpg"},{"id":"webcam-kmeans","path":"../webcam-kmeans/","title":"K-Means","order":2900,"description":"Live k-means on a video feed with Lloyd's algorithm","thumbnailPath":"static/webcam-kmeans-thumbnail.jpg"},{"id":"moire","path":"../moire/","title":"Moiré","order":2800,"description":"Just moiré","thumbnailPath":"static/moire-thumbnail.jpg"},{"id":"ikeda","path":"../ikeda/","title":"Ikeda Map","order":2700,"description":"A discrete chaotic attractor","thumbnailPath":"static/ikeda-thumbnail.jpg"},{"id":"hertzsprung-russell","path":"../hertzsprung-russell/","title":"Hertzsprung-Russell Diagram","order":2600,"description":"Star magnitudes and temperatures","thumbnailPath":"static/hertzsprung-russell-thumbnail.jpg"},{"id":"mandelbrot","path":"../mandelbrot/","title":"Mandelbrot","order":2500,"description":"Drawing the first iterations of the Mandelbrot set as a complex function","thumbnailPath":"static/mandelbrot-thumbnail.jpg"},{"id":"pulsar","path":"../pulsar/","title":"Pulsar","order":2400,"description":"Signals and noise (no physical significance)","thumbnailPath":"static/pulsar-thumbnail.png"},{"id":"multiscale-turing-patterns","path":"../multiscale-turing-patterns/","title":"Multiscale Turing Patterns","order":2300,"description":"Multiscale turing patterns, as described by Jonathan McCabe","thumbnailPath":"static/multiscale-turing-patterns-thumbnail.jpg"},{"id":"magnet","path":"../magnet/","title":"Magnet","order":2200,"description":"Just a magnetic field","thumbnailPath":"static/magnet-thumbnail.jpg"},{"id":"potential-flow","path":"../potential-flow/","title":"Potential Flow","order":2100,"description":"Procedural (almost) potential flow with curl noise","thumbnailPath":"static/potential-flow-thumbnail.jpg"},{"id":"ueda-attractor","path":"../ueda-attractor/","title":"Ueda Attractor","order":2000,"description":"Ueda's chaotic nonlinear oscillator","thumbnailPath":"static/ueda-attractor-thumbnail.jpg"},{"id":"path-integral-diffraction","path":"../path-integral-diffraction/","title":"Single-slit diffraction","order":1900,"description":"Diffraction of a 1D wavefunction through a slit using Feynman's path integral approach","thumbnailPath":"static/path-integral-diffraction-thumbnail.jpg"},{"id":"fibonacci-sphere","path":"../fibonacci-sphere/","title":"Fibonacci Sphere","order":1800,"description":"From Martin Roberts' article about evenly distributed points on a sphere","thumbnailPath":"static/fibonacci-sphere-thumbnail.jpg"},{"id":"gray-scott-reaction-diffusion","path":"../gray-scott-reaction-diffusion/","title":"Gray Scott Reaction Diffusion","order":1700,"description":"Reacting species diffusing at different rates","thumbnailPath":"static/gray-scott-reaction-diffusion-thumbnail.jpg"},{"id":"rule-30","path":"../rule-30/","title":"Rule 30","order":1600,"description":"Stephen Wolfram's 1D cellular automata","thumbnailPath":"static/rule-30-thumbnail.png"},{"id":"line-integral-convolution","path":"../line-integral-convolution/","title":"Line Integral Convolution","order":1500,"description":"Visualizing vector fields with Line Integral Convolution (LIC)","thumbnailPath":"static/line-integral-convolution-thumbnail.jpg"},{"id":"iterative-closest-point","path":"../iterative-closest-point/","title":"Rigid Point Cloud Alignment","order":1400,"description":"Aligning point clouds with the Iterative Closest Point method","thumbnailPath":"static/iterative-closest-point-thumbnail.png"},{"id":"spherical-harmonics","path":"../spherical-harmonics/","title":"Spherical Harmonics","order":1300,"description":"Just a plot of the first few spherical harmonics","thumbnailPath":"static/spherical-harmonics-thumbnail.jpg"},{"id":"domain-coloring-with-scaling","path":"../domain-coloring-with-scaling/","title":"Domain Coloring with Contour Scaling","order":1200,"description":"Using OES_standard_derivatives to scale contours to the local gradient of a function","thumbnailPath":"static/domain-coloring-with-scaling-thumbnail.jpg"},{"id":"flamms-paraboloid","path":"../flamms-paraboloid/","title":"Flamm's Paraboloid","order":1100,"description":"Scroll to build Flamm's Paraboloid","thumbnailPath":"static/flamms-paraboloid-thumbnail.jpg"},{"id":"continuum-gravity","path":"../continuum-gravity/","title":"Continuum Gravity","order":1000,"description":"One million particles interacting gravitationally via a Poisson equation solved on a 2D grid","thumbnailPath":"static/continuum-gravity-thumbnail.jpg"},{"id":"kuramoto-sivashinsky","path":"../kuramoto-sivashinsky/","title":"Kuramoto-Sivashinsky","order":900,"description":"Integrating the 2D Kuramoto-Sivashinsky Equation, ∂u/∂t + ∇⁴u + ∇²u + ½ |∇u|² = 0","thumbnailPath":"static/kuramoto-sivashinsky-thumbnail.jpg"},{"id":"karman-trefftz-airfoil","path":"../karman-trefftz-airfoil/","title":"Karman-Trefftz Airfoil","order":700,"description":"Flow over an airfoil, computed with the Karman-Trefftz conformal map and visualized on the GPU","thumbnailPath":"static/karman-trefftz-airfoil-thumbnail.jpg"},{"id":"periodic-three-body-orbits","path":"../periodic-three-body-orbits/","title":"Periodic Three-Body Orbits","order":600,"description":"Periodic solutions of three bodies interacting via Newtonian gravity","thumbnailPath":"static/periodic-three-body-orbits-thumbnail.jpg"},{"id":"hydrodynamic-instabilities","path":"../hydrodynamic-instabilities/","title":"Hydrodynamic Instabilities","order":500,"description":"The Kelvin-Helmholtz and Rayleigh-Taylor hydrodynamic instabilities","thumbnailPath":"static/hydrodynamic-instabilities-thumbnail.jpg"},{"id":"strange-attractors","path":"../strange-attractors/","title":"Strange Attractors","order":450,"description":"Strange attractors on the GPU","thumbnailPath":"static/strange-attractors-thumbnail.jpg"},{"id":"schwarzschild-spacetime","path":"../schwarzschild-spacetime/","title":"Schwarzschild Trajectories","order":350,"description":"Integrating particle geodesics in Schwarzschild spacetime (a black hole).","thumbnailPath":"static/schwarzschild-spacetime-thumbnail.jpg"},{"id":"random-polynomial-roots","path":"../random-polynomial-roots/","title":"Polynomial Roots","order":300,"description":"Roots of a polynomial with random coefficients, plotted in the complex plane","thumbnailPath":"static/random-polynomial-roots-thumbnail.jpg"},{"id":"umbilic-torus","path":"../umbilic-torus/","title":"Umbilic Torus","order":300,"description":"Umbilic Torus","thumbnailPath":"static/umbilic-torus-thumbnail.jpg"},{"id":"lamb-wave-dispersion","path":"../lamb-wave-dispersion/","title":"Lamb Wave Dispersion Relation","order":220,"description":"Plotting the the complex dispersion relation for elastodynamic plate waves; zeros represent valid modes","thumbnailPath":"static/lamb-wave-dispersion-thumbnail.jpg"},{"id":"fluid-simulation","path":"../fluid-simulation/","title":"Fluid Simluation","order":210,"description":"Classic semi-Lagrangian fluid simulation from Visual Simulation of Smoke","thumbnailPath":"static/fluid-simulation-thumbnail.jpg"},{"id":"erosion","path":"../erosion/","title":"Erosion","order":100,"description":"An ad-hoc particle-based terrain erosion algorithm, computed on the GPU","thumbnailPath":"static/erosion-thumbnail.jpg"},{"id":"centripetal-b-splines","path":"../centripetal-b-splines/","title":"Centripetal B-Splines","order":80,"description":"Experimenting with centripetal parameterization for B-splines","thumbnailPath":"static/centripetal-b-splines-thumbnail.png"},{"id":"smooth-life","path":"../smooth-life/","title":"Smooth Life","order":80,"description":"Conway's Game of Life, generalized to a continuum and solved on the GPU","thumbnailPath":"static/smooth-life-thumbnail.jpg"},{"id":"logistic-map","path":"../logistic-map/","title":"Logistic Map","order":20,"description":"The chaotic logistic map, computed and displayed on the GPU","thumbnailPath":"static/logistic-map-thumbnail.jpg"},{"id":"nose-hoover-attractor","path":"../nose-hoover-attractor/","title":"Nosé-Hoover Attractor","order":8,"description":"Plotting a strange attractor with 2D rectangles","thumbnailPath":"static/nose-hoover-attractor-thumbnail.jpg"},{"id":"vortex-sdf","path":"../vortex-sdf/","title":"Vortex","order":7,"description":"A vortex, rendered as a single signed distance function","thumbnailPath":"static/vortex-sdf-thumbnail.jpg"},{"id":"k-means","path":"../k-means/","title":"K-means clustering","order":5,"description":"WIP refactoring of the kmpp npm module","thumbnailPath":"static/k-means-thumbnail.jpg"},{"id":"double-pendulum","path":"../double-pendulum/","title":"Double Pendulum","order":3,"description":"Accumulating long-term patterns in a chaotic double-pendulum","thumbnailPath":"static/double-pendulum-thumbnail.jpg"}] \ No newline at end of file diff --git a/src/src/sketches/static/lawsons-klein-bottle-thumbnail.jpg b/src/src/sketches/static/lawsons-klein-bottle-thumbnail.jpg new file mode 100644 index 0000000..f42f215 Binary files /dev/null and b/src/src/sketches/static/lawsons-klein-bottle-thumbnail.jpg differ