@3dsource/metabox-front-api
Version:
API for Metabox BASIC configurator
864 lines (832 loc) • 29.5 kB
JavaScript
import { fromEvent } from 'rxjs';
/**
* Base class for commands sent to the Metabox API.
*/
class CommandBase {
}
/**
* Wrapper helper function to use it with rxJs the same as `fromEvent` to listen to events from the Communicator.
* @param {Communicator} target
* @param eventName
*/
function fromCommunicatorEvent(target, eventName) {
return fromEvent(target, eventName);
}
const MetaboxBasicConfiguratorActions = {
metaboxConfig: 'metaboxConfig',
setEnvironment: 'setEnvironment',
setEnvironmentMaterialById: 'setEnvironmentMaterialById',
setProduct: 'setProduct',
setProductMaterialById: 'setProductMaterialById',
getPdf: 'getPdf',
getCallToActionInformation: 'getCallToActionInformation',
getScreenshot: 'getScreenshot',
showEmbeddedMenu: 'showEmbeddedMenu',
forceSetDeviceType: 'forceSetDeviceType',
showOverlayInterface: 'showOverlayInterface',
resetCamera: 'resetCamera',
applyZoom: 'applyZoom',
initShowcase: 'initShowcase',
playShowcase: 'playShowcase',
pauseShowcase: 'pauseShowcase',
stopShowcase: 'stopShowcase',
sendCommandToUnreal: 'sendCommandToUnreal',
watchCallbacks: 'watchCallbacks',
};
/**
* Represents a command to send Metabox Config to Metabox Basic Configurator.
* @remarks
* Automatically sent when the Communicator instance is ready.
*/
class MetaboxConfig extends CommandBase {
/**
* Creates an instance of MetaboxConfig.
* @param {string} appId - The unique identifier for the Communicator Instance
* @param {MetaboxCommandConfig} config - optional initial config: standalone - if true - disable metabox custom template and all logic
*/
constructor(appId, config) {
super();
this.data = {
action: MetaboxBasicConfiguratorActions.metaboxConfig,
payload: { appId, config },
};
}
}
/**
* Represents a command to get a PDF from Metabox Basic Configurator.
* @remarks
* This class sends a message to the Metabox API to generate a PDF based on the current configuration.
* This action does not require any parameters.
*
* **Important**: Invoking this command will buffer it until the viewport is ready. Only then will the request be processed.
*
* @example
* import { GetPdf, Communicator } from '@3dsource/metabox-front-api';
* window.env3DSource.apiReady = (api: Communicator) => {
* api.sendCommandToMetabox(new GetPdf());
* };
*/
class GetPdf extends CommandBase {
/**
* Creates an instance of GetPdf.
*
* @remarks
* This constructor does not require any parameters.
*/
constructor() {
super();
this.data = { action: MetaboxBasicConfiguratorActions.getPdf };
}
}
/**
* Represents a command to get a Call To Action Information from Metabox Basic Configurator.
* @remarks
* This class sends a message to the Metabox API to generate Call To Action information based on the current configuration and sends it to the endpoint url from the cta information.
* This action does not require any parameters.
*
* **Important**: Invoking this command will buffer it until the viewport is ready. Only then will the request be processed.
*
* @example
* import { GetCallToActionInformation, Communicator } from '@3dsource/metabox-front-api';
* window.env3DSource.apiReady = (api: Communicator) => {
* api.sendCommandToMetabox(new GetCallToActionInformation());
* };
*/
class GetCallToActionInformation extends CommandBase {
/**
* Creates an instance of GetCallToActionInformation.
*
* @remarks
* This constructor does not require any parameters.
*/
constructor() {
super();
this.data = {
action: MetaboxBasicConfiguratorActions.getCallToActionInformation,
};
}
}
/**
* Represents a command to send to unreal and reset camera to initial.
* @remarks
* This class sends a message to the Metabox API to reset the camera on a scene.
* This action does not require any parameters.
*
* **Important**: Invoking this command will buffer it until the viewport is ready. Only then will the request be processed.
*
* @example
* import { ResetCamera, Communicator } from '@3dsource/metabox-front-api';
* window.env3DSource.apiReady = (api: Communicator) => {
* api.sendCommandToMetabox(new ResetCamera());
* };
*/
class ResetCamera extends CommandBase {
/**
* Creates an instance of ResetCamera.
*
* @remarks
* This constructor does not require any parameters.
*/
constructor() {
super();
this.data = { action: MetaboxBasicConfiguratorActions.resetCamera };
}
}
/**
* Represents a command to ApplyZoom and change zoom camera on a scene.
* @remarks
* This class sends a command to the Metabox API to change zoom on a scene.
*
* **Important**: Invoking this command will buffer it until the viewport is ready. Only then will the request be processed.
*
* @example
* import { ApplyZoom, Communicator } from '@3dsource/metabox-front-api';
* window.env3DSource.apiReady = (api: Communicator) => {
* api.sendCommandToMetabox(new ApplyZoom(10));
* api.sendCommandToMetabox(new ApplyZoom(-10));
* };
*/
class ApplyZoom extends CommandBase {
/**
* Creates an instance of ApplyZoom.
*
* @param {...number} zoom
*/
constructor(zoom) {
super();
this.data = {
action: MetaboxBasicConfiguratorActions.applyZoom,
payload: { zoom },
};
}
}
/**
* Represents a command to Init Showcase for a product a scene and start a sequence for the product.
* @remarks
* This class sends a command to the Metabox API to init showcase if the product has a sequence.
* For check this needs to find a showcase property in the current product.
* If this property exists, you can send init showcase command.
*
* **Important**: Invoking this command will buffer it until the viewport is ready. Only then will the request be processed.
*
* @example
* ```typescript
* import { InitShowcase, Communicator } from '@3dsource/metabox-front-api';
* window.env3DSource.apiReady = (api: Communicator) => {
* api.sendCommandToMetabox(new InitShowcase());
* };
*/
class InitShowcase extends CommandBase {
/**
* Creates an instance of InitShowcase.
*
* @remarks
* This constructor does not require any parameters.
*/
constructor() {
super();
this.data = {
action: MetaboxBasicConfiguratorActions.initShowcase,
};
}
}
/**
* Represents a command to Play Showcase for a product when it already init, and you call pause, for example, before it.
* @remarks
* This class sends a command to the Metabox API to play showcase for a product if it is already initialized and pause.
*
* **Important**: Invoking this command will buffer it until the viewport is ready. Only then will the request be processed.
*
* @example
* import { PlayShowcase, Communicator } from '@3dsource/metabox-front-api';
* window.env3DSource.apiReady = (api: Communicator) => {
* api.sendCommandToMetabox(new PlayShowcase());
* };
*/
class PlayShowcase extends CommandBase {
/**
* Creates an instance of PlayShowcase.
*
* @remarks
* This constructor does not require any parameters.
*/
constructor() {
super();
this.data = { action: MetaboxBasicConfiguratorActions.playShowcase };
}
}
/**
* @internal
* @hidden
* Represents a command to send Unreal command.
*/
class UnrealCommand extends CommandBase {
constructor(payload) {
super();
this.data = {
action: MetaboxBasicConfiguratorActions.sendCommandToUnreal,
payload,
};
}
}
/**
* Represents a command to Pause Showcase for a product when it already init and play, and you call pause.
* @remarks
* This class sends a command to the Metabox API to pause showcase for a product if it is already initialized and play.
*
* **Important**: Invoking this command will buffer it until the viewport is ready. Only then will the request be processed.
*
* @example
* import { PauseShowcase, Communicator } from '@3dsource/metabox-front-api';
* window.env3DSource.apiReady = (api: Communicator) => {
* api.sendCommandToMetabox(new PauseShowcase());
* };
*/
class PauseShowcase extends CommandBase {
/**
* Creates an instance of PauseShowcase.
*
* @remarks
* This constructor does not require any parameters.
*/
constructor() {
super();
this.data = { action: MetaboxBasicConfiguratorActions.pauseShowcase };
}
}
/**
* Represents a command to Stop Showcase for a product when it already init, and you want to destroy it.
* @remarks
* This class sends a command to the Metabox API to Stop showcase for a product if it is already initialized.
*
* **Important**: Invoking this command will buffer it until the viewport is ready. Only then will the request be processed.
*
* @example
* import { StopShowcase, Communicator } from '@3dsource/metabox-front-api';
* window.env3DSource.apiReady = (api: Communicator) => {
* api.sendCommandToMetabox(new StopShowcase());
* };
*/
class StopShowcase extends CommandBase {
/**
* Creates an instance of StopShowcase.
*
* @remarks
* This constructor does not require any parameters.
*/
constructor() {
super();
this.data = { action: MetaboxBasicConfiguratorActions.stopShowcase };
}
}
/**
* Represents a command to get a screenshot.
*
* **Important**: Invoking this command will buffer it until the viewport is ready. Only then will the request be processed.
*
* @example
* import { GetScreenshot, Communicator, saveImage } from '@3dsource/metabox-front-api';
* window.env3DSource.apiReady = (api: Communicator) => {
* // Listen for events from to the Metabox API
* api.addEventListener('screenshot', (data) => {
* // Process the get screenshot response
* saveImage(data, 'Render.png');
* });
* api.sendCommandToMetabox(new GetScreenshot('image/png', { x: 1024, y: 1024 }));
* };
*/
class GetScreenshot extends CommandBase {
/**
* Constructs an instance of GetScreenshot.
* @param {MimeType} mimeType - The output format.
* @param {{ x: number; y: number }} [size] - Optional size in pixels.
*/
constructor(mimeType, size) {
super();
this.data = {
action: MetaboxBasicConfiguratorActions.getScreenshot,
payload: { format: mimeType, size },
};
}
}
/**
* Represents a command to set a product by its ID.
*
* @remarks
* This action sends a message to the Metabox API to set a product using the provided product ID.
*
* @example
* import { SetProduct, Communicator } from '@3dsource/metabox-front-api';
*
* //...Assume that the integration is already implemented
* window.env3DSource.apiReady = (api: Communicator) => {
* api.setCommandToMetaBox(new SetProduct(
* 'ffea6b5c-3a8a-4f56-9417-e605acb5cca3'
* ));
* };
*/
class SetProduct extends CommandBase {
/**
* Creates an instance of SetProduct.
*
* @param {string} productId - The product ID.
*/
constructor(productId) {
super();
this.data = {
action: MetaboxBasicConfiguratorActions.setProduct,
payload: { productId },
};
}
}
/**
* Represents a command to set a material by its slot ID and Material ID.
*
* @example
* import { SetProductMaterial, Communicator } from '@3dsource/metabox-front-api';
*
* //...Assume that the integration is already implemented
* window.env3DSource.apiReady = (api: Communicator) => {
* api.sendCommandToMetabox(new SetProductMaterial(
* 'carpaint',
* 'dd829d6e-9200-47a7-8d5b-af5df89b7e91',
* ));
* };
*/
class SetProductMaterial extends CommandBase {
/**
* Creates an instance of SetProductMaterial.
*
* @param {string} slotId - The slot ID.
* @param {string} materialId - The material ID.
*/
constructor(slotId, materialId) {
super();
this.data = {
action: MetaboxBasicConfiguratorActions.setProductMaterialById,
payload: { slotId, materialId },
};
}
}
/**
* Represents a command to set the environment by its ID.
*
* @example
* import { SetEnvironment, Communicator } from '@3dsource/metabox-front-api';
*
* //...Assume that the integration is already implemented
* window.env3DSource.apiReady = (api: Communicator) => {
* // Change the environment to '55555555-1234-1234-1234-01234567890'
* api.sendCommandToMetabox(new SetEnvironment('55555555-1234-1234-1234-01234567890'));
* };
*/
class SetEnvironment extends CommandBase {
/**
* Creates an instance of SetEnvironment.
*
* @param {string} environmentId - The environment ID.
*/
constructor(environmentId) {
super();
this.data = {
action: MetaboxBasicConfiguratorActions.setEnvironment,
payload: { id: environmentId },
};
}
}
/**
* Represents a command to set an environment material by its slot ID and Material ID.
*
* @example
* import { SetEnvironmentMaterial, Communicator } from '@3dsource/metabox-front-api';
*
* //...Assume that the integration is already implemented
* window.env3DSource.apiReady = (api: Communicator) => {
* api.sendCommandToMetabox(new SetEnvironmentMaterial(
* 'carpaint',
* 'dd829d6e-9200-47a7-8d5b-af5df89b7e91',
* ));
* };
*/
class SetEnvironmentMaterial extends CommandBase {
/**
* Creates an instance of SetEnvironmentMaterial.
*
* @param {string} slotId - The slot ID.
* @param {string} materialId - The material ID.
*/
constructor(slotId, materialId) {
super();
this.data = {
action: MetaboxBasicConfiguratorActions.setEnvironmentMaterialById,
payload: { slotId, materialId },
};
}
}
/**
* Represents a command to toggle the Embedded to the Metabox Menu.
*
* @example
* import { ShowEmbeddedMenu, Communicator } from '@3dsource/metabox-front-api';
*
* //...Assume that the integration is already implemented
* window.env3DSource.apiReady = (api: Communicator) => {
* api.setCommandToMetaBox(new ShowEmbeddedMenu(true));
* };
*/
class ShowEmbeddedMenu extends CommandBase {
/**
* Creates an instance of ShowEmbeddedMenu.
*
* @param {boolean} visible - A flag indicating whether the embedded menu should be visible.
*/
constructor(visible) {
super();
this.data = {
action: MetaboxBasicConfiguratorActions.showEmbeddedMenu,
payload: { visible },
};
}
}
/**
* Represents a command to toggle the Unreal Overlay Interface Menu.
*
* @remarks
* This action sends a message to the Metabox API to toggle the visibility of the Unreal overlay UI.
*
* @example
* import { ShowOverlayInterface, Communicator } from '@3dsource/metabox-front-api';
*
* //...Assume that the integration is already implemented
* window.env3DSource.apiReady = (api: Communicator) => {
* api.setCommandToMetaBox(new ShowOverlayInterface(true));
* };
*/
class ShowOverlayInterface extends CommandBase {
/**
* Creates an instance of ShowOverlayInterface.
*
* @param {boolean} visible - A flag indicating whether the Unreal overlay UI should be visible.
*/
constructor(visible) {
super();
this.data = {
action: MetaboxBasicConfiguratorActions.showOverlayInterface,
payload: { visible },
};
}
}
/**
* @experimental
* @internal
* @hidden
* @remarks
* Represents a command to watch Unreal callbacks from Unreal engine.
* Can be useful for custom solutions.
*/
class WatchCallbacks extends CommandBase {
/**
* Creates an instance of WatchCallbacks.
*
* @remarks
* This constructor does not require any parameters.
*/
constructor() {
super();
this.data = { action: MetaboxBasicConfiguratorActions.watchCallbacks };
}
}
/**
* EventDispatcher is a class that manages event listeners and dispatches events to them.
*/
class EventDispatcher {
constructor() {
/**
* Storage for callback listeners by message type.
*/
this.listeners = [];
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
destroy(key) {
this.listeners = [];
}
/**
* Adds an event listener for receiving specific types of messages.
*
* @param messageType - The message type to listen for.
* @param callback - The callback function to execute when a message is received.
*/
addEventListener(messageType, callback) {
this.listeners.push({ messageType, callback });
return this;
}
/**
* Dispatches an event to all listeners of a specific message type.
*
* @param messageType - The message type.
* @param data - The data associated with the event.
*/
dispatchEvent(messageType, data) {
this.listeners
.filter((listener) => listener.messageType === messageType)
.forEach((listener) => listener.callback(data));
return this;
}
/**
* Removes an event listener for a specific type of message.
*
* @param messageType - The message type.
* @param callback - The callback function to remove.
*/
removeEventListener(messageType, callback) {
this.listeners = this.listeners.filter((listener) => !(listener.messageType === messageType && listener.callback === callback));
return this;
}
}
const Metabox = 'metabox_v3';
const MetaboxHost = 'metaboxHost_v3';
const MetaboxData = 'metaboxData_v3';
const AppLoaded = 'appLoaded_v3';
const MetaboxDomain = 'metabox.3dsource.com';
const BasicRouteUrl = 'metabox-configurator/basic';
const VERSION = '3.0.5';
const communicatorMap = new Map();
/**
* Handles messaging between the host page and embedded Metabox content.
* @internal Use {@link Communicator.createInstance} or the {@link integrateMetabox} helper to instantiate.
*/
class Communicator extends EventDispatcher {
/**
* Constructs a Communicator, replacing any existing instance, and begins listening for messages.
* @internal
*/
constructor(data, environment, config) {
super();
/**
* Bound handler for incoming postMessage events.
*/
this.binder = this.handleMessageReceived.bind(this, MetaboxData);
const { appId = 'unknown', version = VERSION } = data ?? {};
const key = `${version}_${environment}_${appId}`;
communicatorMap.get(key)?.instance.destroy(key);
communicatorMap.set(key, { instance: this });
window.addEventListener('message', this.binder);
this.sendCommandToMetabox(new MetaboxConfig(appId, {
...config,
hostUrl: location.href,
apiVersion: VERSION,
}));
}
/**
* Listens for Metabox to signal readiness, then initializes communicator.
* @param apiReadyCallback - Called with the new Communicator once to the Metabox is loaded.
* @param {MetaboxEnvironment} environment - The environment in which the Communicator is running.
* @param {MetaboxCommandConfig} config - optional initial config: standalone - if true - disable metabox custom template and all logic
*/
static createInstance(apiReadyCallback, environment, config) {
const startHandler = (event) => {
const message = event.data;
if (message?.envelope?.action === AppLoaded && message.host === Metabox) {
apiReadyCallback(new Communicator(message.envelope.payload, environment, config));
window.removeEventListener('message', startHandler);
}
};
window.addEventListener('message', startHandler);
}
/**
* Cleans up resources and stops listening for messages.
*/
destroy(key) {
super.destroy(key);
window.removeEventListener('message', this.binder);
}
static clearAll() {
if (communicatorMap.size === 0) {
return;
}
communicatorMap.forEach((value, key) => value.instance.destroy(key));
communicatorMap.clear();
}
static getCommunicator(key) {
return communicatorMap.get(key);
}
/**
* Posts a command to the Metabox iframe.
* @param command - An action command containing data to send.
*/
sendCommandToMetabox(command) {
const { data } = command;
const iframe = document.getElementById('embeddedContent');
const message = {
host: MetaboxHost,
payload: { ...data },
};
if (!iframe?.contentWindow) {
console.warn('to the Metabox IFrame not found or not ready. Message sends to the same window');
window.postMessage({ ...message, target: 'metabox' }, '*');
return;
}
// Replace '*' with a specific origin in production for better security.
iframe.contentWindow.postMessage({ ...message, target: 'child' }, '*');
}
/**
* Registers an event listener for messages dispatched by to the Metabox.
* @override
*/
addEventListener(messageType, callback) {
return super.addEventListener(messageType, callback);
}
/**
* Dispatches a typed event to all registered listeners.
* @override
*/
dispatchEvent(messageType, data) {
return super.dispatchEvent(messageType, data);
}
/**
* Removes a previously registered event listener.
* @override
*/
removeEventListener(messageType, callback) {
return super.removeEventListener(messageType, callback);
}
/**
* Filters and dispatches incoming messages from to the Metabox.
* @param {FromMetaBoxApiEvents | 'metaboxData' } messageType - Expected message type for filtering ('metaboxData').
* @param {MessageEvent} event - The postMessage event received on a window.
*/
handleMessageReceived(messageType, event) {
// Optionally validate event.origin for security.
if (messageType !== MetaboxData || event.data?.host !== Metabox) {
return;
}
const data = event.data?.envelope;
this.dispatchEvent(data?.eventType, data?.payload);
}
}
const prepareIframeSrc = (configuratorId, config) => {
const base = `https://${config?.domain || MetaboxDomain}/${BasicRouteUrl}/${configuratorId}`;
const params = new URLSearchParams();
if (config?.introImage) {
params.set('introImage', config.introImage);
}
if (config?.introVideo) {
params.set('introVideo', config.introVideo);
}
if (config?.loadingImage) {
params.set('loadingImage', config.loadingImage);
}
if (config?.state) {
params.set('state', decodeURIComponent(config.state));
}
const query = params.toString();
return query ? `${base}?${query}` : base;
};
/**
* Integrates the Metabox Basic Configurator into the page by injecting an iframe and
* initializing a Communicator instance for host-to-iframe messaging.
*
* @remarks
* - Builds a secure iframe URL using the provided configuratorId and config options.
* - Ensures the resulting URL uses HTTPS and that the target container exists.
* - Removes any previously embedded iframe with id "embeddedContent" before inserting a new one.
*
* @param {string} configuratorId - The Basic Configurator ID (not a full URL). It is appended to
* `https://{domain}/metabox-configurator/basic/{configuratorId}` to form the iframe src.
*
* @param {string} [containerId='embed3DSource'] - The id of the container element where the iframe will be injected.
*
* @param {(api: Communicator) => void} apiReadyCallback - Called when the Communicator instance is created on the host side.
*
* @param {IntegrateMetaboxConfig} config - Optional configuration used to build the iframe URL and initialize the communicator.
* Supported fields:
* - standalone?: boolean — if true, disables Metabox custom template and related logic.
* - introImage?: string — URL to an image shown on the intro screen (added as ?introImage=...).
* - introVideo?: string — URL to a video shown on the intro screen (added as ?introVideo=...).
* - loadingImage?: string — URL to an image displayed while loading (added as ?loadingImage=...).
* - state?: string — Predefined state for configurator for initial loading (added as ?state=...).
* - domain?: string — custom domain for testing (defaults to metabox.3dsource.com). HTTPS is enforced.
*
* @throws Error If configuratorId or containerId are empty strings.
* @throws Error If the computed iframe URL is invalid or does not use HTTPS.
* @throws Error If the container element with the provided id cannot be found.
*
* @example
* import { integrateMetabox } from '@3dsource/metabox-front-api';
*
* integrateMetabox(
* 'configurator-id',
* 'embed3DSource',
* (api) => {
* // Communicator is ready to use
* },
* {
* standalone: false,
* introImage: 'https://example.com/intro.png',
* loadingImage: 'https://example.com/loading.png',
* },
* );
*/
function integrateMetabox(configuratorId, containerId = 'embed3DSource', apiReadyCallback, config) {
if (!configuratorId.trim()) {
throw new Error('integrateMetabox: configuratorId must be a non-empty string');
}
const iframeSrc = prepareIframeSrc(configuratorId, config);
let parsedUrl;
try {
parsedUrl = new URL(iframeSrc);
}
catch {
throw new Error('integrateMetabox: Provided iframeSrc is not a valid URL');
}
if (parsedUrl.protocol !== 'https:') {
throw new Error('integrateMetabox: iframeSrc must use HTTPS protocol');
}
if (!containerId.trim()) {
throw new Error('integrateMetabox: containerId must be a non-empty string');
}
const container = document.getElementById(containerId);
if (!container) {
throw new Error(`Container element with id ${containerId} not found`);
}
const existingIframe = document.getElementById('embeddedContent');
if (existingIframe) {
existingIframe.remove();
}
Communicator.createInstance(apiReadyCallback, 'host', config);
const style = document.createElement('style');
style.innerHTML = `
#${containerId} {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
}
`;
document.head.appendChild(style);
const iframe = document.createElement('iframe');
iframe.setAttribute('allow', 'autoplay; fullscreen; encrypted-media');
iframe.setAttribute('referrerPolicy', 'no-referrer-when-downgrade');
iframe.setAttribute('id', 'embeddedContent');
iframe.style.border = '0';
iframe.style.width = '100%';
iframe.style.height = '100%';
iframe.style.overflow = 'hidden';
iframe.src = iframeSrc;
container.appendChild(iframe);
}
/**
* Saves an image by triggering a download.
*
* @remarks
* This function creates an anchor element, sets its `href` attribute to the provided image URL,
* and triggers a click event to initiate a download with the specified filename.
*
* @param {string} imageUrl - The URL of the image to save.
* @param {string} filename - The name of the file to save.
*/
function saveImage(imageUrl, filename) {
const a = document.createElement('a');
a.href = imageUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
/**
* Sets the URL parameters based on the provided state.
*
* @remarks
* This function updates the current URL by replacing its search parameters with the key-value pairs from the provided state object.
*
* @param {Record<string, string>} state - An object containing key-value pairs to set as URL parameters.
*/
function setUrlParams(state) {
const url = new URL(window.location.href);
url.search = '';
Object.entries(state).forEach(([key, value]) => {
url.searchParams.set(key, value);
});
history.replaceState(null, '', url.toString());
}
/**
* Retrieves the URL parameters as an object.
*
* @remarks
* This function parses the current URL's search parameters and returns them as a key-value object.
*
* @returns An object containing the URL parameters.
*/
function getUrlParams() {
const urlParams = new URLSearchParams(window.location.search);
const selections = {};
urlParams.forEach((value, key) => {
selections[key] = value;
});
return selections;
}
/**
* Generated bundle index. Do not edit.
*/
export { AppLoaded, ApplyZoom, BasicRouteUrl, CommandBase, Communicator, EventDispatcher, GetCallToActionInformation, GetPdf, GetScreenshot, InitShowcase, Metabox, MetaboxBasicConfiguratorActions, MetaboxConfig, MetaboxData, MetaboxDomain, MetaboxHost, PauseShowcase, PlayShowcase, ResetCamera, SetEnvironment, SetEnvironmentMaterial, SetProduct, SetProductMaterial, ShowEmbeddedMenu, ShowOverlayInterface, StopShowcase, UnrealCommand, VERSION, WatchCallbacks, fromCommunicatorEvent, getUrlParams, integrateMetabox, prepareIframeSrc, saveImage, setUrlParams };
//# sourceMappingURL=3dsource-metabox-front-api.mjs.map