Demo = function(statusEl, canvas) {
  /**
   * Element that will get status text.
   * @type {!Element}
   * @private
   */
  this.statusEl_ = statusEl;

  /**
   * Target canvas.
   * @type {!HTMLCanvasElement}
   * @private
   */
  this.canvas_ = canvas;

  /**
   * WebGL context.
   * @type {!WebGLRenderingContext}
   * @private
   */
  this.gl_ = this.createWebGL_(canvas);
  var gl = this.gl_;

  /**
   * Camera.
   * @type {!Camera}
   * @private
   */
  this.camera_ = new Camera();

  /**
   * Stereo renderer.
   * @type {!vr.StereoRenderer}
   * @private
   */
  this.stereoRenderer_ = new vr.StereoRenderer(this.gl_, {
    alpha: false,
    depth: true,
    stencil: false
  });

  /**
   * VR state.
   * @type {!vr.State}
   * @private
   */
  this.vrstate_ = new vr.State();

  /**
   * Time of the previous tick.
   * Used to calculate frame deltas for animation.
   * @type {number}
   * @private
   */
  this.lastTick_ = 0;

  /**
   * Simple shader program used to draw a cube.
   * @type {!vr.Program}
   * @private
   */
  this.cubeProgram_ = new vr.Program(gl, 'CubeProgram',
      [
        'attribute vec3 a_xyz;',
        'attribute vec2 a_uv;',
        'varying vec2 v_uv;',
        'uniform mat4 u_projectionMatrix;',
        'uniform mat4 u_modelViewMatrix;',
        'void main() {',
        '  gl_Position = u_projectionMatrix * u_modelViewMatrix * ',
        '      vec4(a_xyz, 1.0);',
        '  v_uv = a_uv;',
        '}'
      ].join('\n'),
      [
        'precision highp float;',
        'varying vec2 v_uv;',
        'void main() {',
        '  gl_FragColor = vec4(v_uv, 0.0, 1.0);',
        '}'
      ].join('\n'),
      ['a_xyz', 'a_uv'],
      ['u_projectionMatrix', 'u_modelViewMatrix']);
  this.cubeProgram_.beginLinking();
  this.cubeProgram_.endLinking();
  this.cubeBuffer_ = gl.createBuffer();
  this.cubeBuffer_.displayName = 'CubeVertexBuffer';
  gl.bindBuffer(gl.ARRAY_BUFFER, this.cubeBuffer_);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    -1.0, -1.0,  1.0, 0.0, 0.0, // Front face
     1.0, -1.0,  1.0, 1.0, 0.0,
     1.0,  1.0,  1.0, 1.0, 1.0,
    -1.0,  1.0,  1.0, 0.0, 1.0,
    -1.0, -1.0, -1.0, 1.0, 0.0, // Back face
    -1.0,  1.0, -1.0, 1.0, 1.0,
     1.0,  1.0, -1.0, 0.0, 1.0,
     1.0, -1.0, -1.0, 0.0, 0.0,
    -1.0,  1.0, -1.0, 0.0, 1.0, // Top face
    -1.0,  1.0,  1.0, 0.0, 0.0,
     1.0,  1.0,  1.0, 1.0, 0.0,
     1.0,  1.0, -1.0, 1.0, 1.0,
    -1.0, -1.0, -1.0, 1.0, 1.0, // Bottom face
     1.0, -1.0, -1.0, 0.0, 1.0,
     1.0, -1.0,  1.0, 0.0, 0.0,
    -1.0, -1.0,  1.0, 1.0, 0.0,
     1.0, -1.0, -1.0, 1.0, 0.0, // Right face
     1.0,  1.0, -1.0, 1.0, 1.0,
     1.0,  1.0,  1.0, 0.0, 1.0,
     1.0, -1.0,  1.0, 0.0, 0.0,
    -1.0, -1.0, -1.0, 0.0, 0.0, // Left face
    -1.0, -1.0,  1.0, 1.0, 0.0,
    -1.0,  1.0,  1.0, 1.0, 1.0,
    -1.0,  1.0, -1.0, 0.0, 1.0,
  ]), gl.STATIC_DRAW);
  this.cubeIndexBuffer_ = gl.createBuffer();
  this.cubeIndexBuffer_.displayName = 'CubeIndexBuffer';
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.cubeIndexBuffer_);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([
    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.STATIC_DRAW);

  // Common key handlers.
  var self = this;
  document.addEventListener('keydown', function(e) {
    if (self.keyPressed_(e)) {
      e.preventDefault();
    }
  }, false);

  // Kickoff the demo.
  this.tick_();
}
Demo app.
@param {!Element} statusEl Element that will get status text.
@param {!HTMLCanvasElement} canvas Target render canvas.
@constructor