All files / renderer/village GltfErrorBoundary.tsx

0% Statements 0/18
0% Branches 0/1
0% Functions 0/1
0% Lines 0/18

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43                                                                                     
import { Component, type ErrorInfo, type ReactNode } from "react";
import { logger } from "../logger";
 
interface Props {
  /** Rendered when the child throws during load. */
  fallback: ReactNode;
  /** Short label for logs (e.g. "zone:office", "character:mayor"). */
  label: string;
  children: ReactNode;
}
 
interface State {
  failed: boolean;
}
 
/**
 * Small error boundary for GLB-loading subtrees. @react-three/drei's
 * `useGLTF` throws (or rejects the Suspense promise) on a permanent load
 * failure; without a boundary that blows up the whole <Canvas>. This
 * catches the error, logs it once, and renders the provided Tier 1 cube
 * fallback so the scene keeps rendering.
 */
export class GltfErrorBoundary extends Component<Props, State> {
  state: State = { failed: false };
 
  static getDerivedStateFromError(): State {
    return { failed: true };
  }
 
  componentDidCatch(error: Error, info: ErrorInfo): void {
    logger.warn("GLB load failed, falling back to cube", {
      label: this.props.label,
      error: error.message,
      componentStack: info.componentStack
    });
  }
 
  render(): ReactNode {
    if (this.state.failed) return this.props.fallback;
    return this.props.children;
  }
}