Skip to content

Dev#25

Open
eloiberlinger1 wants to merge 2 commits into
mainfrom
dev
Open

Dev#25
eloiberlinger1 wants to merge 2 commits into
mainfrom
dev

Conversation

@eloiberlinger1

Copy link
Copy Markdown
Member

No description provided.

- Implemented a WebGLErrorBoundary to catch WebGL context creation failures.
- Added a function to check WebGL availability and display a fallback UI if unavailable.
- Updated MainCanvas to utilize the new error boundary and fallback mechanism for improved user experience.
Copilot AI review requested due to automatic review settings June 30, 2026 13:28

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces WebGL availability checks and a new WebGLErrorBoundary component to handle WebGL context creation failures gracefully in the 3D wall editor. Feedback focuses on optimizing performance and robustness: caching the WebGL check globally to prevent repeated context creation and ensure SSR safety, logging caught WebGL errors to PostHog for production monitoring, and optimizing the fallback UI rendering by memoizing or moving the JSX definition outside of the component body.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +19 to +30
function isWebGLAvailable(): boolean {
try {
const canvas = document.createElement("canvas");
const ctx =
canvas.getContext("webgl2", { failIfMajorPerformanceCaveat: false }) ||
canvas.getContext("webgl", { failIfMajorPerformanceCaveat: false }) ||
canvas.getContext("experimental-webgl", { failIfMajorPerformanceCaveat: false });
return !!ctx;
} catch {
return false;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The isWebGLAvailable function is called on every mount of MainCanvas via the useState initializer. In single-page applications, repeated creation of WebGL contexts (even if garbage collected) can lead to WebGL context exhaustion or browser warnings. Additionally, if this component is ever rendered in a Server-Side Rendering (SSR) environment, accessing document directly will throw a ReferenceError.

Caching the WebGL support check globally and adding a safe check for document avoids these issues.

let cachedWebGLAvailable: boolean | null = null;

function isWebGLAvailable(): boolean {
  if (typeof window === "undefined" || typeof document === "undefined") {
    return false;
  }
  if (cachedWebGLAvailable !== null) {
    return cachedWebGLAvailable;
  }
  try {
    const canvas = document.createElement("canvas");
    const ctx =
      canvas.getContext("webgl2", { failIfMajorPerformanceCaveat: false }) ||
      canvas.getContext("webgl", { failIfMajorPerformanceCaveat: false }) ||
      canvas.getContext("experimental-webgl", { failIfMajorPerformanceCaveat: false });
    cachedWebGLAvailable = !!ctx;
    return cachedWebGLAvailable;
  } catch {
    cachedWebGLAvailable = false;
    return false;
  }
}

Comment on lines +41 to +60
class WebGLErrorBoundary extends Component<
{ children: React.ReactNode; fallback: React.ReactNode },
WebGLErrorBoundaryState
> {
constructor(props: { children: React.ReactNode; fallback: React.ReactNode }) {
super(props);
this.state = { hasError: false, errorMessage: "" };
}

static getDerivedStateFromError(error: Error): WebGLErrorBoundaryState {
return { hasError: true, errorMessage: error.message };
}

render() {
if (this.state.hasError) {
return this.props.fallback;
}
return this.props.children;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The WebGLErrorBoundary catches WebGL context creation and rendering errors, but it currently does not log or report them. Since WebGL failures are critical to the core functionality of a 3D editor, capturing these errors in your analytics/monitoring platform (like PostHog, which is already imported) is highly recommended for production monitoring.

class WebGLErrorBoundary extends Component<
  { children: React.ReactNode; fallback: React.ReactNode },
  WebGLErrorBoundaryState
> {
  constructor(props: { children: React.ReactNode; fallback: React.ReactNode }) {
    super(props);
    this.state = { hasError: false, errorMessage: "" };
  }

  static getDerivedStateFromError(error: Error): WebGLErrorBoundaryState {
    return { hasError: true, errorMessage: error.message };
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    console.error("WebGL Error caught by boundary:", error, errorInfo);
    posthog.capture("webgl_error_boundary_triggered", {
      message: error.message,
      stack: error.stack,
    });
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback;
    }
    return this.props.children;
  }
}

Comment on lines +555 to +577
const webGLFallback = (
<div className="relative w-full h-full flex items-center justify-center bg-surface">
<div className="text-center max-w-md px-8 py-10 rounded-2xl bg-surface-low shadow-[0_8px_32px_0_rgba(0,0,0,0.4)]">
<span className="material-symbols-outlined text-5xl text-on-surface-variant mb-4 block">broken_image</span>
<h2 className="text-lg font-semibold text-on-surface mb-2">3D viewer unavailable</h2>
<p className="text-sm text-on-surface-variant mb-4">
Your browser could not create a WebGL context, which is required to display the 3D wall editor.
This is usually caused by disabled hardware acceleration or an incompatible graphics driver.
</p>
<p className="text-xs text-on-surface-variant opacity-60 mb-6">
Try enabling hardware acceleration in your browser settings
(<strong>Settings → System → Use hardware acceleration when available</strong>)
and reload the page.
</p>
<button
onClick={() => window.location.reload()}
className="px-4 py-2 rounded-lg bg-surface-high text-on-surface text-sm hover:opacity-80 transition-opacity"
>
Reload page
</button>
</div>
</div>
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The webGLFallback JSX element is defined directly inside the MainCanvas component body. Since MainCanvas re-renders frequently (e.g., during dragging or state updates), this large JSX tree is unnecessarily re-created on every render. Wrapping it in useMemo avoids this overhead.

  const webGLFallback = useMemo(() => (
    <div className="relative w-full h-full flex items-center justify-center bg-surface">
      <div className="text-center max-w-md px-8 py-10 rounded-2xl bg-surface-low shadow-[0_8px_32px_0_rgba(0,0,0,0.4)]">
        <span className="material-symbols-outlined text-5xl text-on-surface-variant mb-4 block">broken_image</span>
        <h2 className="text-lg font-semibold text-on-surface mb-2">3D viewer unavailable</h2>
        <p className="text-sm text-on-surface-variant mb-4">
          Your browser could not create a WebGL context, which is required to display the 3D wall editor.
          This is usually caused by disabled hardware acceleration or an incompatible graphics driver.
        </p>
        <p className="text-xs text-on-surface-variant opacity-60 mb-6">
          Try enabling hardware acceleration in your browser settings
          (<strong>Settings → System → Use hardware acceleration when available</strong>)
          and reload the page.
        </p>
        <button
          onClick={() => window.location.reload()}
          className="px-4 py-2 rounded-lg bg-surface-high text-on-surface text-sm hover:opacity-80 transition-opacity"
        >
          Reload page
        </button>
      </div>
    </div>
  ), []);

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves resilience of the 3D editor canvas by adding proactive WebGL capability detection and a UI fallback, and updates the frontend dependency lockfile (transitive and minor/patch bumps within existing semver ranges).

Changes:

  • Added a WebGL availability check plus a fallback UI when WebGL can’t be initialized.
  • Wrapped the React Three Fiber <Canvas> in an error boundary to prevent WebGL/Three initialization failures from breaking the rest of the editor UI.
  • Updated frontend/package-lock.json to newer resolved versions of dependencies.

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated 4 comments.

File Description
frontend/src/features/editor/components/MainCanvas.tsx Adds WebGL detection + error boundary + fallback UI around the 3D canvas.
frontend/package-lock.json Refreshes resolved dependency versions in the lockfile.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 1 to +3
import { Canvas, useThree } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import { Suspense } from "react";
import { Suspense, Component } from "react";
Comment on lines +32 to +52
interface WebGLErrorBoundaryState {
hasError: boolean;
errorMessage: string;
}

/**
* Error boundary that catches WebGL context creation failures thrown by
* Three.js / React Three Fiber so the rest of the UI stays functional.
*/
class WebGLErrorBoundary extends Component<
{ children: React.ReactNode; fallback: React.ReactNode },
WebGLErrorBoundaryState
> {
constructor(props: { children: React.ReactNode; fallback: React.ReactNode }) {
super(props);
this.state = { hasError: false, errorMessage: "" };
}

static getDerivedStateFromError(error: Error): WebGLErrorBoundaryState {
return { hasError: true, errorMessage: error.message };
}
Comment on lines +558 to +563
<span className="material-symbols-outlined text-5xl text-on-surface-variant mb-4 block">broken_image</span>
<h2 className="text-lg font-semibold text-on-surface mb-2">3D viewer unavailable</h2>
<p className="text-sm text-on-surface-variant mb-4">
Your browser could not create a WebGL context, which is required to display the 3D wall editor.
This is usually caused by disabled hardware acceleration or an incompatible graphics driver.
</p>
Comment on lines +560 to +563
<p className="text-sm text-on-surface-variant mb-4">
Your browser could not create a WebGL context, which is required to display the 3D wall editor.
This is usually caused by disabled hardware acceleration or an incompatible graphics driver.
</p>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants