用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 running
        this.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 images
    genPreviews() {
        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 compatibility

const 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_Position
    layout(location = 0) in int VertexID;
    layout(location = 1) in int InstanceID;
    ivec2 VID;
    ivec3 ID;
#else
    #define varying in
    layout(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;
#endif

uniform 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_InstanceID


 GLSL 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 FRAG
    float 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 active
		const {
			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_ELEMENT
			gl.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_readback
	read(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 deleted
			gl.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 arrays
	if (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 target
	if (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) target
	const 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 program
	if (!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 options
	if (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, Aspect
	gl.viewport(...view)
	const width = view[2],
		height = view[3];
	uniforms.View = view;
	uniforms.Aspect = calcAspect(options.Aspect, width, height);

	// Grid, Mesh
	const [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 textures
	Object.entries(prog.setters).forEach(([name, f]) => f(uniforms[name]));
	// draw
	gl.drawArraysInstanced(gl.TRIANGLE_STRIP, 0, vertN, instN);

	// revert gl state
	if (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
				} else
					for (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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

5.31.15 使用图像到图像转换和 YOLO 技术对先前的乳房 X 光检查结果中的异常进行早期检测和分类

在本研究中&#xff0c;我们研究了基于 You-Only-Look-Once (YOLO) 架构的端到端融合模型的有效性&#xff0c;该模型可同时检测和分类数字乳房 X 光检查中的可疑乳腺病变。包括四类病例&#xff1a;肿块、钙化、结构扭曲和正常&#xff0c;这些病例来自包含 413 个病例的私人数…

JavaEE初阶---多线程编程(一.线程与进程)

目录 &#x1f923;一.线程与进程的概念与联系&#xff1a; 进程的基本概念&#xff1a; 线程的基本概念&#xff1a; 进程和线程的区别与联系&#xff1a; &#x1f643;代码执行实列&#xff1a; 1.通过继承Thread父类来实现多线程 2.通过实现Runnable接口来实现多线程…

【C语言题解】1、写一个宏来计算结构体中某成员相对于首地址的偏移量;2、写一个宏来交换一个整数二进制的奇偶位

&#x1f970;欢迎关注 轻松拿捏C语言系列&#xff0c;来和 小哇 一起进步&#xff01;✊ &#x1f308;感谢大家的阅读、点赞、收藏和关注 &#x1f495;希望大家喜欢我本次的讲解&#x1f495; 目录&#x1f451; 1、写一个宏&#xff0c;计算结构体中某变量相对于首地址的偏…

拼多多第37期:拼多多单品裂变起爆2.0(17节课)

课程下载&#xff1a;拼多多第37期&#xff1a;拼多多单品裂变起爆2.0&#xff08;17节课&#xff09;-课程网盘链接提取码下载.txt资源-CSDN文库 更多资源下载&#xff1a;关注我。 课程内容&#xff1a; 01.《拼多多单品裂变起爆2.0》非标品类成功操作案例.mp4 02.《拼多…

在Windows上用Llama Factory微调Llama 3的基本操作

这篇博客参考了一些文章&#xff0c;例如&#xff1a;教程&#xff1a;利用LLaMA_Factory微调llama3:8b大模型_llama3模型微调保存-CSDN博客 也可以参考Llama Factory的Readme&#xff1a;GitHub - hiyouga/LLaMA-Factory: Unify Efficient Fine-Tuning of 100 LLMsUnify Effi…

Spring Security系列之Handler

概述 与Spring、Spring MVC、Spring Boot一样&#xff0c;Spring Security里也有很多Handler接口、可以分为两大类&#xff0c;一类是普通的XxxHandler&#xff08;见名知意&#xff09;&#xff0c;另一类是对应的ServerXxxHandler&#xff08;RequestRejectedHandler除外&am…

【ArcGIS微课1000例】0119:TIFF与grid格式互相转换

文章目录 一、任务描述二、tiff转grid三、grid转tif四、注意事项一、任务描述 地理栅格数据常用TIFF格式和GRID格式进行存储。TIFF格式的栅格数据常以单文件形式存储,不仅存储有R、G、B三波段的像素值,还保存有地理坐标信息。GRID格式的栅格数据常以多文件的形式进行存储,且…

ElasticSearch学习笔记之三:Logstash数据分析

第3章 Logstash数据分析 Logstash使用管道方式进行日志的搜集处理和输出。有点类似*NIX系统的管道命令 xxx | ccc | ddd&#xff0c;xxx执行完了会执行ccc&#xff0c;然后执行ddd。 在logstash中&#xff0c;包括了三个阶段: 输入input --> 处理filter&#xff08;不是必须…

【MMU】——ARM 二级页表

文章目录 二级页表项即 entry 的格式如下 二级页表项有三种类型 产生中止异常的故障条目。这可能是预取或数据中止、取决于访问类型。这实际上表示虚拟地址未映射 bit[1:0] 00大页 64KB。bit[1:0] 01。小页 4KB。bit[1:0]1x。 一级页表占用 16KB 的内存&#xff0c;二级页表…

Fastgpt接入Whisper本地模型实现语音输入

前言 FastGPT 默认使用了 OpenAI 的 LLM 模型和语音识别模型,如果想要私有化部署的话,可以使用openai 开源模型Whisper。参考文章 《openai 开源模型Whisper语音转文本模型下载使用》 开源项目地址 : 兼容openai接口api服务 https://gitee.com/taisan/whisper-api 设置安…

glm-4v-9b 部署

glm-4v-9b 模型文件地址 GLM-4 仓库文件地址 官方测试 硬件配置和系统要求 官方测试硬件信息: OS: Ubuntu 22.04Memory: 512G…

【Mac】Media Encoder 2022 for Mac(媒体编码器)V22.6.1软件介绍

软件介绍 Media Encoder 2022 for Mac是一款有着十分丰富硬件设备的编码格式设置和专门设计的预设设置功能的媒体编码器软件&#xff0c;Media Encoder Mac版能够帮助用户导出与特定交付媒体兼容的文件&#xff0c;可以很容易地将项目导出到任何屏幕上的可播放内容中。软件同时…

4.通用编程概念

目录 一、变量与常量1.1 变量1.2 常量 二、遮蔽三、数据类型3.1 标量类型1. 整型2. 浮点型3. 布尔类型4.字符类型 3.2 复合类型1. 元组2. 数组 四、函数五、语句和表达式六、函数的返回值 一、变量与常量 1.1 变量 在Rust中默认的变量是不可变的&#xff0c;如果修改其值会导致…

帮助手册到底是什么?怎么制作?

在当今竞争激烈的商业环境中&#xff0c;提供卓越的客户服务已成为企业脱颖而出的关键。而一个优质的帮助手册&#xff0c;不仅可以帮助企业提高客户服务质量&#xff0c;还能够降低客服成本&#xff0c;提升客户满意度。本文将探讨帮助手册的重要性以及如何利用它来提升企业的…

学习VUE3——组件(二)

组件插槽slots 插槽内容与出口 在某些场景中&#xff0c;我们可能想要为子组件传递一些模板片段&#xff0c;让子组件在它们的组件中渲染这些片段。这时就需要用到插槽。 如下例所示&#xff1a; <!-- Parent.vue --> <FancyButton>Click me! <!-- 插槽内容…

conntrack如何限制您的k8s网关

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

如何开发一 VSCode 插件

如何开发一个 VSCode 插件&#xff0c;本文开发一个 VSCode “Hello World” 插件&#xff0c;通过代码了解 VSCode 插件是如何工作的。 安装脚手架 npx --package yo --package generator-code -- yo code根据提示选择&#xff0c;插件开发语言选择 TypeScript ? What type…

网络编程: reactor模式的步步探索与实现

网络编程: reactor模式的步步探索与实现 一.步步探索1.先看一下之前的BUG的影响2.解决拼接式读取问题3.进一步的探索4.Connection的提出5.EpollServer的修改并将监听套接字添加进去6.小演示 二.协议与业务登场1.协议,业务,解决粘包,序列反序列化等等的函数模块实现2.读写异常事…

mac环境基于llama3和metaGPT自动开发2048游戏

1.准备虚拟环境 conda create -n metagpt python3.9 && conda activate metagpt 2.安装metagpt pip install --upgrade metagpt 3.初始化配置文件 metagpt --init-config 4. 安装llama3 5. 修改配置文件 6.让metegpt自动开发2048游戏 7.经过多轮迭代&#xff0c;最终…

彩虹外链网盘图床文件外链系统源码v5.5

彩虹外链网盘&#xff0c;是一款PHP网盘与外链分享程序&#xff0c;支持所有格式文件的上传&#xff0c;可以生成文件外链、图片外链、音乐视频外链&#xff0c;生成外链同时自动生成相应的UBB代码和HTML代码&#xff0c;还可支持文本、图片、音乐、视频在线预览&#xff0c;这…