Repository navigation
fix(web): guard MeshGradient against missing WebGL context #6318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -26,6 +26,15 @@ interface GradientInstance { | |||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| function supportsWebgl(): boolean { | ||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||
| const probe = document.createElement("canvas"); | ||||||||||||||||||||||||||||||||||||||||||||||
| return Boolean(probe.getContext("webgl2") || probe.getContext("webgl")); | ||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+29
to
+36
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Repeated mounts or Prompt for AI agents
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| export function MeshGradient({ | ||||||||||||||||||||||||||||||||||||||||||||||
| colors, | ||||||||||||||||||||||||||||||||||||||||||||||
| className = "", | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -37,18 +46,11 @@ export function MeshGradient({ | |||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||
| const canvas = canvasRef.current; | ||||||||||||||||||||||||||||||||||||||||||||||
| if (!canvas) return; | ||||||||||||||||||||||||||||||||||||||||||||||
| if (!canvas || !supportsWebgl()) return; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const gradient = new Gradient() as GradientInstance; | ||||||||||||||||||||||||||||||||||||||||||||||
| gradient.initGradient(`#${canvasId}`); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout(() => { | ||||||||||||||||||||||||||||||||||||||||||||||
| if (gradient?.uniforms?.u_global?.value?.noiseSpeed) { | ||||||||||||||||||||||||||||||||||||||||||||||
| gradient.uniforms.u_global.value.noiseSpeed.value = speed; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| }, 100); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| return () => { | ||||||||||||||||||||||||||||||||||||||||||||||
| const teardown = () => { | ||||||||||||||||||||||||||||||||||||||||||||||
| if (gradient.pause) { | ||||||||||||||||||||||||||||||||||||||||||||||
| gradient.pause(); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -65,6 +67,23 @@ export function MeshGradient({ | |||||||||||||||||||||||||||||||||||||||||||||
| gradient.disconnect(); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Guard scoped to init only: the library dereferences a null WebGL | ||||||||||||||||||||||||||||||||||||||||||||||
| // context when creation fails despite the probe above. | ||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||
| gradient.initGradient(`#${canvasId}`); | ||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||
| teardown(); | ||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout(() => { | ||||||||||||||||||||||||||||||||||||||||||||||
| if (gradient?.uniforms?.u_global?.value?.noiseSpeed) { | ||||||||||||||||||||||||||||||||||||||||||||||
| gradient.uniforms.u_global.value.noiseSpeed.value = speed; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| }, 100); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| return teardown; | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+80
to
+86
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win Cancel the delayed
Store the handle before defining Proposed fix const gradient = new Gradient() as GradientInstance;
+ let noiseSpeedTimeout: ReturnType<typeof setTimeout> | undefined;
const teardown = () => {
+ if (noiseSpeedTimeout !== undefined) {
+ clearTimeout(noiseSpeedTimeout);
+ }
if (gradient.pause) {
gradient.pause();
}
// existing cleanup
};
- setTimeout(() => {
+ noiseSpeedTimeout = setTimeout(() => {
if (gradient?.uniforms?.u_global?.value?.noiseSpeed) {
gradient.uniforms.u_global.value.noiseSpeed.value = speed;
}
}, 100);🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| }, [canvasId, speed]); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P3: The
supportsWebgl()probe swallows any error fromdocument.createElementorgetContextin a silent empty catch with no rationale comment and no observability. If the failure is something other than WebGL being genuinely unavailable (e.g. an allocation/sandboxing error), it becomes indistinguishable from real lack of support and goes completely unlogged. Since the rest of this PR adds an inline rationale comment to the init catch for exactly this reason, consider adding a brief inline comment here explaining that the probe is a best-effort feature check (so an unsupported environment simply keeps the static background), keeping the fix consistent with the swallow-with-rationale convention used below.Prompt for AI agents