用HTML实现拓扑面,动态4D圆环面,可手动调节,富有创新性的案例。(有源代码)

文章目录

  • 前言
  • 一、示例
  • 二、目录结构
  • 三、index.html(主页面)
  • 四、main.js
  • 五、Tour4D.js
  • 六、swissgl.js
  • 七、dat.gui.min.js
  • 八、style.css


前言

如果你觉得对代码进行复制粘贴很麻烦的话,你可以直接将资源下载到本地。无需部署,直接可以运行。

一、示例

在这里插入图片描述

二、目录结构

在这里插入图片描述

三、index.html(主页面)

<!DOCTYPE html>
<title>WanderTp</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/style.css"><script src='swissgl.js'></script>
<script src='audio.js'></script>
<script src="dat.gui.min.js"> </script><script src='js/Torus4d.js'></script>
<script src='js/main.js'></script><div id="demo"><canvas id="c" width="640" height="360"></canvas></div>
<script>'use strict';const app = new DemoApp([Torus4d,]);</script>

四、main.js

'use strict';const $ = s=>document.querySelector(s);
const setDisplay = (el, val)=>{if ($(el)) $(el).style.display = val};class DemoApp {constructor(demos, defaultDemo='ParticleLife3d') {this.singleMode = demos.length == 1;if (this.singleMode) {defaultDemo = demos[0].name;}this.demos = Object.fromEntries(demos.map(c=>[c.name, c]));this.canvas = document.getElementById('c');const gl = this.canvas.getContext('webgl2', {alpha:false, antialias:true,xrCompatible:true});this.glsl = SwissGL(gl);this.demo = null;this.gui = null;this.xrDemos =  Object.values(this.demos).filter(f=>f.Tags&&f.Tags.includes('3d'));this.xrSession = null;this.xrRefSpace = null;this.xrPose = null;this.lookUpStartTime = 0;this.haveVR = this.haveAR = false;if (navigator.xr) {navigator.xr.isSessionSupported('immersive-vr').then(supported=>{this.haveVR = supported;this.updateVRButtons();})navigator.xr.isSessionSupported('immersive-ar').then(supported=>{this.haveAR = supported;this.updateVRButtons();})}this.viewParams = {DPR: window.devicePixelRatio,canvasSize: new Float32Array(2),pointer: new Float32Array(3),cameraYPD: new Float32Array(3),xrRay: new Float32Array(16*2),xrRayInv: new Float32Array(16*2),xrButton: new Float32Array(4*2),};this.resetCamera();this.glsl_include = `uniform bool xrMode;uniform mat4 xrProjectionMatrix, xrViewMatrix;uniform mat4 xrRay[2], xrRayInv[2];uniform vec4 xrButton[2];uniform vec3 xrPosition;uniform vec3 cameraYPD;vec3 cameraPos() {if (xrMode) return xrPosition;vec3 p = vec3(0, 0, cameraYPD.z);p.yz *= rot2(-cameraYPD.y);p.xy *= rot2(-cameraYPD.x);return p;}vec4 wld2view(vec4 p) {if (xrMode) return xrViewMatrix * p;p.xy *= rot2(cameraYPD.x);p.yz *= rot2(cameraYPD.y);p.z -= cameraYPD.z;return p;}vec4 view2proj(vec4 p) {if (xrMode) return xrProjectionMatrix*p;const float near = 0.1, far = 10.0, fov = 1.0;return vec4(p.xy/tan(fov/2.0),(p.z*(near+far)+2.0*near*far)/(near-far), -p.z);}vec4 wld2proj(vec4 p) {return view2proj(wld2view(p));}vec4 wld2proj(vec3 p) {return wld2proj(vec4(p,1.0));}`;const glsl = this.glsl;this.withCamera = (params, target)=>{params = {...params, Inc:[this.glsl_include].concat(params.Inc||[])};if (target || !params.xrMode) {return glsl(params, target);}delete params.Aspect;let glLayer = this.xrSession.renderState.baseLayer;target = {bindTarget:(gl)=>{gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);return [glLayer.framebufferWidth, glLayer.framebufferHeight];}}for (let view of this.xrPose.views) {const vp = glLayer.getViewport(view);params.View = [vp.x, vp.y, vp.width, vp.height];params.xrProjectionMatrix = view.projectionMatrix;params.xrViewMatrix = view.transform.inverse.matrix;let {x,y,z} = view.transform.position;params.xrPosition = [x, y, z];glsl(params, target);}};const setPointer = (e, buttons)=>{const [w, h] = this.viewParams.canvasSize;const [x, y] = [e.offsetX-w/2, h/2-e.offsetY];this.viewParams.pointer.set([x, y, buttons]);return [x, y];};this.canvas.addEventListener('pointerdown', e=>{if (!e.isPrimary) return;setPointer(e, e.buttons);});this.canvas.addEventListener('pointerout', e=>setPointer(e, 0));this.canvas.addEventListener('pointerup', e=>setPointer(e, 0));this.canvas.addEventListener('pointermove', e=>{const [px, py, _] = this.viewParams.pointer;const [x, y] = setPointer(e, e.buttons);if (!e.isPrimary || e.buttons != 1) return;let [yaw, pitch, dist] = this.viewParams.cameraYPD;yaw -= (x-px)*0.01;pitch += (y-py)*0.01;pitch = Math.min(Math.max(pitch, 0), Math.PI);this.viewParams.cameraYPD.set([yaw, pitch, dist]);});let name = location.hash.slice(1);if (!(name in this.demos)) {name = defaultDemo;}this.runDemo(name);this.populatePreviews();requestAnimationFrame(this.frame.bind(this));}resetCamera() {this.viewParams.cameraYPD.set([Math.PI*3/4, Math.PI/4, 1.8]);}frame(t) {requestAnimationFrame(this.frame.bind(this));if (this.xrSession) return; // skip canvas frames when XR is runningthis.glsl.adjustCanvas();this.viewParams.canvasSize.set([this.canvas.clientWidth, this.canvas.clientHeight]);this.viewParams.DPR = window.devicePixelRatio;this.demo.frame(this.withCamera, {time:t/1000.0, xrMode: false,...this.viewParams,});}xrFrame(t, xrFrame) {this.xrSession.requestAnimationFrame(this.xrFrame.bind(this));this.xrPose = xrFrame.getViewerPose(this.xrRefSpace);if (!this.xrPose) return;this.viewParams.xrRay.fill(0.0);this.viewParams.xrRayInv.fill(0.0);this.viewParams.xrButton.fill(0.0);const params = {time:t/1000.0, xrMode: true, ...this.viewParams};for (let i=0; i<2; ++i) {const inputSource = this.xrSession.inputSources[i];if (inputSource && inputSource.gamepad && inputSource.gamepad.buttons) {inputSource.gamepad.buttons.forEach((btn, btnIdx)=>{if (btnIdx<4) this.viewParams.xrButton[i*4+btnIdx] = btn.value || btn.pressed;});}if (!inputSource || !inputSource.targetRaySpace) continue;const pose = xrFrame.getPose(inputSource.targetRaySpace, this.xrRefSpace);if (!pose) continue;this.viewParams.xrRay.set(pose.transform.matrix, i*16);this.viewParams.xrRayInv.set(pose.transform.inverse.matrix, i*16);}this.demo.frame(this.withCamera, params);this.withCamera({...params, Mesh: [20,20], Grid:[2], DepthTest:1, VP:`varying vec3 p = uv2sphere(UV);varying vec4 buttons = xrButton[ID.x];VPos = wld2proj(xrRay[ID.x]*vec4(p*vec3(0.02, 0.02, 0.1),1));`, FP:`vec3 c = p*0.5+0.5;FOut = vec4(c*0.5,1);float b = c.z*4.0;if (b<4.0 && buttons[int(b)]>fract(b)) FOut += 0.5;`});const lookUpCoef = -this.xrPose.transform.matrix[10];if (!this.singleMode && (lookUpCoef>0.5)) {const dt = (t-this.lookUpStartTime) / 1000;if (dt > 1) {this.lookUpStartTime = t;let i = this.xrDemos.indexOf(this.demo.constructor);i = (i+1)%this.xrDemos.length;this.runDemo(this.xrDemos[i].name);} else {this.withCamera({...params, Mesh: [20,20], dt, DepthTest:1, VP:`vec3 p = uv2sphere(UV)*0.6*clamp(1.0-dt, 0.0, 0.8) + vec3(-2.0, 0.0, 3.0);VPos = wld2proj(vec4(p,1));`, FP:`UV,0.5,1`});}} else {this.lookUpStartTime = t;}}toggleXR(xr) {if (!this.xrSession) {navigator.xr.requestSession(`immersive-${xr}`).then(session=>{this.xrSession = session;session.addEventListener('end', ()=>{this.xrSession = null;});session.updateRenderState({ baseLayer: new XRWebGLLayer(session, this.glsl.gl) });session.requestReferenceSpace('local').then((refSpace) => {this.xrRefSpace = refSpace.getOffsetReferenceSpace(new XRRigidTransform({x:0,y:-0.25,z:-1.0,w:1},   // position offset{x:0.5,y:0.5,z:0.5,w:-0.5}) // rotate z up);session.requestAnimationFrame(this.xrFrame.bind(this));});});} else {this.xrSession.end();}}runDemo(name) {if (this.demo) {if (this.gui) this.gui.destroy();if (this.demo.free) this.demo.free();this.glsl.reset();this.demo = this.gui = null;}if (!this.singleMode) location.hash = name;if (self.dat) {this.gui = new dat.GUI();this.gui.domElement.id = 'gui'this.gui.hide();}this.demo = new this.demos[name](this.withCamera, this.gui);if (this.gui && (this.gui.__controllers.length == 0)) {this.gui.destroy();this.gui = null;}setDisplay('#settingButton', this.gui?'block':'none');if ($('#sourceLink')) {$('#sourceLink').href = `https://github.com/google/swissgl/blob/main/demo/${name}.js`;}this.updateVRButtons();this.resetCamera();}updateVRButtons() {setDisplay('#vrButton', 'none');setDisplay('#arButton', 'none');const tags = this.demo && this.demo.constructor.Tags;if (tags && tags.includes('3d')) {if (this.haveVR ) setDisplay('#vrButton', 'block');if (this.haveAR ) setDisplay('#arButton', 'block');}}populatePreviews() {const panel = document.getElementById('cards');if (!panel) return;Object.keys(this.demos).forEach(name=>{const el = document.createElement('div');el.classList.add('card');el.innerHTML = `<img src="demo/preview/${name}.jpg">${name}`;el.addEventListener('click', ()=>this.runDemo(name));panel.appendChild(el);});}// helper function to render demo preview imagesgenPreviews() {const panel = document.getElementById('cards');panel.innerHTML = '';const canvas = document.createElement('canvas');canvas.width = 400; canvas.height = 300;const glsl = SwissGL(canvas);const withCamera = (params, target)=>glsl({...params, Inc:[this.glsl_include].concat(params.Inc||[])}, target);Object.keys(this.demos).forEach(name=>{if (name == 'Spectrogram') return;const dummyGui = new dat.GUI();const demo = new this.demos[name](withCamera, dummyGui);dummyGui.destroy();this.resetCamera();for (let i=0; i<60*5; ++i) {withCamera({Clear:0}, '')demo.frame(withCamera, {time:i/60.0, ...this.viewParams});}const el = document.createElement('div')const data = canvas.toDataURL('image/jpeg', 0.95);el.innerHTML = `<a href="${data}" download="${name}.jpg"><img src="${data}"></a>${name}`;panel.appendChild(el)if (demo.free) demo.free();glsl.reset();})}toggleGui() {if (!this.gui) return;const style = this.gui.domElement.style;style.display = (style.display == 'none')?'':'none'}fullscreen() {const {canvas} = this;const f = canvas.requestFullscreen || canvas.webkitRequestFullscreen;if (f) f.apply(canvas);}}

五、Tour4D.js

/** @license * Copyright 2023 Google LLC.* SPDX-License-Identifier: Apache-2.0 */
class Torus4d {static Tags = ['3d'];frame(glsl, params) {glsl({...params, Mesh:[100,100], Aspect:'fit', AlphaCoverage:1, DepthTest:1, VP:`vec4 p = vec4(cos(XY*PI), sin(XY*PI))*0.6;p.xw *= rot2(time*0.4);VPos = wld2proj(vec4(p.xyz/(1.0-p.w)*0.5, 1));`, FP:`vec2 v = UV*rot2(PI/4.)*64.0/sqrt(2.);v = smoothstep(0.0, 1.0, (abs(v-round(v))-0.02)/fwidth(v));float a = 1.0-v.x*v.y;if (a<0.1) discard;FOut = vec4(gl_FrontFacing?vec3(.9,.9,.6):vec3(.6,.6,.9), a);`});}
}

六、swissgl.js

// Copyright 2023 Google LLC// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at//     https://www.apache.org/licenses/LICENSE-2.0// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.// Repeat/Loop?
// fbo:
// - multiple named render targets (Out...?)
// - stencil?
// - mipmaps?
// data texture subimage?
// integer textures
// glsl lib
// - hash (overloads)
// - 3d prim/helpers
// - universal geom (mesh)
// devicePixelRatio
// depth test modes// pain points:
// - view transform params
// - fragment only aspect
// - tag already exists
// - texture/array uniform compatibilityconst Type2Setter = {};
const UniformType2TexTarget = {};
const TextureFormats = {}; {const GL = WebGL2RenderingContext;for (const t of ['FLOAT', 'INT', 'BOOL']) {const suf = t == 'FLOAT' ? 'f' : 'i';Type2Setter[GL[t]] = 'uniform1' + suf;for (const i of [2, 3, 4]) {Type2Setter[GL[`${t}_VEC${i}`]] = `uniform${i}${suf}v`;if (suf == 'f') {Type2Setter[GL[`${t}_MAT${i}`]] = `uniformMatrix${i}fv`;}}}UniformType2TexTarget[GL.SAMPLER_2D] = GL.TEXTURE_2D;UniformType2TexTarget[GL.SAMPLER_2D_ARRAY] = GL.TEXTURE_2D_ARRAY;for (const [name, internalFormat, glformat, type, CpuArray, chn] of [['r8', GL.R8, GL.RED, GL.UNSIGNED_BYTE, Uint8Array, 1],['rgba8', GL.RGBA8, GL.RGBA, GL.UNSIGNED_BYTE, Uint8Array, 4],['r16f', GL.R16F, GL.RED, GL.HALF_FLOAT, Uint16Array, 1],['rgba16f', GL.RGBA16F, GL.RGBA, GL.HALF_FLOAT, Uint16Array, 4],['r32f', GL.R32F, GL.RED, GL.FLOAT, Float32Array, 1],['rg32f', GL.RG32F, GL.RG, GL.FLOAT, Float32Array, 2],['rgba32f', GL.RGBA32F, GL.RGBA, GL.FLOAT, Float32Array, 4],['depth', GL.DEPTH_COMPONENT24, GL.DEPTH_COMPONENT, GL.UNSIGNED_INT, Uint32Array, 1],]) TextureFormats[name] = {internalFormat,glformat,type,CpuArray,chn};
}function memoize(f) {const cache = {};const wrap = k => k in cache ? cache[k] : cache[k] = f(k);wrap.cache = cache;return wrap;
}function updateObject(o, updates) {for (const s in updates) {o[s] = updates[s];}return o;
}// Parse strings like 'min(s,d)', 'max(s,d)', 's*d', 's+d*(1-sa)',
// 's*d', 'd*(1-sa) + s*sa', s-d', 'd-s' and so on into
// gl.blendFunc/gl.blendEquation arguments.
function parseBlend(s0) {if (!s0) return;let s = s0.replace(/\s+/g, '');if (!s) return null;const GL = WebGL2RenderingContext;const func2gl = {'min': GL.MIN,'max': GL.MAX,'+': GL.FUNC_ADD,'s-d': GL.FUNC_SUBTRACT,'d-s': GL.FUNC_REVERSE_SUBTRACT};const factor2gl = {'0': GL.ZERO,'1': GL.ONE,'s': GL.SRC_COLOR,'(1-s)': GL.ONE_MINUS_SRC_COLOR,'d': GL.DST_COLOR,'(1-d)': GL.ONE_MINUS_DST_COLOR,'sa': GL.SRC_ALPHA,'(1-sa)': GL.ONE_MINUS_SRC_ALPHA,'da': GL.DST_ALPHA,'(1-da)': GL.ONE_MINUS_DST_ALPHA,'c': GL.CONSTANT_COLOR,'(1-c)': GL.ONE_MINUS_CONSTANT_COLOR,'ca': GL.CONSTANT_ALPHA,'(1-ca)': GL.ONE_MINUS_CONSTANT_ALPHA,};const res = {s: GL.ZERO,d: GL.ZERO,f: null};s = s.replace(/(s|d)(?:\*(\w+|\(1-\w+\)))?/g, (_, term, factor) => {factor = factor || '1';if (!(factor in factor2gl)) {throw `Unknown blend factor: "${factor}"`;}res[term] = factor2gl[factor];return term;});let m;if (m = s.match(/^(min|max)\((s,d|d,s)\)$/)) {res.f = func2gl[m[1]];} else if (s.match(/^(s|d|s\+d|d\+s)$/)) {res.f = func2gl['+'];} else if (s in func2gl) {res.f = func2gl[s];} else {throw `Unable to parse blend spec: "${s0}"`;}return res;
}
parseBlend = memoize(parseBlend);function compileShader(gl, code, type, program) {code = '#version 300 es\n' + code;const shader = gl.createShader(type);gl.shaderSource(shader, code);gl.compileShader(shader);if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {const withLines = code.split('\n').map((s, i) => `${(i+1+'').padStart(4)}: ${s}`).join('\n')throw (withLines + '\n' + '--- GLSL COMPILE ERROR ---\n' + gl.getShaderInfoLog(shader));}gl.attachShader(program, shader);gl.deleteShader(shader);
}function compileProgram(gl, vs, fs) {const program = gl.createProgram();compileShader(gl, vs, gl.VERTEX_SHADER, program);compileShader(gl, fs, gl.FRAGMENT_SHADER, program);gl.linkProgram(program);if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {console.error("shader link error:" + gl.getProgramInfoLog(program));}gl.useProgram(program);program.setters = {};let unitCount = 0;const numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);for (let i = 0; i < numUniforms; ++i) {const info = gl.getActiveUniform(program, i);const loc = gl.getUniformLocation(program, info.name);const name = info.name.match(/^\w+/)[0];if (info.type in UniformType2TexTarget) {const unit = unitCount++;const target = UniformType2TexTarget[info.type];gl.uniform1i(loc, unit);program.setters[name] = tex => {gl.activeTexture(gl.TEXTURE0 + unit);tex ? tex.bindSampler(unit) : gl.bindTexture(target, null);}} else {const fname = Type2Setter[info.type];const setter = fname.startsWith('uniformMatrix') ?v => gl[fname](loc, false, v) : v => gl[fname](loc, v);program.setters[name] = v => v != undefined ? setter(v) : null;}}gl.useProgram(null);console.log('created', program);return program;
}const glsl_template = `
precision highp float;
precision highp int;
precision lowp sampler2DArray;
#ifdef VERT#define varying out#define VPos gl_Positionlayout(location = 0) in int VertexID;layout(location = 1) in int InstanceID;ivec2 VID;ivec3 ID;
#else#define varying inlayout(location = 0) out vec4 FOut;layout(location = 1) out vec4 FOut1;layout(location = 2) out vec4 FOut2;layout(location = 3) out vec4 FOut3;layout(location = 4) out vec4 FOut4;layout(location = 5) out vec4 FOut5;layout(location = 6) out vec4 FOut6;layout(location = 7) out vec4 FOut7;ivec2 I;
#endifuniform ivec3 Grid;
uniform ivec2 Mesh;
uniform ivec4 View;
#define ViewSize (View.zw)
uniform vec2 Aspect;
varying vec2 UV;
#define XY (2.0*UV-1.0)
// #define VertexID gl_VertexID
// #define InstanceID gl_InstanceIDGLSL Utils const float PI  = radians(180.0);
const float TAU = radians(360.0);// source: https://www.shadertoy.com/view/XlXcW4
// TODO more complete hash library
vec3 hash( ivec3 ix ) {uvec3 x = uvec3(ix);const uint k = 1103515245U;x = ((x>>8U)^x.yzx)*k;x = ((x>>8U)^x.yzx)*k;x = ((x>>8U)^x.yzx)*k;return vec3(x)*(1.0/float(0xffffffffU));
}mat2 rot2(float a) {float s=sin(a), c=cos(a);return mat2(c, s, -s, c);
}// https://suricrasia.online/demoscene/functions/
vec3 erot(vec3 p, vec3 ax, float ro) {return mix(dot(ax, p)*ax, p, cos(ro)) + cross(ax,p)*sin(ro);
}vec3 uv2sphere(vec2 uv) {uv *= vec2(-TAU,PI);return vec3(vec2(cos(uv.x), sin(uv.x))*sin(uv.y), cos(uv.y));
}vec3 torus(vec2 uv, float r1, float r2) {uv *= TAU;vec3 p = vec3(r1+cos(uv.x)*r2, 0, sin(uv.x)*r2);return vec3(p.xy * rot2(uv.y), p.z);
}vec3 cubeVert(vec2 xy, int side) {float x=xy.x, y=xy.y;switch (side) {case 0: return vec3(x,y,1); case 1: return vec3(y,x,-1);case 2: return vec3(y,1,x); case 3: return vec3(x,-1,y);case 4: return vec3(1,x,y); case 5: return vec3(-1,y,x);};return vec3(0.0);
}vec3 _surf_f(vec3 p, vec3 a, vec3 b, out vec3 normal) {normal = normalize(cross(a-p, b-p));return p;
}
#define SURF(f, uv, out_normal, eps) _surf_f(f(uv), f(uv+vec2(eps,0)), f(uv+vec2(0,eps)), out_normal)vec4 _sample(sampler2D tex, vec2 uv) {return texture(tex, uv);}
vec4 _sample(sampler2D tex, ivec2 xy) {return texelFetch(tex, xy, 0);}
vec4 _sample(sampler2DArray tex, vec2 uv, int layer) {return texture(tex, vec3(uv, layer));}
vec4 _sample(sampler2DArray tex, ivec2 xy, int layer) {return texelFetch(tex, ivec3(xy, layer), 0);}#ifdef FRAGfloat isoline(float v) {float distToInt = abs(v-round(v));return smoothstep(max(fwidth(v), 0.0001), 0.0, distToInt);}float wireframe() {vec2 m = UV*vec2(Mesh);float d1 = isoline(m.x-m.y), d2 = isoline(m.x+m.y);float d = mix(d1, d2, float(int(m.y)%2));return isoline(m.x)+isoline(m.y)+d;}
#endif
`;function guessUniforms(params) {const uni = [];const len2type = {1: 'float',2: 'vec2',3: 'vec3',4: 'vec4',9: 'mat3',16: 'mat4'};for (const name in params) {const v = params[name];let s = null;if (v instanceof TextureSampler) {const [type, D] = v.layern ? ['sampler2DArray', '3'] : ['sampler2D', '2'];const lookupMacro = v.layern ?`#define ${name}(p,l) (_sample(${name}, (p), (l)))` :`#define ${name}(p) (_sample(${name}, (p)))`;s = `uniform ${type} ${name};${lookupMacro}ivec${D} ${name}_size() {return textureSize(${name}, 0);}vec${D}  ${name}_step() {return 1.0/vec${D}(${name}_size());}`;} else if (typeof v === 'number') {s = `uniform float ${name};`} else if (typeof v === 'boolean') {s = `uniform bool ${name};`} else if (v.length in len2type) {s = `uniform ${len2type[v.length]} ${name};`}if (s) uni.push(s);}return uni.join('\n') + '\n';
}const stripComments = code => code.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');// TODO better parser (use '\b')
function definedUniforms(code) {code = stripComments(code);const lines = Array.from(code.matchAll(/uniform\s+\w+\s+([^;]+)\s*;/g));return new Set(lines.map(m => m[1].split(/[^\w]+/)).flat());
}function expandCode(code, mainFunc, outVar) {const stripped = stripComments(code).trim();if (stripped != '' && stripped.indexOf(';') == -1) {code = `${outVar} = vec4(${stripped});`}if (!stripped.match(new RegExp(`\\b${mainFunc}\s*\\(`))) {code = `void ${mainFunc}() {${code};}`}return code;
}
const expandVP = memoize(code => expandCode(code, 'vertex', 'VPos'));
const expandFP = memoize(code => expandCode(code, 'fragment', 'FOut'));function extractVaryings(VP) {return Array.from(stripComments(VP).matchAll(/\bvarying\s+[^;]+;/g)).map(m => m[0]).map(s => {while (s != (s = s.replace(/\([^()]*\)/g, ''))); // remove nested ()return s.replace(/=[^,;]*/g, '') // remove assigned values }).join('\n');
}function stripVaryings(VP) {return VP.replace(/\bvarying\s+\w+/g, '');
}function linkShader(gl, uniforms, Inc, VP, FP) {Inc = Inc.join('\n');const defined = definedUniforms([glsl_template, Inc, VP, FP].join('\n'));const undefined = Object.entries(uniforms).filter(kv => kv[0].match(/^\w+$/)).filter(kv => !(defined.has(kv[0])));const guessed = guessUniforms(Object.fromEntries(undefined));const varyings = extractVaryings(VP);VP = expandVP(stripVaryings(VP));const prefix = `${glsl_template}\n${guessed}\n${varyings}\n${Inc}\n`;return compileProgram(gl, `#define VERT${prefix}\n${VP}void main() {int rowVertN = Mesh.x*2+3;int rowI = VertexID/rowVertN;int rowVertI = min(VertexID%rowVertN, rowVertN-2);int odd = rowI%2;if (odd==0) rowVertI = rowVertN-rowVertI-2;VID = ivec2(rowVertI>>1, rowI + (rowVertI+odd+1)%2);int ii = InstanceID;ID.x = ii % Grid.x; ii/=Grid.x;ID.y = ii % Grid.y; ii/=Grid.y;ID.z = ii;UV = vec2(VID) / vec2(Mesh);VPos = vec4(XY,0,1);vertex();VPos.xy *= Aspect;}`, `#define FRAG${prefix}\n${expandFP(FP)}void main() {I = ivec2(gl_FragCoord.xy);fragment();}`);
}class TextureSampler {fork(updates) {const {gl,handle,gltarget,layern,filter,wrap} = {...this,...updates};return updateObject(new TextureSampler(), {gl,handle,gltarget,layern,filter,wrap});}get linear() {return this.fork({filter: 'linear'})}get nearest() {return this.fork({filter: 'nearest'})}get miplinear() {return this.fork({filter: 'miplinear'})}get edge() {return this.fork({wrap: 'edge'})}get repeat() {return this.fork({wrap: 'repeat'})}get mirror() {return this.fork({wrap: 'mirror'})}get _sampler() {const {gl,filter,wrap} = this;if (!gl._samplers) {gl._samplers = {};}const id = `${filter}:${wrap}`;if (!(id in gl._samplers)) {const glfilter = {'nearest': gl.NEAREST,'linear': gl.LINEAR,'miplinear': gl.LINEAR_MIPMAP_LINEAR} [filter];const glwrap = {'repeat': gl.REPEAT,'edge': gl.CLAMP_TO_EDGE,'mirror': gl.MIRRORED_REPEAT} [wrap];const sampler = gl.createSampler();const setf = (k, v) => gl.samplerParameteri(sampler, gl['TEXTURE_' + k], v);setf('MIN_FILTER', glfilter);setf('MAG_FILTER', filter == 'miplinear' ? gl.LINEAR : glfilter);setf('WRAP_S', glwrap);setf('WRAP_T', glwrap);gl._samplers[id] = sampler;}return gl._samplers[id];}bindSampler(unit) {// assume unit is already activeconst {gl,gltarget,handle} = this;gl.bindTexture(gltarget, handle);if (this.filter == 'miplinear' && !handle.hasMipmap) {gl.generateMipmap(gltarget)handle.hasMipmap = true;}gl.bindSampler(unit, this._sampler);}
}class TextureTarget extends TextureSampler {constructor(gl, params) {super();let {size,tag,format = 'rgba8',filter = 'nearest',wrap = 'repeat',layern = null,data = null,depth = null} = params;if (!depth && format.includes('+')) {const [mainFormat, depthFormat] = format.split('+');format = mainFormat;depth = new TextureTarget(gl, {...params,tag: tag + '_depth',format: depthFormat,layern: null,depth: null});}this.handle = gl.createTexture(),this.filter = format == 'depth' ? 'nearest' : filter;this.gltarget = layern ? gl.TEXTURE_2D_ARRAY : gl.TEXTURE_2D;this.formatInfo = TextureFormats[format];updateObject(this, {gl,_tag: tag,format,layern,wrap,depth});this.update(size, data);}update(size, data) {const {gl,handle,gltarget,layern} = this;const {internalFormat,glformat,type} = this.formatInfo;const [w, h] = size;gl.bindTexture(gltarget, handle);if (!layern) {gl.texImage2D(gltarget, 0 /*mip level*/ ,internalFormat, w, h, 0 /*border*/ ,glformat, type, data /*data*/ );} else {gl.texImage3D(gltarget, 0 /*mip level*/ ,internalFormat, w, h, layern, 0 /*border*/ ,glformat, type, data /*data*/ );}gl.bindTexture(gltarget, null);this.size = size;if (this.depth) {this.depth.update(size, data);}}attach(gl) {if (!this.layern) {const attachment = this.format == 'depth' ? gl.DEPTH_ATTACHMENT : gl.COLOR_ATTACHMENT0;gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, this.handle, 0 /*level*/ );} else {const drawBuffers = [];for (let i = 0; i < this.layern; ++i) {const attachment = gl.COLOR_ATTACHMENT0 + i;drawBuffers.push(attachment);gl.framebufferTextureLayer(gl.FRAMEBUFFER, attachment, this.handle, 0 /*level*/ , i);}gl.drawBuffers(drawBuffers);}}bindTarget(gl, readonly = false) {if (this.fbo) {gl.bindFramebuffer(gl.FRAMEBUFFER, this.fbo);} else {this.fbo = gl.createFramebuffer();gl.bindFramebuffer(gl.FRAMEBUFFER, this.fbo);this.attach(gl)if (this.depth) this.depth.attach(gl);}if (!readonly) {this.handle.hasMipmap = false;}return this.size;}_getBox(box) {box = (box && box.length) ? box : [0, 0, ...this.size];const [x, y, w, h] = box, n = w * h * this.formatInfo.chn;return {box,n}}_getCPUBuf(n) {if (!this.cpu || this.cpu.length < n) {this.cpu = new this.formatInfo.CpuArray(n);}return this.cpu.length == n ? this.cpu : this.cpu.subarray(0, n);}_readPixels(box, targetBuf) {const {glformat,type} = this.formatInfo;this.bindTarget(this.gl, /*readonly*/ true);this.gl.readPixels(...box, glformat, type, targetBuf);}readSync(...optBox) {const {box,n} = this._getBox(optBox);const buf = this._getCPUBuf(n);this._readPixels(box, buf);return buf}_bindAsyncBuffer(n) {const {gl} = this;const {CpuArray} = this.formatInfo;if (!this.async) {this.async = {all: new Set(),queue: []};}if (this.async.queue.length == 0) {const gpuBuf = gl.createBuffer();this.async.queue.push(gpuBuf);this.async.all.add(gpuBuf);}const gpuBuf = this.async.queue.shift();if (this.async.queue.length > 6) {this._deleteAsyncBuf(this.async.queue.pop());}gl.bindBuffer(gl.PIXEL_PACK_BUFFER, gpuBuf);if (!gpuBuf.length || gpuBuf.length < n) {const byteN = n * this.formatInfo.CpuArray.BYTES_PER_ELEMENTgl.bufferData(gl.PIXEL_PACK_BUFFER, byteN, gl.STREAM_READ);gpuBuf.length = n;console.log(`created/resized async gpu buffer "${this._tag}":`, gpuBuf);}return gpuBuf;}_deleteAsyncBuf(gpuBuf) {delete gpuBuf.length;this.gl.deleteBuffer(gpuBuf);this.async.all.delete(gpuBuf);}// https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#use_non-blocking_async_data_readbackread(callback, optBox, optTarget) {const {gl} = this;const {box,n} = this._getBox(optBox);const gpuBuf = this._bindAsyncBuffer(n);this._readPixels(box, 0);gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);gl.flush();this._asyncFetch(gpuBuf, sync, callback, optTarget);}_asyncFetch(gpuBuf, sync, callback, optTarget) {const {gl} = this;if (!gpuBuf.length) { // check that gpu buffer is not deletedgl.deleteSync(sync);return;}const res = gl.clientWaitSync(sync, 0, 0);if (res === gl.TIMEOUT_EXPIRED) {setTimeout(() => this._asyncFetch(gpuBuf, sync, callback, optTarget), 1 /*ms*/ );return;}if (res === gl.WAIT_FAILED) {console.log(`async read of ${this._tag} failed`);} else {gl.bindBuffer(gl.PIXEL_PACK_BUFFER, gpuBuf);const target = optTarget || this._getCPUBuf(gpuBuf.length);gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0 /*srcOffset*/ ,target, 0 /*dstOffset*/ , gpuBuf.length /*length*/ );gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);callback(target);}gl.deleteSync(sync);this.async.queue.push(gpuBuf);}free() {const gl = this.gl;if (this.depth) this.depth.free();if (this.fbo) gl.deleteFramebuffer(this.fbo);if (this.async) this.async.all.forEach(buf => this._deleteAsyncBuf(buf));gl.deleteTexture(this.handle);}
}function calcAspect(aspect, w, h) {if (!aspect) return [1, 1];let c;switch (aspect) {case 'fit':c = Math.min(w, h);break;case 'cover':c = Math.max(w, h);break;case 'x':c = w;break;case 'y':c = h;break;case 'mean':c = (w + h) / 2;break;default:throw `Unknown aspect mode "${aspect}"`;}return [c / w, c / h];
}function ensureVertexArray(gl, neededSize) {// gl_VertexID / gl_InstanceID seem to be broken in some configurations// (e.g. https://crbug.com/1315104), so I had to fallback to using arraysif (gl._indexVA && neededSize <= gl._indexVA.size)return;const size = neededSize * 2;const va = gl._indexVA || gl.createVertexArray();va.size = size;gl._indexVA = va;gl.bindVertexArray(va);const arr = new Int32Array(size);arr.forEach((v, i) => {arr[i] = i});const buf = va.buf || gl.createBuffer();va.buf = buf;gl.bindBuffer(gl.ARRAY_BUFFER, buf);gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW);for (let loc = 0; loc < 2; ++loc) {gl.enableVertexAttribArray(loc);gl.vertexAttribIPointer(loc, 1 /*size*/ , gl.INT,false /*normalize*/ , 0 /*stride*/ , 0 /*offset*/ );}gl.vertexAttribDivisor(1, 1);gl.bindBuffer(gl.ARRAY_BUFFER, null);gl.bindVertexArray(null);console.log('created:', va);
}function getTargetSize(gl, {size,scale = 1,data
}) {if (!size && (data && data.videoWidth && data.videoHeight)) {size = [data.videoWidth, data.videoHeight];}size = size || [gl.canvas.width, gl.canvas.height];return [Math.ceil(size[0] * scale), Math.ceil(size[1] * scale)];
}function createTarget(gl, params) {if (!params.story) return new TextureTarget(gl, params);return Array(params.story).fill(0).map(_ => new TextureTarget(gl, params));
}function prepareOwnTarget(self, spec) {const buffers = self.buffers;spec.size = getTargetSize(self.gl, spec);if (!buffers[spec.tag]) {const target = buffers[spec.tag] = createTarget(self.gl, spec);console.log('created', target);}const target = buffers[spec.tag];const tex = Array.isArray(target) ? target[target.length - 1] : target;const needResize = tex.size[0] != spec.size[0] || tex.size[1] != spec.size[1];if (needResize || spec.data) {if (needResize) {console.log(`resizing "${spec.tag}" (${tex.size})->(${spec.size})`);}tex.update(spec.size, spec.data);}if (Array.isArray(target)) {target.size = spec.size;}return buffers[spec.tag];
}function bindTarget(gl, target) {if (!target) {gl.bindFramebuffer(gl.FRAMEBUFFER, null);return [gl.canvas.width, gl.canvas.height];}if (Array.isArray(target)) {const next = target.pop();if (target.size[0] != next.size[0] || target.size[1] != next.size[1]) {next.update(target.size, null);}target.unshift(next);target = next;}return target.bindTarget(gl)
}const OptNames = new Set(['Inc', 'VP', 'FP','Clear', 'Blend', 'View', 'Grid', 'Mesh', 'Aspect', 'DepthTest', 'AlphaCoverage', 'Face'
]);function drawQuads(self, params, target) {const options = {},uniforms = {}for (const p in params) {(OptNames.has(p) ? options : uniforms)[p] = params[p];}let Inc = options.Inc || [];if (!Array.isArray(Inc)) {Inc = [Inc];}const [VP, FP] = [options.VP || '', options.FP || ''];const haveShader = VP || FP;const haveClear = options.Clear || options.Clear == 0;// setup targetif (target && target.tag) {target = prepareOwnTarget(self, target);if (!haveShader && !haveClear) return target;}if (Array.isArray(target)) {uniforms.Src = uniforms.Src || target[0];}// bind (and clear) targetconst gl = self.gl;const targetSize = bindTarget(gl, target);let view = options.View || [0, 0, targetSize[0], targetSize[1]];if (view.length == 2) {view = [0, 0, view[0], view[1]]}gl.depthMask(!(options.DepthTest == 'keep'));if (haveClear) {let clear = options.Clear;if (typeof clear === 'number') {clear = [clear, clear, clear, clear];}gl.clearColor(...clear);gl.enable(gl.SCISSOR_TEST);gl.scissor(...view);gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);gl.disable(gl.SCISSOR_TEST);}// setup programif (!haveShader) {return target;}let prog = self.shaders;for (const chunk of Inc) {prog = prog[chunk] || (prog[chunk] = {});}prog = prog[VP] || (prog[VP] = {});prog = prog[FP] || (prog[FP] = linkShader(gl, uniforms, Inc, VP, FP));gl.useProgram(prog);// process optionsif (options.Blend) {const blend = parseBlend(options.Blend);const {s,d,f} = blend;gl.enable(gl.BLEND);gl.blendFunc(s, d);gl.blendEquation(f);}if (options.DepthTest) {gl.enable(gl.DEPTH_TEST);}if (options.Face) {gl.enable(gl.CULL_FACE);const mode = {'front': gl.BACK,'back': gl.FRONT} [options.Face];gl.cullFace(mode);}if (options.AlphaCoverage) {gl.enable(gl.SAMPLE_ALPHA_TO_COVERAGE);}// View, Aspectgl.viewport(...view)const width = view[2],height = view[3];uniforms.View = view;uniforms.Aspect = calcAspect(options.Aspect, width, height);// Grid, Meshconst [gx = 1, gy = 1, gz = 1] = options.Grid || [];uniforms.Grid = [gx, gy, gz];uniforms.Mesh = options.Mesh || [1, 1]; // 3d for cube?const vertN = (uniforms.Mesh[0] * 2 + 3) * uniforms.Mesh[1] - 1;const instN = gx * gy * gz;ensureVertexArray(gl, Math.max(vertN, instN));gl.bindVertexArray(gl._indexVA);// setup uniforms and texturesObject.entries(prog.setters).forEach(([name, f]) => f(uniforms[name]));// drawgl.drawArraysInstanced(gl.TRIANGLE_STRIP, 0, vertN, instN);// revert gl stateif (options.Blend) gl.disable(gl.BLEND);if (options.DepthTest) gl.disable(gl.DEPTH_TEST);if (options.Face) gl.disable(gl.CULL_FACE);if (options.AlphaCoverage) gl.disable(gl.SAMPLE_ALPHA_TO_COVERAGE);gl.bindVertexArray(null);return target;
}function SwissGL(canvas_gl) {const gl = canvas_gl.getContext ?canvas_gl.getContext('webgl2', {alpha: false,antialias: true}) : canvas_gl;gl.getExtension("EXT_color_buffer_float");gl.getExtension("OES_texture_float_linear");gl.pixelStorei(gl.PACK_ALIGNMENT, 1);gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);ensureVertexArray(gl, 1024);const glsl = (params, target) => drawQuads(glsl, params, target);glsl.gl = gl;glsl.shaders = {};glsl.buffers = {};glsl.reset = () => {const freeProg = o => (o instanceof WebGLProgram) ? gl.deleteProgram(o) : Object.values(o).forEach(freeProg);freeProg(glsl.shaders);Object.values(glsl.buffers).flat().forEach(target => target.free());glsl.shaders = {};glsl.buffers = {};};glsl.adjustCanvas = dpr => {dpr = dpr || self.devicePixelRatio;const canvas = gl.canvas;const w = canvas.clientWidth * dpr,h = canvas.clientHeight * dpr;if (canvas.width != w || canvas.height != h) {canvas.width = w;canvas.height = h;}}glsl.loop = callback => {const frameFunc = time => {const res = callback({glsl,time: time / 1000.0});if (res != 'stop') requestAnimationFrame(frameFunc);};requestAnimationFrame(frameFunc);};return glsl;
}self._SwissGL = SwissGL;

七、dat.gui.min.js

/*** dat-gui JavaScript Controller Library* https://github.com/dataarts/dat.gui** Copyright 2011 Data Arts Team, Google Creative Lab** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0*/
! function(e, t) {"object" == typeof exports && "undefined" != typeof module ? t(exports) : "function" == typeof define && define.amd ? define(["exports"], t) : t(e.dat = {})
}(this, function(e) {"use strict";function t(e, t) {var n = e.__state.conversionName.toString(),o = Math.round(e.r),i = Math.round(e.g),r = Math.round(e.b),s = e.a,a = Math.round(e.h),l = e.s.toFixed(1),d = e.v.toFixed(1);if (t || "THREE_CHAR_HEX" === n || "SIX_CHAR_HEX" === n) {for (var c = e.hex.toString(16); c.length < 6;) c = "0" + c;return "#" + c}return "CSS_RGB" === n ? "rgb(" + o + "," + i + "," + r + ")" : "CSS_RGBA" === n ? "rgba(" + o + "," + i +"," + r + "," + s + ")" : "HEX" === n ? "0x" + e.hex.toString(16) : "RGB_ARRAY" === n ? "[" + o + "," +i + "," + r + "]" : "RGBA_ARRAY" === n ? "[" + o + "," + i + "," + r + "," + s + "]" : "RGB_OBJ" === n ?"{r:" + o + ",g:" + i + ",b:" + r + "}" : "RGBA_OBJ" === n ? "{r:" + o + ",g:" + i + ",b:" + r + ",a:" +s + "}" : "HSV_OBJ" === n ? "{h:" + a + ",s:" + l + ",v:" + d + "}" : "HSVA_OBJ" === n ? "{h:" + a +",s:" + l + ",v:" + d + ",a:" + s + "}" : "unknown format"}function n(e, t, n) {Object.defineProperty(e, t, {get: function() {return "RGB" === this.__state.space ? this.__state[t] : (I.recalculateRGB(this, t, n),this.__state[t])},set: function(e) {"RGB" !== this.__state.space && (I.recalculateRGB(this, t, n), this.__state.space ="RGB"), this.__state[t] = e}})}function o(e, t) {Object.defineProperty(e, t, {get: function() {return "HSV" === this.__state.space ? this.__state[t] : (I.recalculateHSV(this), this.__state[t])},set: function(e) {"HSV" !== this.__state.space && (I.recalculateHSV(this), this.__state.space = "HSV"),this.__state[t] = e}})}function i(e) {if ("0" === e || S.isUndefined(e)) return 0;var t = e.match(U);return S.isNull(t) ? 0 : parseFloat(t[1])}function r(e) {var t = e.toString();return t.indexOf(".") > -1 ? t.length - t.indexOf(".") - 1 : 0}function s(e, t) {var n = Math.pow(10, t);return Math.round(e * n) / n}function a(e, t, n, o, i) {return o + (e - t) / (n - t) * (i - o)}function l(e, t, n, o) {e.style.background = "", S.each(ee, function(i) {e.style.cssText += "background: " + i + "linear-gradient(" + t + ", " + n + " 0%, " + o +" 100%); "})}function d(e) {e.style.background = "", e.style.cssText +="background: -moz-linear-gradient(top,  #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);",e.style.cssText +="background: -webkit-linear-gradient(top,  #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText +="background: -o-linear-gradient(top,  #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText +="background: -ms-linear-gradient(top,  #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText +="background: linear-gradient(top,  #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}function c(e, t, n) {var o = document.createElement("li");return t && o.appendChild(t), n ? e.__ul.insertBefore(o, n) : e.__ul.appendChild(o), e.onResize(), o}function u(e) {X.unbind(window, "resize", e.__resizeHandler), e.saveToLocalStorageIfPossible && X.unbind(window, "unload",e.saveToLocalStorageIfPossible)}function _(e, t) {var n = e.__preset_select[e.__preset_select.selectedIndex];n.innerHTML = t ? n.value + "*" : n.value}function h(e, t, n) {if (n.__li = t, n.__gui = e, S.extend(n, {options: function(t) {if (arguments.length > 1) {var o = n.__li.nextElementSibling;return n.remove(), f(e, n.object, n.property, {before: o,factoryArgs: [S.toArray(arguments)]})}if (S.isArray(t) || S.isObject(t)) {var i = n.__li.nextElementSibling;return n.remove(), f(e, n.object, n.property, {before: i,factoryArgs: [t]})}},name: function(e) {return n.__li.firstElementChild.firstElementChild.innerHTML = e, n},listen: function() {return n.__gui.listen(n), n},remove: function() {return n.__gui.remove(n), n}}), n instanceof q) {var o = new Q(n.object, n.property, {min: n.__min,max: n.__max,step: n.__step});S.each(["updateDisplay", "onChange", "onFinishChange", "step", "min", "max"], function(e) {var t = n[e],i = o[e];n[e] = o[e] = function() {var e = Array.prototype.slice.call(arguments);return i.apply(o, e), t.apply(n, e)}}), X.addClass(t, "has-slider"), n.domElement.insertBefore(o.domElement, n.domElement.firstElementChild)} else if (n instanceof Q) {var i = function(t) {if (S.isNumber(n.__min) && S.isNumber(n.__max)) {var o = n.__li.firstElementChild.firstElementChild.innerHTML,i = n.__gui.__listening.indexOf(n) > -1;n.remove();var r = f(e, n.object, n.property, {before: n.__li.nextElementSibling,factoryArgs: [n.__min, n.__max, n.__step]});return r.name(o), i && r.listen(), r}return t};n.min = S.compose(i, n.min), n.max = S.compose(i, n.max)} else n instanceof K ? (X.bind(t, "click", function() {X.fakeEvent(n.__checkbox, "click")}), X.bind(n.__checkbox, "click", function(e) {e.stopPropagation()})) : n instanceof Z ? (X.bind(t, "click", function() {X.fakeEvent(n.__button, "click")}), X.bind(t, "mouseover", function() {X.addClass(n.__button, "hover")}), X.bind(t, "mouseout", function() {X.removeClass(n.__button, "hover")})) : n instanceof $ && (X.addClass(t, "color"), n.updateDisplay = S.compose(function(e) {return t.style.borderLeftColor = n.__color.toString(), e}, n.updateDisplay), n.updateDisplay());n.setValue = S.compose(function(t) {return e.getRoot().__preset_select && n.isModified() && _(e.getRoot(), !0), t}, n.setValue)}function p(e, t) {var n = e.getRoot(),o = n.__rememberedObjects.indexOf(t.object);if (-1 !== o) {var i = n.__rememberedObjectIndecesToControllers[o];if (void 0 === i && (i = {}, n.__rememberedObjectIndecesToControllers[o] = i), i[t.property] = t, n.load && n.load.remembered) {var r = n.load.remembered,s = void 0;if (r[e.preset]) s = r[e.preset];else {if (!r[se]) return;s = r[se]}if (s[o] && void 0 !== s[o][t.property]) {var a = s[o][t.property];t.initialValue = a, t.setValue(a)}}}}function f(e, t, n, o) {if (void 0 === t[n]) throw new Error('Object "' + t + '" has no property "' + n + '"');var i = void 0;if (o.color) i = new $(t, n);else {var r = [t, n].concat(o.factoryArgs);i = ne.apply(e, r)}o.before instanceof z && (o.before = o.before.__li), p(e, i), X.addClass(i.domElement, "c");var s = document.createElement("span");X.addClass(s, "property-name"), s.innerHTML = i.property;var a = document.createElement("div");a.appendChild(s), a.appendChild(i.domElement);var l = c(e, a, o.before);return X.addClass(l, he.CLASS_CONTROLLER_ROW), i instanceof $ ? X.addClass(l, "color") : X.addClass(l, H(i.getValue())), h(e, l, i), e.__controllers.push(i), i}function m(e, t) {return document.location.href + "." + t}function g(e, t, n) {var o = document.createElement("option");o.innerHTML = t, o.value = t, e.__preset_select.appendChild(o), n && (e.__preset_select.selectedIndex = e.__preset_select.length - 1)}function b(e, t) {t.style.display = e.useLocalStorage ? "block" : "none"}function v(e) {var t = e.__save_row = document.createElement("li");X.addClass(e.domElement, "has-save"), e.__ul.insertBefore(t, e.__ul.firstChild), X.addClass(t, "save-row");var n = document.createElement("span");n.innerHTML = "&nbsp;", X.addClass(n, "button gears");var o = document.createElement("span");o.innerHTML = "Save", X.addClass(o, "button"), X.addClass(o, "save");var i = document.createElement("span");i.innerHTML = "New", X.addClass(i, "button"), X.addClass(i, "save-as");var r = document.createElement("span");r.innerHTML = "Revert", X.addClass(r, "button"), X.addClass(r, "revert");var s = e.__preset_select = document.createElement("select");if (e.load && e.load.remembered ? S.each(e.load.remembered, function(t, n) {g(e, n, n === e.preset)}) : g(e, se, !1), X.bind(s, "change", function() {for (var t = 0; t < e.__preset_select.length; t++) e.__preset_select[t].innerHTML = e.__preset_select[t].value;e.preset = this.value}), t.appendChild(s), t.appendChild(n), t.appendChild(o), t.appendChild(i), t.appendChild(r), ae) {var a = document.getElementById("dg-local-explain"),l = document.getElementById("dg-local-storage");document.getElementById("dg-save-locally").style.display = "block", "true" === localStorage.getItem(m(e,"isLocal")) && l.setAttribute("checked", "checked"), b(e, a), X.bind(l, "change", function() {e.useLocalStorage = !e.useLocalStorage, b(e, a)})}var d = document.getElementById("dg-new-constructor");X.bind(d, "keydown", function(e) {!e.metaKey || 67 !== e.which && 67 !== e.keyCode || le.hide()}), X.bind(n, "click", function() {d.innerHTML = JSON.stringify(e.getSaveObject(), void 0, 2), le.show(), d.focus(), d.select()}), X.bind(o, "click", function() {e.save()}), X.bind(i, "click", function() {var t = prompt("Enter a new preset name.");t && e.saveAs(t)}), X.bind(r, "click", function() {e.revert()})}function y(e) {function t(t) {return t.preventDefault(), e.width += i - t.clientX, e.onResize(), i = t.clientX, !1}function n() {X.removeClass(e.__closeButton, he.CLASS_DRAG), X.unbind(window, "mousemove", t), X.unbind(window,"mouseup", n)}function o(o) {return o.preventDefault(), i = o.clientX, X.addClass(e.__closeButton, he.CLASS_DRAG), X.bind(window,"mousemove", t), X.bind(window, "mouseup", n), !1}var i = void 0;e.__resize_handle = document.createElement("div"), S.extend(e.__resize_handle.style, {width: "6px",marginLeft: "-3px",height: "200px",cursor: "ew-resize",position: "absolute"}), X.bind(e.__resize_handle, "mousedown", o), X.bind(e.__closeButton, "mousedown", o), e.domElement.insertBefore(e.__resize_handle, e.domElement.firstElementChild)}function w(e, t) {e.domElement.style.width = t + "px", e.__save_row && e.autoPlace && (e.__save_row.style.width = t + "px"), e.__closeButton && (e.__closeButton.style.width = t + "px")}function x(e, t) {var n = {};return S.each(e.__rememberedObjects, function(o, i) {var r = {},s = e.__rememberedObjectIndecesToControllers[i];S.each(s, function(e, n) {r[n] = t ? e.initialValue : e.getValue()}), n[i] = r}), n}function E(e) {for (var t = 0; t < e.__preset_select.length; t++) e.__preset_select[t].value === e.preset && (e.__preset_select.selectedIndex = t)}function C(e) {0 !== e.length && oe.call(window, function() {C(e)}), S.each(e, function(e) {e.updateDisplay()})}var A = Array.prototype.forEach,k = Array.prototype.slice,S = {BREAK: {},extend: function(e) {return this.each(k.call(arguments, 1), function(t) {(this.isObject(t) ? Object.keys(t) : []).forEach(function(n) {this.isUndefined(t[n]) || (e[n] = t[n])}.bind(this))}, this), e},defaults: function(e) {return this.each(k.call(arguments, 1), function(t) {(this.isObject(t) ? Object.keys(t) : []).forEach(function(n) {this.isUndefined(e[n]) && (e[n] = t[n])}.bind(this))}, this), e},compose: function() {var e = k.call(arguments);return function() {for (var t = k.call(arguments), n = e.length - 1; n >= 0; n--) t = [e[n].apply(this,t)];return t[0]}},each: function(e, t, n) {if (e)if (A && e.forEach && e.forEach === A) e.forEach(t, n);else if (e.length === e.length + 0) {var o = void 0,i = void 0;for (o = 0, i = e.length; o < i; o++)if (o in e && t.call(n, e[o], o) === this.BREAK) return} elsefor (var r in e)if (t.call(n, e[r], r) === this.BREAK) return},defer: function(e) {setTimeout(e, 0)},debounce: function(e, t, n) {var o = void 0;return function() {var i = this,r = arguments,s = n || !o;clearTimeout(o), o = setTimeout(function() {o = null, n || e.apply(i, r)}, t), s && e.apply(i, r)}},toArray: function(e) {return e.toArray ? e.toArray() : k.call(e)},isUndefined: function(e) {return void 0 === e},isNull: function(e) {return null === e},isNaN: function(e) {function t(t) {return e.apply(this, arguments)}return t.toString = function() {return e.toString()}, t}(function(e) {return isNaN(e)}),isArray: Array.isArray || function(e) {return e.constructor === Array},isObject: function(e) {return e === Object(e)},isNumber: function(e) {return e === e + 0},isString: function(e) {return e === e + ""},isBoolean: function(e) {return !1 === e || !0 === e},isFunction: function(e) {return e instanceof Function}},O = [{litmus: S.isString,conversions: {THREE_CHAR_HEX: {read: function(e) {var t = e.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return null !== t && {space: "HEX",hex: parseInt("0x" + t[1].toString() + t[1].toString() + t[2].toString() +t[2].toString() + t[3].toString() + t[3].toString(), 0)}},write: t},SIX_CHAR_HEX: {read: function(e) {var t = e.match(/^#([A-F0-9]{6})$/i);return null !== t && {space: "HEX",hex: parseInt("0x" + t[1].toString(), 0)}},write: t},CSS_RGB: {read: function(e) {var t = e.match(/^rgb\(\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*\)/);return null !== t && {space: "RGB",r: parseFloat(t[1]),g: parseFloat(t[2]),b: parseFloat(t[3])}},write: t},CSS_RGBA: {read: function(e) {var t = e.match(/^rgba\(\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*\)/);return null !== t && {space: "RGB",r: parseFloat(t[1]),g: parseFloat(t[2]),b: parseFloat(t[3]),a: parseFloat(t[4])}},write: t}}}, {litmus: S.isNumber,conversions: {HEX: {read: function(e) {return {space: "HEX",hex: e,conversionName: "HEX"}},write: function(e) {return e.hex}}}}, {litmus: S.isArray,conversions: {RGB_ARRAY: {read: function(e) {return 3 === e.length && {space: "RGB",r: e[0],g: e[1],b: e[2]}},write: function(e) {return [e.r, e.g, e.b]}},RGBA_ARRAY: {read: function(e) {return 4 === e.length && {space: "RGB",r: e[0],g: e[1],b: e[2],a: e[3]}},write: function(e) {return [e.r, e.g, e.b, e.a]}}}}, {litmus: S.isObject,conversions: {RGBA_OBJ: {read: function(e) {return !!(S.isNumber(e.r) && S.isNumber(e.g) && S.isNumber(e.b) && S.isNumber(e.a)) && {space: "RGB",r: e.r,g: e.g,b: e.b,a: e.a}},write: function(e) {return {r: e.r,g: e.g,b: e.b,a: e.a}}},RGB_OBJ: {read: function(e) {return !!(S.isNumber(e.r) && S.isNumber(e.g) && S.isNumber(e.b)) && {space: "RGB",r: e.r,g: e.g,b: e.b}},write: function(e) {return {r: e.r,g: e.g,b: e.b}}},HSVA_OBJ: {read: function(e) {return !!(S.isNumber(e.h) && S.isNumber(e.s) && S.isNumber(e.v) && S.isNumber(e.a)) && {space: "HSV",h: e.h,s: e.s,v: e.v,a: e.a}},write: function(e) {return {h: e.h,s: e.s,v: e.v,a: e.a}}},HSV_OBJ: {read: function(e) {return !!(S.isNumber(e.h) && S.isNumber(e.s) && S.isNumber(e.v)) && {space: "HSV",h: e.h,s: e.s,v: e.v}},write: function(e) {return {h: e.h,s: e.s,v: e.v}}}}}],T = void 0,L = void 0,R = function() {L = !1;var e = arguments.length > 1 ? S.toArray(arguments) : arguments[0];return S.each(O, function(t) {if (t.litmus(e)) return S.each(t.conversions, function(t, n) {if (T = t.read(e), !1 === L && !1 !== T) return L = T, T.conversionName = n,T.conversion = t, S.BREAK}), S.BREAK}), L},B = void 0,N = {hsv_to_rgb: function(e, t, n) {var o = Math.floor(e / 60) % 6,i = e / 60 - Math.floor(e / 60),r = n * (1 - t),s = n * (1 - i * t),a = n * (1 - (1 - i) * t),l = [[n, a, r],[s, n, r],[r, n, a],[r, s, n],[a, r, n],[n, r, s]][o];return {r: 255 * l[0],g: 255 * l[1],b: 255 * l[2]}},rgb_to_hsv: function(e, t, n) {var o = Math.min(e, t, n),i = Math.max(e, t, n),r = i - o,s = void 0,a = void 0;return 0 === i ? {h: NaN,s: 0,v: 0} : (a = r / i, s = e === i ? (t - n) / r : t === i ? 2 + (n - e) / r : 4 + (e - t) / r, (s /= 6) < 0 && (s += 1), {h: 360 * s,s: a,v: i / 255})},rgb_to_hex: function(e, t, n) {var o = this.hex_with_component(0, 2, e);return o = this.hex_with_component(o, 1, t), o = this.hex_with_component(o, 0, n)},component_from_hex: function(e, t) {return e >> 8 * t & 255},hex_with_component: function(e, t, n) {return n << (B = 8 * t) | e & ~(255 << B)}},H = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) {return typeof e} : function(e) {return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ?"symbol" : typeof e},F = function(e, t) {if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function")},P = function() {function e(e, t) {for (var n = 0; n < t.length; n++) {var o = t[n];o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0),Object.defineProperty(e, o.key, o)}}return function(t, n, o) {return n && e(t.prototype, n), o && e(t, o), t}}(),D = function e(t, n, o) {null === t && (t = Function.prototype);var i = Object.getOwnPropertyDescriptor(t, n);if (void 0 === i) {var r = Object.getPrototypeOf(t);return null === r ? void 0 : e(r, n, o)}if ("value" in i) return i.value;var s = i.get;if (void 0 !== s) return s.call(o)},j = function(e, t) {if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + typeof t);e.prototype = Object.create(t && t.prototype, {constructor: {value: e,enumerable: !1,writable: !0,configurable: !0}}), t && (Object.setPrototypeOf ? Object.setPrototypeOf(e, t) : e.__proto__ = t)},V = function(e, t) {if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return !t || "object" != typeof t && "function" != typeof t ? e : t},I = function() {function e() {if (F(this, e), this.__state = R.apply(this, arguments), !1 === this.__state) throw new Error("Failed to interpret color arguments");this.__state.a = this.__state.a || 1}return P(e, [{key: "toString",value: function() {return t(this)}}, {key: "toHexString",value: function() {return t(this, !0)}}, {key: "toOriginal",value: function() {return this.__state.conversion.write(this)}}]), e}();I.recalculateRGB = function(e, t, n) {if ("HEX" === e.__state.space) e.__state[t] = N.component_from_hex(e.__state.hex, n);else {if ("HSV" !== e.__state.space) throw new Error("Corrupted color state");S.extend(e.__state, N.hsv_to_rgb(e.__state.h, e.__state.s, e.__state.v))}}, I.recalculateHSV = function(e) {var t = N.rgb_to_hsv(e.r, e.g, e.b);S.extend(e.__state, {s: t.s,v: t.v}), S.isNaN(t.h) ? S.isUndefined(e.__state.h) && (e.__state.h = 0) : e.__state.h = t.h}, I.COMPONENTS = ["r", "g", "b", "h", "s", "v", "hex", "a"], n(I.prototype, "r", 2), n(I.prototype, "g",1), n(I.prototype, "b", 0), o(I.prototype, "h"), o(I.prototype, "s"), o(I.prototype, "v"), Object.defineProperty(I.prototype, "a", {get: function() {return this.__state.a},set: function(e) {this.__state.a = e}}), Object.defineProperty(I.prototype, "hex", {get: function() {return "HEX" !== this.__state.space && (this.__state.hex = N.rgb_to_hex(this.r, this.g, this.b), this.__state.space = "HEX"), this.__state.hex},set: function(e) {this.__state.space = "HEX", this.__state.hex = e}});var z = function() {function e(t, n) {F(this, e), this.initialValue = t[n], this.domElement = document.createElement("div"), this.object =t, this.property = n, this.__onChange = void 0, this.__onFinishChange = void 0}return P(e, [{key: "onChange",value: function(e) {return this.__onChange = e, this}}, {key: "onFinishChange",value: function(e) {return this.__onFinishChange = e, this}}, {key: "setValue",value: function(e) {return this.object[this.property] = e, this.__onChange && this.__onChange.call(this, e), this.updateDisplay(), this}}, {key: "getValue",value: function() {return this.object[this.property]}}, {key: "updateDisplay",value: function() {return this}}, {key: "isModified",value: function() {return this.initialValue !== this.getValue()}}]), e}(),M = {HTMLEvents: ["change"],MouseEvents: ["click", "mousemove", "mousedown", "mouseup", "mouseover"],KeyboardEvents: ["keydown"]},G = {};S.each(M, function(e, t) {S.each(e, function(e) {G[e] = t})});var U = /(\d+(\.\d+)?)px/,X = {makeSelectable: function(e, t) {void 0 !== e && void 0 !== e.style && (e.onselectstart = t ? function() {return !1} : function() {}, e.style.MozUserSelect = t ? "auto" : "none", e.style.KhtmlUserSelect = t ? "auto" : "none", e.unselectable = t ? "on" : "off")},makeFullscreen: function(e, t, n) {var o = n,i = t;S.isUndefined(i) && (i = !0), S.isUndefined(o) && (o = !0), e.style.position = "absolute", i &&(e.style.left = 0, e.style.right = 0), o && (e.style.top = 0, e.style.bottom = 0)},fakeEvent: function(e, t, n, o) {var i = n || {},r = G[t];if (!r) throw new Error("Event type " + t + " not supported.");var s = document.createEvent(r);switch (r) {case "MouseEvents":var a = i.x || i.clientX || 0,l = i.y || i.clientY || 0;s.initMouseEvent(t, i.bubbles || !1, i.cancelable || !0, window, i.clickCount || 1, 0,0, a, l, !1, !1, !1, !1, 0, null);break;case "KeyboardEvents":var d = s.initKeyboardEvent || s.initKeyEvent;S.defaults(i, {cancelable: !0,ctrlKey: !1,altKey: !1,shiftKey: !1,metaKey: !1,keyCode: void 0,charCode: void 0}), d(t, i.bubbles || !1, i.cancelable, window, i.ctrlKey, i.altKey, i.shiftKey, i.metaKey, i.keyCode, i.charCode);break;default:s.initEvent(t, i.bubbles || !1, i.cancelable || !0)}S.defaults(s, o), e.dispatchEvent(s)},bind: function(e, t, n, o) {var i = o || !1;return e.addEventListener ? e.addEventListener(t, n, i) : e.attachEvent && e.attachEvent("on" +t, n), X},unbind: function(e, t, n, o) {var i = o || !1;return e.removeEventListener ? e.removeEventListener(t, n, i) : e.detachEvent && e.detachEvent("on" + t, n), X},addClass: function(e, t) {if (void 0 === e.className) e.className = t;else if (e.className !== t) {var n = e.className.split(/ +/); - 1 === n.indexOf(t) && (n.push(t), e.className = n.join(" ").replace(/^\s+/, "").replace(/\s+$/, ""))}return X},removeClass: function(e, t) {if (t)if (e.className === t) e.removeAttribute("class");else {var n = e.className.split(/ +/),o = n.indexOf(t); - 1 !== o && (n.splice(o, 1), e.className = n.join(" "))}else e.className = void 0;return X},hasClass: function(e, t) {return new RegExp("(?:^|\\s+)" + t + "(?:\\s+|$)").test(e.className) || !1},getWidth: function(e) {var t = getComputedStyle(e);return i(t["border-left-width"]) + i(t["border-right-width"]) + i(t["padding-left"]) + i(t["padding-right"]) + i(t.width)},getHeight: function(e) {var t = getComputedStyle(e);return i(t["border-top-width"]) + i(t["border-bottom-width"]) + i(t["padding-top"]) + i(t["padding-bottom"]) + i(t.height)},getOffset: function(e) {var t = e,n = {left: 0,top: 0};if (t.offsetParent)do {n.left += t.offsetLeft, n.top += t.offsetTop, t = t.offsetParent} while (t);return n},isActive: function(e) {return e === document.activeElement && (e.type || e.href)}},K = function(e) {function t(e, n) {F(this, t);var o = V(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, n)),i = o;return o.__prev = o.getValue(), o.__checkbox = document.createElement("input"), o.__checkbox.setAttribute("type", "checkbox"), X.bind(o.__checkbox, "change", function() {i.setValue(!i.__prev)}, !1), o.domElement.appendChild(o.__checkbox), o.updateDisplay(), o}return j(t, z), P(t, [{key: "setValue",value: function(e) {var n = D(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype),"setValue", this).call(this, e);return this.__onFinishChange && this.__onFinishChange.call(this, this.getValue()), this.__prev = this.getValue(), n}}, {key: "updateDisplay",value: function() {return !0 === this.getValue() ? (this.__checkbox.setAttribute("checked","checked"), this.__checkbox.checked = !0, this.__prev = !0) : (this.__checkbox.checked = !1, this.__prev = !1), D(t.prototype.__proto__ ||Object.getPrototypeOf(t.prototype), "updateDisplay", this).call(this)}}]), t}(),Y = function(e) {function t(e, n, o) {F(this, t);var i = V(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, n)),r = o,s = i;if (i.__select = document.createElement("select"), S.isArray(r)) {var a = {};S.each(r, function(e) {a[e] = e}), r = a}return S.each(r, function(e, t) {var n = document.createElement("option");n.innerHTML = t, n.setAttribute("value", e), s.__select.appendChild(n)}), i.updateDisplay(), X.bind(i.__select, "change", function() {var e = this.options[this.selectedIndex].value;s.setValue(e)}), i.domElement.appendChild(i.__select), i}return j(t, z), P(t, [{key: "setValue",value: function(e) {var n = D(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype),"setValue", this).call(this, e);return this.__onFinishChange && this.__onFinishChange.call(this, this.getValue()), n}}, {key: "updateDisplay",value: function() {return X.isActive(this.__select) ? this : (this.__select.value = this.getValue(), D(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype),"updateDisplay", this).call(this))}}]), t}(),J = function(e) {function t(e, n) {function o() {r.setValue(r.__input.value)}F(this, t);var i = V(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, n)),r = i;return i.__input = document.createElement("input"), i.__input.setAttribute("type", "text"), X.bind(i.__input, "keyup", o), X.bind(i.__input, "change", o), X.bind(i.__input, "blur",function() {r.__onFinishChange && r.__onFinishChange.call(r, r.getValue())}), X.bind(i.__input, "keydown", function(e) {13 === e.keyCode && this.blur()}), i.updateDisplay(), i.domElement.appendChild(i.__input), i}return j(t, z), P(t, [{key: "updateDisplay",value: function() {return X.isActive(this.__input) || (this.__input.value = this.getValue()), D(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype),"updateDisplay", this).call(this)}}]), t}(),W = function(e) {function t(e, n, o) {F(this, t);var i = V(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, n)),s = o || {};return i.__min = s.min, i.__max = s.max, i.__step = s.step, S.isUndefined(i.__step) ? 0 === i.initialValue ? i.__impliedStep = 1 : i.__impliedStep = Math.pow(10, Math.floor(Math.log(Math.abs(i.initialValue)) / Math.LN10)) / 10 : i.__impliedStep = i.__step, i.__precision = r(i.__impliedStep), i}return j(t, z), P(t, [{key: "setValue",value: function(e) {var n = e;return void 0 !== this.__min && n < this.__min ? n = this.__min : void 0 !==this.__max && n > this.__max && (n = this.__max), void 0 !== this.__step &&n % this.__step != 0 && (n = Math.round(n / this.__step) * this.__step), D(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype), "setValue",this).call(this, n)}}, {key: "min",value: function(e) {return this.__min = e, this}}, {key: "max",value: function(e) {return this.__max = e, this}}, {key: "step",value: function(e) {return this.__step = e, this.__impliedStep = e, this.__precision = r(e), this}}]), t}(),Q = function(e) {function t(e, n, o) {function i() {l.__onFinishChange && l.__onFinishChange.call(l, l.getValue())}function r(e) {var t = d - e.clientY;l.setValue(l.getValue() + t * l.__impliedStep), d = e.clientY}function s() {X.unbind(window, "mousemove", r), X.unbind(window, "mouseup", s), i()}F(this, t);var a = V(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, n, o));a.__truncationSuspended = !1;var l = a,d = void 0;return a.__input = document.createElement("input"), a.__input.setAttribute("type", "text"), X.bind(a.__input, "change",function() {var e = parseFloat(l.__input.value);S.isNaN(e) || l.setValue(e)}), X.bind(a.__input, "blur", function() {i()}), X.bind(a.__input, "mousedown", function(e) {X.bind(window, "mousemove", r), X.bind(window, "mouseup", s), d = e.clientY}), X.bind(a.__input, "keydown", function(e) {13 === e.keyCode && (l.__truncationSuspended = !0, this.blur(), l.__truncationSuspended = !1, i())}), a.updateDisplay(), a.domElement.appendChild(a.__input), a}return j(t, W), P(t, [{key: "updateDisplay",value: function() {return this.__input.value = this.__truncationSuspended ? this.getValue() : s(this.getValue(), this.__precision), D(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype), "updateDisplay", this).call(this)}}]), t}(),q = function(e) {function t(e, n, o, i, r) {function s(e) {e.preventDefault();var t = _.__background.getBoundingClientRect();return _.setValue(a(e.clientX, t.left, t.right, _.__min, _.__max)), !1}function l() {X.unbind(window, "mousemove", s), X.unbind(window, "mouseup", l), _.__onFinishChange && _.__onFinishChange.call(_, _.getValue())}function d(e) {var t = e.touches[0].clientX,n = _.__background.getBoundingClientRect();_.setValue(a(t, n.left, n.right, _.__min, _.__max))}function c() {X.unbind(window, "touchmove", d), X.unbind(window, "touchend", c), _.__onFinishChange && _.__onFinishChange.call(_, _.getValue())}F(this, t);var u = V(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, n, {min: o,max: i,step: r})),_ = u;return u.__background = document.createElement("div"), u.__foreground = document.createElement("div"), X.bind(u.__background, "mousedown", function(e) {document.activeElement.blur(), X.bind(window, "mousemove", s), X.bind(window, "mouseup",l), s(e)}), X.bind(u.__background, "touchstart", function(e) {1 === e.touches.length && (X.bind(window, "touchmove", d), X.bind(window, "touchend",c), d(e))}), X.addClass(u.__background, "slider"), X.addClass(u.__foreground, "slider-fg"), u.updateDisplay(), u.__background.appendChild(u.__foreground), u.domElement.appendChild(u.__background), u}return j(t, W), P(t, [{key: "updateDisplay",value: function() {var e = (this.getValue() - this.__min) / (this.__max - this.__min);return this.__foreground.style.width = 100 * e + "%", D(t.prototype.__proto__ ||Object.getPrototypeOf(t.prototype), "updateDisplay", this).call(this)}}]), t}(),Z = function(e) {function t(e, n, o) {F(this, t);var i = V(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, n)),r = i;return i.__button = document.createElement("div"), i.__button.innerHTML = void 0 === o ? "Fire" : o,X.bind(i.__button, "click", function(e) {return e.preventDefault(), r.fire(), !1}), X.addClass(i.__button, "button"), i.domElement.appendChild(i.__button), i}return j(t, z), P(t, [{key: "fire",value: function() {this.__onChange && this.__onChange.call(this), this.getValue().call(this.object), this.__onFinishChange && this.__onFinishChange.call(this, this.getValue())}}]), t}(),$ = function(e) {function t(e, n) {function o(e) {u(e), X.bind(window, "mousemove", u), X.bind(window, "touchmove", u), X.bind(window, "mouseup",r), X.bind(window, "touchend", r)}function i(e) {_(e), X.bind(window, "mousemove", _), X.bind(window, "touchmove", _), X.bind(window, "mouseup",s), X.bind(window, "touchend", s)}function r() {X.unbind(window, "mousemove", u), X.unbind(window, "touchmove", u), X.unbind(window, "mouseup",r), X.unbind(window, "touchend", r), c()}function s() {X.unbind(window, "mousemove", _), X.unbind(window, "touchmove", _), X.unbind(window, "mouseup",s), X.unbind(window, "touchend", s), c()}function a() {var e = R(this.value);!1 !== e ? (p.__color.__state = e, p.setValue(p.__color.toOriginal())) : this.value = p.__color.toString()}function c() {p.__onFinishChange && p.__onFinishChange.call(p, p.__color.toOriginal())}function u(e) {-1 === e.type.indexOf("touch") && e.preventDefault();var t = p.__saturation_field.getBoundingClientRect(),n = e.touches && e.touches[0] || e,o = n.clientX,i = n.clientY,r = (o - t.left) / (t.right - t.left),s = 1 - (i - t.top) / (t.bottom - t.top);return s > 1 ? s = 1 : s < 0 && (s = 0), r > 1 ? r = 1 : r < 0 && (r = 0), p.__color.v = s, p.__color.s = r, p.setValue(p.__color.toOriginal()), !1}function _(e) {-1 === e.type.indexOf("touch") && e.preventDefault();var t = p.__hue_field.getBoundingClientRect(),n = 1 - ((e.touches && e.touches[0] || e).clientY - t.top) / (t.bottom - t.top);return n > 1 ? n = 1 : n < 0 && (n = 0), p.__color.h = 360 * n, p.setValue(p.__color.toOriginal()), !1}F(this, t);var h = V(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, n));h.__color = new I(h.getValue()), h.__temp = new I(0);var p = h;h.domElement = document.createElement("div"), X.makeSelectable(h.domElement, !1), h.__selector =document.createElement("div"), h.__selector.className = "selector", h.__saturation_field =document.createElement("div"), h.__saturation_field.className = "saturation-field", h.__field_knob = document.createElement("div"), h.__field_knob.className = "field-knob", h.__field_knob_border = "2px solid ", h.__hue_knob = document.createElement("div"), h.__hue_knob.className = "hue-knob", h.__hue_field = document.createElement("div"), h.__hue_field.className = "hue-field", h.__input = document.createElement("input"), h.__input.type = "text",h.__input_textShadow = "0 1px 1px ", X.bind(h.__input, "keydown", function(e) {13 === e.keyCode && a.call(this)}), X.bind(h.__input, "blur", a), X.bind(h.__selector, "mousedown", function() {X.addClass(this, "drag").bind(window, "mouseup", function() {X.removeClass(p.__selector, "drag")})}), X.bind(h.__selector, "touchstart", function() {X.addClass(this, "drag").bind(window, "touchend", function() {X.removeClass(p.__selector, "drag")})});var f = document.createElement("div");return S.extend(h.__selector.style, {width: "122px",height: "102px",padding: "3px",backgroundColor: "#222",boxShadow: "0px 1px 3px rgba(0,0,0,0.3)"}), S.extend(h.__field_knob.style, {position: "absolute",width: "12px",height: "12px",border: h.__field_knob_border + (h.__color.v < .5 ? "#fff" : "#000"),boxShadow: "0px 1px 3px rgba(0,0,0,0.5)",borderRadius: "12px",zIndex: 1}), S.extend(h.__hue_knob.style, {position: "absolute",width: "15px",height: "2px",borderRight: "4px solid #fff",zIndex: 1}), S.extend(h.__saturation_field.style, {width: "100px",height: "100px",border: "1px solid #555",marginRight: "3px",display: "inline-block",cursor: "pointer"}), S.extend(f.style, {width: "100%",height: "100%",background: "none"}), l(f, "top", "rgba(0,0,0,0)", "#000"), S.extend(h.__hue_field.style, {width: "15px",height: "100px",border: "1px solid #555",cursor: "ns-resize",position: "absolute",top: "3px",right: "3px"}), d(h.__hue_field), S.extend(h.__input.style, {outline: "none",textAlign: "center",color: "#fff",border: 0,fontWeight: "bold",textShadow: h.__input_textShadow + "rgba(0,0,0,0.7)"}), X.bind(h.__saturation_field, "mousedown", o), X.bind(h.__saturation_field, "touchstart", o),X.bind(h.__field_knob, "mousedown", o), X.bind(h.__field_knob, "touchstart", o), X.bind(h.__hue_field, "mousedown", i), X.bind(h.__hue_field, "touchstart", i), h.__saturation_field.appendChild(f), h.__selector.appendChild(h.__field_knob), h.__selector.appendChild(h.__saturation_field), h.__selector.appendChild(h.__hue_field), h.__hue_field.appendChild(h.__hue_knob), h.domElement.appendChild(h.__input), h.domElement.appendChild(h.__selector), h.updateDisplay(), h}return j(t, z), P(t, [{key: "updateDisplay",value: function() {var e = R(this.getValue());if (!1 !== e) {var t = !1;S.each(I.COMPONENTS, function(n) {if (!S.isUndefined(e[n]) && !S.isUndefined(this.__color.__state[n]) && e[n] !== this.__color.__state[n]) return t = !0, {}}, this), t && S.extend(this.__color.__state, e)}S.extend(this.__temp.__state, this.__color.__state), this.__temp.a = 1;var n = this.__color.v < .5 || this.__color.s > .5 ? 255 : 0,o = 255 - n;S.extend(this.__field_knob.style, {marginLeft: 100 * this.__color.s - 7 + "px",marginTop: 100 * (1 - this.__color.v) - 7 + "px",backgroundColor: this.__temp.toHexString(),border: this.__field_knob_border + "rgb(" + n + "," + n + "," + n +")"}), this.__hue_knob.style.marginTop = 100 * (1 - this.__color.h / 360) +"px", this.__temp.s = 1, this.__temp.v = 1, l(this.__saturation_field,"left", "#fff", this.__temp.toHexString()), this.__input.value = this.__color.toString(), S.extend(this.__input.style, {backgroundColor: this.__color.toHexString(),color: "rgb(" + n + "," + n + "," + n + ")",textShadow: this.__input_textShadow + "rgba(" + o + "," + o + "," +o + ",.7)"})}}]), t}(),ee = ["-moz-", "-o-", "-webkit-", "-ms-", ""],te = {load: function(e, t) {var n = t || document,o = n.createElement("link");o.type = "text/css", o.rel = "stylesheet", o.href = e, n.getElementsByTagName("head")[0].appendChild(o)},inject: function(e, t) {var n = t || document,o = document.createElement("style");o.type = "text/css", o.innerHTML = e;var i = n.getElementsByTagName("head")[0];try {i.appendChild(o)} catch (e) {}}},ne = function(e, t) {var n = e[t];return S.isArray(arguments[2]) || S.isObject(arguments[2]) ? new Y(e, t, arguments[2]) : S.isNumber(n) ?S.isNumber(arguments[2]) && S.isNumber(arguments[3]) ? S.isNumber(arguments[4]) ? new q(e, t,arguments[2], arguments[3], arguments[4]) : new q(e, t, arguments[2], arguments[3]) : S.isNumber(arguments[4]) ? new Q(e, t, {min: arguments[2],max: arguments[3],step: arguments[4]}) : new Q(e, t, {min: arguments[2],max: arguments[3]}) : S.isString(n) ? new J(e, t) : S.isFunction(n) ? new Z(e, t, "") : S.isBoolean(n) ? new K(e,t) : null},oe = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(e) {setTimeout(e, 1e3 / 60)},ie = function() {function e() {F(this, e), this.backgroundElement = document.createElement("div"), S.extend(this.backgroundElement.style, {backgroundColor: "rgba(0,0,0,0.8)",top: 0,left: 0,display: "none",zIndex: "1000",opacity: 0,WebkitTransition: "opacity 0.2s linear",transition: "opacity 0.2s linear"}), X.makeFullscreen(this.backgroundElement), this.backgroundElement.style.position ="fixed", this.domElement = document.createElement("div"), S.extend(this.domElement.style, {position: "fixed",display: "none",zIndex: "1001",opacity: 0,WebkitTransition: "-webkit-transform 0.2s ease-out, opacity 0.2s linear",transition: "transform 0.2s ease-out, opacity 0.2s linear"}), document.body.appendChild(this.backgroundElement), document.body.appendChild(this.domElement);var t = this;X.bind(this.backgroundElement, "click", function() {t.hide()})}return P(e, [{key: "show",value: function() {var e = this;this.backgroundElement.style.display = "block", this.domElement.style.display ="block", this.domElement.style.opacity = 0, this.domElement.style.webkitTransform = "scale(1.1)", this.layout(), S.defer(function() {e.backgroundElement.style.opacity = 1, e.domElement.style.opacity =1, e.domElement.style.webkitTransform = "scale(1)"})}}, {key: "hide",value: function() {var e = this,t = function t() {e.domElement.style.display = "none", e.backgroundElement.style.display ="none", X.unbind(e.domElement, "webkitTransitionEnd", t), X.unbind(e.domElement, "transitionend", t), X.unbind(e.domElement,"oTransitionEnd", t)};X.bind(this.domElement, "webkitTransitionEnd", t), X.bind(this.domElement,"transitionend", t), X.bind(this.domElement, "oTransitionEnd", t), this.backgroundElement.style.opacity = 0, this.domElement.style.opacity = 0,this.domElement.style.webkitTransform = "scale(1.1)"}}, {key: "layout",value: function() {this.domElement.style.left = window.innerWidth / 2 - X.getWidth(this.domElement) / 2 + "px", this.domElement.style.top = window.innerHeight /2 - X.getHeight(this.domElement) / 2 + "px"}}]), e}(),re = function(e) {if (e && "undefined" != typeof window) {var t = document.createElement("style");return t.setAttribute("type", "text/css"), t.innerHTML = e, document.head.appendChild(t), e}}(".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{-webkit-transition:height .1s ease-out;-o-transition:height .1s ease-out;-moz-transition:height .1s ease-out;transition:height .1s ease-out;-webkit-transition:overflow .1s linear;-o-transition:overflow .1s linear;-moz-transition:overflow .1s linear;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .cr.function .property-name{width:100%}.dg .c{float:left;width:60%;position:relative}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:7px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .cr.color{overflow:visible}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAPPz8yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAPPz8yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2FA1D6}.dg .cr.number input[type=text]{color:#2FA1D6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2FA1D6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n");te.inject(re);var se = "Default",ae = function() {try {return !!window.localStorage} catch (e) {return !1}}(),le = void 0,de = !0,ce = void 0,ue = !1,_e = [],he = function e(t) {var n = this,o = t || {};this.domElement = document.createElement("div"), this.__ul = document.createElement("ul"), this.domElement.appendChild(this.__ul), X.addClass(this.domElement, "dg"), this.__folders = {}, this.__controllers = [], this.__rememberedObjects = [], this.__rememberedObjectIndecesToControllers = [], this.__listening = [], o = S.defaults(o, {closeOnTop: !1,autoPlace: !0,width: e.DEFAULT_WIDTH}), o = S.defaults(o, {resizable: o.autoPlace,hideable: o.autoPlace}), S.isUndefined(o.load) ? o.load = {preset: se} : o.preset && (o.load.preset = o.preset), S.isUndefined(o.parent) && o.hideable && _e.push(this),o.resizable = S.isUndefined(o.parent) && o.resizable, o.autoPlace && S.isUndefined(o.scrollable) &&(o.scrollable = !0);var i = ae && "true" === localStorage.getItem(m(this, "isLocal")),r = void 0,s = void 0;if (Object.defineProperties(this, {parent: {get: function() {return o.parent}},scrollable: {get: function() {return o.scrollable}},autoPlace: {get: function() {return o.autoPlace}},closeOnTop: {get: function() {return o.closeOnTop}},preset: {get: function() {return n.parent ? n.getRoot().preset : o.load.preset},set: function(e) {n.parent ? n.getRoot().preset = e : o.load.preset = e, E(this), n.revert()}},width: {get: function() {return o.width},set: function(e) {o.width = e, w(n, e)}},name: {get: function() {return o.name},set: function(e) {o.name = e, s && (s.innerHTML = o.name)}},closed: {get: function() {return o.closed},set: function(t) {o.closed = t, o.closed ? X.addClass(n.__ul, e.CLASS_CLOSED) : X.removeClass(n.__ul, e.CLASS_CLOSED), this.onResize(), n.__closeButton && (n.__closeButton.innerHTML = t ? e.TEXT_OPEN : e.TEXT_CLOSED)}},load: {get: function() {return o.load}},useLocalStorage: {get: function() {return i},set: function(e) {ae && (i = e, e ? X.bind(window, "unload", r) : X.unbind(window, "unload", r),localStorage.setItem(m(n, "isLocal"), e))}}}), S.isUndefined(o.parent)) {if (this.closed = o.closed || !1, X.addClass(this.domElement, e.CLASS_MAIN), X.makeSelectable(this.domElement, !1), ae && i) {n.useLocalStorage = !0;var a = localStorage.getItem(m(this, "gui"));a && (o.load = JSON.parse(a))}this.__closeButton = document.createElement("div"), this.__closeButton.innerHTML = e.TEXT_CLOSED, X.addClass(this.__closeButton, e.CLASS_CLOSE_BUTTON), o.closeOnTop ? (X.addClass(this.__closeButton, e.CLASS_CLOSE_TOP), this.domElement.insertBefore(this.__closeButton,this.domElement.childNodes[0])) : (X.addClass(this.__closeButton, e.CLASS_CLOSE_BOTTOM),this.domElement.appendChild(this.__closeButton)), X.bind(this.__closeButton, "click",function() {n.closed = !n.closed})} else {void 0 === o.closed && (o.closed = !0);var l = document.createTextNode(o.name);X.addClass(l, "controller-name"), s = c(n, l);X.addClass(this.__ul, e.CLASS_CLOSED), X.addClass(s, "title"), X.bind(s, "click", function(e) {return e.preventDefault(), n.closed = !n.closed, !1}), o.closed || (this.closed = !1)}o.autoPlace && (S.isUndefined(o.parent) && (de && (ce = document.createElement("div"), X.addClass(ce,"dg"), X.addClass(ce, e.CLASS_AUTO_PLACE_CONTAINER), document.body.appendChild(ce),de = !1), ce.appendChild(this.domElement), X.addClass(this.domElement, e.CLASS_AUTO_PLACE)), this.parent || w(n, o.width)), this.__resizeHandler = function() {n.onResizeDebounced()}, X.bind(window, "resize", this.__resizeHandler), X.bind(this.__ul, "webkitTransitionEnd", this.__resizeHandler), X.bind(this.__ul, "transitionend", this.__resizeHandler), X.bind(this.__ul,"oTransitionEnd", this.__resizeHandler), this.onResize(), o.resizable && y(this), r =function() {ae && "true" === localStorage.getItem(m(n, "isLocal")) && localStorage.setItem(m(n, "gui"), JSON.stringify(n.getSaveObject()))}, this.saveToLocalStorageIfPossible = r, o.parent || function() {var e = n.getRoot();e.width += 1, S.defer(function() {e.width -= 1})}()};he.toggleHide = function() {ue = !ue, S.each(_e, function(e) {e.domElement.style.display = ue ? "none" : ""})}, he.CLASS_AUTO_PLACE = "a", he.CLASS_AUTO_PLACE_CONTAINER = "ac", he.CLASS_MAIN = "main", he.CLASS_CONTROLLER_ROW = "cr", he.CLASS_TOO_TALL = "taller-than-window", he.CLASS_CLOSED = "closed", he.CLASS_CLOSE_BUTTON = "close-button", he.CLASS_CLOSE_TOP = "close-top", he.CLASS_CLOSE_BOTTOM ="close-bottom", he.CLASS_DRAG = "drag", he.DEFAULT_WIDTH = 245, he.TEXT_CLOSED = "Close Controls", he.TEXT_OPEN = "Open Controls", he._keydownHandler = function(e) {"text" === document.activeElement.type || 72 !== e.which && 72 !== e.keyCode || he.toggleHide()}, X.bind(window, "keydown", he._keydownHandler, !1), S.extend(he.prototype, {add: function(e, t) {return f(this, e, t, {factoryArgs: Array.prototype.slice.call(arguments, 2)})},addColor: function(e, t) {return f(this, e, t, {color: !0})},remove: function(e) {this.__ul.removeChild(e.__li), this.__controllers.splice(this.__controllers.indexOf(e), 1);var t = this;S.defer(function() {t.onResize()})},destroy: function() {if (this.parent) throw new Error("Only the root GUI should be removed with .destroy(). For subfolders, use gui.removeFolder(folder) instead.");this.autoPlace && ce.removeChild(this.domElement);var e = this;S.each(this.__folders, function(t) {e.removeFolder(t)}), X.unbind(window, "keydown", he._keydownHandler, !1), u(this)},addFolder: function(e) {if (void 0 !== this.__folders[e]) throw new Error('You already have a folder in this GUI by the name "' + e + '"');var t = {name: e,parent: this};t.autoPlace = this.autoPlace, this.load && this.load.folders && this.load.folders[e] && (t.closed = this.load.folders[e].closed, t.load = this.load.folders[e]);var n = new he(t);this.__folders[e] = n;var o = c(this, n.domElement);return X.addClass(o, "folder"), n},removeFolder: function(e) {this.__ul.removeChild(e.domElement.parentElement), delete this.__folders[e.name], this.load && this.load.folders && this.load.folders[e.name] && delete this.load.folders[e.name], u(e);var t = this;S.each(e.__folders, function(t) {e.removeFolder(t)}), S.defer(function() {t.onResize()})},open: function() {this.closed = !1},close: function() {this.closed = !0},hide: function() {this.domElement.style.display = "none"},show: function() {this.domElement.style.display = ""},onResize: function() {var e = this.getRoot();if (e.scrollable) {var t = X.getOffset(e.__ul).top,n = 0;S.each(e.__ul.childNodes, function(t) {e.autoPlace && t === e.__save_row || (n += X.getHeight(t))}), window.innerHeight - t - 20 < n ? (X.addClass(e.domElement, he.CLASS_TOO_TALL),e.__ul.style.height = window.innerHeight - t - 20 + "px") : (X.removeClass(e.domElement, he.CLASS_TOO_TALL), e.__ul.style.height = "auto")}e.__resize_handle && S.defer(function() {e.__resize_handle.style.height = e.__ul.offsetHeight + "px"}), e.__closeButton && (e.__closeButton.style.width = e.width + "px")},onResizeDebounced: S.debounce(function() {this.onResize()}, 50),remember: function() {if (S.isUndefined(le) && ((le = new ie).domElement.innerHTML ='<div id="dg-save" class="dg dialogue">\n\n  Here\'s the new load parameter for your <code>GUI</code>\'s constructor:\n\n  <textarea id="dg-new-constructor"></textarea>\n\n  <div id="dg-save-locally">\n\n    <input id="dg-local-storage" type="checkbox"/> Automatically save\n    values to <code>localStorage</code> on exit.\n\n    <div id="dg-local-explain">The values saved to <code>localStorage</code> will\n      override those passed to <code>dat.GUI</code>\'s constructor. This makes it\n      easier to work incrementally, but <code>localStorage</code> is fragile,\n      and your friends may not see the same values you do.\n\n    </div>\n\n  </div>\n\n</div>'), this.parent) throw new Error("You can only call remember on a top level GUI.");var e = this;S.each(Array.prototype.slice.call(arguments), function(t) {0 === e.__rememberedObjects.length && v(e), -1 === e.__rememberedObjects.indexOf(t) && e.__rememberedObjects.push(t)}), this.autoPlace && w(this, this.width)},getRoot: function() {for (var e = this; e.parent;) e = e.parent;return e},getSaveObject: function() {var e = this.load;return e.closed = this.closed, this.__rememberedObjects.length > 0 && (e.preset = this.preset, e.remembered || (e.remembered = {}), e.remembered[this.preset] = x(this)),e.folders = {}, S.each(this.__folders, function(t, n) {e.folders[n] = t.getSaveObject()}), e},save: function() {this.load.remembered || (this.load.remembered = {}), this.load.remembered[this.preset] = x(this), _(this, !1), this.saveToLocalStorageIfPossible()},saveAs: function(e) {this.load.remembered || (this.load.remembered = {}, this.load.remembered[se] = x(this, !0)),this.load.remembered[e] = x(this), this.preset = e, g(this, e, !0), this.saveToLocalStorageIfPossible()},revert: function(e) {S.each(this.__controllers, function(t) {this.getRoot().load.remembered ? p(e || this.getRoot(), t) : t.setValue(t.initialValue), t.__onFinishChange && t.__onFinishChange.call(t, t.getValue())}, this), S.each(this.__folders, function(e) {e.revert(e)}), e || _(this.getRoot(), !1)},listen: function(e) {var t = 0 === this.__listening.length;this.__listening.push(e), t && C(this.__listening)},updateDisplay: function() {S.each(this.__controllers, function(e) {e.updateDisplay()}), S.each(this.__folders, function(e) {e.updateDisplay()})}});var pe = {Color: I,math: N,interpret: R},fe = {Controller: z,BooleanController: K,OptionController: Y,StringController: J,NumberController: W,NumberControllerBox: Q,NumberControllerSlider: q,FunctionController: Z,ColorController: $},me = {dom: X},ge = {GUI: he},be = he,ve = {color: pe,controllers: fe,dom: me,gui: ge,GUI: be};e.color = pe, e.controllers = fe, e.dom = me, e.gui = ge, e.GUI = be, e.default = ve, Object.defineProperty(e,"__esModule", {value: !0})
});

八、style.css

body {box-sizing: border-box;background:black; margin: 0px;color: white;overflow: hidden;font-family: 'Roboto Mono', monospace;user-select: none;
}#demo {width: 100%; height:100vh;
}#c {width: 100%; height:100%;background:black;touch-action: none;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/25053.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何对stm32查看IO功能。

有些同学对于别人的开发板的资源&#xff0c;或者IO口&#xff0c;或者串口等资源不知道怎么分配。 方法1、看硬石、野火、正点原子的开发板&#xff0c;看下他们的例子&#xff0c;那个资源用什么。自己多看几个原理图&#xff0c;多看几个视频&#xff0c;做一下笔记。以后依…

【面试干货】MySQL 三种锁的级别(表级锁、行级锁和页面锁)

【面试干货】MySQL 三种锁的级别&#xff08;表级锁、行级锁和页面锁&#xff09; 1、表级锁2、行级锁3、页面锁4、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在 MySQL 数据库中&#xff0c;锁是控制并发访问的重要机制&#xff0…

GQA,MLA之外的另一种KV Cache压缩方式:动态内存压缩(DMC)

0x0. 前言 在openreview上看到最近NV的一个KV Cache压缩工作&#xff1a;https://openreview.net/pdf?idtDRYrAkOB7 &#xff0c;感觉思路还是有一些意思的&#xff0c;所以这里就分享一下。 简单来说就是paper提出通过一种特殊的方式continue train一下原始的大模型&#x…

DS:树与二叉树的相关概念

欢迎来到Harper.Lee的学习世界&#xff01;博主主页传送门&#xff1a;Harper.Lee的博客主页想要一起进步的uu可以来后台找我哦&#xff01; 一、树的概念及其结构 1.1 树的概念亲缘关系 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限节点…

汇编:数组-寻址取数据

比例因子寻址&#xff1a; 比例因子寻址&#xff08;也称为比例缩放索引寻址或基址加变址加比例因子寻址&#xff09;是一种复杂的内存寻址方式&#xff0c;常用于数组和指针操作。它允许通过一个基址寄存器、一个变址寄存器和一个比例因子来计算内存地址。 语法 比例因子寻…

经典文献阅读之--Online Monocular Lane Mapping(使用Catmull-Rom样条曲线完成在线单目车道建图)

0. 简介 对于单目摄像头完成SLAM建图这类操作&#xff0c;对于自动驾驶行业非常重要&#xff0c;《Online Monocular Lane Mapping Using Catmull-Rom Spline》介绍了一种仅依靠单个摄像头和里程计生成基于样条的在线单目车道建图方法。我们提出的技术将车道关联过程建模为一个…

Java 习题集

&#x1f496; 单选题 &#x1f496; 填空题 &#x1f496; 判断题 &#x1f496; 程序阅读题 1. 读代码写结果 class A {int m 5;void zengA(int x){m m x;}int jianA(int y){return m - y;} }class B extends A {int m 3;int jianA(int z){return super.jianA(z) m;} …

Java Web学习笔记20——Ajax-Axios

Axios&#xff1a; 介绍&#xff1a;Axios对原生的Ajax进行封装&#xff0c;简化书写&#xff0c;快速开发。 官网&#xff1a;https://www.axios-http.cn Axios 入门&#xff1a; {}是Js的对象。 get的请求参数是在URL后面&#xff1f;和相关参数值。 post的请求参数是在请…

Soildworks学习笔记(二)

放样凸台基体&#xff1a; 自动生成连接两个物体两个面的基体&#xff1a; 2.旋转切除&#xff1a; 3.剪切实体&#xff1a; 4.转换实体引用&#xff1a; 将实体的轮廓线转换至当前草图使其成为当前草图的图元,主要用于在同一平面或另一个坐标中制作草图实体或其尺寸的副本。 …

【深度学习】Transformer分类器,CICIDS2017,入侵检测

文章目录 1 前言2 什么是入侵检测系统&#xff1f;3 为什么选择Transformer&#xff1f;4 数据预处理5 模型架构5.1. 输入嵌入层&#xff08;Input Embedding Layer&#xff09;5.2. 位置编码层&#xff08;Positional Encoding Layer&#xff09;5.3. Transformer编码器层&…

MySQL—多表查询—子查询(介绍)

一、引言 上一篇博客学习完联合查询。 这篇开始&#xff0c;就来到多表查询的最后一种形式语法块——子查询。 &#xff08;1&#xff09;概念 SQL 语句中嵌套 SELECT 语句&#xff0c;那么内部的 select 称为嵌套查询&#xff0c;又称子查询。 表现形式 注意&#xff1a; …

复数的概念

1. 虚数单位&#xff1a;i 引入一个新数 ‘i’&#xff0c;i又叫做虚数单位&#xff0c;并规定&#xff1a; 它的平方等于 -1&#xff0c;即 i -1。实数可以与它进行四则运算&#xff0c;并且原有的加&#xff0c;乘运算律依然成立。 2.定义 复数的定义&#xff1a;形如 a…

CTFHUB-SQL注入-字符型注入

目录 查询数据库名 查询数据库中的表名 查询表中数据 总结 此题目和上一题相似&#xff0c;一个是整数型注入&#xff0c;一个是字符型注入。字符型注入就是注入字符串参数&#xff0c;判断回显是否存在注入漏洞。因为上一题使用手工注入查看题目 flag &#xff0c;这里就不…

GIS数据快捷共享发布工具及操作视频

有网友反映还是不会操作GIS数据快捷共享发布工具&#xff08;建立自己的地图网站&#xff09;&#xff0c;要我录个视频。 好&#xff0c;那就录一个: GIS数据快捷共享发布工具及操作视频 虽然默认例子是二维的&#xff0c;但这个服务器可以为二维、三维系统发布时间服务。都是…

NASA数据集——SARAL 近实时增值业务地球物理数据记录海面高度异常

SARAL Near-Real-Time Value-added Operational Geophysical Data Record Sea Surface Height Anomaly SARAL 近实时增值业务地球物理数据记录海面高度异常 简介 2020 年 3 月 18 日至今 ALTIKA_SARAL_L2_OST_XOGDR 这些数据是近实时&#xff08;NRT&#xff09;&#xff…

SpringCloudAlibaba基础二 Nacos注册中心

一 什么是 Nacos 官方&#xff1a;一个更易于构建云原生应用的动态服务发现(Nacos Discovery )、服务配置(Nacos Config)和服务管理平台。 集 注册中心配置中心服务管理 平台。 Nacos 的关键特性包括: 服务发现和服务健康监测动态配置服务动态 DNS 服务服务及其元数据管理 …

达梦8 探寻达梦排序原理:新排序机制(SORT_FLAG=1)

测试版本&#xff1a;--03134283938-20221019-172201-20018 达梦的排序机制由四个dm.ini参数控制&#xff1a; #maximum sort buffer size in Megabytes &#xff0c;有效值范围&#xff08;1~2048&#xff09; SORT_BUF_SIZE 100 #ma…

mysql数据库打开失败的问题

打不开mysql 1. my.ini未配置路径&#xff1a;找到basedir和datadir&#xff0c;改成如下路径。改完记得去掉井号 &#xff01;&#xff01; 复制路径粘贴&#xff0c;记得去掉井号 &#xff01;&#xff01; 启动&#xff01;方式1 发生系统错误5&#xff1a;没有用管理员身…

Android Media Framework(三)OpenMAX API阅读与分析

这篇文章我们将聚焦Control API的功能与用法&#xff0c;为实现OMX Core、Component打下坚实的基础。 1、OMX_Core.h OMX Core在OpenMAX IL架构中的位置位于IL Client与实际的OMX组件之间&#xff0c;OMX Core提供了两组API给IL Client使用&#xff0c;一组API用于管理OMX组件…

数据库 | 关系数据库设计

第七章 1.简述数据库的设计阶段&#xff1f;&#xff08;简要回答数据库设计步骤&#xff1f;&#xff09;&#xff08;&#xff08;数据库设计有哪几个阶段&#xff1f;&#xff09; 需求分析、概念结构设计、逻辑结构设计、物理结构设计、数据库的实施、数据库的运行和维护…