{"record":{"id":"75d68a8722805170","repo":"DavidHDev/react-bits","slug":"no-webgl-2-context","errorCode":null,"errorMessage":"No WebGL 2 context!","messagePattern":"No WebGL 2 context!","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/content/Components/InfiniteMenu/InfiniteMenu.jsx","lineNumber":637,"sourceCode":"  }\n\n  run(time = 0) {\n    this.#deltaTime = Math.min(32, time - this.#time);\n    this.#time = time;\n    this.#deltaFrames = this.#deltaTime / this.TARGET_FRAME_DURATION;\n    this.#frames += this.#deltaFrames;\n\n    this.#animate(this.#deltaTime);\n    this.#render();\n\n    requestAnimationFrame(t => this.run(t));\n  }\n\n  #init(onInit) {\n    this.gl = this.canvas.getContext('webgl2', { antialias: true, alpha: false });\n    const gl = this.gl;\n    if (!gl) {\n      throw new Error('No WebGL 2 context!');\n    }\n\n    this.viewportSize = vec2.fromValues(this.canvas.clientWidth, this.canvas.clientHeight);\n    this.drawBufferSize = vec2.clone(this.viewportSize);\n\n    this.discProgram = createProgram(gl, [discVertShaderSource, discFragShaderSource], null, {\n      aModelPosition: 0,\n      aModelNormal: 1,\n      aModelUvs: 2,\n      aInstanceMatrix: 3\n    });\n\n    this.discLocations = {\n      aModelPosition: gl.getAttribLocation(this.discProgram, 'aModelPosition'),\n      aModelUvs: gl.getAttribLocation(this.discProgram, 'aModelUvs'),\n      aInstanceMatrix: gl.getAttribLocation(this.discProgram, 'aInstanceMatrix'),\n      uWorldMatrix: gl.getUniformLocation(this.discProgram, 'uWorldMatrix'),\n      uViewMatrix: gl.getUniformLocation(this.discProgram, 'uViewMatrix'),","sourceCodeStart":619,"sourceCodeEnd":655,"githubUrl":"https://github.com/DavidHDev/react-bits/blob/c7109dccb42e06592d1d9bc50bc87204697240e2/src/content/Components/InfiniteMenu/InfiniteMenu.jsx#L619-L655","documentation":"Thrown by InfiniteMenu.#init after canvas.getContext('webgl2', ...) returns null. The menu is built on WebGL2-only features (instanced arrays via aInstanceMatrix, float color buffers), so a null context means the component cannot render at all and aborts during construction. This is a hard capability gate, not a recoverable render glitch.","triggerScenarios":"Instantiating the InfiniteMenu class on a canvas whose browser/driver exposes no 'webgl2' context type. Concretely: this.canvas.getContext('webgl2', { antialias: true, alpha: false }) === null at src/content/Components/InfiniteMenu/InfiniteMenu.jsx:637.","commonSituations":"Headless test runners (jsdom in Jest/Vitest) that have no real GL backend; users on outdated mobile browsers (pre-2020 Safari, older Android Chrome); machines with blacklisted GPU drivers where the browser disables WebGL2 (chrome://gpu shows 'WebGL2: Hardware unavailable'); software/swiftshader renderers that only expose webgl1.","solutions":["Confirm support first: open chrome://gpu (or about:support in Firefox) and verify 'WebGL2' is listed as Hardware accelerated.","Update GPU drivers / browser to a WebGL2-capable version; on Linux prefer the proprietary/Mesa driver over llvmpipe.","In tests/jsdom, skip or mock the component rather than instantiating it, since jsdom provides no webgl2 context.","Feature-detect before mounting and render a static fallback when WebGL2 is absent (see exampleFix)."],"exampleFix":"// before\nimport InfiniteMenu from './InfiniteMenu';\nnew InfiniteMenu({ canvas }); // throws if no webgl2\n\n// after\nconst probe = document.createElement('canvas').getContext('webgl2');\nif (probe) {\n  new InfiniteMenu({ canvas });\n} else {\n  // render a plain HTML/CSS menu fallback\n}","handlingStrategy":"validation","validationCode":"function supportsWebGL2(): boolean {\n  try {\n    return !!document.createElement('canvas').getContext('webgl2');\n  } catch {\n    return false;\n  }\n}\n// before mounting InfiniteMenu:\nif (!supportsWebGL2()) { renderFallbackMenu(); }","typeGuard":"// runtime capability guard (not a type narrowing, but the equivalent gate)\nconst webgl2Available: boolean =\n  typeof HTMLCanvasElement !== 'undefined' &&\n  !!document.createElement('canvas').getContext('webgl2');\n\n// if you wrap the component:\nfunction isWebGL2Canvas(canvas: HTMLCanvasElement): canvas is HTMLCanvasElement & { getContext(c: 'webgl2'): WebGL2RenderingContext } {\n  return !!canvas.getContext('webgl2');\n}","tryCatchPattern":null,"preventionTips":["Run a getContext('webgl2') probe once at app boot and gate WebGL2 components on it.","Never instantiate InfiniteMenu inside jsdom; mock it in unit tests.","Expose a non-WebGL menu variant so feature detection can route to it.","Surface a 'WebGL2 unsupported' message to the user instead of letting the throw crash the page."],"tags":["webgl2","gpu","context","initialization","browser-support"],"backgroundTag":null,"analyzedSha":"c7109dccb42e06592d1d9bc50bc87204697240e2","analyzedAt":"2026-08-13T02:32:07.327Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}