DavidHDev/react-bits · critical · Error

Unable to initialize WebGL.

Error message

Unable to initialize WebGL.

What it means

Tailwind variant of error 2. SplashCursor.getWebGLContext attempts webgl2 then webgl then experimental-webgl; this throw fires only when every context type is unavailable, meaning no WebGL at all.

Source

Thrown at src/ts-tailwind/Animations/SplashCursor/SplashCursor.tsx:133

    function getWebGLContext(canvas: HTMLCanvasElement) {
      const params = {
        alpha: true,
        depth: false,
        stencil: false,
        antialias: false,
        preserveDrawingBuffer: false
      };

      let gl = canvas.getContext('webgl2', params) as WebGL2RenderingContext | null;

      if (!gl) {
        gl = (canvas.getContext('webgl', params) ||
          canvas.getContext('experimental-webgl', params)) as WebGL2RenderingContext | null;
      }

      if (!gl) {
        throw new Error('Unable to initialize WebGL.');
      }

      const isWebGL2 = 'drawBuffers' in gl;

      let supportLinearFiltering = false;
      let halfFloat: OES_texture_half_float | null = null;

      if (isWebGL2) {
        (gl as WebGL2RenderingContext).getExtension('EXT_color_buffer_float');
        supportLinearFiltering = !!(gl as WebGL2RenderingContext).getExtension('OES_texture_float_linear');
      } else {
        halfFloat = gl.getExtension('OES_texture_half_float');
        supportLinearFiltering = !!gl.getExtension('OES_texture_half_float_linear');
      }

      gl.clearColor(0, 0, 0, 1);

      const halfFloatTexType = isWebGL2

View on GitHub (pinned to c7109dccb4)

Solutions

  1. Probe for any GL context before mounting SplashCursor and skip otherwise.
  2. Use a real headless Chromium with SwiftShader/ANGLE for automated tests.
  3. Enable WebGL / update drivers in the user's browser (verify chrome://gpu).
  4. Render a non-WebGL cursor fallback when no GL context exists.

Example fix

// before
const { gl, ext } = getWebGLContext(canvas);

// after
function anyGL() {
  const c = document.createElement('canvas');
  return !!(c.getContext('webgl2') || c.getContext('webgl') || c.getContext('experimental-webgl'));
}
if (!anyGL()) return null;
Defensive patterns

Strategy: validation

Validate before calling

function supportsAnyWebGL(): boolean {
  const c = document.createElement('canvas');
  try {
    return !!(c.getContext('webgl2') || c.getContext('webgl') || c.getContext('experimental-webgl'));
  } catch { return false; }
}

Type guard

function getGL(canvas: HTMLCanvasElement): WebGLRenderingContext | WebGL2RenderingContext | null {
  return (canvas.getContext('webgl2') || canvas.getContext('webgl') || canvas.getContext('experimental-webgl')) as WebGLRenderingContext | null;
}

Prevention

When it happens

Trigger: getContext('webgl2'), getContext('webgl'), and getContext('experimental-webgl') all return null at src/ts-tailwind/Animations/SplashCursor/SplashCursor.tsx:125-133.

Common situations: jsdom/happy-dom with no GL backend; WebGL disabled via browser flags or driver blocklist; locked-down kiosks; extremely old browsers; environments with no GL driver whatsoever.

Related errors


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