function createProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback) {
	    var progOptions = getProgramOptions(opt_attribs, opt_locations, opt_errorCallback);
	    var realShaders = [];
	    var newShaders = [];
	    for (var ndx = 0; ndx < shaders.length; ++ndx) {
	      var shader = shaders[ndx];
	      if (typeof shader === 'string') {
	        var elem = document.getElementById(shader);
	        var src = elem ? elem.text : shader;
	        var type = gl[defaultShaderType[ndx]];
	        if (elem && elem.type) {
	          type = getShaderTypeFromScriptType(elem.type) || type;
	        }
	        shader = loadShader(gl, src, type, progOptions.errorCallback);
	        newShaders.push(shader);
	      }
	      if (shader instanceof WebGLShader) {
	        realShaders.push(shader);
	      }
	    }

	    if (realShaders.length !== shaders.length) {
	      programOptions.errorCallback("not enough shaders for program");
	      deleteShaders(gl, newShaders);
	      return null;
	    }

	    var program = gl.createProgram();
	    realShaders.forEach(function (shader) {
	      gl.attachShader(program, shader);
	    });
	    if (progOptions.attribLocations) {
	      Object.keys(progOptions.attribLocations).forEach(function (attrib) {
	        gl.bindAttribLocation(program, progOptions.attribLocations[attrib], attrib);
	      });
	    }
	    var varyings = progOptions.transformFeedbackVaryings;
	    if (varyings) {
	      if (varyings.attribs) {
	        varyings = varyings.attribs;
	      }
	      if (!Array.isArray(varyings)) {
	        varyings = Object.keys(varyings);
	      }
	      gl.transformFeedbackVaryings(program, varyings, progOptions.transformFeedbackMode || gl.SEPARATE_ATTRIBS);
	    }
	    gl.linkProgram(program);

	    // Check the link status
	    var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
	    if (!linked) {
	      // something went wrong with the link
	      var lastError = gl.getProgramInfoLog(program);
	      progOptions.errorCallback("Error in program linking:" + lastError);

	      gl.deleteProgram(program);
	      deleteShaders(gl, newShaders);
	      return null;
	    }
	    return program;
	  }
/**
	   * Creates a program, attaches (and/or compiles) shaders, binds attrib locations, links the
	   * program and calls useProgram.
	   *
	   * NOTE: There are 4 signatures for this function
	   *
	   *     twgl.createProgram(gl, [vs, fs], options);
	   *     twgl.createProgram(gl, [vs, fs], opt_errFunc);
	   *     twgl.createProgram(gl, [vs, fs], opt_attribs, opt_errFunc);
	   *     twgl.createProgram(gl, [vs, fs], opt_attribs, opt_locations, opt_errFunc);
	   *
	   * @param {WebGLShader[]|string[]} shaders The shaders to attach, or element ids for their source, or strings that contain their source
	   * @param {module:twgl.ProgramOptions|string[]} [opt_attribs] Options for the program or an array of attribs names. Locations will be assigned by index if not passed in
	   * @param {number[]} [opt_locations] The locations for the. A parallel array to opt_attribs letting you assign locations.
	   * @param {module:twgl.ErrorCallback} [opt_errorCallback] callback for errors. By default it just prints an error to the console
	   *        on error. If you want something else pass an callback. It's passed an error message.
	   * @return {WebGLProgram?} the created program or null if error.
	   * @memberOf module:twgl/programs
	   */
Creates a program, attaches (and/or compiles) shaders, binds attrib locations, links the
program and calls useProgram.

There are 4 signatures for this function



@param {WebGLShader[]|string[]} shaders The shaders to attach, or element ids for their source, or strings that contain their source
@param {module:twgl.ProgramOptions|string[]} [opt_attribs] Options for the program or an array of attribs names. Locations will be assigned by index if not passed in
@param {number[]} [opt_locations] The locations for the. A parallel array to opt_attribs letting you assign locations.
Creates a program attaches ( and / or compiles ) shaders binds attrib locations links the program and calls useProgram . There are 4 signatures for this function @param { WebGLShader [] |string [] } shaders The shaders to attach or element ids for their source or strings that contain their source @param { module : twgl . ProgramOptions|string [] } [ opt_attribs ] Options for the program or an array of attribs names . Locations will be assigned by index if not passed in @param { number [] } [ opt_locations ] The locations for the . A parallel array to opt_attribs letting you assign locations .
function createProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback) {
	    var progOptions = getProgramOptions(opt_attribs, opt_locations, opt_errorCallback);
	    var realShaders = [];
	    var newShaders = [];
	    for (var ndx = 0; ndx < shaders.length; ++ndx) {
	      var shader = shaders[ndx];
	      if (typeof shader === 'string') {
	        var elem = document.getElementById(shader);
	        var src = elem ? elem.text : shader;
	        var type = gl[defaultShaderType[ndx]];
	        if (elem && elem.type) {
	          type = getShaderTypeFromScriptType(elem.type) || type;
	        }
	        shader = loadShader(gl, src, type, progOptions.errorCallback);
	        newShaders.push(shader);
	      }
	      if (shader instanceof WebGLShader) {
	        realShaders.push(shader);
	      }
	    }
	    if (realShaders.length !== shaders.length) {
	      programOptions.errorCallback("not enough shaders for program");
	      deleteShaders(gl, newShaders);
	      return null;
	    }
	    var program = gl.createProgram();
	    realShaders.forEach(function (shader) {
	      gl.attachShader(program, shader);
	    });
	    if (progOptions.attribLocations) {
	      Object.keys(progOptions.attribLocations).forEach(function (attrib) {
	        gl.bindAttribLocation(program, progOptions.attribLocations[attrib], attrib);
	      });
	    }
	    var varyings = progOptions.transformFeedbackVaryings;
	    if (varyings) {
	      if (varyings.attribs) {
	        varyings = varyings.attribs;
	      }
	      if (!Array.isArray(varyings)) {
	        varyings = Object.keys(varyings);
	      }
	      gl.transformFeedbackVaryings(program, varyings, progOptions.transformFeedbackMode || gl.SEPARATE_ATTRIBS);
	    }
	    gl.linkProgram(program);
	    var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
	    if (!linked) {
	      var lastError = gl.getProgramInfoLog(program);
	      progOptions.errorCallback("Error in program linking:" + lastError);
	      gl.deleteProgram(program);
	      deleteShaders(gl, newShaders);
	      return null;
	    }
	    return program;
	  }
function createProgram ( gl , shaders , opt_attribs , opt_locations , opt_errorCallback ) { var progOptions = getProgramOptions ( opt_attribs , opt_locations , opt_errorCallback ) ; var realShaders = [ ] ; var newShaders = [ ] ; for ( var ndx = 0 ; ndx < shaders . length ; ++ ndx ) { var shader = shaders [ ndx ] ; if ( typeof shader === 'string' ) { var elem = document . getElementById ( shader ) ; var src = elem ? elem . text : shader ; var type = gl [ defaultShaderType [ ndx ] ] ; if ( elem && elem . type ) { type = getShaderTypeFromScriptType ( elem . type ) || type ; } shader = loadShader ( gl , src , type , progOptions . errorCallback ) ; newShaders . push ( shader ) ; } if ( shader instanceof WebGLShader ) { realShaders . push ( shader ) ; } } if ( realShaders . length !== shaders . length ) { programOptions . errorCallback ( "not enough shaders for program" ) ; deleteShaders ( gl , newShaders ) ; return null ; } var program = gl . createProgram ( ) ; realShaders . forEach ( function ( shader ) { gl . attachShader ( program , shader ) ; } ) ; if ( progOptions . attribLocations ) { Object . keys ( progOptions . attribLocations ) . forEach ( function ( attrib ) { gl . bindAttribLocation ( program , progOptions . attribLocations [ attrib ] , attrib ) ; } ) ; } var varyings = progOptions . transformFeedbackVaryings ; if ( varyings ) { if ( varyings . attribs ) { varyings = varyings . attribs ; } if ( ! Array . isArray ( varyings ) ) { varyings = Object . keys ( varyings ) ; } gl . transformFeedbackVaryings ( program , varyings , progOptions . transformFeedbackMode || gl . SEPARATE_ATTRIBS ) ; } gl . linkProgram ( program ) ; var linked = gl . getProgramParameter ( program , gl . LINK_STATUS ) ; if ( ! linked ) { var lastError = gl . getProgramInfoLog ( program ) ; progOptions . errorCallback ( "Error in program linking:" + lastError ) ; gl . deleteProgram ( program ) ; deleteShaders ( gl , newShaders ) ; return null ; } return program ; }
Creates a program, attaches (and/or compiles) shaders, binds attrib locations, links the
 program and calls useProgram.
Creates a program attaches ( and / or compiles ) shaders binds attrib locations links the program and calls useProgram .
// Check the link status // something went wrong with the link