diff --git a/src/pages/XRSession.tsx b/src/pages/XRSession.tsx index 1df6fb7..0d5bd1a 100644 --- a/src/pages/XRSession.tsx +++ b/src/pages/XRSession.tsx @@ -8,55 +8,15 @@ import { useModelStore } from '@/stores/useModelStore'; import { toast } from 'sonner'; import { ArrowLeft, Move, RotateCw, QrCode, Download, Crosshair } from 'lucide-react'; import { Button } from '@/components/ui/button'; -import { generateTrackingMarker, generateMarkerDownloadURL } from '@/lib/trackingMarker'; +import { generateMarkerDownloadURL } from '@/lib/trackingMarker'; -// --- Marker bitmap singleton --- -let markerBitmapPromise: Promise | null = null; -function getMarkerBitmap(): Promise { - if (!markerBitmapPromise) { - markerBitmapPromise = generateTrackingMarker(); - } - return markerBitmapPromise; -} - -// --- XR Store singleton (lazy-initialized with marker) --- +// --- XR Store singleton --- let xrStoreInstance: ReturnType | null = null; -async function getXRStore() { +function getOrCreateXRStore() { if (xrStoreInstance) return xrStoreInstance; - const bitmap = await getMarkerBitmap(); - // Only emulate when on localhost AND no native XR support - const shouldEmulate = - typeof window !== 'undefined' && - window.location.hostname === 'localhost' && - !navigator.xr; - - xrStoreInstance = createXRStore({ - emulate: shouldEmulate ? 'metaQuest3' : false, - hand: { left: true, right: true }, - controller: { left: true, right: true }, - customSessionInit: { - optionalFeatures: ['image-tracking'], - // @ts-ignore — trackedImages is a WebXR extension not yet in TS types - trackedImages: [ - { - image: bitmap, - widthInMeters: 0.15, // 15cm printed marker - }, - ], - }, - }); - - return xrStoreInstance; -} - -// Create a synchronous fallback store for initial render -// (will be replaced once the async one is ready) -function getInitialXRStore() { - if (xrStoreInstance) return xrStoreInstance; - const shouldEmulate = typeof window !== 'undefined' && window.location.hostname === 'localhost' && @@ -243,24 +203,17 @@ const XRSession = () => { const navigate = useNavigate(); const { model, anchorMode, setAnchorMode } = useModelStore(); const [inXR, setInXR] = useState(false); - const [store, setStore] = useState(() => getInitialXRStore()); + const [store] = useState(() => getOrCreateXRStore()); - // Pre-load marker and rebuild store with customSessionInit useEffect(() => { if (!model) { navigate('/'); - return; } - getXRStore().then((s) => { - // Update store ref if it was replaced with the marker-enabled one - if (s !== store) setStore(s); - }); }, [model, navigate]); const handleEnterAR = useCallback(async () => { try { - const s = await getXRStore(); - const session = await s.enterAR(); + const session = await store.enterAR(); if (session) { session.addEventListener('end', () => { setInXR(false); @@ -268,13 +221,13 @@ const XRSession = () => { }); setInXR(true); setAnchorMode('manual'); - toast.success('Sessão XR iniciada — Buscando QR Code…'); + toast.success('Sessão XR iniciada!'); } } catch (err: any) { console.error('XR error:', err); toast.error(`Falha ao iniciar XR: ${err.message}`); } - }, [setAnchorMode]); + }, [store, setAnchorMode]); const handleDownloadMarker = useCallback(async () => { const url = await generateMarkerDownloadURL();