DavidHDev/react-bits · critical · Error

No WebGL 2 context!

Error message

No WebGL 2 context!

What it means

The TypeScript variant of error 0. InfiniteMenu.init calls canvas.getContext('webgl2', { antialias, alpha:false }) and throws when null, because the disc instancing pipeline (aInstanceMatrix attribute bound at slot 3) requires WebGL2. No webgl1 fallback exists.

Solutions

  1. Probe WebGL2 support before mounting InfiniteMenu and render a fallback if absent.
  2. In tests, use a WebGL2-capable headless browser (Chromium + SwiftShader/ANGLE) or mock the component.
  3. Update GPU drivers / browser; confirm chrome://gpu lists WebGL2 as hardware accelerated.
  4. Enable hardware acceleration in the host browser/WebView.

Example fix

// before
private init(onInit?: InitCallback): void {
  const gl = this.canvas.getContext('webgl2', { antialias: true, alpha: false });
  if (!gl) throw new Error('No WebGL 2 context!');

// after
const gl = this.canvas.getContext('webgl2', { antialias: true, alpha: false });
if (!gl) { onInit?.(new Error('No WebGL 2 context!')); return; } // caller renders fallback
Defensive patterns

Strategy: validation

Validate before calling

function supportsWebGL2(): boolean {
  try { return !!document.createElement('canvas').getContext('webgl2'); }
  catch { return false; }
}
if (!supportsWebGL2()) return <FallbackMenu />;

Type guard

function hasWebGL2(canvas: HTMLCanvasElement): boolean {
  return !!canvas.getContext('webgl2', { antialias: true, alpha: false });
}

Prevention

When it happens

Trigger: getContext('webgl2') returns null at src/ts-default/Components/InfiniteMenu/InfiniteMenu.tsx:766-770 during InfiniteMenu.init, before discProgram is created.

Common situations: jsdom/Vitest test environments; outdated browsers without WebGL2 (old Safari/iOS, embedded WebViews); GPU drivers on the WebGL2 blocklist; software renderers exposing only webgl1; CI without a WebGL2-capable headless browser.

Related errors


AI-assisted analysis of DavidHDev/react-bits@c7109dccb4 (2026-08-13). Data as JSON: /api/errors/b6d1a4a33c4d1fec. Report an issue: GitHub.

Appendix: source

Thrown at src/ts-default/Components/InfiniteMenu/InfiniteMenu.tsx:768

  public run(time = 0): void {
    this._deltaTime = Math.min(32, time - this._time);
    this._time = time;
    this._deltaFrames = this._deltaTime / this.TARGET_FRAME_DURATION;
    this._frames += this._deltaFrames;

    this.animate(this._deltaTime);
    this.render();

    requestAnimationFrame(t => this.run(t));
  }

  private init(onInit?: InitCallback): void {
    const gl = this.canvas.getContext('webgl2', {
      antialias: true,
      alpha: false
    });
    if (!gl) {
      throw new Error('No WebGL 2 context!');
    }
    this.gl = gl;

    vec2.set(this.viewportSize, this.canvas.clientWidth, this.canvas.clientHeight);
    vec2.clone(this.drawBufferSize);

    this.discProgram = createProgram(gl, [discVertShaderSource, discFragShaderSource], null, {
      aModelPosition: 0,
      aModelNormal: 1,
      aModelUvs: 2,
      aInstanceMatrix: 3
    });

    this.discLocations = {
      aModelPosition: gl.getAttribLocation(this.discProgram!, 'aModelPosition'),
      aModelUvs: gl.getAttribLocation(this.discProgram!, 'aModelUvs'),
      aInstanceMatrix: gl.getAttribLocation(this.discProgram!, 'aInstanceMatrix'),
      uWorldMatrix: gl.getUniformLocation(this.discProgram!, 'uWorldMatrix'),

View on GitHub (pinned to c7109dccb4)