Simplified XR store setup

Refactored XRSession to remove marker bitmap preloading and lazy async store initialization. Replaced complex getXRStore flow with a single getOrCreateXRStore, removed manual bitmap handling, and updated AR start flow to use the centralized store. Simplified UX message on successful XR start.

X-Lovable-Edit-ID: edt-a8250c81-169f-4cc7-8370-4f5068a2c078
This commit is contained in:
gpt-engineer-app[bot]
2026-02-27 19:52:59 +00:00
+7 -54
View File
@@ -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<ImageBitmap> | null = null;
function getMarkerBitmap(): Promise<ImageBitmap> {
if (!markerBitmapPromise) {
markerBitmapPromise = generateTrackingMarker();
}
return markerBitmapPromise;
}
// --- XR Store singleton (lazy-initialized with marker) ---
// --- XR Store singleton ---
let xrStoreInstance: ReturnType<typeof createXRStore> | 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();