当前位置: 首页 > news >正文

用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;
}

相关文章:

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

文章目录 前言一、示例二、目录结构三、index.html&#xff08;主页面&#xff09;四、main.js五、Tour4D.js六、swissgl.js七、dat.gui.min.js八、style.css 前言 如果你觉得对代码进行复制粘贴很麻烦的话&#xff0c;你可以直接将资源下载到本地。无需部署&#xff0c;直接可…...

java调用GDAL及JTS实现生成泰森多边形(Voronoi图)的一种方法

目录 一、关于泰森多边形 1.泰森多边形的特性 2.本文的目的 二、实现思路 1.gdal和jts库的maven坐标 2.jts生成泰森多边形的关键代码 3.使用GDAL读取源文件信息的关键代码 4.使用GDAL将生成的泰森多边形写入文件 三、实现结果 1.实现的效果 2.完整代码示例 一、关于…...

Type-C音频转接器方案

在数字化时代&#xff0c;音频设备作为我们生活中不可或缺的一部分&#xff0c;其连接方式的便捷性和高效性显得尤为重要。Type-C音频转接器&#xff0c;作为一种新型的音频连接解决方案&#xff0c;正逐渐走进我们的生活&#xff0c;以其独特的优势改变着我们的音频体验。 一、…...

linux 服务器上离线安装 node nvm

因为是离线环境 如果你是可以访问外网的 下面内容仅供参考 也可以继续按步骤来 node 安装路径 Node.js — Download Node.js nvm 安装路径 Tags nvm-sh/nvm GitHub 后来发现 nvm安装后 nvm use 版本号 报错 让我去nvm install 版本 我是内网环境 install不了 下面 你要 把安…...

Web前端三大主流框架:React、Angular和Vue的比较与选择

Web前端三大主流框架&#xff1a;React、Angular和Vue的比较与选择 Web前端技术的快速发展为开发者提供了丰富的工具和框架&#xff0c;其中React、Angular和Vue是当前最受欢迎的三大框架。这三个框架各有特点&#xff0c;适用于不同的项目需求和开发团队。本文将对React、Ang…...

C# MemoryCache 缓存应用

摘要 缓存是一种非常常见的性能优化技术&#xff0c;在开发过程中经常会用到。.NET提供了内置的内存缓存类 MemoryCache&#xff0c;它可以很方便地存储数据并在后续的请求中快速读取&#xff0c;从而提高应用程序的响应速度。 正文 通过使用 Microsoft.Extensions.Caching.Me…...

【学习笔记】Linux前置准备

视频学习资料 基础&#xff1a; 黑马0基础&#xff08;前面四章即可&#xff0c;包含软件基础安装配置&#xff09; 进阶&#xff1a; 黑马程序员-Linux系统编程 黑马程序员-Linux网络编程 我也还没看&#xff0c;看了眼目录感觉把八股里面很多场景都讲到了&#xff0c;感觉有…...

各种空气能热泵安装图

空气能热泵安装图 循环式空气能热泵安装图 直热循环式空气能热泵安装图 泳池空气能热泵安装图 循环式水源热泵热安装系统原理图 直热循环式水源热泵安装系统图 空气水源热泵安装图...

软件杯 题目:基于深度学习的中文对话问答机器人

文章目录 0 简介1 项目架构2 项目的主要过程2.1 数据清洗、预处理2.2 分桶2.3 训练 3 项目的整体结构4 重要的API4.1 LSTM cells部分&#xff1a;4.2 损失函数&#xff1a;4.3 搭建seq2seq框架&#xff1a;4.4 测试部分&#xff1a;4.5 评价NLP测试效果&#xff1a;4.6 梯度截断…...

UI学习笔记(一)

UI学习 一&#xff1a;UIView基础frame属性隐藏视图对象&#xff1a;UIView的层级关系 二&#xff1a;UIWindow对象三&#xff1a;UIViewController基础UIViewController使用 四&#xff1a;定时器与视图移动五&#xff1a;UISwitch控件六&#xff1a;滑动条和进度条七&#xf…...

【C语言训练题库】扫雷->简单小游戏!

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 目录 1. 题目 2. 解析 3. 代码 4. 小结 1. 题目 小sun上课的时候非常喜欢玩扫雷。他现小sun有一个初始的雷矩阵&#xff0c;他希望你帮他生成一个扫雷矩阵。 扫雷…...

WMS仓储管理系统高效驱动制造企业物料管理

在现代制造业的快速发展中&#xff0c;仓储管理作为供应链的核心环节&#xff0c;其效率直接影响到企业的生产力和市场竞争力。随着科技的进步&#xff0c;实施WMS仓储管理系统逐渐成为推动仓储管理向智能化转型的关键力量。本文将深入探讨WMS仓储管理系统如何以创新的方式驱动…...

python使用appium打开程序后,为什么没有操作后程序就自动退出了

当使用Appium打开应用程序并在没有执行任何操作后它自动退出&#xff0c;这可能是由于几个不同的原因。以下是一些可能的原因和相应的解决方案&#xff1a; 应用程序的默认行为&#xff1a; 有些应用程序在启动后如果没有用户交互&#xff0c;可能会因为超时或其他逻辑而自动关…...

MacBook M系列芯片安装php8.2

适用于M1\M2\M3等系列的MacBook&#xff0c;记录下安装过程 安装brew 打开终端&#xff0c;执行如下命令&#xff1a; /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"安装zsh&#xff08;非必须&#xff09; …...

OlSoul系统调校程序v2024.06.05

软件介绍 OlSoul是一款能够适配用于Win各个系统的系统调校软件&#xff0c;OlSoul内置有众多调校功能可以直接使用&#xff0c;如有启用无线网络功能、启用打印机功能、系统快速休眠与休眠开关、快捷方式小箭头去除功能等&#xff0c;具体的调校功能多达几十项&#xff0c;可自…...

图像特征提取 python

1. 边缘检测 (Edge Detection) 1.1 Sobel 算子 Sobel 算子是一种边缘检测算子&#xff0c;通过计算图像梯度来检测边缘。 import cv2 import numpy as np# 读取图像 image cv2.imread(image.jpg, 0)# 应用 Sobel 算子 sobel_x cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize5)…...

width: 100%和 width: 100vw这两种写法有什么区别

width: 100%; 和 width: 100vw; 是两种不同的 CSS 写法&#xff0c;它们在实际应用中会有不同的效果。以下是这两种写法的主要区别&#xff1a; width: 100%; 定义&#xff1a;将元素的宽度设置为其包含块&#xff08;通常是父元素&#xff09;宽度的 100%。效果&#xff1a;元…...

如何在另一台电脑上使用相同的Python环境和依赖包

如果您想在另一台电脑上使用相同的Python环境和依赖包&#xff0c;有几种方法可以实现&#xff1a; 使用requirements.txt&#xff1a; 在您当前的虚拟环境中&#xff0c;您可以使用pip freeze > requirements.txt命令生成一个包含所有已安装包及其版本的文件。然后&#x…...

Vue3 响应式 API:工具函数(一)

isRef() isRef 是一个简单的工具函数&#xff0c;它接受一个参数并返回一个布尔值&#xff0c;指示该参数是否是一个由 ref 创建的响应式引用。 在某些情况下&#xff0c;你可能需要编写一些通用逻辑或函数&#xff0c;这些逻辑或函数需要处理不同类型的响应式数据&#xff08…...

开发常用软件

开发相关 代码编译 Visual Studio 2019 Visual Studio 2022 代码测试工具 LINQPad Premium 5 LINQPad 7 打包工具 Advanced Installer 反编译工具 ILSpy dnSpy spy 数据库相关 SQLite Expert Professional 5 DLL扫描工具 depends 界面设计 SvgToXaml Materi…...

conntrack如何限制您的k8s网关

1.1 conntrack 介绍 对于那些不熟悉的人来说,conntrack简单来说是Linux内核的一个子系统,它跟踪所有进入、出去或通过系统的网络连接,允许它监控和管理每个连接的状态,这对于诸如NAT(网络地址转换)、防火墙和保持会话连续性等任务至关重要。它作为Netfilter的一部分运行,…...

SwiftUI六组合复杂用户界面

代码下载 应用的首页是一个纵向滚动的地标类别列表&#xff0c;每一个类别内部是一个横向滑动列表。随后将构建应用的页面导航&#xff0c;这个过程中可以学习到如果组合各种视图&#xff0c;并让它们适配不同的设备尺寸和设备方向。 下载起步项目并跟着本篇教程一步步实践&a…...

高考分数查询结果自动推送至微信

又是一年高考时&#xff0c;祝各位学子金榜题名&#xff0c;天遂人愿! 在您阅读以下内容时&#xff0c;请注意&#xff1a;各省查分API接口可能不相同&#xff0c;本人仅就技术层面谈谈&#xff0c; 纯属无聊&#xff0c;因为实用意义不大&#xff0c;毕竟一年一次&#xff0c;…...

flask_sqlalchemy时间缓存导致datetime.now()时间不变问题

问题是这样的&#xff0c;项目在本地没什么问题&#xff0c;但是部署到服务器过一阵子发现&#xff0c;这个时间会在某一刻定死不变。 重启uwsgi后&#xff0c;发现第一条数据更新到了目前最新时间&#xff0c;过了一会儿再次发送也变了时间&#xff0c;但是再过几分钟再发就会…...

使用 PAI-DSW x Free Prompt Editing图像编辑算法,开发个人AIGC绘图小助理

教程简述 在本教程中&#xff0c;您将学习在阿里云交互式建模平台PAI-DSW x Free Prompt Editing&#xff08;CVPR2024中选论文算法&#xff09;图像编辑算法&#xff0c;开发个人AIGC绘图小助理&#xff0c;实现文本驱动的图像编辑功能单卡即可完成AIGC图片风格变化、背景变化…...

Nginx03-动态资源和LNMP介绍与实验、自动索引模块、基础认证模块、状态模块

目录 写在前面Nginx03案例1 模拟视频下载网站自动索引autoindex基础认证auth_basic模块状态stub_status模块模块小结 案例2 动态网站&#xff08;部署php代码&#xff09;概述常见的动态网站的架构LNMP架构流程数据库Mariadb安装安全配置基本操作 PHP安装php修改配置文件 Nginx…...

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(二十九)- 微服务(9)

目录 12. ElastisSearch 12.1 安装es 12.2 部署kibana 12.2.1 部署 12.2. 2 DevTools 12.3 索引库操作 12.3.1 mapping映射 12.3.2 创建索引库 12.3.3 查询索引库 12.3.4 删除索引库 12.3.5 修改索引库 12.4 文档操作 12.4.1 新增文档 12.4.2 查询文档 12.4.3 删…...

Matplotlib常见图汇总

Matplotlib是python的一个画图库&#xff0c;便于数据可视化。 安装命令 pip install matplotlib 常用命令&#xff1a; 绘制直线&#xff0c;连接两个点 import matplotlib.pyplot as plt plt.plot([0,5],[2,4]) plt.show() 运行结果如下&#xff1a; 多条线&#xff1a;…...

MTK联发科MT6897(天玑8300)5G智能移动处理器规格参数

天玑 8300 采用台积电第二代 4nm 制程&#xff0c;基于 Armv9 CPU 架构&#xff0c;八核 CPU 包含 4 个 Cortex-A715 性能核心和 4 个 Cortex-A510 能效核心&#xff0c;CPU 峰值性能较上一代提升 20%&#xff0c;功耗节省 30%。 此外&#xff0c;天玑 8300 搭载 6 核 GPU Mal…...

【AIoT-Robot】3d hand pose

手语是聋哑人士的主要沟通工具,它是利用手部和身体的动作来传达意义。虽然手语帮助它的使用者之间互相沟通,但聋哑人士与一般人的沟通却十分困难,这个沟通障碍是源于大部分人不懂得手语。 1. 手势&&手语 手势:手的姿势 ,通常称作手势。它指的是人在运用手臂时,所…...

网站开发需求方案模板/电脑培训班价目表

正则表达式 正则表达式&#xff0c;是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里&#xff0c;正则表达式通常被用来检索、替换那些符合某个模式的文本。 如在注册时需要输入一个邮箱的地址或者手机号码…...

深圳网站制作哪家专业/网站app免费生成软件

UbuntuForumWikiLinuxPasteChat搜索 頁面討論編輯歷史简体繁体導航 首頁最近更改隨機頁面页面分类幫助编辑 编辑指南沙盒現時事件字词处理工具箱 鏈入頁面鏈出更改所有特殊頁面個人工具 登入SubVersion 目錄 [隱藏]1 SubVersion服務安裝設置 1.1 簡介1.2 假設1.3 本文涉及的範…...

鳌江网站建设/东莞seo网络培训

http://blog.csdn.net/u010509774/article/details/50593231一、rpm包安装方式步骤&#xff1a;1、找到相应的软件包&#xff0c;比如soft.version.rpm&#xff0c;下载到本机某个目录&#xff1b;2、打开一个终端&#xff0c;su -成root用户&#xff1b;3、cd soft.version.rp…...

金钟街网站建设哪家好/武汉seo顾问

图像处理中&#xff0c;有很多算法由于其内在的复杂性是天然的耗时大户&#xff0c;加之图像本身蕴涵的数据量比一般的对象就大&#xff0c;因此&#xff0c;针对这类算法&#xff0c;执行速度的提在很大程度上依赖于硬件的性能&#xff0c;现在流行的CPU都是至少2核的&#xf…...

门户网站盈利模式/苏州疫情最新情况

1.字符串格式化&#xff0c;用sprintf如asprintf(%.2f_除以%d等于%.3f,1.5,2,0.75)%则a1.50除以2等于0.750 2.for循环只能针对整数&#xff0c;不能遍历字符串或其他类型 3.公用的全局变量在各个使用的.m文件中都要声明。 4.一个.m文件若包含X为函数&#xff0c;则文件名必须为…...

域名注册网站推荐/如何制作网页链接教程

分词的重要性对于一个搜索引擎来说是相当重要的&#xff0c;英文的分词相对简单&#xff0c;因为英文的每个单词都具有天然的分隔符&#xff0c;但当遇到中文时&#xff0c;就显得无能为力了。 中文是世界上最复杂的语言之一&#xff0c;不同的字在不同的词语中可能代表不同的意…...