diff --git a/lib/pinball/usePinballInstance.ts b/lib/pinball/usePinballInstance.ts index 182f17e..f9c73d1 100644 --- a/lib/pinball/usePinballInstance.ts +++ b/lib/pinball/usePinballInstance.ts @@ -61,6 +61,32 @@ export function usePinballInstance( const canvas = canvasRef.current; if (!canvas || !webgl2Supported) return; + // The engine sets a table-supplied image as the page favicon via a + // blob: URL (see vpinball.js's rel~='icon' link handling) — undesirable + // here, where the app's own favicon should stay put. Snapshot the + // current icon links up front and revert any blob: href the moment it + // appears, rather than patching the (compiled) engine itself. + const originalIconHrefs = new Map(); + document.querySelectorAll("link[rel~='icon']").forEach((link) => { + originalIconHrefs.set(link, link.href); + }); + const faviconObserver = new MutationObserver(() => { + document.querySelectorAll("link[rel~='icon']").forEach((link) => { + if (!link.href.startsWith("blob:")) return; + const blobUrl = link.href; + const original = originalIconHrefs.get(link); + if (original) link.href = original; + else link.remove(); + URL.revokeObjectURL(blobUrl); + }); + }); + faviconObserver.observe(document.head, { + childList: true, + subtree: true, + attributes: true, + attributeFilter: ["href"], + }); + setStatus("loading"); const startedAt = performance.now(); @@ -103,6 +129,7 @@ export function usePinballInstance( })(); return () => { + faviconObserver.disconnect(); disposedRef.current = true; const instance = instanceRef.current; instanceRef.current = null;