aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xp/cgxp/1.html14
-rw-r--r--xp/cgxp/2.html14
-rw-r--r--xp/cgxp/main1.js320
-rw-r--r--xp/cgxp/main2.js280
-rw-r--r--xp/cgxp/wglmath.js102
-rw-r--r--xp/vco/.htaccess5
-rw-r--r--xp/vco/LICENSE116
-rw-r--r--xp/vco/README.md4
-rw-r--r--xp/vco/app-icons/icon-128.pngbin0 -> 3953 bytes
-rw-r--r--xp/vco/app-icons/icon-16.pngbin0 -> 48386 bytes
-rw-r--r--xp/vco/app-icons/icon-60.pngbin0 -> 1843 bytes
-rw-r--r--xp/vco/favicon.icobin0 -> 1150 bytes
-rw-r--r--xp/vco/index.html23
-rw-r--r--xp/vco/manifest.webapp18
-rw-r--r--xp/vco/scripts/app.js129
-rw-r--r--xp/vco/scripts/install.js37
-rw-r--r--xp/vco/scripts/respond.js6
-rw-r--r--xp/vco/styles/app.css205
-rw-r--r--xp/vco/styles/install-button.css20
-rw-r--r--xp/vco/styles/normalize.css406
20 files changed, 1699 insertions, 0 deletions
diff --git a/xp/cgxp/1.html b/xp/cgxp/1.html
new file mode 100644
index 0000000..b05e78f
--- /dev/null
+++ b/xp/cgxp/1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>CGxp1</title>
+<link rel="icon" href="/favicon.png">
+<link rel="stylesheet" type="text/css" href="/common.css">
+<script type="text/javascript" src="main1.js"></script>
+<script type="text/javascript" src="wglmath.js"></script>
+</head>
+<body onload="init();" style="margin:0;">
+<canvas id="glCvs" width="800" height="450" style=""></canvas>
+</body>
+</html>
diff --git a/xp/cgxp/2.html b/xp/cgxp/2.html
new file mode 100644
index 0000000..880c0cb
--- /dev/null
+++ b/xp/cgxp/2.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>CGxp2</title>
+<link rel="icon" href="/favicon.png">
+<link rel="stylesheet" type="text/css" href="/common.css">
+<script type="text/javascript" src="main2.js"></script>
+<script type="text/javascript" src="wglmath.js"></script>
+</head>
+<body onload="init();" style="margin:0;">
+<canvas id="glCvs" width="800" height="450" style=""></canvas>
+</body>
+</html>
diff --git a/xp/cgxp/main1.js b/xp/cgxp/main1.js
new file mode 100644
index 0000000..bd52e13
--- /dev/null
+++ b/xp/cgxp/main1.js
@@ -0,0 +1,320 @@
+//Copyright Chris Xiong 2018
+//License: Expat (MIT)
+var cvs,WGL,vpw,vph,hdiv;
+var fsh=`
+varying lowp vec4 vC;
+void main(void)
+{
+ gl_FragColor=vC;
+}`;
+var vsh=`
+attribute vec3 vp;
+attribute vec4 vc;
+uniform mat4 mmodelview;
+uniform mat4 mprojection;
+varying lowp vec4 vC;
+void main(void)
+{
+ gl_Position=mprojection*mmodelview*vec4(vp,1.);
+ vC=vc;
+}`;
+var shp;
+var vbufsize=4096;
+var vbo,ibo;
+var vb=new Float32Array(vbufsize*7);
+var ib=new Uint16Array(vbufsize*6/4);
+var Mprojection,Mmodelview;
+var primc;
+var kst=[];
+var dbc,mbtn,mup,mdn,mx,my,mox,moy;
+var shapes=[];
+var curshape=null;
+var dragging=false,drg;
+
+var Shape=function(t)
+{
+ this.type=t;
+ this.vert=[];
+}
+function copyshape(s)
+{
+ var r=new Shape(s.type);
+ for(var i=0;i<s.vert.length;++i)
+ r.vert.push(new v3d(s.vert[i].x,s.vert[i].y,s.vert[i].z));
+ return r;
+}
+Shape.prototype.draw=function(a,r,g,b)
+{
+ var drawseg=function(a,b,c,d,aa,rr,gg,bb)
+ {
+ var pa=new v3d(a,b,0);
+ var pb=new v3d(c,d,0);
+ var d=pb.subtract(pa);
+ var pd1=new v3d(-d.y,d.x,0),pd2=new v3d(d.y,-d.x,0);
+ pd1=pd1.n();pd2=pd2.n();
+ var p1=pa.add(pd1),p2=pa.add(pd2);
+ var p3=pb.add(pd2),p4=pb.add(pd1);
+ var q=[];
+ q.push(p1.x);q.push(vph-p1.y);q.push(p1.z);
+ q.push(rr);q.push(gg);q.push(bb);q.push(aa);
+ q.push(p2.x);q.push(vph-p2.y);q.push(p2.z);
+ q.push(rr);q.push(gg);q.push(bb);q.push(aa);
+ q.push(p3.x);q.push(vph-p3.y);q.push(p3.z);
+ q.push(rr);q.push(gg);q.push(bb);q.push(aa);
+ q.push(p4.x);q.push(vph-p4.y);q.push(p4.z);
+ q.push(rr);q.push(gg);q.push(bb);q.push(aa);
+ pushQuad(q);
+ }
+ if(this.type=='segment')
+ drawseg(this.vert[0].x,this.vert[0].y,this.vert[1].x,this.vert[1].y,
+ a,r,g,b);
+ if(this.type=='segstrip'||this.type=='segloop')
+ {
+ for(var i=0;i<this.vert.length-1;++i)
+ drawseg(this.vert[i].x,this.vert[i].y,this.vert[i+1].x,this.vert[i+1].y,
+ a,r,g,b);
+ if(this.type=='segloop')
+ {
+ var i=this.vert.length-1;
+ drawseg(this.vert[i].x,this.vert[i].y,this.vert[0].x,this.vert[0].y,
+ a,r,g,b);
+ }
+ }
+}
+Shape.prototype.coltest=function(x,y)
+{
+ var dp2s=function(x,y,_a,_b,_c,_d)
+ {
+ var a=new v3d(_a,_b,0);
+ var b=new v3d(_c,_d,0);
+ var p=new v3d(x,y,0);
+ var ab=b.subtract(a);
+ var ap=p.subtract(a);
+ var pl=ab.dot(ap)/ab.l();
+ var pp=a.add(ab.n().ms(pl));
+ if(pl<0||pl>ab.l())pp=new v3d(1e9,1e9,1e9);
+ return Math.min(p.subtract(pp).l(),p.subtract(a).l(),p.subtract(b).l());
+ }
+ if(this.type=='segment')
+ {
+ var d=dp2s(x,y,this.vert[0].x,this.vert[0].y,
+ this.vert[1].x,this.vert[1].y);
+ if(d<5)return true;
+ }
+ if(this.type=='segstrip'||this.type=="segloop")
+ {
+ for(var i=0;i<this.vert.length-1;++i)
+ {
+ var d=dp2s(x,y,this.vert[i].x,this.vert[i].y,
+ this.vert[i+1].x,this.vert[i+1].y);
+ if(d<5)return true;
+ }
+ if(this.type=="segloop")
+ {
+ var i=this.vert.length-1;
+ var d=dp2s(x,y,this.vert[i].x,this.vert[i].y,
+ this.vert[0].x,this.vert[0].y);
+ if(d<5)return true;
+ }
+ }
+ return false;
+}
+
+function createShader(sh,t)
+{
+ var shader=WGL.createShader(t);
+ WGL.shaderSource(shader,sh);
+ WGL.compileShader(shader);
+ if(!WGL.getShaderParameter(shader,WGL.COMPILE_STATUS))
+ {
+ alert("shader error..."+WGL.getShaderInfoLog(shader));
+ return null;
+ }
+ return shader;
+}
+function pushQuad(a)
+{
+ if(primc>=vbufsize/4)batchGL();
+ for(var i=0;i<4;++i)
+ for(var j=0;j<7;++j)vb[primc*7*4+i*7+j]=a[i*7+j];
+ ++primc;
+}
+
+function init()
+{
+ cvs=document.getElementById("glCvs");
+ if(!window.devicePixelRatio)window.devicePixelRatio=1;
+ cvs.width=window.innerWidth;
+ cvs.height=window.innerHeight;
+ cvs.style.width=cvs.width+"px";
+ cvs.style.height=cvs.height+"px";
+ cvs.width=cvs.width*window.devicePixelRatio;
+ cvs.height=cvs.height*window.devicePixelRatio;
+ vpw=cvs.width;vph=cvs.height;
+ try
+ {WGL=cvs.getContext("webgl")||cvs.getContext("experimental-webgl");}
+ catch(e){WGL=null;}
+ if(!WGL){alert("WebGL is not supported by your browser...");return;}
+
+ WGL.clearColor(0.5,0.5,0.5,1.0);
+ WGL.clearDepth(1);
+ WGL.enable(WGL.DEPTH_TEST);
+ WGL.depthFunc(WGL.LESS);
+ WGL.enable(WGL.BLEND);
+ WGL.blendFunc(WGL.SRC_ALPHA,WGL.ONE_MINUS_SRC_ALPHA);
+ WGL.clear(WGL.COLOR_BUFFER_BIT|WGL.DEPTH_BUFFER_BIT);
+ WGL.viewport(0,0,cvs.width,cvs.height);
+
+ shp=WGL.createProgram();
+ var fshs=createShader(fsh,WGL.FRAGMENT_SHADER);
+ var vshs=createShader(vsh,WGL.VERTEX_SHADER);
+ WGL.attachShader(shp,vshs);WGL.attachShader(shp,fshs);
+ WGL.linkProgram(shp);
+ if(!WGL.getProgramParameter(shp,WGL.LINK_STATUS))
+ {
+ alert("shader link error...");
+ }
+ WGL.useProgram(shp);
+
+ vbo=WGL.createBuffer();
+ WGL.bindBuffer(WGL.ARRAY_BUFFER,vbo);
+ WGL.bufferData(WGL.ARRAY_BUFFER,vb,WGL.STATIC_DRAW);
+ var vpp=WGL.getAttribLocation(shp,"vp");
+ var vcp=WGL.getAttribLocation(shp,"vc");
+ WGL.enableVertexAttribArray(vpp);
+ WGL.enableVertexAttribArray(vcp);
+ WGL.bindBuffer(WGL.ARRAY_BUFFER,vbo);
+ WGL.vertexAttribPointer(vpp,3,WGL.FLOAT,false,7*4,0);
+ WGL.vertexAttribPointer(vcp,4,WGL.FLOAT,false,7*4,3*4);
+
+ for(var i=0,n=0,p=0;i<vbufsize/4;++i)
+ {
+ ib[p++]=n;ib[p++]=n+1;
+ ib[p++]=n+2;ib[p++]=n+2;
+ ib[p++]=n+3;ib[p++]=n;
+ n+=4;
+ }
+ ibo=WGL.createBuffer();
+ WGL.bindBuffer(WGL.ELEMENT_ARRAY_BUFFER,ibo);
+ WGL.bufferData(WGL.ELEMENT_ARRAY_BUFFER,ib,WGL.STATIC_DRAW);
+
+ document.addEventListener('keydown',function(e){kst[e.code]=1;});
+ document.addEventListener('keyup',function(e){kst[e.code]=0;});
+ document.addEventListener('mousedown',function(e){mdn=true;mbtn=e.button;});
+ document.addEventListener('contextmenu',function(e){e.preventDefault();});
+ document.addEventListener('mouseup',function(e){mup=true;});
+ document.addEventListener('dblclick',function(e){dbc=true;});
+ document.addEventListener('mousemove',function(e)
+ {mx=e.clientX/window.innerWidth*vpw;my=e.clientY/window.innerHeight*vph;});
+
+ requestAnimationFrame(mainloop);
+}
+function getpick()
+{
+ for(var i=0;i<shapes.length;++i)
+ if(shapes[i].coltest(mx,my))return i;
+ return -1;
+}
+
+function mainloop()
+{
+ WGL.clearColor(0.5,0.5,0.5,1.0);
+ WGL.clearDepth(1);
+ WGL.clear(WGL.COLOR_BUFFER_BIT|WGL.DEPTH_BUFFER_BIT);
+ primc=0;
+ Mmodelview=buildIdentityMatrix();
+ var picked=getpick();
+
+ //interaction shit
+ if(dragging)
+ {
+ if(mup)
+ {dragging=false;curshape=null;mdn=mup=false;}
+ if(!mdn&&mbtn==0&&dragging)
+ for(var i=0;i<shapes[drg].vert.length;++i)
+ shapes[drg].vert[i]=curshape.vert[i].add(new v3d(mx,my,0).subtract(new v3d(mox,moy,0)));
+ if(!mdn&&mbtn==2&&dragging)
+ {
+ var newscale=new v3d(mox,moy,0).subtract(new v3d(mx,my,0)).l()/20;
+ if(mx<mox||my<moy)newscale=-newscale;
+ if(newscale<-95)newscale=-95;
+ var sc=(100+newscale)/100.;
+ var mmx=curshape.vert[0].x,mmy=curshape.vert[0].y;
+ for(var i=1;i<curshape.vert.length;++i)
+ mmx=Math.min(mmx,curshape.vert[i].x),
+ mmy=Math.min(mmy,curshape.vert[i].y);
+ var c=new v3d(mmx,mmy,0);
+ for(var i=0;i<shapes[drg].vert.length;++i)
+ shapes[drg].vert[i]=curshape.vert[i].subtract(c).n().ms
+ (curshape.vert[i].subtract(c).l()*sc).add(c);
+ }
+
+ }
+ if(dbc)
+ {
+ if(dragging)
+ {dragging=false;curshape=null;}
+ else
+ if(curshape)
+ {
+ if(kst['ControlLeft']==1&&curshape.type=='segstrip')
+ curshape.type='segloop';
+ shapes.push(curshape);
+ curshape=null;
+ }
+ }
+ else
+ {
+ if(mup&&kst['ControlLeft']==1&&!curshape)
+ {
+ if(picked!=-1)
+ {
+ dragging=true;
+ mox=mx,moy=my;drg=picked;
+ curshape=copyshape(shapes[picked]);
+ }
+ }
+ if(mup&&!dragging&&!kst['ControlLeft'])
+ {
+ if(!curshape)
+ {
+ curshape=new Shape('segment');
+ curshape.vert.push(new v3d(mx,my,0));
+ curshape.vert.push(new v3d(mx,my,0));
+ }
+ else
+ {
+ if(curshape.type=='segment')curshape.type='segstrip';
+ curshape.vert.push(new v3d(mx,my,0));
+ }
+ }
+ }
+
+ if(curshape&&!dragging)
+ curshape.vert[curshape.vert.length-1]=new v3d(mx,my,0);
+
+ for(var i=0;i<shapes.length;++i)
+ if(!curshape&&!dragging&&i==picked)shapes[i].draw(1,0.8,0,0);
+ else shapes[i].draw(1,0.8,0.8,0.8);
+
+ if(curshape&&!dragging)curshape.draw(1,0.8,0.8,0);
+
+ batchGL();
+
+ mup=mdn=dbc=false;
+ requestAnimationFrame(mainloop);
+}
+
+function batchGL()
+{
+ Mprojection=buildProjectionMatrix2D(vpw,vph);
+ var mpp=WGL.getUniformLocation(shp,"mprojection");
+ WGL.uniformMatrix4fv(mpp,false,Mprojection);
+ var mvpp=WGL.getUniformLocation(shp,"mmodelview");
+ WGL.uniformMatrix4fv(mvpp,false,Mmodelview);
+ WGL.bindBuffer(WGL.ARRAY_BUFFER,vbo);
+ WGL.bufferData(WGL.ARRAY_BUFFER,vb,WGL.STATIC_DRAW);
+ WGL.drawElements(WGL.TRIANGLES,6*primc,WGL.UNSIGNED_SHORT,0);
+ primc=0;
+}
+
diff --git a/xp/cgxp/main2.js b/xp/cgxp/main2.js
new file mode 100644
index 0000000..05b1fdb
--- /dev/null
+++ b/xp/cgxp/main2.js
@@ -0,0 +1,280 @@
+//Copyright Chris Xiong 2018
+//License: Expat (MIT)
+var cvs,WGL,vpw,vph,hdiv;
+var fsh=`
+varying lowp vec4 vC;
+void main(void)
+{
+ gl_FragColor=vC;
+}`;
+var vsh=`
+attribute vec3 vp;
+attribute vec4 vc;
+uniform mat4 mmodelview;
+uniform mat4 mprojection;
+varying lowp vec4 vC;
+void main(void)
+{
+ gl_Position=mprojection*mmodelview*vec4(vp,1.);
+ vC=vc;
+}`;
+var shp;
+var vbufsize=4096;
+var vbo,ibo;
+var vb=new Float32Array(vbufsize*7);
+var ib=new Uint16Array(vbufsize*6/4);
+var Mprojection,Mmodelview;
+var primc;
+var kst=[];
+var pos=[15,4,30];
+var ofs=[0.9,3.5,20];
+var mzw=50,mzh=35,ppx,ppy,ex,ey;
+var maz=[];
+
+var Sphere=function()
+{
+ this.x=10-Math.random()*20;
+ this.y=10-Math.random()*20;
+ this.timer=0;this.r=0.2;
+}
+Sphere.prototype.update=function()
+{
+ var d=Math.sqrt((this.x-pp.x)*(this.x-pp.x)+(this.y-pp.y)*(this.y-pp.y));
+ if(d<0.5&&this.timer===0)this.timer=1;
+ if(this.timer>0&&state===0)
+ {
+ ++this.timer;health+=0.01;
+ this.r+=0.02;if(health>1)health=1;
+ }
+ if(this.timer>25)this.timer=-1;
+}
+Sphere.prototype.draw=function(x,y,a)
+{
+ if(this.timer!==-1)pushSphere(x,y,0,this.r,[0,1,0,a*(0.6-this.timer*0.6/25)]);
+}
+
+function createShader(sh,t)
+{
+ var shader=WGL.createShader(t);
+ WGL.shaderSource(shader,sh);
+ WGL.compileShader(shader);
+ if(!WGL.getShaderParameter(shader,WGL.COMPILE_STATUS))
+ {
+ alert("shader error..."+WGL.getShaderInfoLog(shader));
+ return null;
+ }
+ return shader;
+}
+function pushQuad(a)
+{
+ if(primc>=vbufsize/4)batchGL();
+ for(var i=0;i<4;++i)
+ for(var j=0;j<7;++j)vb[primc*7*4+i*7+j]=a[i*7+j];
+ ++primc;
+}
+function cube(x,y,z,l,r,g,b,a)
+{
+ var L=x-l/2,R=x+l/2;
+ var B=y-l/2,T=y+l/2;
+ var N=z-l/2,F=z+l/2;
+ pushQuad([
+ L,B,N,r,g,b,a,
+ L,T,N,r,g,b,a,
+ R,T,N,r,g,b,a,
+ R,B,N,r,g,b,a
+ ]);
+ pushQuad([
+ L,B,F,r,g,b,a,
+ L,T,F,r,g,b,a,
+ R,T,F,r,g,b,a,
+ R,B,F,r,g,b,a
+ ]);
+ pushQuad([
+ L,B,N,r,g,b,a,
+ L,T,N,r,g,b,a,
+ L,T,F,r,g,b,a,
+ L,B,F,r,g,b,a
+ ]);
+ pushQuad([
+ R,B,N,r,g,b,a,
+ R,T,N,r,g,b,a,
+ R,T,F,r,g,b,a,
+ R,B,F,r,g,b,a
+ ]);
+ pushQuad([
+ L,B,N,r,g,b,a,
+ R,B,N,r,g,b,a,
+ R,B,F,r,g,b,a,
+ L,B,F,r,g,b,a
+ ]);
+ pushQuad([
+ L,T,N,r,g,b,a,
+ R,T,N,r,g,b,a,
+ R,T,F,r,g,b,a,
+ L,T,F,r,g,b,a
+ ]);
+}
+function pushSphere(x,y,z,r,col)
+{
+ for(var i=0;i<12;++i)
+ for(var j=0;j<12;++j)
+ {
+ var r1=r*Math.sin(i*Math.PI/12);
+ var a=new v3d(x+r1*Math.cos(j*Math.PI/12*2),y+r1*Math.sin(j*Math.PI/12*2),z+r*Math.cos(i*Math.PI/12));
+ var b=new v3d(x+r1*Math.cos((j+1)*Math.PI/12*2),y+r1*Math.sin((j+1)*Math.PI/12*2),z+r*Math.cos(i*Math.PI/12));
+ r1=r*Math.sin((i+1)*Math.PI/12);
+ var c=new v3d(x+r1*Math.cos(j*Math.PI/12*2),y+r1*Math.sin(j*Math.PI/12*2),z+r*Math.cos((i+1)*Math.PI/12));
+ var d=new v3d(x+r1*Math.cos((j+1)*Math.PI/12*2),y+r1*Math.sin((j+1)*Math.PI/12*2),z+r*Math.cos((i+1)*Math.PI/12));
+ pushQuad([
+ a.x,a.y,a.z,col[0],col[1],col[2],col[3],
+ b.x,b.y,b.z,col[0],col[1],col[2],col[3],
+ d.x,d.y,d.z,col[0],col[1],col[2],col[3],
+ c.x,c.y,c.z,col[0],col[1],col[2],col[3]
+ ]);
+ }
+}
+function randint(c)
+{return Math.floor(Math.random()*c);}
+function genmaze()
+{
+ for(var i=0;i<mzw;++i)
+ {
+ maz[i]=[];
+ for(var j=0;j<mzh;++j)maz[i][j]=false;
+ }
+ var dx=[0,0,-1,1],
+ dy=[1,-1,0,0];
+ var lst=[];
+ var cx=randint(mzw),cy=randint(mzh);
+ lst.push({x:cx,y:cy,z:cx,w:cy});
+ while(lst.length)
+ {
+ var rm=lst.splice(randint(lst.length),1);
+ var x=rm[0].z,y=rm[0].w;
+ if(maz[x][y]==false)
+ {
+ maz[x][y]=maz[rm[0].x][rm[0].y]=true;
+ for(var i=0;i<4;++i)
+ {
+ cx=x+dx[i]*2;cy=y+dy[i]*2;
+ if(cx>=0&&cy>=0&&cx<mzw&&cy<mzh&&
+ maz[cx][cy]==false)
+ lst.push({x:x+dx[i],y:y+dy[i],z:cx,w:cy});
+ }
+ }
+ }
+ for(var i=0;i<mzh;++i)maz[0][i]=maz[mzw-1][i]=false;
+ for(var i=0;i<mzw;++i)maz[i][0]=maz[i][mzh-1]=false;
+ for(var i=0;i<mzh;++i){if(maz[1][i])lst.push({x:1,y:i});if(maz[mzw-2][i])lst.push({x:mzw-2,y:i});}
+ for(var i=0;i<mzw;++i){if(maz[i][1])lst.push({x:i,y:1});if(maz[i][mzh-2])lst.push({x:i,y:mzh-2});}
+ if(lst.length<2)return genmaze();
+ var rm=lst.splice(randint(lst.length),1);
+ ppx=rm[0].x,ppy=rm[0].y;
+ rm=lst.splice(randint(lst.length),1);
+ ex=rm[0].x,ey=rm[0].y;
+}
+function init()
+{
+ cvs=document.getElementById("glCvs");
+ if(!window.devicePixelRatio)window.devicePixelRatio=1;
+ cvs.width=window.innerWidth;
+ cvs.height=window.innerHeight;
+ cvs.style.width=cvs.width+"px";
+ cvs.style.height=cvs.height+"px";
+ cvs.width=cvs.width*window.devicePixelRatio;
+ cvs.height=cvs.height*window.devicePixelRatio;
+ vpw=cvs.width;vph=cvs.height;
+ try
+ {WGL=cvs.getContext("webgl")||cvs.getContext("experimental-webgl");}
+ catch(e){WGL=null;}
+ if(!WGL){alert("WebGL is not supported by your browser...");return;}
+
+ WGL.clearColor(0.5,0.5,0.5,1.0);
+ WGL.clearDepth(1);
+ WGL.enable(WGL.DEPTH_TEST);
+ WGL.depthFunc(WGL.LESS);
+ WGL.enable(WGL.BLEND);
+ WGL.blendFunc(WGL.SRC_ALPHA,WGL.ONE_MINUS_SRC_ALPHA);
+ WGL.clear(WGL.COLOR_BUFFER_BIT|WGL.DEPTH_BUFFER_BIT);
+ WGL.viewport(0,0,cvs.width,cvs.height);
+
+ shp=WGL.createProgram();
+ var fshs=createShader(fsh,WGL.FRAGMENT_SHADER);
+ var vshs=createShader(vsh,WGL.VERTEX_SHADER);
+ WGL.attachShader(shp,vshs);WGL.attachShader(shp,fshs);
+ WGL.linkProgram(shp);
+ if(!WGL.getProgramParameter(shp,WGL.LINK_STATUS))
+ {
+ alert("shader link error...");
+ }
+ WGL.useProgram(shp);
+
+ vbo=WGL.createBuffer();
+ WGL.bindBuffer(WGL.ARRAY_BUFFER,vbo);
+ WGL.bufferData(WGL.ARRAY_BUFFER,vb,WGL.STATIC_DRAW);
+ var vpp=WGL.getAttribLocation(shp,"vp");
+ var vcp=WGL.getAttribLocation(shp,"vc");
+ WGL.enableVertexAttribArray(vpp);
+ WGL.enableVertexAttribArray(vcp);
+ WGL.bindBuffer(WGL.ARRAY_BUFFER,vbo);
+ WGL.vertexAttribPointer(vpp,3,WGL.FLOAT,false,7*4,0);
+ WGL.vertexAttribPointer(vcp,4,WGL.FLOAT,false,7*4,3*4);
+
+ for(var i=0,n=0,p=0;i<vbufsize/4;++i)
+ {
+ ib[p++]=n;ib[p++]=n+1;
+ ib[p++]=n+2;ib[p++]=n+2;
+ ib[p++]=n+3;ib[p++]=n;
+ n+=4;
+ }
+ ibo=WGL.createBuffer();
+ WGL.bindBuffer(WGL.ELEMENT_ARRAY_BUFFER,ibo);
+ WGL.bufferData(WGL.ELEMENT_ARRAY_BUFFER,ib,WGL.STATIC_DRAW);
+
+ document.addEventListener('keydown',function(e){kst[e.code]=1;});
+ document.addEventListener('keyup',function(e)
+ {
+ kst[e.code]=0;
+ if(e.code=='KeyD'){if(ppx+1<mzw&&maz[ppx+1][ppy])++ppx;}
+ if(e.code=='KeyA'){if(ppx-1>=0&&maz[ppx-1][ppy])--ppx;}
+ if(e.code=='KeyW'){if(ppy+1<mzh&&maz[ppx][ppy+1])++ppy;}
+ if(e.code=='KeyS'){if(ppy-1>=0&&maz[ppx][ppy-1])--ppy;}
+ });
+ genmaze();
+ requestAnimationFrame(mainloop);
+}
+
+function mainloop()
+{
+ const ofx=-9,ofy=-11;
+ WGL.clearColor(0.5,0.5,0.5,1.0);
+ WGL.clearDepth(1);
+ WGL.clear(WGL.COLOR_BUFFER_BIT|WGL.DEPTH_BUFFER_BIT);
+ primc=0;
+ Mmodelview=buildIdentityMatrix();
+
+ Mmodelview=buildLookAtMatrix(pos,[15,10,0],[0,0,1]);
+ for(var i=0;i<mzw;++i)
+ for(var j=0;j<mzh;++j)
+ if(!maz[i][j])cube(i+ofx,j+ofy,0,1,0.1,0.1,0.1,1);
+
+ cube(ppx+ofx,ppy+ofy,0,0.6,0.1,0.8,0.1,1);
+ cube(ex+ofx,ey+ofy,0,0.8,0.4,0.9,0.9,1);
+
+ batchGL();
+
+ requestAnimationFrame(mainloop);
+}
+
+function batchGL()
+{
+ Mprojection=buildProjectionMatrix3D(vpw,vph,60,0.1,100);
+ var mpp=WGL.getUniformLocation(shp,"mprojection");
+ WGL.uniformMatrix4fv(mpp,false,Mprojection);
+ var mvpp=WGL.getUniformLocation(shp,"mmodelview");
+ WGL.uniformMatrix4fv(mvpp,false,Mmodelview);
+ WGL.bindBuffer(WGL.ARRAY_BUFFER,vbo);
+ WGL.bufferData(WGL.ARRAY_BUFFER,vb,WGL.STATIC_DRAW);
+ WGL.drawElements(WGL.TRIANGLES,6*primc,WGL.UNSIGNED_SHORT,0);
+ primc=0;
+}
diff --git a/xp/cgxp/wglmath.js b/xp/cgxp/wglmath.js
new file mode 100644
index 0000000..1b9b9e3
--- /dev/null
+++ b/xp/cgxp/wglmath.js
@@ -0,0 +1,102 @@
+//Copyright Chris Xiong 2018
+//License: Expat (MIT)
+var v3d=function(x,y,z)
+{
+ this.x=(x!==undefined)?x:0;
+ this.y=(y!==undefined)?y:0;
+ this.z=(z!==undefined)?z:0;
+}
+v3d.prototype.l=function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z);}
+v3d.prototype.n=function(){var L=this.l();if(L==0)return new v3d();return new v3d(this.x/L,this.y/L,this.z/L);}
+v3d.prototype.ms=function(s)
+{
+ return new v3d(this.x*s,this.y*s,this.z*s);
+}
+v3d.prototype.mm=function(m)
+{
+ return new v3d(
+ m[0]*this.x+m[4]*this.y+m[8]*this.z,
+ m[1]*this.x+m[5]*this.y+m[9]*this.z,
+ m[2]*this.x+m[6]*this.y+m[10]*this.z
+ );
+}
+v3d.prototype.add=function(b)
+{
+ return new v3d(this.x+b.x,this.y+b.y,this.z+b.z);
+}
+v3d.prototype.subtract=function(b)
+{
+ return new v3d(this.x-b.x,this.y-b.y,this.z-b.z);
+}
+v3d.prototype.dot=function(b)
+{
+ return this.x*b.x+this.y*b.y+this.z*b.z;
+}
+v3d.prototype.cross=function(b)
+{
+ return new v3d(
+ this.y*b.z-this.z*b.y,
+ this.z*b.x-this.x*b.z,
+ this.x*b.y-this.y*b.x
+ );
+}
+function buildIdentityMatrix()
+{
+ var m=new Float32Array(16);
+ for(var i=0;i<4;++i)m[i*4+i]=1.;
+ return m;
+}
+function buildProjectionMatrix2D(w,h)
+{
+ var m=buildIdentityMatrix();
+ m[0]=2/w;m[5]=2/h;m[10]=-2;
+ m[12]=m[13]=m[14]=-1;
+ return m;
+}
+function buildProjectionMatrix3D(w,h,fov,near,far)
+{
+ var m=new Float32Array(16);
+ var f=1./Math.tan(Math.PI*fov/360.);
+ var ar=w/h;
+ m[0]=f/ar;m[5]=f;m[10]=(far+near)/(near-far);
+ m[11]=-1.;m[14]=(2*far*near)/(near-far);
+ return m;
+}
+function buildTranslationMatrix(x,y,z)
+{
+ var m=buildIdentityMatrix();
+ m[12]=x;m[13]=y;m[14]=z;
+ return m;
+}
+function buildRotationMatrix(a,x,y,z)
+{
+ var m=buildIdentityMatrix();
+ //check (x,y,z) here
+ var c=Math.cos(a),s=Math.sin(a);
+ m[0]=x*x*(1-c)+c;m[4]=x*y*(1-c)-z*s;m[8]=x*z*(1-c)+y*s;
+ m[1]=y*x*(1-c)+z*s;m[5]=y*y*(1-c)+c;m[9]=y*z*(1-c)-x*s;
+ m[2]=x*z*(1-c)-y*s;m[6]=y*z*(1-c)+x*s;m[10]=z*x*(1-c)+c;
+ m[15]=1.;
+ return m;
+}
+function buildLookAtMatrix(e,a,u)
+{
+ var f=new v3d(a[0]-e[0],a[1]-e[1],a[2]-e[2]).n();
+ var up=new v3d(u[0],u[1],u[2]).n();
+ var r=f.cross(up).n();var p=r.cross(f);
+ var m=buildIdentityMatrix();
+ m[0]=r.x;m[4]=r.y;m[8]=r.z;
+ m[1]=p.x;m[5]=p.y;m[9]=p.z;
+ m[2]=-f.x;m[6]=-f.y;m[10]=-f.z;
+ m=multMatrix(m,buildTranslationMatrix(-e[0],-e[1],-e[2]));
+ return m;
+}
+function multMatrix(a,b)
+{
+ var r=new Float32Array(16);
+ for(var i=0;i<4;++i)
+ for(var j=0;j<4;++j)
+ for(var k=0;k<4;++k)
+ r[i*4+j]+=a[i*4+k]*b[k*4+j];
+ return r;
+}
diff --git a/xp/vco/.htaccess b/xp/vco/.htaccess
new file mode 100644
index 0000000..677b3a8
--- /dev/null
+++ b/xp/vco/.htaccess
@@ -0,0 +1,5 @@
+AddType application/x-web-app-manifest+json .webapp
+
+AddType video/ogg .ogv
+AddType video/mp4 .mp4
+AddType video/webm .webm \ No newline at end of file
diff --git a/xp/vco/LICENSE b/xp/vco/LICENSE
new file mode 100644
index 0000000..670154e
--- /dev/null
+++ b/xp/vco/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+<http://creativecommons.org/publicdomain/zero/1.0/>
diff --git a/xp/vco/README.md b/xp/vco/README.md
new file mode 100644
index 0000000..080808e
--- /dev/null
+++ b/xp/vco/README.md
@@ -0,0 +1,4 @@
+#Voice-change-o-matic
+A Web Audio API-powered voice changer and visualizer.
+
+[Run the demo live](https://mdn.github.io/voice-change-o-matic/)
diff --git a/xp/vco/app-icons/icon-128.png b/xp/vco/app-icons/icon-128.png
new file mode 100644
index 0000000..5223c0d
--- /dev/null
+++ b/xp/vco/app-icons/icon-128.png
Binary files differ
diff --git a/xp/vco/app-icons/icon-16.png b/xp/vco/app-icons/icon-16.png
new file mode 100644
index 0000000..4f4f56e
--- /dev/null
+++ b/xp/vco/app-icons/icon-16.png
Binary files differ
diff --git a/xp/vco/app-icons/icon-60.png b/xp/vco/app-icons/icon-60.png
new file mode 100644
index 0000000..fc048ff
--- /dev/null
+++ b/xp/vco/app-icons/icon-60.png
Binary files differ
diff --git a/xp/vco/favicon.ico b/xp/vco/favicon.ico
new file mode 100644
index 0000000..f6a62e7
--- /dev/null
+++ b/xp/vco/favicon.ico
Binary files differ
diff --git a/xp/vco/index.html b/xp/vco/index.html
new file mode 100644
index 0000000..6438bd3
--- /dev/null
+++ b/xp/vco/index.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html lang="en-us">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width">
+ <title>VCO</title>
+ <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
+ <link href='https://fonts.googleapis.com/css?family=Righteous|Nova+Square' rel='stylesheet' type='text/css'>
+ <link href="styles/normalize.css" rel="stylesheet" type="text/css">
+ <link href="styles/app.css" rel="stylesheet" type="text/css">
+ <link href="manifest.webapp" rel="manifest">
+</head>
+<body>
+ <div class="wrapper">
+ <canvas class="visualizer" width="1280" height="800" style="height:400px;"></canvas>
+ <br><br><br>
+ <div style="position:relative;width:100%;background:linear-gradient(to right,green,red);height:2em;">
+ <div id="bar" style="background-color:#999;position:absolute;right:0;width:0;height:100%;"></div>
+ </div>
+ </div>
+ <script src="scripts/app.js"></script>
+</body>
+</html>
diff --git a/xp/vco/manifest.webapp b/xp/vco/manifest.webapp
new file mode 100644
index 0000000..3636263
--- /dev/null
+++ b/xp/vco/manifest.webapp
@@ -0,0 +1,18 @@
+{
+ "version": "0.1",
+ "name": "VCO",
+ "description": "A sample app that uses getUserMedia to grab an audio stream, which is then passed to the Web Audio API to apply effects to the audio and create visualizations.",
+ "launch_path": "/index.html",
+ "icons": {
+ "60": "app-icons/icon-60.png",
+ "128": "app-icons/icon-128.png"
+ },
+ "default_locale": "en",
+ "permissions": {
+ "audio-capture": {
+ "description": "Required to capture audio via getUserMedia"
+ }
+ },
+ "orientation" : "portrait",
+ "display" : "fullscreen"
+}
diff --git a/xp/vco/scripts/app.js b/xp/vco/scripts/app.js
new file mode 100644
index 0000000..cec78be
--- /dev/null
+++ b/xp/vco/scripts/app.js
@@ -0,0 +1,129 @@
+// fork getUserMedia for multiple browser versions, for those
+// that need prefixes
+
+navigator.getUserMedia = (navigator.getUserMedia ||
+ navigator.webkitGetUserMedia ||
+ navigator.mozGetUserMedia ||
+ navigator.msGetUserMedia);
+
+// set up forked web audio context, for multiple browsers
+// window. is needed otherwise Safari explodes
+
+var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
+var source;
+var stream;
+
+// grab the mute button to use below
+
+var mute = document.querySelector('.mute');
+
+//set up the different audio nodes we will use for the app
+
+var analyser = audioCtx.createAnalyser();
+analyser.minDecibels = -90;
+analyser.maxDecibels = -10;
+analyser.smoothingTimeConstant = 0.85;
+
+var distortion = audioCtx.createWaveShaper();
+var gainNode = audioCtx.createGain();
+var biquadFilter = audioCtx.createBiquadFilter();
+var convolver = audioCtx.createConvolver();
+
+// set up canvas context for visualizer
+
+var canvas = document.querySelector('.visualizer');
+var canvasCtx = canvas.getContext("2d");
+var bar = document.getElementById("bar");
+var intendedWidth = document.querySelector('.wrapper').clientWidth;
+
+canvas.setAttribute('width',intendedWidth*2);
+canvas.style.width=intendedWidth+'px';
+
+
+var drawVisual;
+
+//main block for doing the audio recording
+
+if (navigator.getUserMedia) {
+console.log('getUserMedia supported.');
+navigator.getUserMedia (
+ // constraints - only audio needed for this app
+ {
+ audio: true
+ },
+
+ // Success callback
+ function(stream) {
+ source = audioCtx.createMediaStreamSource(stream);
+ source.connect(analyser);
+ analyser.connect(distortion);
+ distortion.connect(biquadFilter);
+ biquadFilter.connect(convolver);
+ convolver.connect(gainNode);
+ gainNode.connect(audioCtx.destination);
+
+ visualize();
+
+ },
+
+ // Error callback
+ function(err) {
+ console.log('The following gUM error occured: ' + err);
+ }
+);
+} else {
+console.log('getUserMedia not supported on your browser!');
+}
+
+function visualize() {
+ WIDTH = canvas.width;
+ HEIGHT = canvas.height;
+ analyser.fftSize = 2048;
+ var bufferLength = analyser.fftSize;
+ console.log(bufferLength);
+ var dataArray = new Uint8Array(bufferLength);
+
+ canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
+
+ var draw = function() {
+
+ drawVisual = requestAnimationFrame(draw);
+
+ analyser.getByteTimeDomainData(dataArray);
+
+ canvasCtx.fillStyle = 'rgb(200, 200, 200)';
+ canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
+
+ canvasCtx.lineWidth = 2;
+ canvasCtx.strokeStyle = 'rgb(0, 0, 0)';
+
+ canvasCtx.beginPath();
+
+ var sliceWidth = WIDTH * 1.0 / bufferLength;
+ var x = 0, s = 0;
+
+ for(var i = 0; i < bufferLength; i++) {
+
+ var v = dataArray[i] / 128.0;
+ var t=Math.abs(dataArray[i]-128.)/128.0;
+ s+=t*t;
+ var y = v * HEIGHT/2;
+
+ if(i === 0) {
+ canvasCtx.moveTo(x, y);
+ } else {
+ canvasCtx.lineTo(x, y);
+ }
+
+ x += sliceWidth;
+ }
+ s/=bufferLength;s=Math.sqrt(s);s=1-s;
+ bar.style.width=100*s+'%';
+
+ canvasCtx.lineTo(canvas.width, canvas.height/2);
+ canvasCtx.stroke();
+ };
+
+ draw();
+
+}
diff --git a/xp/vco/scripts/install.js b/xp/vco/scripts/install.js
new file mode 100644
index 0000000..d44f1bb
--- /dev/null
+++ b/xp/vco/scripts/install.js
@@ -0,0 +1,37 @@
+// get a reference to the install button
+var button = document.getElementById('install-btn');
+
+if(navigator.mozApps) {
+
+var manifest_url = location.href + 'manifest.webapp';
+
+function install(ev) {
+ ev.preventDefault();
+ // define the manifest URL
+ // install the app
+ var installLocFind = navigator.mozApps.install(manifest_url);
+ installLocFind.onsuccess = function(data) {
+ // App is installed, do something
+ };
+ installLocFind.onerror = function() {
+ // App wasn't installed, info is in
+ // installapp.error.name
+ alert(installLocFind.error.name);
+ };
+};
+
+//call install() on click if the app isn't already installed. If it is, hide the button.
+
+var installCheck = navigator.mozApps.checkInstalled(manifest_url);
+
+installCheck.onsuccess = function() {
+ if(installCheck.result) {
+ button.style.display = "none";
+ } else {
+ button.addEventListener('click', install, false);
+ };
+};
+
+} else {
+ button.style.display = "none";
+}
diff --git a/xp/vco/scripts/respond.js b/xp/vco/scripts/respond.js
new file mode 100644
index 0000000..e3dc2c0
--- /dev/null
+++ b/xp/vco/scripts/respond.js
@@ -0,0 +1,6 @@
+/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
+/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
+window.matchMedia=window.matchMedia||function(a){"use strict";var c,d=a.documentElement,e=d.firstElementChild||d.firstChild,f=a.createElement("body"),g=a.createElement("div");return g.id="mq-test-1",g.style.cssText="position:absolute;top:-100em",f.style.background="none",f.appendChild(g),function(a){return g.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',d.insertBefore(f,e),c=42===g.offsetWidth,d.removeChild(f),{matches:c,media:a}}}(document);
+
+/*! Respond.js v1.3.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
+(function(a){"use strict";function x(){u(!0)}var b={};if(a.respond=b,b.update=function(){},b.mediaQueriesSupported=a.matchMedia&&a.matchMedia("only all").matches,!b.mediaQueriesSupported){var q,r,t,c=a.document,d=c.documentElement,e=[],f=[],g=[],h={},i=30,j=c.getElementsByTagName("head")[0]||d,k=c.getElementsByTagName("base")[0],l=j.getElementsByTagName("link"),m=[],n=function(){for(var b=0;l.length>b;b++){var c=l[b],d=c.href,e=c.media,f=c.rel&&"stylesheet"===c.rel.toLowerCase();d&&f&&!h[d]&&(c.styleSheet&&c.styleSheet.rawCssText?(p(c.styleSheet.rawCssText,d,e),h[d]=!0):(!/^([a-zA-Z:]*\/\/)/.test(d)&&!k||d.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&m.push({href:d,media:e}))}o()},o=function(){if(m.length){var b=m.shift();v(b.href,function(c){p(c,b.href,b.media),h[b.href]=!0,a.setTimeout(function(){o()},0)})}},p=function(a,b,c){var d=a.match(/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi),g=d&&d.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,"$1"+b+"$2$3")},i=!g&&c;b.length&&(b+="/"),i&&(g=1);for(var j=0;g>j;j++){var k,l,m,n;i?(k=c,f.push(h(a))):(k=d[j].match(/@media *([^\{]+)\{([\S\s]+?)$/)&&RegExp.$1,f.push(RegExp.$2&&h(RegExp.$2))),m=k.split(","),n=m.length;for(var o=0;n>o;o++)l=m[o],e.push({media:l.split("(")[0].match(/(only\s+)?([a-zA-Z]+)\s?/)&&RegExp.$2||"all",rules:f.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},s=function(){var a,b=c.createElement("div"),e=c.body,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",e||(e=f=c.createElement("body"),e.style.background="none"),e.appendChild(b),d.insertBefore(e,d.firstChild),a=b.offsetWidth,f?d.removeChild(e):e.removeChild(b),a=t=parseFloat(a)},u=function(b){var h="clientWidth",k=d[h],m="CSS1Compat"===c.compatMode&&k||c.body[h]||k,n={},o=l[l.length-1],p=(new Date).getTime();if(b&&q&&i>p-q)return a.clearTimeout(r),r=a.setTimeout(u,i),void 0;q=p;for(var v in e)if(e.hasOwnProperty(v)){var w=e[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?t||s():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?t||s():1)),w.hasquery&&(z&&A||!(z||m>=x)||!(A||y>=m))||(n[w.media]||(n[w.media]=[]),n[w.media].push(f[w.rules]))}for(var C in g)g.hasOwnProperty(C)&&g[C]&&g[C].parentNode===j&&j.removeChild(g[C]);for(var D in n)if(n.hasOwnProperty(D)){var E=c.createElement("style"),F=n[D].join("\n");E.type="text/css",E.media=D,j.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(c.createTextNode(F)),g.push(E)}},v=function(a,b){var c=w();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},w=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}();n(),b.update=n,a.addEventListener?a.addEventListener("resize",x,!1):a.attachEvent&&a.attachEvent("onresize",x)}})(this);
diff --git a/xp/vco/styles/app.css b/xp/vco/styles/app.css
new file mode 100644
index 0000000..5020353
--- /dev/null
+++ b/xp/vco/styles/app.css
@@ -0,0 +1,205 @@
+/* || General layout rules for narrow screens */
+
+html {
+ font-family: 'Righteous', cursive;
+ font-size: 10px;
+ background-color: black;
+}
+
+body {
+ width: 100%;
+ background-color: #999;
+ /*background-image: url(../images/pattern.png);*/
+}
+
+h1, h2, label {
+ font-size: 3rem;
+ font-family: 'Nova Square', cursive;
+ text-align: center;
+ color: black;
+ text-shadow: -1px -1px 1px #aaa,
+ 0px 1px 1px rgba(255,255,255,0.5),
+ 1px 1px 2px rgba(255,255,255,0.7),
+ 0px 0px 2px rgba(255,255,255,0.4);
+ margin: 0;
+}
+
+h1 {
+ font-size: 3.5rem;
+ padding-top: 1.2rem;
+}
+
+.wrapper {
+ height: 100%;
+ max-width: 800px;
+ margin: 0 auto;
+}
+
+/* || main UI sections */
+
+header {
+ height: 120px;
+}
+
+canvas {
+ /*border-top: 1px solid black;
+ border-bottom: 1px solid black;
+ margin-bottom: -3px;
+ box-shadow: 0 -2px 4px rgba(0,0,0,0.7),
+ 0 3px 4px rgba(0,0,0,0.7);*/
+}
+
+.controls {
+ background-color: rgba(0,0,0,0.1);
+ height: calc(100% - 225px);
+}
+
+/* || select element styling */
+
+.controls div {
+ width: 100%;
+ padding-top: 1rem;
+}
+
+.controls label, .controls select {
+ display: block;
+ margin: 0 auto;
+}
+
+.controls label {
+ width: 100%;
+ text-align: center;
+ line-height: 3rem;
+ padding: 1rem 0;
+}
+
+.controls select {
+ width: 80%;
+ font-size: 2rem;
+}
+
+/* || button styling */
+
+button, form a {
+ background-color: #0088cc;
+ background-image: linear-gradient(to bottom, #0088cc 0%,#0055cc 100%);
+ text-shadow: 1px 1px 1px black;
+ text-align: center;
+ color: white;
+ border: none;
+ width: 90%;
+ margin: 1rem auto 0.5rem;
+ max-width: 80%;
+ font-size: 1.6rem;
+ line-height: 3rem;
+ padding: .5rem;
+ display: block;
+}
+
+button:hover, button:focus, form a:hover, form a:focus {
+ box-shadow: inset 1px 1px 2px rgba(0,0,0,0.7);
+}
+
+button:active, form a:active {
+ box-shadow: inset 2px 2px 3px rgba(0,0,0,0.7);
+}
+
+a#activated {
+ background-color: #fff;
+ background-image: linear-gradient(to bottom, #f00 0%,#a06 100%);
+}
+
+/* || Checkbox hack to control information box display */
+
+label[for="toggle"] {
+ font-family: 'NotoColorEmoji';
+ font-size: 3rem;
+ position: absolute;
+ top: 4px;
+ right: 5px;
+ z-index: 5;
+ cursor: pointer;
+}
+
+input[type=checkbox] {
+ position: absolute;
+ top: -100px;
+}
+
+aside {
+ position: fixed;
+ top: 0;
+ left: 0;
+ padding-top: 1.5rem;
+ text-shadow: 1px 1px 1px black;
+ width: 100%;
+ height: 100%;
+ transform: translateX(100%);
+ transition: 0.6s all;
+ background-color: #999;
+ background-image: linear-gradient(to top right, rgba(0,0,0,0), rgba(0,0,0,0.5));
+}
+
+aside p, aside li {
+ font-size: 1.6rem;
+ line-height: 1.3;
+ padding: 0rem 2rem 1rem;
+ color: white;
+}
+
+aside li {
+ padding-left: 10px;
+}
+
+
+/* Toggled State of information box */
+
+input[type=checkbox]:checked ~ aside {
+ transform: translateX(0);
+}
+
+/* || Link styles */
+
+a {
+ color: #aaa;
+}
+
+a:hover, a:focus {
+ text-decoration: none;
+}
+
+@media (min-width: 481px) {
+ /*CSS for medium width screens*/
+
+ /* || Basic layout changes for the main control buttons */
+
+}
+
+@media all and (min-width: 800px) {
+ /*CSS for wide screens*/
+
+ h1 {
+ font-size: 5rem;
+ padding-top: 2.5rem;
+ }
+
+ aside {
+ top: 0;
+ left: 100%;
+ text-shadow: 1px 1px 1px black;
+ width: 480px;
+ transform: translateX(0);
+ border-left: 2px solid black;
+ }
+
+ /* Toggled State of information box */
+
+ input[type=checkbox]:checked ~ aside {
+ transform: translateX(-480px);
+ }
+
+}
+
+@media (min-width: 1100px) {
+ /*CSS for really wide screens*/
+}
diff --git a/xp/vco/styles/install-button.css b/xp/vco/styles/install-button.css
new file mode 100644
index 0000000..ed0d408
--- /dev/null
+++ b/xp/vco/styles/install-button.css
@@ -0,0 +1,20 @@
+#install-btn {
+ background: #0088cc; /* Old browsers */
+ background: -moz-linear-gradient(top, #0088cc 0%, #0055cc 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#0088cc), color-stop(100%,#0055cc)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #0088cc 0%,#0055cc 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #0088cc 0%,#0055cc 100%); /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #0088cc 0%,#0055cc 100%); /* IE10+ */
+ background: linear-gradient(to bottom, #0088cc 0%,#0055cc 100%); /* W3C */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#0088cc', endColorstr='#0055cc',GradientType=0 ); /* IE6-9 */
+
+ text-align: center;
+ font-size: 200%;
+ margin: 1em auto;
+ display: block;
+ padding: .5em;
+ color: white;
+ width: 10em;
+ max-width: 80%;
+ line-height: 1.2em;
+} \ No newline at end of file
diff --git a/xp/vco/styles/normalize.css b/xp/vco/styles/normalize.css
new file mode 100644
index 0000000..c2de8df
--- /dev/null
+++ b/xp/vco/styles/normalize.css
@@ -0,0 +1,406 @@
+/*! normalize.css v2.1.3 | MIT License | git.io/normalize */
+
+/* ==========================================================================
+ HTML5 display definitions
+ ========================================================================== */
+
+/**
+ * Correct `block` display not defined in IE 8/9.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section,
+summary {
+ display: block;
+}
+
+/**
+ * Correct `inline-block` display not defined in IE 8/9.
+ */
+
+audio,
+canvas,
+video {
+ display: inline-block;
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/**
+ * Address `[hidden]` styling not present in IE 8/9.
+ * Hide the `template` element in IE, Safari, and Firefox < 22.
+ */
+
+[hidden],
+template {
+ display: none;
+}
+
+/* ==========================================================================
+ Base
+ ========================================================================== */
+
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS text size adjust after orientation change, without disabling
+ * user zoom.
+ */
+
+html {
+ font-family: sans-serif; /* 1 */
+ -ms-text-size-adjust: 100%; /* 2 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/**
+ * Remove default margin.
+ */
+
+body {
+ margin: 0;
+}
+
+/* ==========================================================================
+ Links
+ ========================================================================== */
+
+/**
+ * Remove the gray background color from active links in IE 10.
+ */
+
+a {
+ background: transparent;
+}
+
+/**
+ * Address `outline` inconsistency between Chrome and other browsers.
+ */
+
+a:focus {
+ outline: thin dotted;
+}
+
+/**
+ * Improve readability when focused and also mouse hovered in all browsers.
+ */
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+/* ==========================================================================
+ Typography
+ ========================================================================== */
+
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari 5, and Chrome.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/**
+ * Address styling not present in IE 8/9, Safari 5, and Chrome.
+ */
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
+ */
+
+b,
+strong {
+ font-weight: bold;
+}
+
+/**
+ * Address styling not present in Safari 5 and Chrome.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ */
+
+hr {
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ height: 0;
+}
+
+/**
+ * Address styling not present in IE 8/9.
+ */
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+/**
+ * Correct font family set oddly in Safari 5 and Chrome.
+ */
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, serif;
+ font-size: 1em;
+}
+
+/**
+ * Improve readability of pre-formatted text in all browsers.
+ */
+
+pre {
+ white-space: pre-wrap;
+}
+
+/**
+ * Set consistent quote types.
+ */
+
+q {
+ quotes: "\201C" "\201D" "\2018" "\2019";
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+/* ==========================================================================
+ Embedded content
+ ========================================================================== */
+
+/**
+ * Remove border when inside `a` element in IE 8/9.
+ */
+
+img {
+ border: 0;
+}
+
+/**
+ * Correct overflow displayed oddly in IE 9.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* ==========================================================================
+ Figures
+ ========================================================================== */
+
+/**
+ * Address margin not present in IE 8/9 and Safari 5.
+ */
+
+figure {
+ margin: 0;
+}
+
+/* ==========================================================================
+ Forms
+ ========================================================================== */
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct `color` not being inherited in IE 8/9.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+ border: 0; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * 1. Correct font family not being inherited in all browsers.
+ * 2. Correct font size not being inherited in all browsers.
+ * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
+ */
+
+button,
+input,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 2 */
+ margin: 0; /* 3 */
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+button,
+input {
+ line-height: normal;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
+ * Correct `select` style inheritance in Firefox 4+ and Opera.
+ */
+
+button,
+select {
+ text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ * and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ * `input` and others.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; /* 2 */
+ cursor: pointer; /* 3 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+
+/**
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
+ * 2. Remove excess padding in IE 8/9/10.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
+ * (include `-moz` to future-proof).
+ */
+
+input[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box; /* 2 */
+ box-sizing: content-box;
+}
+
+/**
+ * Remove inner padding and search cancel button in Safari 5 and Chrome
+ * on OS X.
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+/**
+ * 1. Remove default vertical scrollbar in IE 8/9.
+ * 2. Improve readability and alignment in all browsers.
+ */
+
+textarea {
+ overflow: auto; /* 1 */
+ vertical-align: top; /* 2 */
+}
+
+/* ==========================================================================
+ Tables
+ ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}