src/glsl-transition-core.js
function createTransition (glsl) {
    // Second level variables
    var buffer, shader, textureUnits, textures;

    function load () {
      if (!gl) return;
      buffer = gl.createBuffer();
      shader = createShader(gl, VERTEX_SHADER, glsl);
      
      textureUnits = {};
      textures = {};
      var i = 0;
      for (var name in shader.types.uniforms) {
        var t = shader.types.uniforms[name];
        if (t === "sampler2D") {
          textureUnits[name] = i;
          i ++;
        }
      }
    }

    function onContextLost () {
      if (shader) shader.dispose();
      shader = null;
    }

    function onContextRestored () {
      load();
    }

    function syncViewport () {
      var w = canvas.width, h = canvas.height;
      var x1 = 0, x2 = w, y1 = 0, y2 = h;
      if (currentShader) {
        currentShader.uniforms[RESOLUTION_UNIFORM] = new Float32Array([ w, h ]);
      }
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
      shader.attributes.position.pointer();
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        x1, y1,
        x2, y1,
        x1, y2,
        x1, y2,
        x2, y1,
        x2, y2
      ]), gl.STATIC_DRAW);
      gl.viewport(x1, y1, x2, y2);
    }

    function setProgress (p) {
      shader.uniforms[PROGRESS_UNIFORM] = p;
    }

    function setUniform (name, value) {
      if (name in textureUnits) {
        var i = textureUnits[name];
        gl.activeTexture(gl.TEXTURE0 + i);

        var texture = textures[name];
        // Destroy the previous texture
        if (texture) texture.dispose();

        if (value === null) {
          // Texture is now a black texture
          textures[name] = texture = createTexture(gl, 2, 2);
        }
        else {
          gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
          // Create a new texture
          textures[name] = texture = createTexture(gl, value);
        }

        shader.uniforms[name] = texture.bind(i);
      }
      else {
        shader.uniforms[name] = value;
      }
    }

    function reset () {
      var hasChanged = false;
      if (!shader) {
        load(); // Possibly shader was not loaded.
        hasChanged = true;
      }
      if (currentShader !== shader) {
        currentShader = shader;
        shader.bind();
        hasChanged = true;
      }
      syncViewport();
      return hasChanged;
    }

    function destroy () {
      if (currentShader === shader) {
        currentShader = null;
      }
      if (shader) {
        for (var t in textures) {
          textures[t].dispose();
        }
        textures = null;
        shader.dispose();
        shader = null;
      }
    }

    function getUniforms () {
      if (!shader) load();
      return extend({}, shader.types.uniforms);
    }

    var transition = {
      getGL: function () {
        return gl;
      },
      load: function () {
        // Possibly shader was not loaded.
        if (!shader) load();
      },
      bind: function () {
        // If shader has changed, we need to bind it
        if (currentShader !== shader) {
          currentShader = shader;
          if (!shader) load();
          shader.bind();
        }
      },
      isCurrentTransition: function () {
        return currentShader === shader;
      },
      onContextLost: onContextLost,
      onContextRestored: onContextRestored,
      syncViewport: syncViewport,
      setProgress: setProgress,
      setUniform: setUniform,
      reset: reset,
      draw: draw,
      destroy: destroy,
      getUniforms: getUniforms
    };

    transitions.push(transition);

    return transition;
  }
function createTransition (glsl) {
    // Second level variables
    var buffer, shader, textureUnits, textures;

    function load () {
      if (!gl) return;
      buffer = gl.createBuffer();
      shader = createShader(gl, VERTEX_SHADER, glsl);
      
      textureUnits = {};
      textures = {};
      var i = 0;
      for (var name in shader.types.uniforms) {
        var t = shader.types.uniforms[name];
        if (t === "sampler2D") {
          textureUnits[name] = i;
          i ++;
        }
      }
    }

    function onContextLost () {
      if (shader) shader.dispose();
      shader = null;
    }

    function onContextRestored () {
      load();
    }

    function syncViewport () {
      var w = canvas.width, h = canvas.height;
      var x1 = 0, x2 = w, y1 = 0, y2 = h;
      if (currentShader) {
        currentShader.uniforms[RESOLUTION_UNIFORM] = new Float32Array([ w, h ]);
      }
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
      shader.attributes.position.pointer();
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        x1, y1,
        x2, y1,
        x1, y2,
        x1, y2,
        x2, y1,
        x2, y2
      ]), gl.STATIC_DRAW);
      gl.viewport(x1, y1, x2, y2);
    }

    function setProgress (p) {
      shader.uniforms[PROGRESS_UNIFORM] = p;
    }

    function setUniform (name, value) {
      if (name in textureUnits) {
        var i = textureUnits[name];
        gl.activeTexture(gl.TEXTURE0 + i);

        var texture = textures[name];
        // Destroy the previous texture
        if (texture) texture.dispose();

        if (value === null) {
          // Texture is now a black texture
          textures[name] = texture = createTexture(gl, 2, 2);
        }
        else {
          gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
          // Create a new texture
          textures[name] = texture = createTexture(gl, value);
        }

        shader.uniforms[name] = texture.bind(i);
      }
      else {
        shader.uniforms[name] = value;
      }
    }

    function reset () {
      var hasChanged = false;
      if (!shader) {
        load(); // Possibly shader was not loaded.
        hasChanged = true;
      }
      if (currentShader !== shader) {
        currentShader = shader;
        shader.bind();
        hasChanged = true;
      }
      syncViewport();
      return hasChanged;
    }

    function destroy () {
      if (currentShader === shader) {
        currentShader = null;
      }
      if (shader) {
        for (var t in textures) {
          textures[t].dispose();
        }
        textures = null;
        shader.dispose();
        shader = null;
      }
    }

    function getUniforms () {
      if (!shader) load();
      return extend({}, shader.types.uniforms);
    }

    var transition = {
      getGL: function () {
        return gl;
      },
      load: function () {
        // Possibly shader was not loaded.
        if (!shader) load();
      },
      bind: function () {
        // If shader has changed, we need to bind it
        if (currentShader !== shader) {
          currentShader = shader;
          if (!shader) load();
          shader.bind();
        }
      },
      isCurrentTransition: function () {
        return currentShader === shader;
      },
      onContextLost: onContextLost,
      onContextRestored: onContextRestored,
      syncViewport: syncViewport,
      setProgress: setProgress,
      setUniform: setUniform,
      reset: reset,
      draw: draw,
      destroy: destroy,
      getUniforms: getUniforms
    };

    transitions.push(transition);

    return transition;
  }
~~~ Second Call in the API
createTransition(glslSource, [uniforms])
Creates a GLSL Transition for the current canvas context.