Problems with a shader overlaying a webgl2 canvas with a 2D image

canvasGUI V3 was released in April 2026 and the biggest change was the use of a shader to overlay a 2D image of the gui onto a webgl canvas. In earlier sketches this has worked without a problem and this sketch shows it in action using the latest version of p5.js (2.3.2)

I am using VSC on a local server to develop a new 3D sketch but have problems displaying the gui. I have created a cut down version of the sketch and you can see it here in the p5js web editor.

When run on my desktop I get the messages shown below. Although they don’t appear in the web editor console the sketch behaves the same in both scenarios.

Firefox browser

WebGL warning: uniform setter: UniformLocation is not from the current active Program. 32
After reporting 32, no further warnings will be reported for this WebGL context. 

Duckduckgo browser

[Error] WebGL: INVALID_OPERATION: uniform1i: location not for current program
	uniform1i
	_updateTexture (p5.js:125775)
	bindTextures (p5.js:61984)
	_drawFills (p5.js:54777)
	_drawGeometry (p5.js:54756)
	model (p5.js:54724)
	(anonymous function) (p5.js:114039)
	(anonymous function) (p5.js:92654)
	draw (test 01.js:30)
	(anonymous function) (p5.js:3571)
[Warning] WebGL: too many errors, no more errors will be reported to the console for this context.

Now I know very little about creating shaders, the one used in canvasGUI was kindly created by @scudly

The code below (TypeScript) is part of the GUI class and shows the creation and use of the shader program to overlay the webgl canvas.

This method (lines 259 - 307) creates the shader program and is called when a GUI object is instantiated for a webgl2 canvas

  /**
   * Create the shader program to overlay a 2D HUD over a 3D canvas
   * @hidden
   */
  _createGuiShaderProgram() {
    const gl = this._canvasContext;

    // Vertex shader program
    const vsSource = `
    precision mediump float;

    uniform vec2 uScale;
    attribute vec3 aVertexPosition;
    varying vec2 vTextureCoord;

    void main(void) {
        gl_Position = vec4(aVertexPosition, 1.0);
        vTextureCoord.x = (1.0 + aVertexPosition.x) * 0.5;
        vTextureCoord.y = (1.0 - aVertexPosition.y) * 0.5;
    }
    `;

    // Fragment shader program
    const fsSource = `
    precision mediump float;

    varying vec2 vTextureCoord;
    uniform sampler2D uSampler;

    void main(void) {
        gl_FragColor = texture2D(uSampler, vTextureCoord);
    }
    `;

    // Compile shaders and link the program
    const vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, vsSource);
    gl.compileShader(vertexShader);

    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, fsSource);
    gl.compileShader(fragmentShader);

    const shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);
    return shaderProgram;
  }

This method (lines 223 - 257) is called to overlay the gui buffer image each frame

  /**
   * Show GUI over a 'webgl2' canvas
   * @hidden
   */
  _showOverWebGL() {
    const gl = this._canvasContext;
    // Create texture from 2D canvas
    const texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE,
      this._uiBuffer);
    gl.generateMipmap(gl.TEXTURE_2D);

    // Create and bind a buffer for the vertices
    const vertexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, GUI.VERTS, gl.STATIC_DRAW);

    gl.useProgram(this._guiShader);

    // Bind vertex position attribute
    const position = gl.getAttribLocation(this._guiShader, 'aVertexPosition');
    gl.enableVertexAttribArray(position);
    gl.vertexAttribPointer(position, 3, gl.FLOAT, false, 0, 0);

    // Set the texture sampler uniform
    const uSampler = gl.getUniformLocation(this._guiShader, 'uSampler');
    gl.uniform1i(uSampler, 0);

    gl.clear(gl.DEPTH_BUFFER_BIT);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
    gl.disable(gl.BLEND);
  }

Sorry about the length of this post but i wanted to give as much information as possible in one place.

Any help or advice on identifying the problem would be greatly appreciated.
:smiley: