text: let c, gl;
  let aLoc = [];
  let uLoc = [];
  
  function initWebGL() {
      c = document.getElementById("c");
      gl = c.getContext("webgl");
      gl.enable(gl.DEPTH_TEST);
      resizeCanvas();
      window.addEventListener("resize", function(){
          resizeCanvas();
      });
  }
  
  function resizeCanvas() {
      c.width = window.innerWidth;
      c.height = window.innerHeight;
      gl.viewport(0, 0, c.width, c.height);
  }
  
  function initShaders() {
      let p = gl.createProgram();
      let vs = gl.createShader(gl.VERTEX_SHADER);
      let fs = gl.createShader(gl.FRAGMENT_SHADER);
      let v = document.getElementById("vs").textContent;
      let f = document.getElementById("fs").textContent;
      gl.shaderSource(vs, v);
      gl.shaderSource(fs, f);
      gl.compileShader(vs);
      gl.compileShader(fs);
      gl.attachShader(p, vs);
      gl.attachShader(p, fs);
      gl.linkProgram(p);
      gl.useProgram(p);
      aLoc[0] = gl.getAttribLocation(p, "position");
      aLoc[1] = gl.getAttribLocation(p, "textureCoord");
      uLoc[0] = gl.getUniformLocation(p, "uPMatrix");
      uLoc[1] = gl.getUniformLocation(p, "uMVMatrix");
      uLoc[2]  = gl.getUniformLocation(p, "uTexture");
      gl.enableVertexAttribArray(aLoc[0]);
      gl.enableVertexAttribArray(aLoc[1]);
  }
  
  let mvMatrix = mat4.create();
  let pMatrix = mat4.create();
  
  let vertexPositionBuffer;
  let coordBuffer
  let vertexIndexBuffer;
  
  function initBuffers() {
      vertexPositionBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
      // Cube data
      //             1.0 y 
      //              ^  -1.0 
      //              | / z
      //              |/       x
      // -1.0 -----------------> +1.0
      //            / |
      //      +1.0 /  |
      //           -1.0
      // 
      //         [7]------[6]
      //        / |      / |
      //      [3]------[2] |
      //       |  |     |  |
      //       | [4]----|-[5]
      //       |/       |/
      //      [0]------[1]
      //
      const positions = [ 
          // Front face
          -0.5, -0.5,  0.5, // v0
           0.5, -0.5,  0.5, // v1
           0.5,  0.5,  0.5, // v2
          -0.5,  0.5,  0.5, // v3
          // Back face
          -0.5, -0.5, -0.5, // v4
           0.5, -0.5, -0.5, // v5
           0.5,  0.5, -0.5, // v6
          -0.5,  0.5, -0.5, // v7
          // Top face
           0.5,  0.5,  0.5, // v2
          -0.5,  0.5,  0.5, // v3
          -0.5,  0.5, -0.5, // v7
           0.5,  0.5, -0.5, // v6
          // Bottom face
          -0.5, -0.5,  0.5, // v0
           0.5, -0.5,  0.5, // v1
           0.5, -0.5, -0.5, // v5
          -0.5, -0.5, -0.5, // v4
           // Right face
           0.5, -0.5,  0.5, // v1
           0.5,  0.5,  0.5, // v2
           0.5,  0.5, -0.5, // v6
           0.5, -0.5, -0.5, // v5
           // Left face
          -0.5, -0.5,  0.5, // v0
          -0.5,  0.5,  0.5, // v3
          -0.5,  0.5, -0.5, // v7
          -0.5, -0.5, -0.5  // v4
      ];
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
  
      coordBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, coordBuffer);
      const textureCoords = [
          // Front face
          0.0, 0.0,
          1.0, 0.0,
          1.0, 1.0,
          0.0, 1.0,
  
          // Back face
          1.0, 0.0,
          1.0, 1.0,
          0.0, 1.0,
          0.0, 0.0,
  
          // Top face
          0.0, 1.0,
          0.0, 0.0,
          1.0, 0.0,
          1.0, 1.0,
  
          // Bottom face
          1.0, 1.0,
          0.0, 1.0,
          0.0, 0.0,
          1.0, 0.0,
  
          // Right face
          1.0, 0.0,
          1.0, 1.0,
          0.0, 1.0,
          0.0, 0.0,
  
          // Left face
          0.0, 0.0,
          1.0, 0.0,
          1.0, 1.0,
          0.0, 1.0,
      ];
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
      
      vertexIndexBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);
      const indices = [
           0,  1,  2,    0,  2 , 3,  // Front face
           4,  5,  6,    4,  6 , 7,  // Back face
           8,  9, 10,    8, 10, 11,  // Top face
          12, 13, 14,   12, 14, 15,  // Bottom face
          16, 17, 18,   16, 18, 19,  // Right face
          20, 21, 22,   20, 22, 23   // Left face
      ];
      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
  
      let img = new Image();
      let texture;
      img.onload = function(){
          texture = gl.createTexture();
          gl.bindTexture(gl.TEXTURE_2D, texture);
          gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
          gl.generateMipmap(gl.TEXTURE_2D);
      };
      img.src = "../../../assets/textures/frog.jpg";  // 256x256
  }
  
  let rad = 0;
  function draw(timestamp) {
      //rad += Math.PI * 1.0 / 180.0;
      rad = timestamp / 1000; // Seconds since the first requestAnimationFrame (ms)
      mat4.perspective(pMatrix, 45, c.width / c.height, 0.1, 100.0);
      mat4.identity(mvMatrix);
      let translation = vec3.create();
      vec3.set(translation, 0.0, 0.0, -2.0);
      mat4.translate(mvMatrix, mvMatrix, translation);
      mat4.rotate(mvMatrix, mvMatrix, rad, [1, 1, 1]);
  
      gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
      gl.vertexAttribPointer(aLoc[0], 3, gl.FLOAT, false, 0, 0);
      
      gl.bindBuffer(gl.ARRAY_BUFFER, coordBuffer);
      gl.vertexAttribPointer(aLoc[1], 2, gl.FLOAT, false, 0, 0);
      
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);
      gl.uniformMatrix4fv(uLoc[0], false, pMatrix);
      gl.uniformMatrix4fv(uLoc[1], false, mvMatrix);
  
      gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
      gl.flush();
  }
  
  function animate(timestamp) {
      draw(timestamp);
      requestAnimationFrame(animate);
  }
  
  initWebGL();
  initShaders();
  initBuffers();
  animate();