import { DEFAULT_PROJECTION, PLAYER_SELECTOR, type ProjectionMode, VALID_PROJECTIONS } from './config.js'; import { create2DControlPanel, createPlayButton, injectPlayerStyles } from './dom/dom.js'; import { createMediaAdapter, type SupportedMediaAdapter } from './media/media-adapter.js'; export type BootstrapContext = { mediaAdapter: SupportedMediaAdapter; playButton: HTMLButtonElement; playerContainer: HTMLElement; projectionMode: ProjectionMode; }; export function bootstrapPlayer(playerBase: string, onReady: (context: BootstrapContext) => void): void { injectPlayerStyles(playerBase); onDocumentReady(() => { const containers = document.querySelectorAll(PLAYER_SELECTOR); if (containers.length === 0) { console.error(`VR_WEB_PLAYER_DOM: Expected exactly one ${PLAYER_SELECTOR} container, found none.`); return; } if (containers.length > 1) { console.warn(`VR_WEB_PLAYER_DOM: This version supports exactly one ${PLAYER_SELECTOR} container per page. Found ${containers.length}; no player was initialized.`); return; } const playerContainer = containers[0]; playerContainer.classList.add('vrwp'); const configuredProjection = (playerContainer.dataset.projection || DEFAULT_PROJECTION).trim().toLowerCase(); if (!VALID_PROJECTIONS.has(configuredProjection as ProjectionMode)) { console.error(`VR_WEB_PLAYER_CONFIG: Unsupported data-projection="${configuredProjection}". Use "vr180" or "plane".`); return; } const mediaAdapter = createMediaAdapter(playerContainer); if (!mediaAdapter) { console.error(`VR_WEB_PLAYER_DOM: ${PLAYER_SELECTOR} must contain exactly one supported media element: video or img.`); return; } const playButton = createPlayButton(); playerContainer.appendChild(playButton); playerContainer.appendChild(create2DControlPanel()); playButton.disabled = true; mediaAdapter.bindLoadState({ onError: (event) => { console.error(`VR_WEB_PLAYER_MEDIA: Failed to load ${mediaAdapter.kind} media.`, event); playButton.disabled = true; }, onReady: () => { playButton.disabled = false; } }); mediaAdapter.load(); completeXrSupportCheck(playButton, () => { onReady({ mediaAdapter, playButton, playerContainer, projectionMode: configuredProjection as ProjectionMode }); }); }); } function onDocumentReady(callback: () => void): void { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', callback, { once: true }); return; } callback(); } function completeXrSupportCheck(playButton: HTMLButtonElement, onComplete: () => void): void { if (!navigator.xr) { markXrUnsupported(playButton); onComplete(); return; } navigator.xr.isSessionSupported('immersive-vr').then((supported) => { if (supported) { playButton.dataset.xrSupported = 'true'; } else { markXrUnsupported(playButton); } onComplete(); }).catch((err) => { console.error('XR Support Check Error:', err); markXrUnsupported(playButton); onComplete(); }); } function markXrUnsupported(playButton: HTMLButtonElement): void { playButton.dataset.xrSupported = 'false'; playButton.disabled = false; }