{"record":{"id":"61b5e024ee12e427","repo":"MiniMax-AI/skills","slug":"no-webgl2","errorCode":null,"errorMessage":"No WebGL2","messagePattern":"No WebGL2","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skills/shader-dev/techniques/simulation-physics.md","lineNumber":21,"sourceCode":"### WebGL2 Multi-Pass Rendering Complete Template\n\nBelow is a complete standalone HTML template demonstrating how to set up WebGL2 double buffering (ping-pong) for physics simulation:\n\n**IMPORTANT: WebGL2 ping-pong core rule: The texture bound to the write-target framebuffer must never simultaneously serve as input for any iChannel.** Violating this rule causes undefined behavior (typically all-black/all-zero output).\n\nFor simulations requiring \"current frame\" and \"previous frame\" two time steps (such as the wave equation), use **dual-channel encoding**: R channel stores current height, G channel stores previous frame height. This way only one buffer is read from (iChannel0 = currentBuf), writing to another buffer (nextBuf), avoiding read-write conflicts.\n\n```html\n<!DOCTYPE html>\n<html>\n<head><meta charset=\"utf-8\"><title>GPU Physics</title>\n<style>body{margin:0;overflow:hidden}canvas{display:block;width:100vw;height:100vh}</style>\n</head>\n<body><canvas id=\"c\"></canvas>\n<script>\nconst canvas = document.getElementById('c');\nconst gl = canvas.getContext('webgl2', { antialias: false });\nif (!gl) { document.body.innerHTML = 'WebGL2 not supported'; throw new Error('No WebGL2'); }\n\nfunction resize() {\n    canvas.width = window.innerWidth;\n    canvas.height = window.innerHeight;\n}\nwindow.addEventListener('resize', resize);\nresize();\n\nfunction createShader(type, src) {\n    const s = gl.createShader(type);\n    gl.shaderSource(s, src);\n    gl.compileShader(s);\n    if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {\n        console.error(gl.getShaderInfoLog(s));\n        gl.deleteShader(s);\n        return null;\n    }\n    return s;","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/MiniMax-AI/skills/blob/60aaae52bb2af8162732751a4332f62a5fef518b/skills/shader-dev/techniques/simulation-physics.md#L3-L39","documentation":"`throw new Error('No WebGL2')` in the GPU physics simulation demo. `canvas.getContext('webgl2', { antialias: false })` returned null, so the script replaces the body with 'WebGL2 not supported' and throws to stop init before the resize/shader helpers touch the null context. The dual-channel/ping-pong simulation design is fundamentally WebGL2-only (it relies on float textures and `#version 300 es`).","triggerScenarios":"No WebGL2 context available — old browser, acceleration disabled, blocklisted driver, or a headless/software-only runtime.","commonSituations":"Pre-Safari-15 environments, VMs without GPU, CI runners, or users who disabled acceleration.","solutions":["Run in a WebGL2-capable browser with hardware acceleration on.","For automated runs, use a software GL backend or skip the demo.","Render a fallback message via a guard rather than throwing, so the rest of the page stays usable."],"exampleFix":"// before\nconst gl = canvas.getContext('webgl2', { antialias: false });\nif (!gl) { document.body.innerHTML = 'WebGL2 not supported'; throw new Error('No WebGL2'); }\n\n// after\nconst gl = canvas.getContext('webgl2', { antialias: false });\nif (!gl) { document.body.innerHTML = '<p>This demo needs WebGL2.</p>'; return; }\ninitPhysics(gl);","handlingStrategy":"fallback","validationCode":"const gl = canvas.getContext('webgl2', { antialias: false });\nif (!gl) { document.body.innerHTML = '<p>This demo needs WebGL2.</p>'; return; }\ninitPhysics(gl);","typeGuard":"const supportsWebGL2 = (() => {\n  try { return !!document.createElement('canvas').getContext('webgl2', { antialias: false }); }\n  catch { return false; }\n})();","tryCatchPattern":"try {\n  const gl = canvas.getContext('webgl2', { antialias: false });\n  if (!gl) throw new Error('No WebGL2');\n  initPhysics(gl);\n} catch (e) {\n  if (e instanceof Error && /WebGL2/i.test(e.message)) renderFallback();\n  else throw e;\n}","preventionTips":["Convert the throw into a return after showing a fallback so dependent code is skipped cleanly.","Feature-detect WebGL2 (and float color buffers) before mounting the simulation UI.","Keep the simulation init behind the capability gate so a null context never reaches shader helpers.","Test on a software GL backend in CI to confirm graceful degradation."],"tags":["webgl","webgl2","browser","gpu","simulation","javascript"],"backgroundTag":null,"analyzedSha":"60aaae52bb2af8162732751a4332f62a5fef518b","analyzedAt":"2026-08-13T17:32:34.717Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}