fix(handtracking): reduce GPU pressure on WebGL context loss

Several mitigations against the WebGL context lost that fires when
hand tracking starts on a loaded scene:

- Canvas: fixed DPR [1,1], antialias off, scoped id="game-canvas",
  context-lost handler releases MediaPipe and logs GPU memory counters
- optimizeGLTFScene: cap anisotropy at 2 and stop forcing mipmaps /
  needsUpdate on every pass — avoids massive texture re-uploads
- MediaPipe: force CPU delegate (HAND_TRACKING_BROWSER_DELEGATE),
  cache the landmarker instance, and expose releaseBrowserHandLandmarker
- useBrowserHandTracking / useRemoteHandTracking: idempotent cleanup
  guarded by a cleanedUp flag, try/catch around the detect loop, and
  release of the landmarker on stop
- World: mount HandTrackingGlove only when the matching hand is
  actually present in the snapshot (status connected + hands.length > 0)
- HandTrackingGlove: drop the eager useGLTF.preload that was running
  at startup whether or not hand tracking was used

Does not yet absorb the React StrictMode double-mount — that is the
follow-up commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tom Boullay
2026-06-02 16:48:39 +02:00
parent 864e075b42
commit d217c3376b
8 changed files with 156 additions and 35 deletions
+8 -7
View File
@@ -19,20 +19,21 @@ type TexturedMaterial = THREE.Material &
Partial<Record<TextureKey, THREE.Texture>>;
const optimizedTextures = new WeakSet<THREE.Texture>();
const MAX_GLTF_TEXTURE_ANISOTROPY = 2;
function optimizeTexture(texture: THREE.Texture, maxAnisotropy: number): void {
if (optimizedTextures.has(texture)) return;
optimizedTextures.add(texture);
texture.anisotropy = Math.min(4, Math.max(1, maxAnisotropy));
const nextAnisotropy = Math.min(
MAX_GLTF_TEXTURE_ANISOTROPY,
Math.max(1, maxAnisotropy),
);
if (!(texture instanceof THREE.CompressedTexture)) {
texture.generateMipmaps = true;
texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.magFilter = THREE.LinearFilter;
if (texture.anisotropy > nextAnisotropy) {
texture.anisotropy = nextAnisotropy;
texture.needsUpdate = true;
}
texture.needsUpdate = true;
}
function optimizeMaterialTextures(