packages feed

hylogen-0.1.0.6: app/index.html

<!DOCTYPE html>
<html>
  <head>
    <title>HYLOGEN</title>
    <style>
     html, body {
         width: 100%;
         height: 100%;
         margin: 0;
         padding: 0;
         overflow: hidden;
     }
     body {
         display: flex;
         justify-content: center;
         align-items: center;
     }
     #canvas {
         width: 100vmax;
         height: 100vmax;
         background: white;
     }
     #landing {
         width: 100vw;
         height: 100vh;
         position: fixed;
         right: 0;
         top: 0;
         color: white;
         display: flex;
         justify-content: center;
         align-items: center;
         font-family: arial;
         line-height: 10em;
         pointer-events: none;
     }
     #bg {
         background: black;
         width: 100vw;
         height: 100vh;
         position: fixed;
         right: 0;
         top: 0;
         pointer-events: none;
     }

     #title {
         text-transform: uppercase;
         font-style: italic;
         font-weight: bold;
         font-size: 15vw;
         letter-spacing: 0.1em;
         text-shadow: 0 0 0.2em white;
         pointer-events: auto;
     }
     @keyframes fadeOut {
         0% {opacity: 1;}
         100% {opacity: 0;} 
     } 
     .removing {
         -webkit-animation: fadeOut 1000ms;
         -moz-animation: fadeOut 1000ms;
         animation: fadeOut 1000ms;
     }
     a {
         text-decoration: inherit;
         color: white;
     }

     a:visited {
         color: inherit;
     }

    </style>
  </head>
  <body>
    <div id="bg"> </div>
    <div id="landing">
      <div id="title">
        <a href="https://github.com/sleexyz/hylogen">
          Hylogen
        </a>
      </div>
    </div>

    <canvas id="canvas"></canvas>
    <script>
     const vsSource = `
attribute vec3 aPosition;
varying vec2 uvN;
void main() {
  gl_Position = vec4(aPosition, 1.0);
  uvN = aPosition.xy;
}
`;
     const fsHeader=`
precision mediump float;
const float pi = 3.141592653589793238462643383;
uniform float time;
uniform vec2 mouse;
uniform vec4 audio;
uniform sampler2D backBuffer;
varying vec2 uvN;

vec2 uv() {
  return 0.5 * uvN  + 0.5;
}

`

     const initialFsSource = `
void main() {
    gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
`;


     function loadProgram (gl, state, vsSource, fsSource) {

       // compileShader :: (gl, source, shaderType) -> Shader
       // throws Error on compilation error

       function compileShader (gl, source, shaderType) {
         //assert(shaderType === gl.FRAGMENT_SHADER || shaderType === g.VERTEXT_SHADER);

         let shader = gl.createShader(shaderType);

         gl.shaderSource(shader, source);
         gl.compileShader(shader);


         let success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
         if (!success) {
           console.log(source);
           throw "could not compile shader:" + gl.getShaderInfoLog(shader);
         }

         return shader;
       };



       let vs = compileShader(gl, vsSource, gl.VERTEX_SHADER);
       let fs = compileShader(gl, fsSource, gl.FRAGMENT_SHADER);


       let program = gl.createProgram();

       gl.attachShader(program, vs);
       gl.attachShader(program, fs);

       gl.linkProgram(program);

       let success = gl.getProgramParameter(program, gl.LINK_STATUS);
       if (!success) {
         throw ("program failed to link:" + gl.getProgramInfoLog(program));
       }

       gl.useProgram(program);


       // Create a square as a strip of two triangles.
       gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
       gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ -1,1,0, 1,1,0, -1,-1,0, 1,-1,0 ]), gl.STATIC_DRAW);


       // Assign attribute aPosition to each of the square's vertices.
       gl.aPosition = gl.getAttribLocation(program, "aPosition");
       gl.enableVertexAttribArray(gl.aPosition);
       gl.vertexAttribPointer(gl.aPosition, 3, gl.FLOAT, false, 0, 0);

       // backBuffer stuff
       function createTarget() {
         let target = {
           texture: gl.createTexture(),
           framebuffer: gl.createFramebuffer()
         };
         // set up framebuffer
         gl.bindTexture( gl.TEXTURE_2D, target.texture);
         gl.texImage2D( gl.TEXTURE_2D, 0,  gl.RGBA, WIDTH, HEIGHT, 0,  gl.RGBA,  gl.UNSIGNED_BYTE, null);

         gl.texParameteri( gl.TEXTURE_2D,  gl.TEXTURE_WRAP_S,  gl.CLAMP_TO_EDGE);
         gl.texParameteri( gl.TEXTURE_2D,  gl.TEXTURE_WRAP_T,  gl.CLAMP_TO_EDGE);

         gl.texParameteri( gl.TEXTURE_2D,  gl.TEXTURE_MAG_FILTER,  gl.NEAREST);
         gl.texParameteri( gl.TEXTURE_2D,  gl.TEXTURE_MIN_FILTER,  gl.NEAREST);

         gl.bindFramebuffer( gl.FRAMEBUFFER, target.framebuffer);
         gl.framebufferTexture2D( gl.FRAMEBUFFER,  gl.COLOR_ATTACHMENT0,  gl.TEXTURE_2D, target.texture, 0);

         // clean up
         gl.bindTexture( gl.TEXTURE_2D, null);
         gl.bindFramebuffer( gl.FRAMEBUFFER, null);

         return target;
       }
       state.fb[0] = createTarget();
       state.fb[1] = createTarget();

       // remember the address within the fragment shader of each of my uniforms variables
       gl.time = gl.getUniformLocation(program, "time");
       gl.mouse = gl.getUniformLocation(program, "mouse");
       gl.audio = gl.getUniformLocation(program, "audio");
       gl.backBuffer = gl.getUniformLocation(program, "backBuffer");

       draw(gl, state);

       if (state.animationFrameRequest === null) {
         state.animationFrameRequest = requestAnimationFrame(() => animate(gl, state));
       }
     }

     function draw (gl, state) {
       gl.uniform1f(gl.time, (new Date().getTime() / 1000 - state.time0));
       gl.uniform2f(gl.mouse, state.mouse.x, state.mouse.y);
       gl.uniform4f(gl.audio, state.audio.low, state.audio.mid, state.audio.upper, state.audio.high);

       gl.uniform1i(gl.backBuffer, 0); // Do I need to check for null?

       gl.activeTexture(gl.TEXTURE0);
       gl.bindTexture(gl.TEXTURE_2D, state.fb[state.bit].texture);
       state.bit = (state.bit + 1) % 2;
       gl.bindFramebuffer( gl.FRAMEBUFFER, state.fb[state.bit].framebuffer);
       gl.clear(gl.COLOR_BUFFER_BIT);

       gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

       gl.activeTexture(gl.TEXTURE0);
       gl.bindTexture(gl.TEXTURE_2D, state.fb[state.bit].texture);
       gl.bindFramebuffer( gl.FRAMEBUFFER, null);
       gl.clear(gl.COLOR_BUFFER_BIT);

       gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
     };

     function animate (gl, state) {
       draw(gl, state);
       state.animationFrameRequest = requestAnimationFrame(() => animate(gl, state));
     };



     function setupState (state, canvas){
       state.animationFrameRequest = null;

       state.bit = 0
       state.fb = [null, null];

       state.time0 = new Date() / 1000;


       function setMouse (event) {
         let r = event.target.getBoundingClientRect();
         state.mouse.x = (event.clientX - r.left) / (r.right - r.left) * 2 -1;
         state.mouse.y = (event.clientY - r.bottom) / (r.top - r.bottom) * 2 - 1;
       };
       /* canvas.onmousedown = (event) => setMouse(event, 1); */
       /* canvas.onmouseup = (event) => setMouse(event, 0); */

       canvas.onmousemove = (event) => setMouse(event);
       state.mouse = {x: 0, y: 0};


       state.audio = {low: 0.0, mid: 0.0, upper: 0.0, high: 0.0};
       state.audioAgain = null;

       function onAccept (stream) {
         let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
         let source = audioCtx.createMediaStreamSource(stream);
         let analyser = audioCtx.createAnalyser();
         source.connect(analyser);

         analyser.fftSize = 512;
         let bufferLength = analyser.frequencyBinCount;
         let dataArray = new Uint8Array(bufferLength);


         function toAudio() {
           state.audioAgain = requestAnimationFrame(toAudio);
           analyser.getByteFrequencyData(dataArray);

           // Taken from The_Force
           let k = 0, f = 0.0;
           let a = 5, b = 11, c = 24, d = bufferLength, i = 0;

           for(; i < a; i++) {
             f += dataArray[i];
           }

           f *= .2; // 1/(a-0)
           f *= .003921569; // 1/255
           state.audio.low = f;

           f = 0.0;
           for(; i < b; i++) {
             f += dataArray[i];
           }

           f *= .166666667; // 1/(b-a)
           f *= .003921569; // 1/255
           state.audio.mid = f;

           f = 0.0;
           for(; i < c; i++) {
             f += dataArray[i];
           }

           f *= .076923077; // 1/(c-b)
           f *= .003921569; // 1/255
           state.audio.upper = f;

           f = 0.0;
           for(; i < d; i++) {
             f += dataArray[i];
           }
           f *= .00204918; // 1/(d-c)
           f *= .003921569; // 1/255
           state.audio.high = f;
         };

         toAudio();
       }
       function onFail(e) {
         console.error(e);
       }
       navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
       navigator.getUserMedia({audio: true}, onAccept, onFail);
     }




     // stateful variables

     const canvas = document.getElementById("canvas");
     let WIDTH = Math.max(window.innerHeight, window.innerWidth);
     let HEIGHT =  Math.max(window.innerHeight, window.innerWidth);
     canvas.width = WIDTH;
     canvas.height = HEIGHT;

     const gl = canvas.getContext("webgl");

     const state = {};

     setupState(state, canvas);


     loadProgram (gl, state,  vsSource, fsHeader + initialFsSource);


     function fadeOut(elem) {
       elem.className = "removing";
       window.setTimeout(function() {
         elem.remove();
       }, 1000);
     }

     function connectToHylogen() {
       const wsConn = new WebSocket("ws://localhost:8080/");

       wsConn.onopen = function() {
         const landing = document.getElementById("landing");
         if (landing) {
           fadeOut(document.getElementById("bg"));
           window.setTimeout(() => {fadeOut(landing);}, 500);
         }
         console.log('websocket opened');

       };

       wsConn.onclose = function() {
         console.log('websocket closed');
         window.setTimeout(connectToHylogen, 100);
       };

       wsConn.onmessage = function (m) {
         console.log(m.data);
         loadProgram(gl, state,  vsSource, fsHeader + m.data);
       };
     }

     connectToHylogen();
    </script>
  </body>
</html>