// src/hooks/useAssetLoader.ts import { useState, useEffect } from 'react'; // Defines the structure for our asset map export type AssetSource = { id: string; label: string; src: string; }; // The hook returns the loaded images and the loading status export const useAssetLoader = (assets: AssetSource[]) => { const [loadedImages, setLoadedImages] = useState< Record >({}); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { // Reset state when assets change setIsLoading(true); setLoadedImages({}); setError(null); if (assets.length === 0) { setIsLoading(false); return; } const loadImages = async () => { try { const promises = assets.map((asset) => { return new Promise((resolve, reject) => { const img = new Image(); // --- THIS IS THE CRITICAL FIX --- // This attribute tells the browser it's okay to use this cross-origin image on a canvas // that you intend to capture a stream from. img.crossOrigin = "anonymous"; // -------------------------------- img.src = asset.src; img.onload = () => { setLoadedImages((prev) => ({ ...prev, [asset.id]: img })); resolve(); }; img.onerror = (err) => { console.error( `Failed to load asset: ${asset.label} from ${asset.src}`, err ); reject(new Error(`Failed to load ${asset.label}`)); }; }); }); await Promise.all(promises); } catch (err: unknown) { console.error("Failed to load one or more assets:", err); if (err instanceof Error) { setError(err.message); } else { setError("An unknown error occurred during asset loading."); } } finally { setIsLoading(false); } }; loadImages(); }, [JSON.stringify(assets)]); // Use stringify to deep-compare the assets array dependency return { loadedImages, isLoading, error }; };