sickn33/agentic-awesome-skills · error

WebGL context unavailable

Error message

WebGL context unavailable

What it means

The spectral-field renderer's constructor calls canvas.getContext('webgl', {...}) and throws immediately if the context is null: the browser refused to create a WebGL1 context — disabled, blocklisted, or exhausted.

Source

Thrown at skills/liuguang-banlan-ui/assets/starter/shared/spectral-field.js:262

      this.available = false;
      this.error = null;
      this.motionPreference = window.matchMedia("(prefers-reduced-motion: reduce)");
      this.motionEnabled = !this.motionPreference.matches;
      this.visible = !document.hidden;
      this.startTime = performance.now();
      this.phaseTime = null;
      this.lastFrame = 0;
      this.frameHandle = 0;
      try {
        this.gl = canvas.getContext("webgl", {
          alpha: false,
          antialias: false,
          depth: false,
          stencil: false,
          powerPreference: "low-power",
          preserveDrawingBuffer: true
        });
        if (!this.gl) throw new Error("WebGL context unavailable");

        this.program = createProgram(this.gl);
        this.gl.useProgram(this.program);
        const buffer = this.gl.createBuffer();
        if (!buffer) throw new Error("WebGL buffer creation failed");
        this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
        this.gl.bufferData(
          this.gl.ARRAY_BUFFER,
          new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),
          this.gl.STATIC_DRAW
        );
        const position = this.gl.getAttribLocation(this.program, "aPosition");
        if (position < 0) throw new Error("WebGL position attribute unavailable");
        this.gl.enableVertexAttribArray(position);
        this.gl.vertexAttribPointer(position, 2, this.gl.FLOAT, false, 0, 0);

        this.locations = {
          resolution: uniform(this.gl, this.program, "uResolution"),

View on GitHub (pinned to 58d857988f)

Solutions

  1. Feature-detect WebGL before mounting and fall back to a 2D-canvas/CSS animation
  2. For headless tests, launch Chrome with --enable-unsafe-swiftshader or --use-gl=swiftshader
  3. Reuse one instance/canvas; call WEBGL_lose_context.loseContext() on teardown
  4. Ask desktop users to re-enable hardware acceleration

Example fix

// before
const gl = canvas.getContext('webgl', opts);
if (!gl) throw new Error('WebGL context unavailable');

// after
const gl = canvas.getContext('webgl', opts) || canvas.getContext('experimental-webgl', opts);
if (!gl) return SpectralField.cssFallback(canvas);
Defensive patterns

Strategy: fallback

Validate before calling

const probe = document.createElement('canvas');
const supported = !!(probe.getContext('webgl') || probe.getContext('experimental-webgl'));
if (!supported) mountCssFallback(el); else new SpectralField(el);

Type guard

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

Try / catch

try { renderer = new SpectralField(canvas); }
catch (e) {
  if (e.message === 'WebGL context unavailable') { renderer = null; mountCssFallback(canvas); }
  else throw e;
}

Prevention

When it happens

Trigger: Instantiating the renderer where getContext('webgl') returns null: hardware acceleration disabled in the browser, GPU blocklisted (some Linux/VM setups), too many live WebGL contexts already open, or a headless test environment without GPU support.

Common situations: Users with hardware acceleration off; headless Jest/Playwright runs without SwiftShader; VMs and remote desktops; pages that spawn many canvases and leak contexts.

Related errors


AI-assisted analysis of sickn33/agentic-awesome-skills@58d857988f (2026-08-26). Data as JSON: /api/errors/e520c6388eae1cef. Report an issue: GitHub.