@virtualdisplay.io/client 4.0.0-alpha.2 → 4.0.0-alpha.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1,461 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={NO_MAPPING:`NO_MAPPING`,ATTRIBUTE_NOT_FOUND:`ATTRIBUTE_NOT_FOUND`,VALUE_NOT_FOUND:`VALUE_NOT_FOUND`,PARENT_NOT_FOUND:`PARENT_NOT_FOUND`,INVALID_PARAMETER:`INVALID_PARAMETER`,SNAPSHOT_FAILED:`SNAPSHOT_FAILED`},t=class t extends Error{code;constructor(e,n){super(e),this.name=`VirtualdisplayError`,this.code=n,Error.captureStackTrace!==void 0&&Error.captureStackTrace(this,t)}static noMapping(){return new t(`No attributes available. Waiting for server metadata.`,e.NO_MAPPING)}static attributeNotFound(n){return new t(`Attribute "${n}" not found in mapping`,e.ATTRIBUTE_NOT_FOUND)}static valueNotFound(n,r){return new t(`Value "${r}" not found for attribute "${n}"`,e.VALUE_NOT_FOUND)}static parentNotFound(n){return new t(`Parent element not found: ${n}`,e.PARENT_NOT_FOUND)}static invalidParameter(n){return new t(n,e.INVALID_PARAMETER)}static snapshotFailed(n,r){return new t(`Snapshot failed for "${n}": ${r}`,e.SNAPSHOT_FAILED)}},n=class{defaultServer=`https://server.virtualdisplay.io`;options;constructor(e){this.options=e}create(){let e=this.createIframe();return this.attachToParent(e),e}createIframe(){let e=document.createElement(`iframe`);return e.src=this.buildUrl(),Object.assign(e.style,{width:`100%`,height:`100%`,border:`none`}),e.setAttribute(`allow`,`xr-spatial-tracking; fullscreen`),e}attachToParent(e){this.getParentElement().appendChild(e)}buildUrl(){let e=this.getServerUrl(),t=new URL(e);return t.searchParams.set(`license`,this.options.license),t.searchParams.set(`model`,this.options.model),this.options.debug===!0&&t.searchParams.set(`debug`,`true`),this.options.language!==void 0&&t.searchParams.set(`language`,this.options.language),t.toString()}getServerUrl(){return this.defaultServer}getParentElement(){if(typeof this.options.parent!=`string`)return this.options.parent;let e=document.querySelector(this.options.parent);if(e===null)throw t.parentNotFound(this.options.parent);return e}};function r(e){let t=new Date(e.timestamp).toLocaleTimeString(`en-GB`,{hour12:!1}),n=e.level.toUpperCase().padEnd(5),r=e.trace_id?.slice(0,8)??`--------`,i=e.msg,a=[`timestamp`,`level`,`msg`,`service`,`trace_id`,`span_id`],o=Object.entries(e).filter(([e])=>!a.includes(e)).map(([e,t])=>`${e}=${JSON.stringify(t)}`).join(` `);return`${t} ${n} [${r}] ${i}${o?` `+o:``}`}function i(e){return JSON.stringify(e)}function a(e,t){let n=t?r(e):i(e);e.level===`error`?console.error(n):e.level===`warn`?console.warn(n):console.log(n)}function o(){return new Date}function s(e){return e.toISOString()}var c=class e{constructor(e){this.config=e}log(e,t,n={}){let r=this.config.traceProvider?.()??{};a({timestamp:s(o()),level:e,msg:t,service:this.config.service,...r,...n},this.config.isDev)}debug(e,t){this.config.isDev&&this.log(`debug`,e,t)}info(e,t){this.log(`info`,e,t)}warn(e,t){this.log(`warn`,e,t)}error(e,t){this.log(`error`,e,t)}with(t){let n=new e(this.config);return n.log=((e,n,r={})=>{this.log(e,n,{...t,...r})}).bind(this),n}};function l(e,t){return new c({service:e,isDev:t?.isDev===void 0?typeof process<`u`?process.env.NODE_ENV!==`production`:!0:t.isDev,traceProvider:t?.traceProvider})}function u(e){if(e!==void 0)return typeof e==`object`&&e&&!Array.isArray(e)&&!(e instanceof Error)?e:e instanceof Error?{error:e.message}:{value:e}}function d(e){return{debug:(t,n)=>e.debug(t,u(n)),info:(t,n)=>e.info(t,u(n)),warn:(t,n)=>e.warn(t,u(n)),error:(t,n)=>e.error(t,u(n))}}var f=!1,p=d(l(`client`,{isDev:!1}));function m(){f=!0,p=d(l(`client`,{isDev:!0}))}function h(){return f}var g=class{ready=!1;onReady;constructor(e){this.onReady=e}handleMappingReceived(){this.markReady(`Mapping received from server`)}handleMutationResult(e){e.isInitial&&this.markReady(`Initial mutations processed`)}get isReady(){return this.ready}clear(){this.ready=!1}markReady(e){this.ready||(this.ready=!0,p.info(`${e} - client is now ready`),this.onReady?.())}},_=class{isSelectedValue=!1;constructor(e,t){this.value=e,this.attribute=t}get isSelected(){return this.isSelectedValue}setSelected(e){this.isSelectedValue=e}},v=class{name;defaultValue;values;onSelect;onChangeCallback;constructor(e){this.name=e.name,this.defaultValue=e.defaultValue,this.onSelect=e.onSelect,this.values=this.createValues(e.values)}select(e){if(!this.values.has(e))throw t.valueNotFound(this.name,e);this.onSelect(this.name,e)}getValues(){return Array.from(this.values.values())}getValue(e){return this.values.get(e)}onChange(e){this.onChangeCallback=e}handleResult(e){let t;for(let n of this.values.values()){let r=n.value===e;n.setSelected(r),r&&(t=n)}t!==void 0&&this.onChangeCallback!==void 0&&this.onChangeCallback(t)}createValues(e){let t=new Map;for(let n of e){let e=new _(n,this.name);n===this.defaultValue&&e.setSelected(!0),t.set(n,e)}return t}},y=class{attributes=new Map;constructor(e,t,n){for(let n of e){let e=this.buildOptions(n,t);this.attributes.set(n.name,new v(e))}this.onMutationFailed=n}onMutationFailed;get(e){return this.attributes.get(e)}defaults(){let e=[];for(let t of this.attributes.values())t.defaultValue!==void 0&&e.push({name:t.name,value:t.defaultValue});return e}handleResults(e){for(let t of e){if(!t.success){this.onMutationFailed?.(t.name,t.value);continue}this.get(t.name)?.handleResult(t.value)}}buildOptions(e,t){let n={name:e.name,values:e.values,onSelect:(e,n)=>{t([{name:e,value:n}],!1)}};return e.defaultValue===void 0?n:{...n,defaultValue:e.defaultValue}}},b={READY:`ready`,MUTATION:`mutation`,STATE:`state`,CONFIG:`config`,CAMERA:`camera`,SNAPSHOT:`snapshot`,MAPPING:`mapping`},x=new Set(Object.values(b));function S(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.target==`string`?!1:typeof t.type==`string`&&x.has(t.type)}function C(e){let t=O(e);return t!==null&&t.type===b.READY}function w(e){let t=O(e);return t!==null&&t.type===b.MUTATION&&Array.isArray(t.results)}function T(e){let t=O(e);return t!==null&&t.type===b.SNAPSHOT&&(`data`in t||`error`in t)}function E(e){let t=O(e);return t!==null&&t.type===b.CAMERA&&Array.isArray(t.transforms)}function D(e){let t=O(e);return t!==null&&t.type===b.MAPPING&&Array.isArray(t.attributes)}function O(e){return typeof e!=`object`||!e?null:e}var k=class{pending=[];isReady=!1;constructor(e){this.processor=e}enqueue(e){if(this.isReady){this.processor(e);return}this.pending.push(e)}markReady(){if(this.isReady||(this.isReady=!0,this.pending.length===0))return;let e=[...this.pending];this.pending.length=0;for(let t of e)this.processor(t)}get ready(){return this.isReady}get pendingCount(){return this.pending.length}hasPending(e){return this.pending.some(t=>t.type===e)}clear(){this.pending.length=0}},A=class{handlers=new Map;publisher;consumer;shouldBuffer;listener=null;sourceId;constructor(e,t){this.getTarget=e,this.sourceId=`vd-${Math.random().toString(36).slice(2,8)}`,this.publisher=new k(e=>this.post(e)),this.consumer=new k(e=>this.routeToHandler(e)),this.shouldBuffer=t?.shouldBuffer??null,t?.bufferIncoming!==!0&&this.consumer.markReady()}on(e,t){this.handlers.set(e,t)}off(e){this.handlers.delete(e)}send(e){this.publisher.enqueue(e)}markReady(){this.publisher.markReady()}markConsumerReady(){this.consumer.markReady()}consumerHasPending(e){return this.consumer.hasPending(e)}start(){this.listener===null&&(this.listener=e=>{let{data:t}=e;if(!S(t)||t._source===this.sourceId)return;let n=t;if(this.shouldBuffer!==null&&!this.shouldBuffer(n)){this.routeToHandler(n);return}this.consumer.enqueue(n)},window.addEventListener(`message`,this.listener))}destroy(){this.listener!==null&&(window.removeEventListener(`message`,this.listener),this.listener=null),this.publisher.clear(),this.consumer.clear(),this.handlers.clear()}get ready(){return this.publisher.ready}get pendingCount(){return this.publisher.pendingCount}post(e){let t=this.getTarget();t!==null&&t.postMessage({...e,_source:this.sourceId},`*`)}routeToHandler(e){let t=this.handlers.get(e.type);if(t===void 0)return;let n=t(e);n instanceof Promise&&n.catch(t=>{let n=t instanceof Error?t.message:String(t);console.error(`Virtualdisplay: error handling ${e.type}: ${n}`)})}};new Set([b.CAMERA]);var j=class{registry;pendingCallbacks=[];constructor(e,t){this.send=e,this.onMutationFailed=t}handleMappingReceived(e){p.debug(`Initializing from server mapping`,{attributeCount:e.attributes.length}),this.registry=new y(e.attributes,(e,t)=>this.sendMutation(e,t),this.onMutationFailed);let t=this.registry.defaults();t.length>0&&this.sendMutation(t,!0),this.replayPendingCallbacks()}handleMutationResult(e){this.registry?.handleResults(e.results)}select(e,t){this.sendMutation([{name:e,value:t}],!1)}getValues(e){return this.registry?.get(e)?.getValues()??[]}getValue(e,t){return this.registry?.get(e)?.getValue(t)}onChange(e,t){if(this.registry===void 0){this.pendingCallbacks.push({name:e,callback:t});return}let n=this.registry.get(e);if(n===void 0){p.warn(`onChange: attribute "${e}" not found — callback will not fire`);return}n.onChange(t)}getAttribute(e){return this.registry?.get(e)}get hasMapping(){return this.registry!==void 0}sendMutation(e,t){let n={type:b.MUTATION,mutations:e,isInitial:t};this.send(n)}replayPendingCallbacks(){for(let{name:e,callback:t}of this.pendingCallbacks){let n=this.registry?.get(e);n===void 0&&p.warn(`onChange: attribute "${e}" not found — buffered callback will not fire`),n?.onChange(t)}this.pendingCallbacks.length=0}},M=class{commands=[];constructor(e){this.send=e}rotate(e){return this.validateFiniteNumber(e,`rotate`),this.commands.push({action:`rotate`,value:e}),this}tilt(e){return this.validateFiniteNumber(e,`tilt`),this.commands.push({action:`tilt`,value:e}),this}zoom(e){return this.validateFiniteNumber(e,`zoom`),this.commands.push({action:`zoom`,value:e}),this}set(){if(this.commands.length===0)throw t.invalidParameter(`No camera commands to execute. Call rotate(), tilt(), or zoom() before set().`);let e={type:b.CAMERA,commands:this.commands};this.send(e),this.commands=[]}validateFiniteNumber(e,n){if(!Number.isFinite(e))throw t.invalidParameter(`${n}() requires a finite number, got ${String(e)}`)}reset(){let e={type:b.CAMERA,commands:[{action:`reset`}]};this.send(e)}},N=class{state;changeCallbacks=[];constructor(){this.state={rotation:0,tilt:0,zoom:0}}get rotation(){return this.state.rotation}get tilt(){return this.state.tilt}get zoom(){return this.state.zoom}onChange(e){this.changeCallbacks.push(e)}handlePositionUpdate(e){this.update(e.transforms)}update(e){let t=!1;for(let n of e)switch(n.type){case`rotation`:this.state.rotation=n.value,t=!0;break;case`tilt`:this.state.tilt=n.value,t=!0;break;case`zoom`:this.state.zoom=n.value,t=!0;break;default:break}if(t){let e={rotation:this.rotation,tilt:this.tilt,zoom:this.zoom};for(let t of this.changeCallbacks)t(e)}}},P=class{developedCallbacks=new Set;errorCallbacks=new Set;developed=!1;failed=!1;photoData=null;constructor(e){this.filename=e}onDeveloped(e){return this.developed&&this.photoData!==null?(e(this.photoData),this):(this.developedCallbacks.add(e),this)}onError(e){return this.errorCallbacks.add(e),this}getFilename(){return this.filename}develop(e){this.developed||this.failed||(this.photoData=e,this.developed=!0,this.developedCallbacks.forEach(e=>{e(this.photoData)}),this.developedCallbacks.clear(),this.errorCallbacks.clear())}fail(e){this.developed||this.failed||(this.failed=!0,this.errorCallbacks.forEach(t=>{t(e)}),this.developedCallbacks.clear(),this.errorCallbacks.clear())}},F=class{validExtensions=[`.png`];pendingPhotos=new Map;constructor(e){this.send=e}take(e){this.validateFilename(e),p.debug(`Taking snapshot`,{filename:e});let t=new P(e);return this.pendingPhotos.set(t.getFilename(),t),this.send({type:b.SNAPSHOT,filename:e}),t}handleSnapshotResult(n){let r=this.pendingPhotos.get(n.filename);if(r===void 0){p.warn(`No pending photo found for filename`,{filename:n.filename,pendingFilenames:Array.from(this.pendingPhotos.keys())});return}if(this.pendingPhotos.delete(n.filename),n.error!==void 0){r.fail(new t(n.error,e.SNAPSHOT_FAILED));return}n.data!==void 0&&r.develop({filename:n.filename,data:n.data})}validateFilename(n){if(n===``||typeof n!=`string`)throw new t(`Filename must be a non-empty string`,e.INVALID_PARAMETER);if(!this.validExtensions.some(e=>n.toLowerCase().endsWith(e)))throw new t(`Invalid filename: "${n}". Filename must end with one of: ${this.validExtensions.join(`, `)}`,e.INVALID_PARAMETER);if(n.includes(`..`)||n.includes(`/`)||n.includes(`\\`))throw new t(`Filename cannot contain path separators or ".."`,e.INVALID_PARAMETER)}},I=class{send;constructor(e){this.send=e}sendInitialConfig(e){let t=this.buildUIConfig(e),n=this.buildViewerConfig(t,e.camera);n!==void 0&&this.sendConfig(n)}buildUIConfig(e){let t=this.extractUIValues(e);if(Object.values(t).some(e=>e!==void 0))return{...t.arEnabled!==void 0&&{arEnabled:t.arEnabled},...t.fullscreenEnabled!==void 0&&{fullscreenEnabled:t.fullscreenEnabled},...t.loadingIndicatorEnabled!==void 0&&{loadingIndicatorEnabled:t.loadingIndicatorEnabled}}}extractUIValues(e){return{arEnabled:e.arEnabled??e.ui?.arEnabled,fullscreenEnabled:e.fullscreenEnabled??e.ui?.fullscreenEnabled,loadingIndicatorEnabled:e.loadingIndicatorEnabled??e.ui?.loadingIndicatorEnabled}}buildViewerConfig(e,t){if(!(e===void 0&&t===void 0))return{...e!==void 0&&{ui:e},...t!==void 0&&{camera:t}}}setArEnabled(e){p.debug(`Setting AR button enabled: ${e}`),this.updateUIConfig({arEnabled:e})}setFullscreenEnabled(e){p.debug(`Setting fullscreen button enabled: ${e}`),this.updateUIConfig({fullscreenEnabled:e})}setLoadingIndicatorEnabled(e){p.debug(`Setting loading indicator enabled: ${e}`),this.updateUIConfig({loadingIndicatorEnabled:e})}updateUIConfig(e){p.debug(`Updating UI configuration`,e),Object.keys(e).length>0&&this.sendConfig({ui:e})}hideAllUI(){p.debug(`Hiding all UI elements`),this.sendUIConfig({arEnabled:!1,fullscreenEnabled:!1,loadingIndicatorEnabled:!1})}showAllUI(){p.debug(`Showing all UI elements`),this.sendUIConfig({arEnabled:!0,fullscreenEnabled:!0,loadingIndicatorEnabled:!0})}sendUIConfig(e){this.sendConfig({ui:e})}sendConfig(e){let t={type:b.CONFIG,config:e};p.debug(`Sending config`,t),this.send(t)}},L=class{attributes;readyStateTracker;messenger;viewerService;cameraApi;cameraPositionApi;snapshotApi;options;iframe;readyCallbacks=[];mutationFailedCallbacks=[];constructor(e){this.options=e,this.initializeLogging(),this.messenger=new A(()=>this.iframe?.contentWindow??null);let t=e=>{this.messenger.send(e)};this.attributes=new j(t,(e,t)=>{for(let n of this.mutationFailedCallbacks)n({attribute:e,value:t})}),this.readyStateTracker=new g(()=>{let e=this.readyCallbacks;this.readyCallbacks=[];for(let t of e)t(this)}),this.viewerService=new I(t),this.cameraApi=new M(t),this.cameraPositionApi=new N,this.snapshotApi=new F(t),this.registerHandlers(),this.messenger.start(),this.createAndConnectIframe()}registerHandlers(){this.messenger.on(b.READY,e=>{C(e)&&(p.info(`Server ready — flushing publisher queue`),this.messenger.markReady(),this.viewerService.sendInitialConfig(this.options))}),this.messenger.on(b.MUTATION,e=>{w(e)&&(this.attributes.handleMutationResult(e),this.readyStateTracker.handleMutationResult(e))}),this.messenger.on(b.SNAPSHOT,e=>{T(e)&&this.snapshotApi.handleSnapshotResult(e)}),this.messenger.on(b.CAMERA,e=>{E(e)&&this.cameraPositionApi.handlePositionUpdate(e)}),this.messenger.on(b.MAPPING,e=>{D(e)&&(this.attributes.handleMappingReceived(e),this.readyStateTracker.handleMappingReceived())})}initializeLogging(){this.options.debug===!0&&m(),p.info(`Initializing Virtualdisplay client`,{model:this.options.model,debug:this.options.debug,language:this.options.language})}createAndConnectIframe(){p.debug(`Creating iframe for Virtualdisplay viewer`),this.iframe=new n(this.options).create(),p.debug(`Iframe created, waiting for server READY`)}select(e,t){this.attributes.select(e,t)}getValues(e){return this.attributes.getValues(e)}getValue(e,t){return this.attributes.getValue(e,t)}onChange(e,t){this.attributes.onChange(e,t)}getAttribute(e){return this.attributes.getAttribute(e)}get isReady(){return this.readyStateTracker.isReady}onReady(e){if(this.readyStateTracker.isReady){e(this);return}this.readyCallbacks.push(e)}onMutationFailed(e){this.mutationFailedCallbacks.push(e)}get viewer(){return this.viewerService}get camera(){return this.cameraApi}get cameraPosition(){return this.cameraPositionApi}get snapshot(){return this.snapshotApi}destroy(){p.info(`Destroying Virtualdisplay client`),this.readyStateTracker.clear(),this.readyCallbacks=[],this.messenger.destroy(),this.iframe?.parentElement!==null&&this.iframe?.parentElement!==void 0&&this.iframe.parentElement.removeChild(this.iframe),this.iframe=void 0,p.debug(`Virtualdisplay client destroyed`)}};exports.Attribute=v,exports.AttributeValue=_,exports.Camera=M,exports.ERROR_CODES=e,exports.Photo=P,exports.Snapshot=F,exports.VirtualdisplayClient=L,exports.VirtualdisplayError=t,exports.VirtualdisplayViewerService=I,exports.enableDebugMode=m,exports.isDebugMode=h,Object.defineProperty(exports,`logger`,{enumerable:!0,get:function(){return p}});
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c={HANDSHAKE:"handshake",SESSION:"session",MUTATION:"mutation",STATE:"state",LOADING_INDICATOR:"loading_indicator",CAMERA:"camera",SNAPSHOT:"snapshot",MAPPING:"mapping",AR_ACTIVATE:"ar_activate",FULLSCREEN:"fullscreen",CONFIG:"config",ANNOTATION_TOGGLE:"annotation_toggle",FOCUS:"focus",PRICING:"pricing"},W={FOCUS:"focus",UNFOCUS:"unfocus"},It={FOCUSED:"focused"},Nt={HIDDEN:"hidden"},Lt=new Set(Object.values(c));function Mt(n){if(typeof n!="object"||n===null)return!1;const t=n;return typeof t.target=="string"?!1:typeof t.type=="string"&&Lt.has(t.type)}function zt(n){const t=S(n);return t!==null&&t.type===c.HANDSHAKE}function Pt(n){const t=S(n);return t!==null&&t.type===c.SESSION&&typeof t.sessionId=="string"}function Ft(n){const t=S(n);return t!==null&&t.type===c.MUTATION&&Array.isArray(t.results)}function $t(n){const t=S(n);return t!==null&&t.type===c.SNAPSHOT&&("data"in t||"error"in t)}function Dt(n){const t=S(n);return t!==null&&t.type===c.CAMERA&&Array.isArray(t.transforms)}function Bt(n){const t=S(n);return t!==null&&t.type===c.MAPPING&&Array.isArray(t.attributes)}function Ut(n){const t=S(n);return t!==null&&t.type===c.LOADING_INDICATOR&&typeof t.progress=="number"}function Vt(n){const t=S(n);return t!==null&&t.type===c.CONFIG&&typeof t.viewerSettings=="object"}function jt(n){const t=S(n);return t!==null&&t.type===c.FOCUS&&typeof t.state=="string"}function Ht(n){const t=S(n);return t!==null&&t.type===c.PRICING&&typeof t.pricing=="object"&&t.pricing!==null}function S(n){return typeof n!="object"||n===null?null:n}class Y{constructor(t){this.processor=t}processor;pending=[];isReady=!1;enqueue(t){if(this.isReady){this.processor(t);return}this.pending.push(t)}markReady(){if(this.isReady||(this.isReady=!0,this.pending.length===0))return;const t=[...this.pending];this.pending.length=0;for(const e of t)this.processor(e)}get ready(){return this.isReady}get pendingCount(){return this.pending.length}hasPending(t){return this.pending.some(e=>e.type===t)}clear(){this.pending.length=0}}class Gt{constructor(t,e){this.getTarget=t,this.sourceId=`vd-${Math.random().toString(36).slice(2,8)}`,this.targetOrigin=e?.targetOrigin??"*",this.isValid=e?.isValid??Mt,this.publisher=new Y(i=>this.post(i)),this.consumer=new Y(i=>this.routeToHandler(i)),this.shouldBuffer=e?.shouldBuffer??null,e?.bufferIncoming!==!0&&this.consumer.markReady()}getTarget;handlers=new Map;publisher;consumer;shouldBuffer;listener=null;sourceId;targetOrigin;isValid;on(t,e){this.handlers.set(t,e)}off(t){this.handlers.delete(t)}setTargetOrigin(t){this.targetOrigin=t}send(t){this.publisher.enqueue(t)}markReady(){this.publisher.markReady()}markConsumerReady(){this.consumer.markReady()}consumerHasPending(t){return this.consumer.hasPending(t)}start(){this.listener===null&&(this.listener=t=>{const{data:e}=t;if(!this.isValid(e)||e._source===this.sourceId)return;const i=this.getTarget();if(i!==null&&t.source!==null&&t.source!==i)return;const o=e;if(this.shouldBuffer!==null&&!this.shouldBuffer(o)){this.routeToHandler(o);return}this.consumer.enqueue(o)},window.addEventListener("message",this.listener))}destroy(){this.listener!==null&&(window.removeEventListener("message",this.listener),this.listener=null),this.publisher.clear(),this.consumer.clear(),this.handlers.clear()}get ready(){return this.publisher.ready}get pendingCount(){return this.publisher.pendingCount}post(t){const e=this.getTarget();e!==null&&e.postMessage({...t,_source:this.sourceId},this.targetOrigin)}routeToHandler(t){const e=this.handlers.get(t.type);if(e===void 0)return;const i=e(t);i instanceof Promise&&i.catch(o=>{const s=o instanceof Error?o.message:String(o);console.error(`Virtualdisplay: error handling ${t.type}: ${s}`)})}}class g{element;constructor({variant:t="default",size:e="default",label:i,icon:o,onClick:s,disabled:r=!1}={}){this.element=document.createElement("button"),this.element.className=`ui-btn ui-btn--${t} ui-btn--size-${e}`,i!==void 0&&(this.element.setAttribute("aria-label",i),this.element.title=i),o!==void 0?this.element.appendChild(o):i!==void 0&&(this.element.textContent=i),s&&this.element.addEventListener("click",s),this.element.disabled=r}setIcon(t){const e=this.element.querySelector("svg");e!==null?e.replaceWith(t):this.element.appendChild(t)}}const qt={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"};const at=([n,t,e])=>{const i=document.createElementNS("http://www.w3.org/2000/svg",n);return Object.keys(t).forEach(o=>{i.setAttribute(o,String(t[o]))}),e?.length&&e.forEach(o=>{const s=at(o);i.appendChild(s)}),i},lt=(n,t={})=>{const i={...qt,...t};return at(["svg",i,n])};const Zt=[["path",{d:"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"}],["path",{d:"m3.3 7 8.7 5 8.7-5"}],["path",{d:"M12 22V12"}]];const Wt=[["path",{d:"M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z"}],["circle",{cx:"12",cy:"13",r:"3"}]];const ct=[["path",{d:"m6 9 6 6 6-6"}]];const Yt=[["path",{d:"m15 18-6-6 6-6"}]];const Xt=[["path",{d:"m9 18 6-6-6-6"}]];const Kt=[["path",{d:"m18 15-6-6-6 6"}]];const Qt=[["path",{d:"M15 3h6v6"}],["path",{d:"m21 3-7 7"}],["path",{d:"m3 21 7-7"}],["path",{d:"M9 21H3v-6"}]];const Jt=[["path",{d:"m14 10 7-7"}],["path",{d:"M20 10h-6V4"}],["path",{d:"m3 21 7-7"}],["path",{d:"M4 14h6v6"}]];const te=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"}],["path",{d:"M3 3v5h5"}]];const ee=[["path",{d:"M10 5H3"}],["path",{d:"M12 19H3"}],["path",{d:"M14 3v4"}],["path",{d:"M16 17v4"}],["path",{d:"M21 12h-9"}],["path",{d:"M21 19h-5"}],["path",{d:"M21 5h-7"}],["path",{d:"M8 10v4"}],["path",{d:"M8 12H3"}]];const ne=[["path",{d:"M18 6 6 18"}],["path",{d:"m6 6 12 12"}]];const ie=[["circle",{cx:"11",cy:"11",r:"8"}],["line",{x1:"21",x2:"16.65",y1:"21",y2:"16.65"}],["line",{x1:"11",x2:"11",y1:"8",y2:"14"}],["line",{x1:"8",x2:"14",y1:"11",y2:"11"}]];const oe=[["circle",{cx:"11",cy:"11",r:"8"}],["line",{x1:"21",x2:"16.65",y1:"21",y2:"16.65"}],["line",{x1:"8",x2:"14",y1:"11",y2:"11"}]],m={semantic:{error:"#dc2626"},neutral:{500:"#737373",600:"#525252",900:"#171717"},white:"#ffffff",black:"#000000"},a={0:"0",.5:"0.125rem",1:"0.25rem",1.5:"0.375rem",2:"0.5rem",3:"0.75rem",4:"1rem",5:"1.25rem",6:"1.5rem",8:"2rem",9:"2.25rem",24:"6rem"};class se{element;constructor(){this.element=document.createElement("div"),Object.assign(this.element.style,{background:m.white,borderRadius:a[3],padding:a[6],boxShadow:`0 ${a[2]} ${a[8]} oklch(0% 0 0 / 20%)`,maxWidth:"20rem",width:"100%"})}}class re{constructor(t={}){this.options=t,this.card=new se,this.backdrop=this.createBackdrop(),this.backdrop.appendChild(this.card.element)}options;card;backdrop;keyHandler=null;open(){document.body.appendChild(this.backdrop),this.keyHandler=t=>{t.key==="Escape"&&this.close()},document.addEventListener("keydown",this.keyHandler)}close(){this.backdrop.remove(),this.keyHandler!==null&&(document.removeEventListener("keydown",this.keyHandler),this.keyHandler=null),this.options.onClose?.()}createBackdrop(){const t=document.createElement("div");return Object.assign(t.style,{position:"fixed",inset:a[0],background:"oklch(0% 0 0 / 50%)",zIndex:"9999",display:"flex",alignItems:"center",justifyContent:"center"}),t.addEventListener("click",e=>{e.target===t&&this.close()}),t}}class ae{element;selectCallback=null;constructor(t,e,i){this.element=document.createElement("div"),this.element.className="ui-toggle-group";for(let o=0;o<t.length;o++){const s=t[o],r=document.createElement("button");r.className="ui-toggle-group-item",r.dataset.value=s,r.textContent=i?.[o]??s,r.dataset.state=s===e?"on":"off",r.setAttribute("aria-pressed",s===e?"true":"false"),r.addEventListener("click",()=>{this.selectCallback?.(s)}),this.element.appendChild(r)}}setSelected(t){for(const e of this.element.querySelectorAll(".ui-toggle-group-item")){const i=e.dataset.value===t;e.dataset.state=i?"on":"off",e.setAttribute("aria-pressed",i?"true":"false")}}onSelect(t){this.selectCallback=t}}class le{element;select;constructor(t,e,i,o,s){this.select=document.createElement("select"),this.select.className="ui-native-select",this.select.dataset.name=t,this.select.setAttribute("aria-label",i);const r=document.createElement("option");r.value="",r.disabled=!0,r.textContent=i,this.select.appendChild(r);let l=!1;for(let u=0;u<e.length;u++){const p=e[u],v=document.createElement("option");v.value=p,v.textContent=s?.[u]??p,p===o&&(v.selected=!0,l=!0),this.select.appendChild(v)}l||(r.selected=!0);const d=lt(ct,{width:16,height:16,"stroke-width":2});d.classList.add("ui-native-select-icon"),this.element=document.createElement("div"),this.element.className="ui-native-select-wrap",this.element.appendChild(this.select),this.element.appendChild(d)}setSelected(t){this.select.value=t}onSelect(t){this.select.addEventListener("change",()=>{t(this.select.value)})}}const ce={},ue="en",ut=["en","nl","de"],q=["baseLocale"],X=[];let K,Q;function de(n){if(X.length===0)return;const t=typeof n=="string"?n:n.href;if(K===t)return Q;const e=new URL(t,"http://dummy.com");let i;for(const o of X)if(new ce(o.match,e.href).exec(e.href)){i=o;break}return K=t,Q=i,i}function dt(n){const t=de(n);return t&&t.exclude!==!0&&Array.isArray(t.strategy)?t.strategy:q}const G=typeof window>"u";globalThis.__paraglide=globalThis.__paraglide??{};globalThis.__paraglide.ssr=globalThis.__paraglide.ssr??{};let J=!1,h=()=>{let n=q;!G&&typeof window<"u"&&window.location?.href&&(n=dt(window.location.href));const t=he(n);if(t)return J||(J=!0,ht(t,{reload:!1})),t;throw new Error("No locale found. Read the docs https://paraglidejs.com/errors#no-locale-found")};function he(n,t){let e;for(const i of n){if(i==="baseLocale")e=ue;else if(pt(i)&&I.has(i)){const s=I.get(i);if(s){const r=s.getLocale();if(r instanceof Promise)continue;if(r!==void 0)return pe(r)}}const o=mt(e);if(o)return o}}const me=n=>{window.location.reload()};let ht=(n,t)=>{const e={reload:!0,...t};let i;try{i=h()}catch{}const o=[];let s=q;!G&&typeof window<"u"&&window.location?.href&&(s=dt(window.location.href));for(const l of s)if(l!=="baseLocale"&&pt(l)&&I.has(l)){const d=I.get(l);if(d){let u=d.setLocale(n);u instanceof Promise&&(u=u.catch(p=>{throw new Error(`Custom strategy "${l}" setLocale failed.`,{cause:p})}),o.push(u))}}const r=()=>{!G&&e.reload&&window.location&&n!==i&&me()};if(o.length)return Promise.all(o).then(()=>{r()});r()};function mt(n){if(typeof n!="string")return;const t=n.toLowerCase();for(const e of ut)if(e.toLowerCase()===t)return e}function pe(n){const t=mt(n);if(t)return t;throw new Error(`Invalid locale: ${n}. Expected one of: ${ut.join(", ")}`)}const I=new Map;function pt(n){return typeof n=="string"&&/^custom-[A-Za-z0-9_-]+$/.test(n)}const fe=()=>"Activate AR",ge=()=>"AR activeren",be=()=>"AR aktivieren",ve=((n={},t={})=>{const e=t.locale??h();return e==="en"?fe():e==="nl"?ge():be()}),ye=()=>"Scan to view in AR",_e=()=>"Scan om in AR te bekijken",we=()=>"Scannen für AR-Ansicht",Ce=((n={},t={})=>{const e=t.locale??h();return e==="en"?ye():e==="nl"?_e():we()}),Se=()=>"Use your smartphone camera to scan this QR code",ke=()=>"Gebruik de camera van je smartphone om deze QR-code te scannen",Ee=()=>"Verwende die Kamera deines Smartphones, um diesen QR-Code zu scannen",Ae=((n={},t={})=>{const e=t.locale??h();return e==="en"?Se():e==="nl"?ke():Ee()}),xe=()=>"Your phone will open the 3D model in AR mode.",Te=()=>"Je telefoon opent het 3D-model in AR-modus.",Re=()=>"Dein Telefon öffnet das 3D-Modell im AR-Modus.",Oe=((n={},t={})=>{const e=t.locale??h();return e==="en"?xe():e==="nl"?Te():Re()}),Ie=()=>"Close",Ne=()=>"Sluiten",Le=()=>"Schließen",Me=((n={},t={})=>{const e=t.locale??h();return e==="en"?Ie():e==="nl"?Ne():Le()}),ze=()=>"Fullscreen",Pe=()=>"Volledig scherm",Fe=()=>"Vollbild",$e=((n={},t={})=>{const e=t.locale??h();return e==="en"?ze():e==="nl"?Pe():Fe()}),De=()=>"Downloading",Be=()=>"Downloaden",Ue=()=>"Herunterladen",ft=((n={},t={})=>{const e=t.locale??h();return e==="en"?De():e==="nl"?Be():Ue()}),Ve=()=>"Rendering",je=()=>"Renderen",He=()=>"Rendern",Ge=((n={},t={})=>{const e=t.locale??h();return e==="en"?Ve():e==="nl"?je():He()}),qe=()=>"Screenshot",Ze=()=>"Screenshot",We=()=>"Screenshot",Ye=((n={},t={})=>{const e=t.locale??h();return e==="en"?qe():e==="nl"?Ze():We()}),Xe=()=>"Configure",Ke=()=>"Configureren",Qe=()=>"Konfigurieren",Je=((n={},t={})=>{const e=t.locale??h();return e==="en"?Xe():e==="nl"?Ke():Qe()}),tn=()=>"Close",en=()=>"Sluiten",nn=()=>"Schließen",on=((n={},t={})=>{const e=t.locale??h();return e==="en"?tn():e==="nl"?en():nn()}),sn=()=>"Reset camera",rn=()=>"Camera resetten",an=()=>"Kamera zurücksetzen",ln=((n={},t={})=>{const e=t.locale??h();return e==="en"?sn():e==="nl"?rn():an()}),cn=()=>"Zoom in",un=()=>"Inzoomen",dn=()=>"Hineinzoomen",hn=((n={},t={})=>{const e=t.locale??h();return e==="en"?cn():e==="nl"?un():dn()}),mn=()=>"Zoom out",pn=()=>"Uitzoomen",fn=()=>"Herauszoomen",gn=((n={},t={})=>{const e=t.locale??h();return e==="en"?mn():e==="nl"?pn():fn()}),bn=()=>"Rotate left",vn=()=>"Naar links draaien",yn=()=>"Nach links drehen",_n=((n={},t={})=>{const e=t.locale??h();return e==="en"?bn():e==="nl"?vn():yn()}),wn=()=>"Rotate right",Cn=()=>"Naar rechts draaien",Sn=()=>"Nach rechts drehen",kn=((n={},t={})=>{const e=t.locale??h();return e==="en"?wn():e==="nl"?Cn():Sn()}),En=()=>"Tilt up",An=()=>"Omhoog kantelen",xn=()=>"Nach oben kippen",Tn=((n={},t={})=>{const e=t.locale??h();return e==="en"?En():e==="nl"?An():xn()}),Rn=()=>"Tilt down",On=()=>"Omlaag kantelen",In=()=>"Nach unten kippen",Nn=((n={},t={})=>{const e=t.locale??h();return e==="en"?Rn():e==="nl"?On():In()}),Ln=()=>"Working…",Mn=()=>"Bezig…",zn=()=>"Läuft…",Pn=((n={},t={})=>{const e=t.locale??h();return e==="en"?Ln():e==="nl"?Mn():zn()}),Fn=()=>"Done",$n=()=>"Gelukt",Dn=()=>"Fertig",Bn=((n={},t={})=>{const e=t.locale??h();return e==="en"?Fn():e==="nl"?$n():Dn()}),Un=()=>"Failed",Vn=()=>"Mislukt",jn=()=>"Fehlgeschlagen",Hn=((n={},t={})=>{const e=t.locale??h();return e==="en"?Un():e==="nl"?Vn():jn()}),_={fontFamily:{sans:["Mona Sans","ui-sans-serif","system-ui","sans-serif","Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"]},fontSize:{xs:"0.75rem",sm:"0.875rem",base:"1rem",lg:"1.125rem"},fontWeight:{medium:"500",semibold:"600"}},Gn=_.fontFamily.sans.join(", ");class qn{qrLib=null;dialog=null;async show(t){this.hide(),this.qrLib??=await Promise.resolve().then(()=>require("./browser-DfB_An57.cjs")).then(o=>o.browser);const e=await this.qrLib.toDataURL(t,{width:256,margin:4,errorCorrectionLevel:"M",color:{dark:m.black,light:m.white}});this.dialog=new re({onClose:()=>{this.dialog=null}}),Object.assign(this.dialog.card.element.style,{display:"flex",flexDirection:"column",alignItems:"center",gap:a[3],fontFamily:Gn}),this.dialog.card.element.appendChild(this.createText(Ce(),{fontSize:_.fontSize.base,fontWeight:_.fontWeight.semibold,color:m.neutral[900]})),this.dialog.card.element.appendChild(this.createText(Ae(),{fontSize:_.fontSize.sm,color:m.neutral[600]})),this.dialog.card.element.appendChild(this.createQrImage(e)),this.dialog.card.element.appendChild(this.createText(Oe(),{fontSize:_.fontSize.xs,color:m.neutral[500]}));const i=new g({variant:"outline",label:Me(),onClick:()=>{this.hide()}});this.dialog.card.element.appendChild(i.element),this.dialog.open()}hide(){this.dialog?.close(),this.dialog=null}createText(t,e){const i=document.createElement("p");return i.textContent=t,Object.assign(i.style,{margin:"0",textAlign:"center",...e}),i}createQrImage(t){const e=document.createElement("img");return e.src=t,e.alt="QR code",Object.assign(e.style,{width:a[24],height:a[24],borderRadius:a[1]}),e}}const A=_.fontFamily.sans.join(", "),Zn=`
2
+ --primary: oklch(5% 0 0);
3
+ --primary-foreground: oklch(100% 0 0);
4
+ --secondary: oklch(92% 0 0);
5
+ --secondary-foreground: oklch(5% 0 0);
6
+ --background: oklch(100% 0 0);
7
+ --foreground: oklch(5% 0 0);
8
+ --border: oklch(92% 0 0);
9
+ --ring: oklch(44% 0 0);
10
+ --radius: 0.625rem;
11
+ --accent: oklch(92% 0 0);
12
+ --accent-foreground: oklch(5% 0 0);
13
+ --muted-foreground: oklch(44% 0 0);
14
+ `,Wn=`
15
+ :root { ${Zn} }
16
+
17
+ /* ── Button ──────────────────────────────────────────────── */
18
+ .ui-btn {
19
+ display: inline-flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ gap: 0.5rem;
23
+ border: 1px solid transparent;
24
+ border-radius: var(--radius);
25
+ font-family: ${A};
26
+ font-size: 0.875rem;
27
+ font-weight: 600;
28
+ white-space: nowrap;
29
+ cursor: pointer;
30
+ transition: all 200ms;
31
+ flex-shrink: 0;
32
+ }
33
+ .ui-btn:active { transform: scale(0.98); }
34
+ .ui-btn:disabled { opacity: 0.5; pointer-events: none; }
35
+ .ui-btn svg { inline-size: 1rem; block-size: 1rem; pointer-events: none; flex-shrink: 0; }
36
+
37
+ .ui-btn--default {
38
+ background: var(--primary);
39
+ color: var(--primary-foreground);
40
+ box-shadow: 0 1px 3px oklch(5% 0 0 / 20%);
41
+ }
42
+ .ui-btn--default:hover { background: oklch(10% 0 0); }
43
+
44
+ .ui-btn--outline {
45
+ background: var(--background);
46
+ color: var(--foreground);
47
+ border-color: var(--border);
48
+ box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
49
+ }
50
+ .ui-btn--outline:hover { background: var(--accent); border-color: oklch(85% 0 0); }
51
+
52
+ .ui-btn--secondary {
53
+ background: var(--secondary);
54
+ color: var(--secondary-foreground);
55
+ box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
56
+ }
57
+ .ui-btn--secondary:hover { background: oklch(88% 0 0); }
58
+
59
+ .ui-btn--ghost { background: transparent; color: var(--foreground); }
60
+ .ui-btn--ghost:hover { background: var(--accent); }
61
+
62
+ .ui-btn--size-default { block-size: 2.25rem; padding: 0 1rem; }
63
+ .ui-btn--size-sm { block-size: 2rem; padding: 0 0.75rem; border-radius: calc(var(--radius) - 0.125rem); }
64
+ .ui-btn--size-lg { block-size: 2.5rem; padding: 0 1.5rem; }
65
+ .ui-btn--size-icon { inline-size: 2.25rem; block-size: 2.25rem; padding: 0; }
66
+ .ui-btn--size-icon-sm { inline-size: 2rem; block-size: 2rem; padding: 0; }
67
+ .ui-btn--size-icon-lg { inline-size: 2.5rem; block-size: 2.5rem; padding: 0; }
68
+
69
+ /* ── Toggle group ────────────────────────────────────────── */
70
+ .ui-toggle-group { display: inline-flex; flex-wrap: wrap; gap: 0.25rem; }
71
+
72
+ .ui-toggle-group-item {
73
+ display: inline-flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ block-size: 2rem;
77
+ padding: 0 0.75rem;
78
+ border: 1px solid var(--border);
79
+ border-radius: var(--radius);
80
+ background: var(--background);
81
+ color: var(--foreground);
82
+ font-family: ${A};
83
+ font-size: 0.875rem;
84
+ font-weight: 600;
85
+ cursor: pointer;
86
+ white-space: nowrap;
87
+ transition: all 200ms;
88
+ box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
89
+ }
90
+ .ui-toggle-group-item:hover { background: var(--accent); border-color: oklch(85% 0 0); }
91
+ .ui-toggle-group-item:active { transform: scale(0.98); }
92
+ .ui-toggle-group-item:focus-visible {
93
+ outline: none;
94
+ border-color: var(--ring);
95
+ box-shadow: 0 0 0 3px oklch(5% 0 0 / 12%);
96
+ }
97
+ .ui-toggle-group-item[data-state="on"] {
98
+ background: var(--primary);
99
+ color: var(--primary-foreground);
100
+ border-color: var(--primary);
101
+ }
102
+ .ui-toggle-group-item[data-state="on"]:hover { background: oklch(10% 0 0); }
103
+
104
+ /* ── Native select ───────────────────────────────────────── */
105
+ .ui-native-select-wrap {
106
+ position: relative;
107
+ display: inline-flex;
108
+ min-inline-size: 8rem;
109
+ }
110
+
111
+ .ui-native-select {
112
+ display: block;
113
+ inline-size: 100%;
114
+ block-size: 2.25rem;
115
+ padding: 0 2.25rem 0 0.75rem;
116
+ border: 1px solid var(--border);
117
+ border-radius: var(--radius);
118
+ background: var(--background);
119
+ appearance: none;
120
+ color: var(--foreground);
121
+ font-family: ${A};
122
+ font-size: 0.875rem;
123
+ font-weight: 400;
124
+ cursor: pointer;
125
+ transition: color 200ms, box-shadow 200ms, border-color 200ms;
126
+ box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
127
+ }
128
+ .ui-native-select:hover { border-color: oklch(85% 0 0); }
129
+ .ui-native-select:focus-visible {
130
+ outline: none;
131
+ border-color: var(--ring);
132
+ box-shadow: 0 0 0 3px oklch(5% 0 0 / 12%);
133
+ }
134
+
135
+ .ui-native-select-icon {
136
+ position: absolute;
137
+ inset-block-start: 50%;
138
+ inset-inline-end: 0.625rem;
139
+ transform: translateY(-50%);
140
+ color: var(--muted-foreground);
141
+ pointer-events: none;
142
+ }
143
+
144
+ /* ── Annotation layer ───────────────────────────────────── */
145
+ .vd-annotations-layer {
146
+ position: absolute;
147
+ inset-block-start: 0;
148
+ inset-inline-start: 0;
149
+ inline-size: 100%;
150
+ block-size: 100%;
151
+ pointer-events: none;
152
+ overflow: visible !important; /* override CSS2DRenderer inline style */
153
+ }
154
+
155
+ .vd-annotation-anchor {
156
+ position: relative;
157
+ }
158
+
159
+ .vd-annotation-marker {
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+ inline-size: 1.75rem;
164
+ block-size: 1.75rem;
165
+ border-radius: 50%;
166
+ border: 2px solid oklch(100% 0 0);
167
+ background: var(--primary);
168
+ color: var(--primary-foreground);
169
+ font-family: ${A};
170
+ font-size: 0.8125rem;
171
+ font-weight: 600;
172
+ cursor: pointer;
173
+ pointer-events: auto;
174
+ box-shadow: 0 2px 8px oklch(5% 0 0 / 20%);
175
+ transition: transform 100ms ease;
176
+ position: relative;
177
+ }
178
+ .vd-annotation-marker:hover { transform: scale(1.1); }
179
+ .vd-annotation-marker:focus-visible {
180
+ outline: 2px solid var(--ring);
181
+ outline-offset: 2px;
182
+ }
183
+
184
+ .vd-annotation-popup {
185
+ position: absolute;
186
+ inset-block-end: calc(100% + 0.5rem);
187
+ inset-inline-start: 50%;
188
+ transform: translateX(-50%);
189
+ background: var(--background);
190
+ color: var(--foreground);
191
+ border: 1px solid var(--border);
192
+ border-radius: var(--radius);
193
+ padding: 0.75rem 1rem;
194
+ max-inline-size: 15rem;
195
+ box-shadow: 0 4px 6px oklch(5% 0 0 / 8%), 0 2px 4px oklch(5% 0 0 / 6%);
196
+ pointer-events: auto;
197
+ white-space: normal;
198
+ }
199
+ .vd-annotation-popup:focus { outline: none; }
200
+
201
+ .vd-annotation-popup-close {
202
+ position: absolute;
203
+ inset-block-start: 0.375rem;
204
+ inset-inline-end: 0.375rem;
205
+ display: flex;
206
+ align-items: center;
207
+ justify-content: center;
208
+ inline-size: 1.25rem;
209
+ block-size: 1.25rem;
210
+ padding: 0;
211
+ border: none;
212
+ border-radius: calc(var(--radius) - 4px);
213
+ background: transparent;
214
+ color: var(--muted-foreground);
215
+ cursor: pointer;
216
+ pointer-events: auto;
217
+ }
218
+ .vd-annotation-popup-close:hover {
219
+ color: var(--foreground);
220
+ background: var(--secondary);
221
+ }
222
+ .vd-annotation-popup-close:focus-visible {
223
+ outline: 2px solid var(--ring);
224
+ outline-offset: 1px;
225
+ }
226
+ .vd-annotation-popup-close svg {
227
+ inline-size: 0.875rem;
228
+ block-size: 0.875rem;
229
+ }
230
+
231
+ @media (prefers-reduced-motion: no-preference) {
232
+ .vd-annotation-popup {
233
+ animation: vd-popup-in 150ms ease;
234
+ }
235
+ }
236
+
237
+ @keyframes vd-popup-in {
238
+ from { opacity: 0; transform: translateX(-50%) translateY(4px); }
239
+ to { opacity: 1; transform: translateX(-50%) translateY(0); }
240
+ }
241
+
242
+ .vd-annotation-popup-title {
243
+ font-family: ${A};
244
+ font-size: 0.875rem;
245
+ font-weight: 600;
246
+ line-height: 1.25rem;
247
+ /* Keep the title clear of the absolutely positioned close button. */
248
+ padding-inline-end: 1.5rem;
249
+ }
250
+
251
+ .vd-annotation-popup-description {
252
+ font-family: ${A};
253
+ font-size: 0.8125rem;
254
+ font-weight: 400;
255
+ line-height: 1.125rem;
256
+ color: var(--muted-foreground);
257
+ margin-block-start: 0.25rem;
258
+ }
259
+ `;let tt=!1;function Yn(){if(tt||typeof document>"u")return;tt=!0;const n=document.createElement("style");n.id="vd-ui-vanilla",n.textContent=Wn,document.head.appendChild(n)}function Xn(){return new Date}function Kn(n){return n.toISOString()}function gt(){return typeof navigator>"u"?"":navigator.userAgent}function Qn(){return typeof navigator>"u"?!1:navigator.platform==="MacIntel"&&navigator.maxTouchPoints>1}function Jn(){return/iPhone|iPad|iPod/i.test(gt())||Qn()}function ti(){return/Android/i.test(gt())}function ei(){return Jn()||ti()}class bt{constructor(t){this.send=t}send;setEnabled(t){this.send({type:c.ANNOTATION_TOGGLE,enabled:t})}}class vt{constructor(t,e){this.value=t,this.attribute=e}value;attribute;isSelectedValue=!1;get isSelected(){return this.isSelectedValue}setSelected(t){this.isSelectedValue=t}}const C={NO_MAPPING:"NO_MAPPING",ATTRIBUTE_NOT_FOUND:"ATTRIBUTE_NOT_FOUND",VALUE_NOT_FOUND:"VALUE_NOT_FOUND",PARENT_NOT_FOUND:"PARENT_NOT_FOUND",INVALID_PARAMETER:"INVALID_PARAMETER",SNAPSHOT_FAILED:"SNAPSHOT_FAILED"};class f extends Error{code;constructor(t,e){super(t),this.name="VirtualdisplayError",this.code=e}static valueNotFound(t,e){return new f(`Value "${e}" not found for attribute "${t}"`,C.VALUE_NOT_FOUND)}static parentNotFound(t){return new f(`Parent element not found: ${t}`,C.PARENT_NOT_FOUND)}static invalidParameter(t){return new f(t,C.INVALID_PARAMETER)}}class yt{name;defaultValue;values;onSelect;onChangeCallback;constructor(t){this.name=t.name,this.defaultValue=t.defaultValue,this.onSelect=t.onSelect,this.values=this.createValues(t.values)}select(t){if(!this.values.has(t))throw f.valueNotFound(this.name,t);this.onSelect(this.name,t)}getValues(){return Array.from(this.values.values())}getValue(t){return this.values.get(t)}get selected(){for(const t of this.values.values())if(t.isSelected)return t.value}onChange(t){this.onChangeCallback=t}handleResult(t){let e;for(const i of this.values.values()){const o=i.value===t;i.setSelected(o),o&&(e=i)}e!==void 0&&this.onChangeCallback!==void 0&&this.onChangeCallback(e)}createValues(t){const e=new Map;for(const i of t){const o=new vt(i,this.name);i===this.defaultValue&&o.setSelected(!0),e.set(i,o)}return e}}class ni{attributes=new Map;constructor(t,e,i){for(const o of t){const s=this.buildOptions(o,e);this.attributes.set(o.name,new yt(s))}this.onMutationFailed=i}onMutationFailed;get(t){return this.attributes.get(t)}getSelection(){const t={};for(const[e,i]of this.attributes){const o=i.selected;o!==void 0&&(t[e]=o)}return t}handleResults(t){for(const e of t){if(!e.success){this.onMutationFailed?.(e.name,e.value);continue}this.get(e.name)?.handleResult(e.value)}}buildOptions(t,e){const i={name:t.name,values:t.values,onSelect:(o,s)=>{e([{name:o,value:s}],!1)}};return t.defaultValue!==void 0?{...i,defaultValue:t.defaultValue}:i}}function ii(n){const t=new Date(n.timestamp).toLocaleTimeString("en-GB",{hour12:!1}),e=n.level.toUpperCase().padEnd(5),i=n.trace_id?.slice(0,8)??"--------",o=n.msg,s=["timestamp","level","msg","service","trace_id","span_id"],r=Object.entries(n).filter(([l])=>!s.includes(l)).map(([l,d])=>`${l}=${JSON.stringify(d)}`).join(" ");return`${t} ${e} [${i}] ${o}${r?" "+r:""}`}function oi(n){return JSON.stringify(n)}function si(n,t){const e=t?ii(n):oi(n);n.level==="error"?console.error(e):n.level==="warn"?console.warn(e):console.log(e)}function _t(n,t=0){const e={name:n.name,message:n.message};n.stack!==void 0&&(e.stack=n.stack);for(const i of Object.getOwnPropertyNames(n)){if(i==="name"||i==="message"||i==="stack"||i==="cause")continue;const o=n[i];o!==void 0&&(e[i]=o)}return n.cause!==void 0&&n.cause!==null&&(e.cause=n.cause instanceof Error&&t<5?_t(n.cause,t+1):String(n.cause)),e}function ri(n){const t={};for(const[e,i]of Object.entries(n))t[e]=i instanceof Error?_t(i):i;return t}class ai{constructor(t){this.config=t}config;log(t,e,i={}){const o=this.config.traceProvider?.()??{},s={timestamp:Kn(Xn()),level:t,msg:e,service:this.config.service,...o,...ri(i)};si(s,this.config.isDev)}debug(t,e){this.config.isDev&&this.log("debug",t,e)}info(t,e){this.log("info",t,e)}warn(t,e){this.log("warn",t,e)}error(t,e){this.log("error",t,e)}}function wt(n,t){const e=t?.isDev!==void 0?t.isDev:typeof process<"u"?process.env.NODE_ENV!=="production":!0;return new ai({service:n,isDev:e,traceProvider:t?.traceProvider})}function O(n){if(n!==void 0)return typeof n=="object"&&n!==null&&!Array.isArray(n)&&!(n instanceof Error)?n:n instanceof Error?{error:n.message}:{value:n}}function Ct(n){return{debug:(t,e)=>n.debug(t,O(e)),info:(t,e)=>n.info(t,O(e)),warn:(t,e)=>n.warn(t,O(e)),error:(t,e)=>n.error(t,O(e))}}let St=!1;exports.logger=Ct(wt("client",{isDev:!1}));function kt(){St=!0,exports.logger=Ct(wt("client",{isDev:!0}))}function li(){return St}class ci{constructor(t,e){this.send=t,this.onMutationFailed=e}send;onMutationFailed;registry;pendingCallbacks=[];handleMappingReceived(t){exports.logger.debug("Initializing from server mapping",{attributeCount:t.attributes.length}),this.registry=new ni(t.attributes,(e,i)=>this.sendMutation(e,i),this.onMutationFailed),this.replayPendingCallbacks()}handleMutationResult(t){this.registry?.handleResults(t.results)}select(t,e){this.sendMutation([{name:t,value:e}],!1)}getValues(t){return this.registry?.get(t)?.getValues()??[]}getValue(t,e){return this.registry?.get(t)?.getValue(e)}onChange(t,e){if(this.registry===void 0){this.pendingCallbacks.push({name:t,callback:e});return}const i=this.registry.get(t);if(i===void 0){exports.logger.warn(`onChange: attribute "${t}" not found — callback will not fire`);return}i.onChange(e)}getAttribute(t){return this.registry?.get(t)}getSelection(){return this.registry?.getSelection()??{}}get hasMapping(){return this.registry!==void 0}sendMutation(t,e){const i={type:c.MUTATION,mutations:t,isInitial:e};this.send(i)}replayPendingCallbacks(){for(const{name:t,callback:e}of this.pendingCallbacks){const i=this.registry?.get(t);i===void 0&&exports.logger.warn(`onChange: attribute "${t}" not found — buffered callback will not fire`),i?.onChange(e)}this.pendingCallbacks.length=0}}class Et{constructor(t){this.send=t}send;commands=[];rotate(t){return this.validateFiniteNumber(t,"rotate"),this.commands.push({action:"rotate",value:t}),this}tilt(t){return this.validateFiniteNumber(t,"tilt"),this.commands.push({action:"tilt",value:t}),this}zoom(t){return this.validateFiniteNumber(t,"zoom"),this.commands.push({action:"zoom",value:t}),this}set(){if(this.commands.length===0)throw f.invalidParameter("No camera commands to execute. Call rotate(), tilt(), or zoom() before set().");const t={type:c.CAMERA,commands:this.commands};this.send(t),this.commands=[]}validateFiniteNumber(t,e){if(!Number.isFinite(t))throw f.invalidParameter(`${e}() requires a finite number, got ${String(t)}`)}reset(){const t={type:c.CAMERA,commands:[{action:"reset"}]};this.send(t)}}class ui{state;limitsState;changeCallbacks=[];constructor(){this.state={rotation:0,tilt:0,zoom:100}}get rotation(){return this.state.rotation}get tilt(){return this.state.tilt}get zoom(){return this.state.zoom}onChange(t){this.changeCallbacks.push(t)}get limits(){return this.limitsState}applyLimits(t){this.limitsState=t;const e={rotation:this.rotation,tilt:this.tilt,zoom:this.zoom};for(const i of this.changeCallbacks)i(e)}handlePositionUpdate(t){this.update(t.transforms)}update(t){let e=!1;for(const i of t)switch(i.type){case"rotation":this.state.rotation=i.value,e=!0;break;case"tilt":this.state.tilt=i.value,e=!0;break;case"zoom":this.state.zoom=i.value,e=!0;break}if(e){const i={rotation:this.rotation,tilt:this.tilt,zoom:this.zoom};for(const o of this.changeCallbacks)o(i)}}}function di(n,t){const e=n.filter(s=>hi(s,t));if(e.length===0)return;const i=Math.max(...e.map(et)),o=e.filter(s=>et(s)===i);return o.length===1?o[0]:void 0}function hi(n,t){return Object.entries(n.attributes).every(([e,i])=>t[e]===i)}function et(n){return Object.keys(n.attributes).length}class At{constructor(t,e){this.dispatchChange=t,this.dispatchSubmit=e}dispatchChange;dispatchSubmit;pricing;selection={};resolved;changeCallbacks=[];renderCallbacks=[];submitCallback;submitDefaultLabel;get current(){return this.resolved}get vatDisplay(){return this.pricing?.vatDisplay}get buttonLabel(){const t=this.pricing?.buttonLabel;if(t!=null&&t!=="")return t;if(this.submitDefaultLabel!==void 0&&this.submitDefaultLabel!=="")return this.submitDefaultLabel}get submittable(){return this.submitCallback===void 0?!1:this.pricing===void 0?!0:this.resolved?.availability==="available"}get submitEnabled(){return this.submittable&&this.buttonLabel!==void 0}onChange(t){this.changeCallbacks.push(t)}onSubmit(t,e){this.submitCallback=t,this.submitDefaultLabel=e?.defaultLabel,this.notifyRender()}onRender(t){return this.renderCallbacks.push(t),()=>{const e=this.renderCallbacks.indexOf(t);e!==-1&&this.renderCallbacks.splice(e,1)}}async submit(){if(!this.submittable)return;const t=this.resolved!==void 0?{attributes:this.resolved.attributes,reference:this.resolved.reference}:{attributes:{...this.selection},reference:""};this.dispatchSubmit(t),await this.submitCallback?.(t)}handlePricingReceived(t){this.pricing=t,this.recompute()}handleSelectionChanged(t){this.selection=t,this.recompute()}recompute(){this.resolved=this.resolve();for(const t of this.changeCallbacks)t(this.resolved);this.dispatchChange(this.resolved),this.notifyRender()}notifyRender(){for(const t of this.renderCallbacks)t()}resolve(){if(this.pricing===void 0)return;const t=di(this.pricing.rules,this.selection);if(!(t===void 0||t.availability===Nt.HIDDEN))return{attributes:{...this.selection},reference:t.reference,price:t.priceCents,currency:this.pricing.currency,availability:t.availability}}}class xt{constructor(t,e){this.send=t,this.dispatch=e}send;dispatch;focused=null;attributes=[];changeCallbacks=[];get current(){return this.focused}set(t){if(typeof t!="string"||t.length===0)throw f.invalidParameter(`set() requires a non-empty component name, got ${String(t)}`);this.send({type:c.FOCUS,action:W.FOCUS,component:t})}clear(){this.send({type:c.FOCUS,action:W.UNFOCUS})}onChange(t){this.changeCallbacks.push(t)}handleStateReceived(t){t.state===It.FOCUSED&&t.component!==void 0?(this.focused=t.component,this.attributes=t.attributes??[]):(this.focused=null,this.attributes=[]);const e=this.focused!==null?{component:this.focused,attributes:this.attributes}:null;for(const i of this.changeCallbacks)i(e);this.dispatch(e)}}class Tt{constructor(t){this.filename=t}filename;developedCallbacks=new Set;errorCallbacks=new Set;developed=!1;failed=!1;photoData=null;onDeveloped(t){return this.developed&&this.photoData!==null?(t(this.photoData),this):(this.developedCallbacks.add(t),this)}onError(t){return this.errorCallbacks.add(t),this}getFilename(){return this.filename}develop(t){this.developed||this.failed||(this.photoData=t,this.developed=!0,this.developedCallbacks.forEach(e=>{e(this.photoData)}),this.developedCallbacks.clear(),this.errorCallbacks.clear())}fail(t){this.developed||this.failed||(this.failed=!0,this.errorCallbacks.forEach(e=>{e(t)}),this.developedCallbacks.clear(),this.errorCallbacks.clear())}}const nt=3e4;class Rt{constructor(t){this.send=t}send;validExtensions=[".png"];pendingPhotos=new Map;take(t){this.validateFilename(t),exports.logger.debug("Taking snapshot",{filename:t});const e=new Tt(t),i=setTimeout(()=>{this.pendingPhotos.delete(t),exports.logger.warn("Snapshot timed out",{filename:t}),e.fail(new f(`Snapshot timed out: the viewer did not respond within ${nt}ms`,C.SNAPSHOT_FAILED))},nt);return this.pendingPhotos.set(t,{photo:e,timeout:i}),this.send({type:c.SNAPSHOT,filename:t}),e}handleSnapshotResult(t){const e=this.pendingPhotos.get(t.filename);if(e===void 0){exports.logger.warn("No pending photo found for filename",{filename:t.filename,pendingFilenames:Array.from(this.pendingPhotos.keys())});return}clearTimeout(e.timeout),this.pendingPhotos.delete(t.filename);const{photo:i}=e;if(t.error!==void 0){i.fail(new f(t.error,C.SNAPSHOT_FAILED));return}t.data!==void 0&&i.develop({filename:t.filename,data:t.data})}clear(){if(this.pendingPhotos.size===0)return;const t=new f("Client destroyed before snapshot completed",C.SNAPSHOT_FAILED);for(const{photo:e,timeout:i}of this.pendingPhotos.values())clearTimeout(i),e.fail(t);this.pendingPhotos.clear()}validateFilename(t){if(t===""||typeof t!="string")throw new f("Filename must be a non-empty string",C.INVALID_PARAMETER);if(!this.validExtensions.some(i=>t.toLowerCase().endsWith(i)))throw new f(`Invalid filename: "${t}". Filename must end with one of: ${this.validExtensions.join(", ")}`,C.INVALID_PARAMETER);if(t.includes("..")||t.includes("/")||t.includes("\\"))throw new f('Filename cannot contain path separators or ".."',C.INVALID_PARAMETER)}}class mi{container=null;attach(t){this.container=t}dispatch(t,e,i=!1){const o=new CustomEvent(t,{detail:e,cancelable:i});return this.container?.dispatchEvent(o),o}on(t,e){const i=o=>{const s=o,r={...s.detail,preventDefault:()=>{s.preventDefault()}};e(r)};return this.container?.addEventListener(t,i),()=>{this.container?.removeEventListener(t,i)}}}function y(n,{size:t=20,strokeWidth:e=1.75}={}){return lt(n,{width:t,height:t,"stroke-width":e})}const b={ar:n=>y(Zt,n),fullscreen:n=>y(Qt,n),exitFullscreen:n=>y(Jt,n),screenshot:n=>y(Wt,n),tiltUp:n=>y(Kt,n),tiltDown:n=>y(ct,n),rotateLeft:n=>y(Yt,n),rotateRight:n=>y(Xt,n),zoomIn:n=>y(ie,n),zoomOut:n=>y(oe,n),reset:n=>y(te,n),configurator:n=>y(ee,n),close:n=>y(ne,n)};function it(n){const t=Math.max(0,Math.min(1,n));return t*t*(3-2*t)}function pi(n,t,e,i,o,s){const[r,l,d]=n,u=Math.cos(t),p=Math.sin(t),v=u*r+p*d,E=-p*r+u*d,k=Math.cos(e),w=Math.sin(e),R=k*l-w*E,L=w*l+k*E,Z=.55;return[i+v*s*Z,o-R*s*Z,L]}function fi(n,t,e){n.beginPath(),n.moveTo(t[0],t[1]),n.lineTo(e[0],e[1]),n.strokeStyle="#000",n.lineWidth=2,n.stroke()}function gi(n,t,e,i,o){const s=t(e),r=t(i),l=[s[0]+(r[0]-s[0])*o,s[1]+(r[1]-s[1])*o,s[2]];fi(n,s,l)}const M=[-1,-1,1],z=[1,-1,1],P=[1,-1,-1],F=[-1,-1,-1],$=[-1,1,1],D=[1,1,1],B=[1,1,-1],U=[-1,1,-1],ot=[[M,z],[z,P],[P,F],[F,M],[M,$],[z,D],[P,B],[F,U],[$,D],[D,B],[B,U],[U,$]],bi=400,st='-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif';function vi(){const n=document.createElement("div");Object.assign(n.style,{position:"absolute",inset:"0",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",background:"#fff",zIndex:"20",opacity:"0",transition:"opacity 0.3s ease-in-out"});const t=document.createElement("canvas");Object.assign(t.style,{width:"100%",height:"100%",position:"absolute",inset:"0"});const e=document.createElement("div");Object.assign(e.style,{position:"absolute",top:"56%",left:"0",right:"0",textAlign:"center",pointerEvents:"none"});const i=document.createElement("span");Object.assign(i.style,{fontSize:"13px",fontWeight:"400",color:"#000",fontVariantNumeric:"tabular-nums",fontFamily:st});const o=document.createElement("span");return Object.assign(o.style,{fontSize:"13px",color:"#000",fontFamily:st}),o.textContent=ft(),e.appendChild(i),e.appendChild(o),n.appendChild(t),n.appendChild(e),{overlay:n,canvas:t,pctEl:i,phaseEl:o}}class yi{overlay;canvas;ctx;pctEl;phaseEl;animationId=null;showTimerId=null;startTime;hidden=!1;visible=!1;constructor(t,e={}){this.startTime=performance.now();const i=vi();this.overlay=i.overlay,this.canvas=i.canvas,this.pctEl=i.pctEl,this.phaseEl=i.phaseEl,t.appendChild(this.overlay),this.ctx=this.canvas.getContext("2d"),this.ctx!==null&&(this.sizeCanvas(),this.tick());const o=e.showDelay??bi;this.showTimerId=setTimeout(()=>{this.reveal()},o)}get loadingTexts(){return{downloading:ft(),rendering:Ge()}}updateProgress(t,e){this.hidden||(this.pctEl.textContent=`${Math.round(t)}%`,this.phaseEl.textContent=e!==""?` · ${e}`:"")}showError(t){if(this.hidden=!1,this.animationId!==null&&(cancelAnimationFrame(this.animationId),this.animationId=null),this.ctx!==null){const e=Math.min(devicePixelRatio,2),i=this.canvas.width/e,o=this.canvas.height/e;this.ctx.fillStyle="#fff",this.ctx.fillRect(0,0,i*e,o*e)}this.pctEl.textContent="",this.phaseEl.textContent=t,this.phaseEl.style.color="#b91c1c",this.reveal()}hide(){if(!this.hidden){if(this.hidden=!0,this.cancelShowTimer(),!this.visible){this.destroy();return}this.overlay.style.opacity="0",this.overlay.addEventListener("transitionend",()=>{this.destroy()},{once:!0}),setTimeout(()=>{this.destroy()},500)}}destroy(){this.cancelShowTimer(),this.animationId!==null&&(cancelAnimationFrame(this.animationId),this.animationId=null),this.overlay.remove()}reveal(){this.hidden||this.visible||(this.visible=!0,this.overlay.style.opacity="1")}cancelShowTimer(){this.showTimerId!==null&&(clearTimeout(this.showTimerId),this.showTimerId=null)}sizeCanvas(){if(this.ctx===null)return;const t=Math.min(devicePixelRatio,2),e=this.overlay.clientWidth||440,i=this.overlay.clientHeight||360;this.canvas.width=e*t,this.canvas.height=i*t,this.ctx.scale(t,t),this.ctx.lineCap="round",this.ctx.lineJoin="round"}tick=()=>{this.hidden||(this.drawFrame(),this.animationId=requestAnimationFrame(this.tick))};drawFrame(){if(this.ctx===null)return;const t=this.canvas.width/Math.min(devicePixelRatio,2),e=this.canvas.height/Math.min(devicePixelRatio,2),i=(performance.now()-this.startTime)/1e3;this.ctx.fillStyle="#fff",this.ctx.fillRect(0,0,t,e);const o=t/2,s=e*.44,r=Math.min(t,e)*.08,l=.785,d=.615,u=w=>pi(w,l,d,o,s,r),p=6,v=i%p/p,E=ot.length;let k;v<.35?k=it(v/.35)*E:v<.55?k=E:v<.9?k=(1-it((v-.55)/.35))*E:k=0,this.ctx.shadowBlur=5,this.ctx.shadowColor="rgba(30,30,30,0.08)";for(let w=0;w<E&&!(w>=k);w++){const R=ot[w];if(R===void 0)continue;const L=Math.min(1,k-w);gi(this.ctx,u,R[0],R[1],L)}this.ctx.shadowBlur=0}}class _i{constructor(t){this.options=t,this.element=document.createElement("div"),Object.assign(this.element.style,{display:"flex",gap:"0.375rem"}),this.onFullscreenChange=()=>{this.setFullscreenIcon(document.fullscreenElement!==null)},document.addEventListener("fullscreenchange",this.onFullscreenChange)}options;element;arBtn=null;fullscreenBtn=null;onFullscreenChange;setFullscreenIcon(t){this.fullscreenBtn!==null&&this.fullscreenBtn.setIcon(t?b.exitFullscreen():b.fullscreen())}syncButton(t,e,i){if(e&&t===null){const o=i();return this.element.appendChild(o.element),o}return!e&&t!==null?(t.element.remove(),null):t}applySettings(t){this.arBtn=this.syncButton(this.arBtn,t.ar!==!1&&this.options.onAr!==void 0,()=>new g({variant:"outline",size:"icon",label:ve(),icon:b.ar(),onClick:()=>{this.options.onAr?.()}})),this.fullscreenBtn=this.syncButton(this.fullscreenBtn,t.fullscreen!==!1&&this.options.onFullscreen!==void 0,()=>new g({variant:"outline",size:"icon",label:$e(),icon:b.fullscreen(),onClick:()=>{this.options.onFullscreen?.()}}))}destroy(){document.removeEventListener("fullscreenchange",this.onFullscreenChange)}}const x=.5;class N{element;constructor(t,e){this.element=Object.assign(document.createElement("div"),{className:"vd-camera-controls"});const i={targetRotation:e.rotation,targetTilt:e.tilt,targetZoom:e.zoom,thetaOffset:0},o=wi(t,e,i);e.onChange(s=>{i.targetRotation=s.rotation-i.thetaOffset,i.targetTilt=s.tilt,i.targetZoom=s.zoom,Ci(o,e,s)}),this.element.appendChild(N.buildZoom(o.zoomOut,o.zoomIn)),this.element.appendChild(N.buildDpad(o.tiltUp,o.rotateLeft,o.reset,o.rotateRight,o.tiltDown))}static buildZoom(t,e){const i=document.createElement("div");return i.className="vd-zoom",i.appendChild(t.element),i.appendChild(e.element),i}static buildDpad(t,e,i,o,s){const r=document.createElement("div");r.className="vd-dpad";for(const[l,d]of[[t,"up"],[e,"left"],[i,"center"],[o,"right"],[s,"down"]])l.element.classList.add(`vd-dpad-${d}`),r.appendChild(l.element);return r}}function wi(n,t,e){const i=r=>Math.max(t.limits?.minZoom??1,Math.min(t.limits?.maxZoom??1/0,r)),o=r=>{const l=t.limits?.minRotate,d=t.limits?.maxRotate;return l!==void 0||d!==void 0?Math.max(l??-1/0,Math.min(d??1/0,r)):r},s=r=>{const l=t.limits?.minTilt,d=t.limits?.maxTilt;if(l!==void 0||d!==void 0){e.targetTilt=Math.max(l??0,Math.min(d??180,e.targetTilt+r)),n.tilt(e.targetTilt).set();return}const u=e.targetTilt+r;u>180||u<0?(e.targetTilt=u>180?360-u:-u,e.thetaOffset=(e.thetaOffset+180)%360,n.tilt(e.targetTilt).rotate(e.targetRotation+e.thetaOffset).set()):(e.targetTilt=u,n.tilt(e.targetTilt).set())};return{zoomOut:new g({variant:"outline",size:"icon",label:gn(),icon:b.zoomOut(),onClick:()=>{e.targetZoom=i(e.targetZoom-10),n.zoom(e.targetZoom).set()}}),zoomIn:new g({variant:"outline",size:"icon",label:hn(),icon:b.zoomIn(),onClick:()=>{e.targetZoom=i(e.targetZoom+10),n.zoom(e.targetZoom).set()}}),tiltUp:new g({variant:"outline",size:"icon",label:Tn(),icon:b.tiltUp(),onClick:()=>{s(-15)}}),rotateLeft:new g({variant:"outline",size:"icon",label:_n(),icon:b.rotateLeft(),onClick:()=>{e.targetRotation=o(e.targetRotation-15),n.rotate(e.targetRotation+e.thetaOffset).set()}}),reset:new g({variant:"outline",size:"icon",label:ln(),icon:b.reset(),onClick:()=>{e.thetaOffset=0,n.reset()}}),rotateRight:new g({variant:"outline",size:"icon",label:kn(),icon:b.rotateRight(),onClick:()=>{e.targetRotation=o(e.targetRotation+15),n.rotate(e.targetRotation+e.thetaOffset).set()}}),tiltDown:new g({variant:"outline",size:"icon",label:Nn(),icon:b.tiltDown(),onClick:()=>{s(15)}})}}function Ci(n,t,e){const i=t.limits;i!==void 0&&(n.zoomOut.element.disabled=i.minZoom!==void 0&&e.zoom<=i.minZoom+x,n.zoomIn.element.disabled=i.maxZoom!==void 0&&e.zoom>=i.maxZoom-x,n.tiltUp.element.disabled=i.minTilt!==void 0&&e.tilt<=i.minTilt+x,n.tiltDown.element.disabled=i.maxTilt!==void 0&&e.tilt>=i.maxTilt-x,n.rotateLeft.element.disabled=i.minRotate!==void 0&&e.rotation<=i.minRotate+x,n.rotateRight.element.disabled=i.maxRotate!==void 0&&e.rotation>=i.maxRotate-x)}const T={SELECT:"ui:select",SELECTED:"ui:selected",FOCUS_CHANGE:"vd:focus-change",CONFIGURATION_CHANGE:"vd:configuration-change",CONFIGURATION_SUBMIT:"vd:configuration-submit"},Si=5;let ki=0;function V(n){const t=n.replace(/([A-Z])/g," $1").trim();return t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()}function Ei(n,t,e,i,o){const s=document.createElement("div");s.className="vd-attribute",s.dataset.name=n.name;const r=document.createElement("span");r.className="vd-attribute-label",r.textContent=V(n.name),r.id=`vd-attribute-label-${ki++}`,s.appendChild(r),s.setAttribute("role","group"),s.setAttribute("aria-labelledby",r.id);const l=n.values.find(p=>t.getValue(n.name,p)?.isSelected===!0),d=n.values.map(V),u=n.values.length<=Si?new ae(n.values,l,d):new le(n.name,n.values,V(n.name),l,d);return u.onSelect(p=>{e.dispatch(T.SELECT,{attribute:n.name,value:p},!0).defaultPrevented||i(n.name,p)}),o(n.name,p=>{u.setSelected(p.value),e.dispatch(T.SELECTED,{attribute:n.name,value:p.value})}),s.appendChild(u.element),s}const Ai=80,xi=2500;class Ti{constructor(t,e=xi){this.configuration=t,this.resetMs=e,this.element=document.createElement("div"),this.element.className="vd-commerce vd-hidden";const i=document.createElement("div");i.className="vd-commerce-price",this.priceEl=document.createElement("span"),this.priceEl.className="vd-price",this.vatEl=document.createElement("span"),this.vatEl.className="vd-vat",i.append(this.priceEl,this.vatEl),this.button=new g({variant:"default",onClick:()=>{this.handleSubmit()}}),this.button.element.classList.add("vd-cta","vd-hidden"),this.element.append(i,this.button.element),this.unsubscribe=this.configuration.onRender(()=>{this.update()}),this.update()}configuration;resetMs;element;priceEl;vatEl;button;unsubscribe;state="idle";resetTimer;update(){this.renderPrice(this.configuration.current),this.renderButton();const t=this.configuration.current!==void 0||this.configuration.submitEnabled;this.element.classList.toggle("vd-hidden",!t)}destroy(){this.unsubscribe(),this.resetTimer!==void 0&&clearTimeout(this.resetTimer),this.element.remove()}renderPrice(t){if(t===void 0){this.priceEl.textContent="",this.vatEl.textContent="";return}this.priceEl.textContent=Ri(t.price,t.currency),this.vatEl.textContent=rt(this.configuration.vatDisplay)}renderButton(){const t=this.configuration.submitEnabled;this.button.element.classList.toggle("vd-hidden",!t),t&&this.state==="idle"&&this.setButtonText(rt(this.configuration.buttonLabel))}async handleSubmit(){if(this.state!=="busy"){this.setState("busy",Pn());try{await this.configuration.submit(),this.setState("success",Bn())}catch{this.setState("failed",Hn())}this.scheduleReset()}}scheduleReset(){this.resetTimer!==void 0&&clearTimeout(this.resetTimer),this.resetTimer=setTimeout(()=>{this.state="idle",this.update()},this.resetMs)}setState(t,e){this.state=t,this.element.dataset.submit=t,this.button.element.disabled=t==="busy",this.setButtonText(e)}setButtonText(t){this.button.element.textContent=t,this.button.element.setAttribute("aria-label",t)}}function rt(n){return(n??"").slice(0,Ai)}function Ri(n,t){try{const e=new Intl.NumberFormat(h(),{style:"currency",currency:t}),i=e.resolvedOptions().maximumFractionDigits??2;return e.format(n/10**i)}catch{return`${t} ${(n/100).toFixed(2)}`}}class Ot{slot=null;panel=null;attach(t,e){this.panel=e,e.style.display="none",this.slot=document.createElement("div"),this.slot.className="vd-slot-bottom-left",this.slot.appendChild(e),t.appendChild(this.slot)}setVisible(t){this.panel!==null&&(this.panel.style.display=t?"flex":"none")}destroy(){this.slot?.remove(),this.slot=null,this.panel=null}}const Oi=572;class Ii{element=null;body=null;openButton=null;closeButton=null;container=null;observer=null;collapsible=!1;expanded=!0;visible=!1;attach(t,e){this.container=t,e.classList.add("vd-attributes-sidebar"),this.closeButton=new g({variant:"ghost",size:"icon-sm",label:on(),icon:b.close({size:18}),onClick:()=>{this.expanded=!1,this.render()}});const i=document.createElement("div");i.className="vd-sidebar-header",i.appendChild(this.closeButton.element),this.body=document.createElement("div"),this.body.className="vd-sidebar-body",this.body.appendChild(e),this.element=document.createElement("div"),this.element.className="vd-sidebar vd-hidden",this.element.append(i,this.body),t.appendChild(this.element),this.openButton=new g({variant:"outline",size:"default",label:Je(),icon:b.configurator({size:18}),onClick:()=>{this.expanded=!0,this.render()}}),this.openButton.element.classList.add("vd-configurator-toggle","vd-hidden"),t.appendChild(this.openButton.element),this.observe()}setVisible(t){this.visible=t,this.render()}destroy(){this.observer?.disconnect(),this.observer=null,this.openButton?.element.remove(),this.element?.remove(),this.container?.classList.remove("vd-layout-sidebar-right","vd-layout-sidebar-collapsed"),this.container=null}observe(){typeof ResizeObserver>"u"||this.container===null||(this.observer=new ResizeObserver(t=>{const e=t[0]?.contentRect.width??0;this.setCollapsible(e>0&&e<Oi)}),this.observer.observe(this.container))}setCollapsible(t){t!==this.collapsible&&(this.collapsible=t,this.expanded=!t,this.render())}render(){if(this.element===null||this.openButton===null||this.closeButton===null||this.container===null)return;const t=this.visible&&this.expanded,e=this.visible&&!this.expanded;this.element.classList.toggle("vd-hidden",!this.visible),this.element.classList.toggle("vd-sidebar-collapsed",e),this.openButton.element.classList.toggle("vd-hidden",!e),this.closeButton.element.style.display=this.collapsible?"":"none",this.container.classList.toggle("vd-layout-sidebar-right",t),this.container.classList.toggle("vd-layout-sidebar-collapsed",e)}}class Ni{attach(t,e){}setVisible(t){}destroy(){}}const Li={"inframe-bottom-left":()=>new Ot,"sidebar-right":()=>new Ii,hidden:()=>new Ni};function Mi(n){return(Li[n??""]??(()=>new Ot))()}const j=_.fontFamily.sans.join(", "),H=`
260
+ position: absolute;
261
+ display: flex;
262
+ z-index: 10;
263
+ transition: inset-inline-end 0.18s ease;
264
+ `,zi=`
265
+ /* Override browser's default black fullscreen backdrop */
266
+ .vd-container:fullscreen {
267
+ background: oklch(100% 0 0);
268
+ }
269
+
270
+ /* Layout slots — four corners */
271
+ .vd-slot-top-right {
272
+ ${H}
273
+ inset-block-start: ${a[3]};
274
+ inset-inline-end: ${a[3]};
275
+ flex-direction: column;
276
+ align-items: flex-end;
277
+ gap: ${a[1.5]};
278
+ }
279
+
280
+ .vd-slot-bottom-left {
281
+ ${H}
282
+ inset-block-end: ${a[3]};
283
+ inset-inline-start: ${a[3]};
284
+ flex-direction: column;
285
+ align-items: flex-start;
286
+ gap: ${a[1.5]};
287
+ }
288
+
289
+ .vd-slot-bottom-right {
290
+ ${H}
291
+ inset-block-end: ${a[3]};
292
+ inset-inline-end: ${a[3]};
293
+ flex-direction: row;
294
+ gap: ${a[1.5]};
295
+ }
296
+
297
+ /* Component styles — no positioning */
298
+ .vd-camera-controls {
299
+ display: flex;
300
+ flex-direction: column;
301
+ gap: ${a[1]};
302
+ background: color-mix(in oklch, ${m.white} 85%, transparent);
303
+ backdrop-filter: blur(8px);
304
+ border-radius: ${a[2]};
305
+ padding: ${a[2]};
306
+ }
307
+
308
+ .vd-zoom {
309
+ display: flex;
310
+ gap: ${a[.5]};
311
+ }
312
+
313
+ .vd-dpad {
314
+ display: grid;
315
+ grid-template-columns: repeat(3, ${a[9]});
316
+ grid-template-rows: repeat(3, ${a[9]});
317
+ gap: ${a[.5]};
318
+ }
319
+
320
+ .vd-dpad-up { grid-column: 2; grid-row: 1; }
321
+ .vd-dpad-left { grid-column: 1; grid-row: 2; }
322
+ .vd-dpad-center { grid-column: 2; grid-row: 2; }
323
+ .vd-dpad-right { grid-column: 3; grid-row: 2; }
324
+ .vd-dpad-down { grid-column: 2; grid-row: 3; }
325
+
326
+ .vd-attributes {
327
+ display: flex;
328
+ flex-direction: column;
329
+ gap: ${a[3]};
330
+ background: color-mix(in oklch, ${m.white} 85%, transparent);
331
+ backdrop-filter: blur(8px);
332
+ border: 1px solid color-mix(in oklch, ${m.neutral[900]} 8%, transparent);
333
+ border-radius: ${a[3]};
334
+ padding: ${a[3]};
335
+ box-shadow: 0 ${a[1]} ${a[4]} color-mix(in oklch, ${m.neutral[900]} 6%, transparent);
336
+ font-family: ${j};
337
+ }
338
+
339
+ .vd-attribute {
340
+ display: flex;
341
+ flex-direction: column;
342
+ gap: ${a[1.5]};
343
+ }
344
+
345
+ /* Micro-label: recedes so the controls lead. */
346
+ .vd-attribute-label {
347
+ font-size: ${_.fontSize.xs};
348
+ font-weight: ${_.fontWeight.medium};
349
+ color: ${m.neutral[500]};
350
+ text-transform: uppercase;
351
+ letter-spacing: 0.05em;
352
+ font-family: ${j};
353
+ }
354
+
355
+ /* sidebar-right layout — a docked, full-height right panel */
356
+ .vd-container { --vd-sidebar-width: 300px; }
357
+
358
+ .vd-hidden { display: none !important; }
359
+
360
+ .vd-sidebar {
361
+ position: absolute;
362
+ inset-block: 0;
363
+ inset-inline-end: 0;
364
+ inline-size: var(--vd-sidebar-width);
365
+ z-index: 11;
366
+ display: flex;
367
+ flex-direction: column;
368
+ background: color-mix(in oklch, ${m.white} 90%, transparent);
369
+ backdrop-filter: blur(10px);
370
+ border-inline-start: 1px solid color-mix(in oklch, ${m.neutral[900]} 8%, transparent);
371
+ box-shadow: -${a[1]} 0 ${a[4]} color-mix(in oklch, ${m.neutral[900]} 5%, transparent);
372
+ }
373
+
374
+ @media (prefers-reduced-motion: no-preference) {
375
+ .vd-sidebar { transition: transform 0.18s ease; }
376
+ }
377
+
378
+ .vd-sidebar-collapsed { transform: translateX(100%); }
379
+
380
+ .vd-sidebar-header {
381
+ display: flex;
382
+ justify-content: flex-end;
383
+ padding: ${a[1.5]} ${a[1.5]} 0;
384
+ }
385
+
386
+ .vd-sidebar-body {
387
+ flex: 1;
388
+ overflow-y: auto;
389
+ padding: ${a[4]};
390
+ }
391
+
392
+ /* attributes inside the sidebar: flat and full-width — the panel provides the frosting */
393
+ .vd-attributes.vd-attributes-sidebar {
394
+ background: transparent;
395
+ backdrop-filter: none;
396
+ border: none;
397
+ border-radius: 0;
398
+ padding: 0;
399
+ box-shadow: none;
400
+ gap: ${a[5]};
401
+ }
402
+
403
+ /* floating toggle, shown when the sidebar is collapsed on narrow embeds */
404
+ .vd-configurator-toggle {
405
+ position: absolute;
406
+ inset-block-end: ${a[3]};
407
+ inset-inline-end: ${a[3]};
408
+ z-index: 12;
409
+ }
410
+
411
+ /* while the panel is open, keep the corner controls clear of it */
412
+ .vd-layout-sidebar-right .vd-slot-top-right { inset-inline-end: calc(var(--vd-sidebar-width) + ${a[3]}); }
413
+ .vd-layout-sidebar-right .vd-slot-bottom-right { inset-inline-end: calc(var(--vd-sidebar-width) + ${a[3]}); }
414
+
415
+ /* while collapsed on a narrow embed, lift the bottom-right controls above the
416
+ floating toggle so the AR/fullscreen buttons aren't hidden behind the
417
+ "open configurator" button (spacing[9] = the default toggle button height) */
418
+ .vd-layout-sidebar-collapsed .vd-slot-bottom-right {
419
+ inset-block-end: calc(${a[3]} + ${a[9]} + ${a[1.5]});
420
+ }
421
+
422
+ /* Price + CTA — sit under the attribute controls, separated by a hairline */
423
+ .vd-commerce {
424
+ display: flex;
425
+ flex-direction: column;
426
+ gap: ${a[2]};
427
+ padding-block-start: ${a[3]};
428
+ border-block-start: 1px solid color-mix(in oklch, ${m.neutral[900]} 8%, transparent);
429
+ font-family: ${j};
430
+ }
431
+
432
+ .vd-commerce-price {
433
+ display: flex;
434
+ align-items: baseline;
435
+ gap: ${a[1.5]};
436
+ }
437
+
438
+ .vd-price {
439
+ font-size: ${_.fontSize.lg};
440
+ font-weight: ${_.fontWeight.semibold};
441
+ color: ${m.neutral[900]};
442
+ }
443
+
444
+ .vd-vat {
445
+ font-size: ${_.fontSize.xs};
446
+ color: ${m.neutral[500]};
447
+ }
448
+
449
+ .vd-cta {
450
+ inline-size: 100%;
451
+ justify-content: center;
452
+ }
453
+
454
+ /* Failed submit is the one place red belongs: a clear, recoverable error state. */
455
+ .vd-commerce[data-submit="failed"] .vd-cta {
456
+ background: ${m.semantic.error};
457
+ border-color: ${m.semantic.error};
458
+ color: ${m.white};
459
+ }
460
+
461
+ `;function Pi(){if(Yn(),document.getElementById("vd-styles")!==null)return;const n=document.createElement("style");n.id="vd-styles",n.textContent=zi,document.head.appendChild(n)}function Fi(n,t){const e=document.createElement("a");e.href=`data:image/png;base64,${n}`,e.download=t,e.click()}class $i{options;settings={};container=null;loading=null;slots={topRight:null,bottomRight:null};screenshotBtn=null;actionBar=null;cameraControls=null;attributes=null;layout=null;commerce=null;constructor(t){this.options=t}attach(t){Pi(),this.container=t,this.loading=new yi(t),this.slots.topRight=this.createSlot(t,"vd-slot-top-right"),this.slots.bottomRight=this.createSlot(t,"vd-slot-bottom-right")}onReady(){this.loading?.hide(),this.loading=null,this.mountToolbar(),this.cameraControls!==null&&(this.cameraControls.element.style.display="flex"),this.layout?.setVisible(!0)}mountToolbar(){if(this.actionBar!==null||this.slots.bottomRight===null||this.container===null)return;const t=typeof this.container.requestFullscreen=="function";this.actionBar=new _i({onAr:this.options.onAr,onFullscreen:t?()=>{this.toggleFullscreen()}:void 0}),this.actionBar.applySettings(this.settings),this.slots.bottomRight.appendChild(this.actionBar.element),this.syncScreenshotButton(),this.placeScreenshotButton()}toggleFullscreen(){this.container!==null&&(document.fullscreenElement!==null?document.exitFullscreen():(this.options.onFullscreenEnter?.(),this.container.requestFullscreen()))}updateProgress(t,e){this.loading?.updateProgress(t,e)}showError(t){this.loading?.showError(t)}applyViewerSettings(t){this.settings=t,t.language!==void 0&&ht(t.language,{reload:!1}),this.syncScreenshotButton(),this.actionBar?.applySettings(t),this.cameraControls!==null&&(this.cameraControls.element.style.display=t.cameraControls===!0?"flex":"none"),this.placeScreenshotButton()}renderAttributeControls(t,e){if(!(this.container===null||this.slots.topRight===null)&&(this.cameraControls?.element.remove(),this.cameraControls=null,this.teardownConfigurator(),this.settings.cameraControls===!0&&(this.cameraControls=new N(this.options.cameraApi,this.options.cameraPositionApi),this.cameraControls.element.style.display="none",this.slots.topRight.appendChild(this.cameraControls.element)),this.placeScreenshotButton(),e.length!==0)){this.attributes=document.createElement("div"),this.attributes.className="vd-attributes";for(const i of e)this.attributes.appendChild(Ei(i,t,this.options.eventBus,this.options.onSelect,this.options.onSubscribe));this.commerce=new Ti(this.options.configuration),this.attributes.appendChild(this.commerce.element),this.layout=Mi(this.settings.configuratorLayout),this.layout.attach(this.container,this.attributes)}}get viewerSettings(){return this.settings}teardownConfigurator(){this.commerce?.destroy(),this.commerce=null,this.attributes?.remove(),this.attributes=null,this.layout?.destroy(),this.layout=null}destroy(){this.loading?.destroy(),this.screenshotBtn?.element.remove(),this.actionBar?.destroy(),this.actionBar?.element.remove(),this.cameraControls?.element.remove(),this.teardownConfigurator();for(const t of Object.values(this.slots))t?.remove();this.container=null}createSlot(t,e){const i=document.createElement("div");return i.className=e,t.appendChild(i),i}syncScreenshotButton(){const t=this.settings.screenshot===!0;t&&this.screenshotBtn===null&&(this.screenshotBtn=new g({variant:"outline",size:"icon",label:Ye(),icon:b.screenshot(),onClick:()=>{this.options.snapshotApi.take("snapshot.png").onDeveloped(({data:e,filename:i})=>{Fi(e,i)})}})),!t&&this.screenshotBtn!==null&&(this.screenshotBtn.element.remove(),this.screenshotBtn=null)}placeScreenshotButton(){this.screenshotBtn===null||this.slots.topRight===null||(this.cameraControls!==null?this.cameraControls.element.appendChild(this.screenshotBtn.element):this.slots.topRight.appendChild(this.screenshotBtn.element))}}const Di={};class Bi{defaultServer="https://server.virtualdisplay.io";options;serverHost;constructor(t,e){this.options=t,this.serverHost=e}create(){const t=this.createContainer(),e=this.createIframe();return t.appendChild(e),this.attachToParent(t),{container:t,iframe:e}}createContainer(){const t=document.createElement("div");return t.className="vd-container",Object.assign(t.style,{position:"relative",width:"100%",height:"100%",overflow:"hidden"}),t}createIframe(){const t=document.createElement("iframe");return t.src=this.buildUrl(),Object.assign(t.style,{width:"100%",height:"100%",border:"none",display:"block"}),t.setAttribute("allow","xr-spatial-tracking; fullscreen"),t}attachToParent(t){this.getParentElement().appendChild(t)}buildUrl(){const t=this.getServerUrl(),e=new URL(t);return e.searchParams.set("license",this.options.license),e.searchParams.set("model",this.options.model),this.options.language!==void 0&&e.searchParams.set("language",this.options.language),this.options.debug===!0&&e.searchParams.set("debug","true"),this.options.traceparent!==void 0&&e.searchParams.set("traceparent",this.options.traceparent),e.toString()}getServerUrl(){if(this.serverHost!==void 0)return this.serverHost;if(Di?.VITE_VIRTUALDISPLAY_SERVER_HOST===void 0)return this.defaultServer}getParentElement(){if(typeof this.options.parent!="string")return this.options.parent;const t=document.querySelector(this.options.parent);if(t===null)throw f.parentNotFound(this.options.parent);return t}}function Ui(n){const{messenger:t}=n;t.on(c.HANDSHAKE,e=>{zt(e)&&(exports.logger.info("Server handshake received, flushing publisher queue"),t.markReady())}),t.on(c.SESSION,e=>{Pt(e)&&n.onSession(e.sessionId)}),t.on(c.MUTATION,e=>{Ft(e)&&(n.attributes.handleMutationResult(e),n.configuration.handleSelectionChanged(n.attributes.getSelection()))}),t.on(c.SNAPSHOT,e=>{$t(e)&&n.snapshot.handleSnapshotResult(e)}),t.on(c.CAMERA,e=>{Dt(e)&&n.cameraPosition.handlePositionUpdate(e)}),t.on(c.LOADING_INDICATOR,e=>{Ut(e)&&(e.error!==void 0?n.ui.showError(e.error):n.ui.updateProgress(e.progress,e.phase))}),t.on(c.CONFIG,e=>{Vt(e)&&n.applyConfig(e)}),t.on(c.MAPPING,e=>{Bt(e)&&(n.attributes.handleMappingReceived(e),n.configuration.handleSelectionChanged(n.attributes.getSelection()),n.ui.renderAttributeControls(n.attributes,e.attributes),n.readyStateTracker.handleMappingReceived())}),Vi(n)}function Vi(n){const{messenger:t}=n;t.on(c.FOCUS,e=>{jt(e)&&n.focus.handleStateReceived(e)}),t.on(c.PRICING,e=>{Ht(e)&&n.configuration.handlePricingReceived(e.pricing)})}class ji{ready=!1;onReady;constructor(t){this.onReady=t}handleMappingReceived(){this.ready||(this.ready=!0,exports.logger.info("Mapping received from server, client is now ready"),this.onReady?.())}get isReady(){return this.ready}clear(){this.ready=!1}}class Hi{attributes;readyStateTracker;messenger;cameraApi;cameraPositionApi;focusApi;configurationApi;snapshotApi;annotationsApi;eventBus;ui;qrModal;options;serverHost;iframe;container;readyCallbacks=[];mutationFailedCallbacks=[];viewerSessionId;constructor(t,e){this.options=t,this.serverHost=e?.serverHost,this.initializeLogging(),this.messenger=new Gt(()=>this.iframe?.contentWindow??null,e?.messengerOptions);const i=o=>{this.messenger.send(o)};this.attributes=new ci(i,(o,s)=>{for(const r of this.mutationFailedCallbacks)r({attribute:o,value:s})}),this.snapshotApi=new Rt(i),this.annotationsApi=new bt(i),this.cameraApi=new Et(i),this.cameraPositionApi=new ui,this.focusApi=new xt(i,o=>{this.dispatchFocusChange(o)}),this.configurationApi=new At(o=>{this.dispatchConfigurationChange(o)},o=>{this.dispatchConfigurationSubmit(o)}),this.eventBus=new mi,this.qrModal=new qn,this.readyStateTracker=new ji(()=>{const o=this.readyCallbacks;this.readyCallbacks=[];for(const s of o)s(this);this.ui.onReady()}),this.ui=new $i({snapshotApi:this.snapshotApi,cameraApi:this.cameraApi,cameraPositionApi:this.cameraPositionApi,eventBus:this.eventBus,configuration:this.configurationApi,onSelect:(o,s)=>this.attributes.select(o,s),onSubscribe:(o,s)=>this.attributes.onChange(o,s),onAr:()=>{this.activateAr()},onFullscreenEnter:()=>{this.trackFullscreen()}}),this.wireIncomingMessages(),e?.registerHandlers?.(this.messenger,i),this.messenger.start(),this.createAndConnectIframe()}wireIncomingMessages(){Ui({messenger:this.messenger,attributes:this.attributes,configuration:this.configurationApi,snapshot:this.snapshotApi,cameraPosition:this.cameraPositionApi,focus:this.focusApi,ui:this.ui,readyStateTracker:this.readyStateTracker,applyConfig:t=>{this.handleConfig(t)},onSession:t=>{this.viewerSessionId=t}})}dispatchFocusChange(t){this.container?.dispatchEvent(new CustomEvent(T.FOCUS_CHANGE,{detail:t,bubbles:!0}))}dispatchConfigurationChange(t){this.container?.dispatchEvent(new CustomEvent(T.CONFIGURATION_CHANGE,{detail:t??null,bubbles:!0}))}dispatchConfigurationSubmit(t){this.container?.dispatchEvent(new CustomEvent(T.CONFIGURATION_SUBMIT,{detail:t,bubbles:!0}))}handleConfig(t){const e=t.viewerSettings,i=this.options.viewerSettings;if(e!==void 0||i!==void 0){const o=i!==void 0?{...e??{},...i}:e;if(i!==void 0&&e!==void 0){const s=Object.entries(i).filter(([r,l])=>e[r]!==l).map(([r,l])=>`${r} (metadata: ${e[r]??"undefined"}, override: ${l})`);s.length>0&&exports.logger.warn(`Viewer settings override active: ${s.join(", ")}`)}this.ui.applyViewerSettings(o),this.annotationsApi.setEnabled(o.annotations!==!1)}this.cameraPositionApi.applyLimits(t.cameraLimits)}activateAr(){if(ei()){this.messenger.send({type:c.AR_ACTIVATE});return}this.qrModal.show(this.iframe?.src??"")}trackFullscreen(){this.messenger.send({type:c.FULLSCREEN})}initializeLogging(){this.options.debug===!0&&kt(),exports.logger.info("Initializing Virtualdisplay client",{model:this.options.model})}createAndConnectIframe(){const e=new Bi(this.options,this.serverHost).create();this.container=e.container,this.iframe=e.iframe,this.eventBus.attach(this.container),this.ui.attach(this.container);try{const i=new URL(this.iframe.src).origin;this.messenger.setTargetOrigin(i)}catch{}}select(t,e){this.attributes.select(t,e)}getValues(t){return this.attributes.getValues(t)}getValue(t,e){return this.attributes.getValue(t,e)}onChange(t,e){this.attributes.onChange(t,e)}getAttribute(t){return this.attributes.getAttribute(t)}get isReady(){return this.readyStateTracker.isReady}onReady(t){if(this.readyStateTracker.isReady){t(this);return}this.readyCallbacks.push(t)}onMutationFailed(t){this.mutationFailedCallbacks.push(t)}on(t,e){this.eventBus.on(t,e)}get annotations(){return this.annotationsApi}get camera(){return this.cameraApi}get focus(){return this.focusApi}get configuration(){return this.configurationApi}get cameraPosition(){return this.cameraPositionApi}get snapshot(){return this.snapshotApi}get sessionId(){return this.viewerSessionId}get viewerSettings(){return this.ui.viewerSettings}destroy(){this.readyStateTracker.clear(),this.readyCallbacks=[],this.mutationFailedCallbacks.length=0,this.snapshotApi.clear(),this.messenger.destroy(),this.qrModal.hide(),this.ui.destroy(),this.container?.parentElement!==null&&this.container?.parentElement!==void 0&&this.container.parentElement.removeChild(this.container),this.container=void 0,this.iframe=void 0}}class Gi extends Hi{}exports.Annotations=bt;exports.Attribute=yt;exports.AttributeValue=vt;exports.Camera=Et;exports.Configuration=At;exports.ERROR_CODES=C;exports.Focus=xt;exports.Photo=Tt;exports.Snapshot=Rt;exports.VD_EVENTS=T;exports.VirtualdisplayClient=Gi;exports.VirtualdisplayError=f;exports.enableDebugMode=kt;exports.isDebugMode=li;