title: "Cannot read property 'projection' of undefined" :webgl error in my 1st 3D geometry program
body: <p>I am looking at webglfundamentals blog series and learning animations. Based on my understanding, I am trying to replicate <a href="https://webglfundamentals.org/webgl/webgl-3d-step2.html" rel="nofollow noreferrer">this</a> in a slightly different manner, such that I do not have dependency on util files of the blog series. I am unable to resolve this error: </p>
  
  <pre><code>Cannot read property 'projection' of undefined
      at createVertices.
  </code></pre>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>var gl,
      shaderProgram,
      vertices;
  
  initGL();
  createShaders();
  createVertices();
  
  function initGL() {
    var canvas = document.getElementById("canvas");
    console.log(canvas);
    gl = canvas.getContext("webgl");
    gl.viewport(0, 0, canvas.width, canvas.height);
    gl.clearColor(1, 1, 1, 1);
  }
  
  function createShaders() {
    var vertexShader = getShader(gl, "3d-vertex-shader");
    var fragmentShader = getShader(gl, "3d-fragment-shader");
    
    shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);
  
  }
  
  function createVertices() {
    vertices = [
     // left column
              0,   0,  0,
             30,   0,  0,
              0, 150,  0,
              0, 150,  0,
             30,   0,  0,
             30, 150,  0,
   
            // top rung
             30,   0,  0,
            100,   0,  0,
             30,  30,  0,
             30,  30,  0,
            100,   0,  0,
            100,  30,  0,
   
            // middle rung
             30,  60,  0,
             67,  60,  0,
             30,  90,  0,
             30,  90,  0,
             67,  60,  0,
             67,  90,  0
    ];
     
  
    
    //create buffer
    var buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    
    
    function radToDeg(r) {
      return r * 180 / Math.PI;
    }
  
    function degToRad(d) {
      return d * Math.PI / 180;
    }
  
    var translation = [45, 150, 0];
    var rotation = [degToRad(40), degToRad(25), degToRad(325)];
    var scale = [1, 1, 1];
    var color = [Math.random(), Math.random(), Math.random(), 1];
    
    
    
    // look up where the vertex data needs to go.
    var positionLocation = gl.getAttribLocation(shaderProgram, "a_position");
  
    // lookup uniforms
    var colorLocation = gl.getUniformLocation(shaderProgram, "u_color");
    var matrixLocation = gl.getUniformLocation(shaderProgram, "u_matrix");
    
     
     // webglUtils.resizeCanvasToDisplaySize(gl.canvas);
  
      // Tell it to use our program (pair of shaders)
      gl.useProgram(shaderProgram);
  
      // Turn on the attribute
      gl.enableVertexAttribArray(positionLocation);
    
      // Create a buffer to put positions in
      var positionBuffer = gl.createBuffer();
      // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
      gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  
      // Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
      var size = 3;          // 3 components per iteration
      var type = gl.FLOAT;   // the data is 32bit floats
      var normalize = false; // don't normalize the data
      var stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
      var offset = 0;        // start at the beginning of the buffer
      gl.vertexAttribPointer(
          positionLocation, size, type, normalize, stride, offset)
  
      // set the color
      gl.uniform4fv(colorLocation, color);
  
      // Compute the matrices
      var matrix = m4.projection(gl.canvas.clientWidth, gl.canvas.clientHeight, 400);
      matrix = m4.translate(matrix, translation[0], translation[1], translation[2]);
      matrix = m4.xRotate(matrix, rotation[0]);
      matrix = m4.yRotate(matrix, rotation[1]);
      matrix = m4.zRotate(matrix, rotation[2]);
      matrix = m4.scale(matrix, scale[0], scale[1], scale[2]);
  
      // Set the matrix.
      gl.uniformMatrix4fv(matrixLocation, false, matrix);
  
      // Draw the geometry.
      var primitiveType = gl.TRIANGLES;
      var offset = 0;
      var count = 18;  // 6 triangles in the 'F', 3 points per triangle
      gl.drawArrays(primitiveType, offset, count);
  }
  
  //m4 
  var m4 = {
  
    projection: function(width, height, depth) {
      // Note: This matrix flips the Y axis so 0 is at the top.
      return [
         2 / width, 0, 0, 0,
         0, -2 / height, 0, 0,
         0, 0, 2 / depth, 0,
        -1, 1, 0, 1,
      ];
    },
  
    multiply: function(a, b) {
      var a00 = a[0 * 4 + 0];
      var a01 = a[0 * 4 + 1];
      var a02 = a[0 * 4 + 2];
      var a03 = a[0 * 4 + 3];
      var a10 = a[1 * 4 + 0];
      var a11 = a[1 * 4 + 1];
      var a12 = a[1 * 4 + 2];
      var a13 = a[1 * 4 + 3];
      var a20 = a[2 * 4 + 0];
      var a21 = a[2 * 4 + 1];
      var a22 = a[2 * 4 + 2];
      var a23 = a[2 * 4 + 3];
      var a30 = a[3 * 4 + 0];
      var a31 = a[3 * 4 + 1];
      var a32 = a[3 * 4 + 2];
      var a33 = a[3 * 4 + 3];
      var b00 = b[0 * 4 + 0];
      var b01 = b[0 * 4 + 1];
      var b02 = b[0 * 4 + 2];
      var b03 = b[0 * 4 + 3];
      var b10 = b[1 * 4 + 0];
      var b11 = b[1 * 4 + 1];
      var b12 = b[1 * 4 + 2];
      var b13 = b[1 * 4 + 3];
      var b20 = b[2 * 4 + 0];
      var b21 = b[2 * 4 + 1];
      var b22 = b[2 * 4 + 2];
      var b23 = b[2 * 4 + 3];
      var b30 = b[3 * 4 + 0];
      var b31 = b[3 * 4 + 1];
      var b32 = b[3 * 4 + 2];
      var b33 = b[3 * 4 + 3];
      return [
        b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
        b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
        b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
        b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
        b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
        b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
        b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
        b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
        b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
        b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
        b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
        b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
        b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
        b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
        b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
        b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33,
      ];
    },
  
    translation: function(tx, ty, tz) {
      return [
         1,  0,  0,  0,
         0,  1,  0,  0,
         0,  0,  1,  0,
         tx, ty, tz, 1,
      ];
    },
  
    xRotation: function(angleInRadians) {
      var c = Math.cos(angleInRadians);
      var s = Math.sin(angleInRadians);
  
      return [
        1, 0, 0, 0,
        0, c, s, 0,
        0, -s, c, 0,
        0, 0, 0, 1,
      ];
    },
  
    yRotation: function(angleInRadians) {
      var c = Math.cos(angleInRadians);
      var s = Math.sin(angleInRadians);
  
      return [
        c, 0, -s, 0,
        0, 1, 0, 0,
        s, 0, c, 0,
        0, 0, 0, 1,
      ];
    },
  
    zRotation: function(angleInRadians) {
      var c = Math.cos(angleInRadians);
      var s = Math.sin(angleInRadians);
  
      return [
         c, s, 0, 0,
        -s, c, 0, 0,
         0, 0, 1, 0,
         0, 0, 0, 1,
      ];
    },
  
    scaling: function(sx, sy, sz) {
      return [
        sx, 0,  0,  0,
        0, sy,  0,  0,
        0,  0, sz,  0,
        0,  0,  0,  1,
      ];
    },
  
    translate: function(m, tx, ty, tz) {
      return m4.multiply(m, m4.translation(tx, ty, tz));
    },
  
    xRotate: function(m, angleInRadians) {
      return m4.multiply(m, m4.xRotation(angleInRadians));
    },
  
    yRotate: function(m, angleInRadians) {
      return m4.multiply(m, m4.yRotation(angleInRadians));
    },
  
    zRotate: function(m, angleInRadians) {
      return m4.multiply(m, m4.zRotation(angleInRadians));
    },
  
    scale: function(m, sx, sy, sz) {
      return m4.multiply(m, m4.scaling(sx, sy, sz));
    },
  
  };
  // m4 ends
  
  
    /*
     * https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context
     */
    function getShader(gl, id) {
      var shaderScript, theSource, currentChild, shader;
  
      shaderScript = document.getElementById(id);
  
      if (!shaderScript) {
        return null;
      }
  
      theSource = "";
      currentChild = shaderScript.firstChild;
  
      while (currentChild) {
        if (currentChild.nodeType == currentChild.TEXT_NODE) {
          theSource += currentChild.textContent;
        }
  
        currentChild = currentChild.nextSibling;
      }
      if (shaderScript.type == "x-shader/x-fragment") {
        shader = gl.createShader(gl.FRAGMENT_SHADER);
      } else if (shaderScript.type == "x-shader/x-vertex") {
        shader = gl.createShader(gl.VERTEX_SHADER);
      } else {
        // Unknown shader type
        return null;
      }
      gl.shaderSource(shader, theSource);
  
  // Compile the shader program
      gl.compileShader(shader);
  
  // See if it compiled successfully
      if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));
        return null;
      }
  
      return shader;
    }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;canvas id="canvas"&gt;&lt;/canvas&gt;
  
  
  &lt;!-- vertex shader --&gt;
  &lt;script id="3d-vertex-shader" type="x-shader/x-vertex"&gt;
  attribute vec4 a_position;
  
  uniform mat4 u_matrix;
  
  void main() {
    // Multiply the position by the matrix.
    gl_Position = u_matrix * a_position;
  }
  &lt;/script&gt;
  &lt;!-- fragment shader --&gt;
  &lt;script id="3d-fragment-shader" type="x-shader/x-fragment"&gt;
  precision mediump float;
  
  uniform vec4 u_color;
  
  void main() {
     gl_FragColor = u_color;
  }
  &lt;/script&gt;
  &lt;!--
  for most samples webgl-utils only provides shader compiling/linking and
  canvas resizing because why clutter the examples with code that's the same in every sample.
  See http://webglfundamentals.org/webgl/lessons/webgl-boilerplate.html
  and http://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
  for webgl-utils, m3, m4, and webgl-lessons-ui.
  --&gt;
  &lt;script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"&gt;&lt;/script&gt;
  &lt;script src="https://webglfundamentals.org/webgl/resources/webgl-lessons-ui.js"&gt;&lt;/script&gt;
  &lt;script src="https://webglfundamentals.org/webgl/resources/webgl-lessons-helper.js"&gt;&lt;/script&gt;</code></pre>
  </div>
  </div>
  </p>
  
  <p>My version of the pen is <a href="https://codepen.io/anon/pen/pdEmMy" rel="nofollow noreferrer">here.</a></p>
  
  <p>It would be great if somebody could help me fix this error.</p>