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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | 7x 97x 97x 97x 97x 97x 97x 97x 68x 68x 62x 62x 6x 3x 3x 2x 3x 6x 1x 1x 6x 6x 6x 6x 6x 7x 2x 2x 2x 2x 2x 1x 1x 7x 2x 2x 2x 2x 2x 1x 1x | /**
* useWebGLContextLossHandler - React hook for handling WebGL context loss
*
* This hook sets up event listeners for WebGL context loss and restoration,
* which can occur due to GPU issues, memory pressure, or browser tab switching.
*
* @example
* ```tsx
* const Canvas = () => {
* useWebGLContextLossHandler();
* return <Canvas>...</Canvas>;
* };
* ```
*/
import { useEffect, useRef } from 'react';
import type React from 'react';
export interface WebGLContextLossOptions {
/**
* Callback when context is lost
*/
readonly onContextLost?: () => void;
/**
* Callback when context is restored
*/
readonly onContextRestored?: () => void;
/**
* Whether to attempt automatic restoration (default: true)
*/
readonly autoRestore?: boolean;
/**
* Optional canvas ref to attach to a specific canvas element
* If not provided, will query for the first canvas in the document
*/
readonly canvasRef?: React.RefObject<HTMLCanvasElement>;
}
/**
* Hook to handle WebGL context loss and restoration
*/
export const useWebGLContextLossHandler = (
options: WebGLContextLossOptions = {}
): void => {
const { onContextLost, onContextRestored, autoRestore = true, canvasRef } = options;
// Use refs to store the latest callbacks to avoid re-registering event listeners
const onContextLostRef = useRef(onContextLost);
const onContextRestoredRef = useRef(onContextRestored);
// Update refs when callbacks change
useEffect(() => {
onContextLostRef.current = onContextLost;
onContextRestoredRef.current = onContextRestored;
});
useEffect(() => {
const canvas = canvasRef?.current ?? document.querySelector('canvas');
if (!canvas) {
console.warn('useWebGLContextLossHandler: No canvas element found');
return;
}
const handleContextLost = (event: Event) => {
console.warn('WebGL context lost - attempting to restore');
// Prevent default behavior to allow restoration
if (autoRestore) {
event.preventDefault();
}
onContextLostRef.current?.();
};
const handleContextRestored = () => {
console.log('WebGL context restored successfully');
onContextRestoredRef.current?.();
};
// Add event listeners for context loss/restoration
canvas.addEventListener('webglcontextlost', handleContextLost, false);
canvas.addEventListener('webglcontextrestored', handleContextRestored, false);
// Cleanup
return () => {
canvas.removeEventListener('webglcontextlost', handleContextLost);
canvas.removeEventListener('webglcontextrestored', handleContextRestored);
};
}, [autoRestore, canvasRef]);
};
/**
* Check if WebGL is available in the current browser
*/
export const isWebGLAvailable = (): boolean => {
try {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
const available = gl !== null;
// Help GC by cleaning up WebGL context
Iif (gl && 'getExtension' in gl) {
const loseContext = gl.getExtension('WEBGL_lose_context');
loseContext?.loseContext();
}
return available;
} catch (e) {
return false;
}
};
/**
* Check if WebGL2 is available in the current browser
*/
export const isWebGL2Available = (): boolean => {
try {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');
const available = gl !== null;
// Help GC by cleaning up WebGL context
Iif (gl && 'getExtension' in gl) {
const loseContext = gl.getExtension('WEBGL_lose_context');
loseContext?.loseContext();
}
return available;
} catch (e) {
return false;
}
};
|