All files / utils/performance usePerformanceMonitor.ts

63.63% Statements 14/22
42.85% Branches 3/7
75% Functions 6/8
68.42% Lines 13/19

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                                                                                                        60x   60x     60x 30x       60x 30x       60x           60x     60x                                     60x 30x 30x       60x        
/**
 * React hook for Three.js performance monitoring
 * 
 * Integrates PerformanceMonitor with useFrame for real-time FPS tracking
 */
 
import { useFrame, useThree } from '@react-three/fiber';
import { useEffect, useMemo, useRef, useState } from 'react';
import { PerformanceMonitor, PerformanceMetrics, PerformanceThresholds } from './PerformanceMonitor';
 
export interface UsePerformanceMonitorOptions {
  readonly enabled?: boolean;
  readonly thresholds?: Partial<PerformanceThresholds>;
  readonly updateInterval?: number; // Update interval in ms for React state
}
 
export interface PerformanceMonitorState {
  readonly metrics: PerformanceMetrics;
  readonly isGood: boolean;
  readonly warnings: readonly string[];
}
 
/**
 * Hook for monitoring Three.js performance in real-time
 * 
 * @param options Configuration options
 * @returns Current performance state
 * 
 * @example
 * ```tsx
 * function CombatScene() {
 *   const { metrics, isGood, warnings } = usePerformanceMonitor({
 *     enabled: import.meta.env.DEV,
 *     thresholds: { minAcceptableFps: 55 }
 *   });
 * 
 *   return (
 *     <>
 *       {import.meta.env.DEV && (
 *         <Html position={[0, 5, 0]}>
 *           <div>FPS: {metrics.fps.toFixed(1)}</div>
 *         </Html>
 *       )}
 *       {/* 3D content */}
 *     </>
 *   );
 * }
 * ```
 */
export function usePerformanceMonitor(
  options: UsePerformanceMonitorOptions = {}
): PerformanceMonitorState {
  const { enabled = true, thresholds, updateInterval = 1000 } = options;
 
  const gl = useThree((state) => state.gl);
  
  // Memoize thresholds to prevent unnecessary monitor recreation
  const stableThresholds = useMemo(
    () => thresholds,
    [thresholds]
  );
 
  const monitor = useMemo(
    () => new PerformanceMonitor(stableThresholds),
    [stableThresholds]
  );
 
  const [state, setState] = useState<PerformanceMonitorState>(() => ({
    metrics: monitor.getMetrics(gl),
    isGood: monitor.isPerformanceGood(),
    warnings: monitor.getWarnings(),
  }));
 
  const lastUpdateRef = useRef(0);
 
  // Update performance monitor every frame
  useFrame(() => {
    if (!enabled) return;
 
    monitor.update(gl);
 
    // Update React state at specified interval
    const now = performance.now();
    if (now - lastUpdateRef.current >= updateInterval) {
      lastUpdateRef.current = now;
      
      setState({
        metrics: monitor.getMetrics(gl),
        isGood: monitor.isPerformanceGood(),
        warnings: monitor.getWarnings(),
      });
    }
  });
 
  // Reset monitor on unmount
  useEffect(() => {
    return () => {
      monitor.reset();
    };
  }, [monitor]);
 
  return state;
}
 
export default usePerformanceMonitor;