@virtualdisplay.io/client 4.0.0-alpha.3 → 4.0.0-alpha.32

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +254 -1
  2. package/README.md +127 -156
  3. package/dist/browser-7qZ1KQYo.cjs +8 -0
  4. package/dist/browser-B8yql1bQ.js +1226 -0
  5. package/dist/index.d.ts +672 -0
  6. package/dist/rolldown-runtime-5iZMYShA.cjs +1 -0
  7. package/dist/rolldown-runtime-CYdcPHCu.js +12 -0
  8. package/dist/virtualdisplay.client.cjs.js +691 -1
  9. package/dist/virtualdisplay.client.es.js +3142 -458
  10. package/dist/virtualdisplay.client.umd.js +698 -1
  11. package/package.json +3 -3
  12. package/dist/src/attributes/attribute.d.ts +0 -38
  13. package/dist/src/attributes/attribute.d.ts.map +0 -1
  14. package/dist/src/attributes/attributes.d.ts +0 -43
  15. package/dist/src/attributes/attributes.d.ts.map +0 -1
  16. package/dist/src/attributes/selections.d.ts +0 -16
  17. package/dist/src/attributes/selections.d.ts.map +0 -1
  18. package/dist/src/attributes/value.d.ts +0 -13
  19. package/dist/src/attributes/value.d.ts.map +0 -1
  20. package/dist/src/camera/camera.d.ts +0 -40
  21. package/dist/src/camera/camera.d.ts.map +0 -1
  22. package/dist/src/camera/index.d.ts +0 -4
  23. package/dist/src/camera/index.d.ts.map +0 -1
  24. package/dist/src/camera/position.d.ts +0 -43
  25. package/dist/src/camera/position.d.ts.map +0 -1
  26. package/dist/src/client/client.d.ts +0 -83
  27. package/dist/src/client/client.d.ts.map +0 -1
  28. package/dist/src/client/error.d.ts +0 -26
  29. package/dist/src/client/error.d.ts.map +0 -1
  30. package/dist/src/client/iframe-builder.d.ts +0 -25
  31. package/dist/src/client/iframe-builder.d.ts.map +0 -1
  32. package/dist/src/client/options.d.ts +0 -17
  33. package/dist/src/client/options.d.ts.map +0 -1
  34. package/dist/src/client/ready-state-tracker.d.ts +0 -26
  35. package/dist/src/client/ready-state-tracker.d.ts.map +0 -1
  36. package/dist/src/client/types.d.ts +0 -5
  37. package/dist/src/client/types.d.ts.map +0 -1
  38. package/dist/src/index.d.ts +0 -11
  39. package/dist/src/index.d.ts.map +0 -1
  40. package/dist/src/snapshot/index.d.ts +0 -3
  41. package/dist/src/snapshot/index.d.ts.map +0 -1
  42. package/dist/src/snapshot/photo.d.ts +0 -47
  43. package/dist/src/snapshot/photo.d.ts.map +0 -1
  44. package/dist/src/snapshot/snapshot.d.ts +0 -30
  45. package/dist/src/snapshot/snapshot.d.ts.map +0 -1
  46. package/dist/src/ui/viewer-config.d.ts +0 -63
  47. package/dist/src/ui/viewer-config.d.ts.map +0 -1
  48. package/dist/src/utils/logger.d.ts +0 -11
  49. package/dist/src/utils/logger.d.ts.map +0 -1
@@ -1 +1,691 @@
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?.(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
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./rolldown-runtime-5iZMYShA.cjs");var t={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`,QR_SHOWN:`qr_shown`,SYNC:`sync`,SELECTABLE:`selectable`,APP_RESOLVED:`app_resolved`},n=`main`,r={FOCUS:`focus`,UNFOCUS:`unfocus`},i={FOCUSED:`focused`,UNFOCUSED:`unfocused`},a={AVAILABLE:`available`,VIEW_ONLY:`view_only`,HIDDEN:`hidden`};function o(e){return typeof e!=`object`||!e?null:e}var s=new Set(Object.values(t));function c(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.target!=`string`&&typeof t.type==`string`&&s.has(t.type)}function l(e){let n=o(e);return n!==null&&n.type===t.HANDSHAKE}function u(e){let n=o(e);return n!==null&&n.type===t.SESSION&&typeof n.sessionId==`string`}function ee(e){let n=o(e);return n!==null&&n.type===t.APP_RESOLVED&&typeof n.appType==`string`&&n.appType!==``&&typeof n.name==`string`}function d(e){let n=o(e);return n!==null&&n.type===t.MUTATION&&typeof n.instance==`string`&&n.instance!==``&&Array.isArray(n.results)}function f(e){let n=o(e);return n!==null&&n.type===t.SNAPSHOT&&(`data`in n||`error`in n)}function p(e){let n=o(e);return n!==null&&n.type===t.CAMERA&&Array.isArray(n.transforms)}function te(e){let n=o(e);return n!==null&&n.type===t.MAPPING&&typeof n.instance==`string`&&n.instance!==``&&Array.isArray(n.attributes)}function ne(e){let n=o(e);return n!==null&&n.type===t.LOADING_INDICATOR&&typeof n.progress==`number`}function m(e){let n=o(e);return n!==null&&n.type===t.SYNC&&typeof n.connected==`boolean`}function re(e){let n=o(e);return n!==null&&n.type===t.SELECTABLE&&typeof n.instance==`string`&&n.instance!==``&&Array.isArray(n.attributes)}function ie(e){let n=o(e);return n!==null&&n.type===t.CONFIG&&typeof n.viewerSettings==`object`}function ae(e){let n=o(e);return n!==null&&n.type===t.FOCUS&&typeof n.instance==`string`&&n.instance!==``&&typeof n.state==`string`}function oe(e){let n=o(e);return n!==null&&n.type===t.PRICING&&typeof n.instance==`string`&&n.instance!==``&&typeof n.pricing==`object`&&n.pricing!==null}var se=class{processor;pending=[];isReady=!1;constructor(e){this.processor=e}enqueue(e){this.isReady?this.processor(e):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)}hasPending(e){return this.pending.some(t=>t.type===e)}clear(){this.pending.length=0}},ce=class{getTarget;handlers=new Map;publisher;consumer;listener=null;sourceId;targetOrigin;isValid;onHandlerError;constructor(e,t){this.getTarget=e,this.sourceId=`vd-${Math.random().toString(36).slice(2,8)}`,this.targetOrigin=`*`,this.isValid=t?.isValid??c,this.onHandlerError=t?.onHandlerError??le,this.publisher=new se(e=>this.post(e)),this.consumer=new se(e=>this.routeToHandler(e)),t?.bufferIncoming!==!0&&this.consumer.markReady()}on(e,t){this.handlers.set(e,t)}setTargetOrigin(e){this.targetOrigin=e}send(e){this.publisher.enqueue(e)}receive(e){this.isValid(e)&&this.consumer.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(!this.isValid(t)||t._source===this.sourceId)return;let n=this.getTarget();if(n!==null&&e.source!==null&&e.source!==n)return;let r=t;this.consumer.enqueue(r)},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()}post(e){let t=this.getTarget();t!==null&&t.postMessage({...e,_source:this.sourceId},this.targetOrigin)}routeToHandler(e){let t=this.handlers.get(e.type);if(t===void 0)return;let n;try{n=t(e)}catch(t){this.onHandlerError(e,t);return}n instanceof Promise&&n.catch(t=>{this.onHandlerError(e,t)})}};function le(e,t){let n=t instanceof Error?t.message:String(t);console.error(`Virtualdisplay: error handling ${e.type}: ${n}`)}t.CAMERA,t.LOADING_INDICATOR;var ue=class{send;instance;constructor(e,t){this.send=e,this.instance=t}setEnabled(e){this.send({type:t.ANNOTATION_TOGGLE,instance:this.instance,enabled:e})}},de=class{value;attribute;label;isSelectedValue=!1;constructor(e,t,n){this.value=e,this.attribute=t,this.label=n}get isSelected(){return this.isSelectedValue}setSelected(e){this.isSelectedValue=e}},fe={},pe=[`en`,`nl`,`de`],me=`PARAGLIDE_LOCALE`,h=[`globalVariable`,`baseLocale`],he=[],g=typeof window>`u`;globalThis.__paraglide=globalThis.__paraglide??{},globalThis.__paraglide.ssr=globalThis.__paraglide.ssr??{};var _,ge=!1,v=()=>{let e=h;!g&&typeof window<`u`&&window.location?.href&&(e=Ne(window.location.href));let t=_e(e,typeof window<`u`?window.location?.href:void 0);if(t)return ge||(_=t,ge=!0,ye(t,{reload:!1})),t;throw Error(`No locale found. Read the docs https://paraglidejs.com/errors#no-locale-found`)};function _e(e,t){let n;for(let t of e){if(t===`baseLocale`)n=`en`;else if(t===`globalVariable`&&_!==void 0)n=_;else if(Pe(t)&&x.has(t)){let e=x.get(t);if(e){let t=e.getLocale();if(t instanceof Promise)continue;if(t!==void 0)return xe(t)}}let e=y(n);if(e)return e}}var ve=e=>{e?window.location.href=e:window.location.reload()},ye=(e,t)=>{let n={reload:!0,...t},r;try{r=v()}catch{}let i=[],a=h;!g&&typeof window<`u`&&window.location?.href&&(a=Ne(window.location.href));for(let t of a)if(t===`globalVariable`)_=e;else if(t===`baseLocale`)continue;else if(Pe(t)&&x.has(t)){let n=x.get(t);if(n){let r=n.setLocale(e);r instanceof Promise&&(r=r.catch(e=>{throw Error(`Custom strategy "${t}" setLocale failed.`,{cause:e})}),i.push(r))}}let o=()=>{!g&&n.reload&&window.location&&e!==r&&ve(void 0)};if(i.length)return Promise.all(i).then(()=>{o()});o()},be=()=>typeof window<`u`?window.location.origin:`http://fallback.com`;function y(e){if(typeof e!=`string`)return;let t=e.toLowerCase();for(let e of pe)if(e.toLowerCase()===t)return e}function xe(e){let t=y(e);if(t)return t;throw Error(`Invalid locale: ${e}. Expected one of: ${pe.join(`, `)}`)}function b(e){return e}function Se(e,t){return new fe(e,t.href)}function Ce(){return 0}function we(e){return he}function Te(e,t){return e.exec(t.href)}var Ee=me.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`);RegExp(`(?:^|;\\s*)${Ee}=([^;]*)`);function De(e){return Oe(e)}function Oe(e){let t=b(typeof e==`string`?new URL(e,be()):new URL(e.href)),n=t.pathname.replace(/^\/+/,``).split(`/`);return n.length>0&&y(n[0])&&(t.pathname=`/`+n.slice(1).join(`/`)),b(t)}var ke=-1,Ae,je;function Me(e){if(he.length===0)return;let t=typeof e==`string`?e:e.href,n=Ce();if(Ae===t&&ke===n)return je;let r=b(new URL(t,`http://example.com`)),i=De(r),a=i.href===r.href?[r]:[r,i],o;for(let e of a){for(let t of we(e))if(Te(Se(t.match,e),e)){o=t;break}if(o)break}return ke=n,Ae=t,je=o,o}function Ne(e){let t=Me(e);return t&&t.exclude!==!0&&Array.isArray(t.strategy)?t.strategy:h}var x=new Map;function Pe(e){return typeof e==`string`&&/^custom-[A-Za-z0-9_-]+$/.test(e)}function Fe(e,t){return Ie(t!==void 0&&Object.hasOwn(t,e)?t[e]:void 0)??S(e)}function Ie(e){if(e===void 0)return;for(let t of[v(),`nl`,`en`])if(Object.hasOwn(e,t)&&e[t]!==void 0)return e[t];let[t]=Object.values(e);return t}function S(e){let t=e.replace(/([A-Z])/g,` $1`).trim();return t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()}var 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`},w=class e extends Error{code;constructor(e,t){super(e),this.name=`VirtualdisplayError`,this.code=t}static valueNotFound(t,n){return new e(`Value "${n}" not found for attribute "${t}"`,C.VALUE_NOT_FOUND)}static parentNotFound(t){return new e(`Parent element not found: ${t}`,C.PARENT_NOT_FOUND)}static invalidParameter(t){return new e(t,C.INVALID_PARAMETER)}},Le=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,e.labels)}select(e){if(!this.values.has(e))throw w.valueNotFound(this.name,e);this.onSelect(this.name,e)}getValues(){return Array.from(this.values.values())}getValue(e){return this.values.get(e)}get selected(){for(let e of this.values.values())if(e.isSelected)return e.value}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,t){let n=new Map;for(let r of e){let e=new de(r,this.name,Fe(r,t));r===this.defaultValue&&e.setSelected(!0),n.set(r,e)}return n}},Re=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 Le(e))}this.onMutationFailed=n}onMutationFailed;get(e){return this.attributes.get(e)}getSelection(){let e={};for(let[t,n]of this.attributes){let r=n.selected;r!==void 0&&(e[t]=r)}return e}handleResults(e){for(let t of e)t.success?this.get(t.name)?.handleResult(t.value):this.onMutationFailed?.(t.name,t.value)}buildOptions(e,t){let n={name:e.name,values:e.values,...e.labels!==void 0&&{labels:e.labels},onSelect:(e,n)=>{t([{name:e,value:n}],!1)}};return e.defaultValue===void 0?n:{...n,defaultValue:e.defaultValue}}},T=4096,E=16384,ze=[1024,256,64],Be=20,D=[`timestamp`,`level`,`msg`,`service`,`trace_id`,`span_id`];function Ve(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=Object.entries(e).filter(([e])=>!D.includes(e)).map(([e,t])=>`${e}=${O(t,T).line}`).join(` `);return`${t} ${n} [${r}] ${i}${a?` `+a:``}`}function He(e){for(let t of[T,...ze]){let{line:n,truncated:r}=O(e,t);if(!r){if(n.length<=E)return n;continue}let{line:i}=O({...e,log_truncated:!0},t);if(i.length<=E)return i}let t=Object.keys(e).filter(e=>!D.includes(e)),n={...We(e,D),log_truncated:!0,log_dropped_count:t.length},r=O({...n,log_dropped_attrs:t.slice(0,Be)},T);return r.line.length<=E?r.line:O(n,T).line}function O(e,t){let n=[],r=!1;return{line:JSON.stringify(e,function(e,i){if(typeof i==`string`)return i.length>t&&(r=!0),Ue(i,t);if(typeof i==`bigint`)return i.toString();if(typeof i!=`object`||!i)return i;for(;n.length>0&&n.at(-1)!==this;)n.pop();return n.includes(i)?`[Circular]`:(n.push(i),i)}),truncated:r}}function Ue(e,t){return e.length<=t?e:`${e.slice(0,t)}...[truncated ${e.length-t} chars]`}function We(e,t){let n={};for(let r of t)e[r]!==void 0&&(n[r]=e[r]);return n}function Ge(e,t){let n=t?Ve(e):He(e);e.level===`error`?console.error(n):e.level===`warn`?console.warn(n):console.log(n)}function Ke(e,t=0){let n={name:e.name,message:e.message};return e.stack!==void 0&&(n.stack=e.stack),Je(e,n),e.cause!==void 0&&e.cause!==null&&(n.cause=e.cause instanceof Error&&t<5?Ke(e.cause,t+1):String(e.cause)),n}var qe=new Set([`name`,`message`,`stack`,`cause`]);function Je(e,t){for(let n of Object.getOwnPropertyNames(e)){if(qe.has(n))continue;let r=e[n];r!==void 0&&(t[n]=r)}}function Ye(e){let t={};for(let[n,r]of Object.entries(e))t[n]=r instanceof Error?Ke(r):r;return t}function Xe(){return new Date}function Ze(){return typeof navigator>`u`?``:navigator.userAgent}function Qe(){return typeof navigator>`u`?!1:navigator.platform===`MacIntel`&&navigator.maxTouchPoints>1}function $e(){return/iPhone|iPad|iPod/i.test(Ze())||Qe()}function et(){return/Android/i.test(Ze())}function tt(){return $e()||et()}var nt=class{config;constructor(e){this.config=e}log(e,t,n={}){let r=this.config.traceProvider?.()??{};Ge({timestamp:Xe().toISOString(),level:e,msg:t,service:this.config.service,...r,...Ye(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)}};function rt(e,t){return new nt({service:e,isDev:t?.isDev===void 0?typeof process<`u`?process.env.NODE_ENV!==`production`:!0:t.isDev,traceProvider:t?.traceProvider})}function k(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 it(e){return{debug:(t,n)=>e.debug(t,k(n)),info:(t,n)=>e.info(t,k(n)),warn:(t,n)=>e.warn(t,k(n)),error:(t,n)=>e.error(t,k(n))}}var at=!1,A=it(rt(`client`,{isDev:!1}));function ot(){at=!0,A=it(rt(`client`,{isDev:!0}))}function st(){return at}var ct=class{send;instance;onMutationFailed;registry;pendingCallbacks=[];constructor(e,t,n){this.send=e,this.instance=t,this.onMutationFailed=n}handleMappingReceived(e){A.debug(`Initializing from server mapping`,{attributeCount:e.attributes.length}),this.registry=new Re(e.attributes,(e,t)=>this.sendMutation(e,t),this.onMutationFailed),this.replayPendingCallbacks()}handleMutationResult(e){this.registry?.handleResults(e.results)}select(e,t){this.sendMutation([{name:e,value:t}],!1)}selectTransient(e,t){this.sendMutation([{name:e,value:t}],!1,!0)}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);n===void 0?A.warn(`onChange: attribute "${e}" not found — callback will not fire`):n.onChange(t)}getAttribute(e){return this.registry?.get(e)}getSelection(){return this.registry?.getSelection()??{}}sendMutation(e,n,r=!1){let i={type:t.MUTATION,instance:this.instance,mutations:e,isInitial:n,...r&&{transient:!0}};this.send(i)}replayPendingCallbacks(){for(let{name:e,callback:t}of this.pendingCallbacks){let n=this.registry?.get(e);n===void 0&&A.warn(`onChange: attribute "${e}" not found — buffered callback will not fire`),n?.onChange(t)}this.pendingCallbacks.length=0}},lt=class{snapshot;callbacks=[];handleSnapshot(e){this.snapshot=e.attributes;for(let t of this.callbacks)t(e.attributes)}onChange(e){this.callbacks.push(e),this.snapshot!==void 0&&e(this.snapshot)}selectableFor(e){return this.snapshot?.find(t=>t.name===e)?.selectable??null}get current(){return this.snapshot??[]}},ut=class{send;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 w.invalidParameter(`No camera commands to execute. Call rotate(), tilt(), or zoom() before set().`);let e={type:t.CAMERA,commands:this.commands};this.send(e),this.commands=[]}validateFiniteNumber(e,t){if(!Number.isFinite(e))throw w.invalidParameter(`${t}() requires a finite number, got ${String(e)}`)}reset(){let e={type:t.CAMERA,commands:[{action:`reset`}]};this.send(e)}},dt=class{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(e){this.changeCallbacks.push(e)}get limits(){return this.limitsState}applyLimits(e){this.limitsState=e;let t={rotation:this.rotation,tilt:this.tilt,zoom:this.zoom};for(let e of this.changeCallbacks)e(t)}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}if(t){let e={rotation:this.rotation,tilt:this.tilt,zoom:this.zoom};for(let t of this.changeCallbacks)t(e)}}};function ft(e,t){let n=e.filter(e=>pt(e,t));if(n.length===0)return;let r=Math.max(...n.map(mt)),i=n.filter(e=>mt(e)===r);return i.length===1?i[0]:void 0}function pt(e,t){return Object.entries(e.attributes).every(([e,n])=>t[e]===n)}function mt(e){return Object.keys(e.attributes).length}var ht=class{dispatchChange;dispatchSubmit;pricing;selection={};resolved;changeCallbacks=[];renderCallbacks=[];submitCallback;submitDefaultLabel;constructor(e,t){this.dispatchChange=e,this.dispatchSubmit=t}get current(){return this.resolved}get vatDisplay(){return this.pricing?.vatDisplay}get buttonLabel(){let e=this.pricing?.buttonLabel;if(e!=null&&e!==``)return e;if(this.submitDefaultLabel!==void 0&&this.submitDefaultLabel!==``)return this.submitDefaultLabel}get submittable(){return this.submitCallback===void 0?!1:this.pricing===void 0||this.resolved?.availability===`available`}get submitEnabled(){return this.submittable&&this.buttonLabel!==void 0}onChange(e){this.changeCallbacks.push(e)}onSubmit(e,t){this.submitCallback=e,this.submitDefaultLabel=t?.defaultLabel,this.notifyRender()}onRender(e){return this.renderCallbacks.push(e),()=>{let t=this.renderCallbacks.indexOf(e);t!==-1&&this.renderCallbacks.splice(t,1)}}async submit(){if(!this.submittable)return;let e=this.resolved===void 0?{attributes:{...this.selection},reference:``}:{attributes:this.resolved.attributes,reference:this.resolved.reference};this.dispatchSubmit(e),await this.submitCallback?.(e)}handlePricingReceived(e){this.pricing=e,this.recompute()}handleSelectionChanged(e){this.selection=e,this.recompute()}recompute(){this.resolved=this.resolve();for(let e of this.changeCallbacks)e(this.resolved);this.dispatchChange(this.resolved),this.notifyRender()}notifyRender(){for(let e of this.renderCallbacks)e()}resolve(){if(this.pricing===void 0)return;let e=ft(this.pricing.rules,this.selection);if(e!==void 0&&e.availability!==a.HIDDEN)return{attributes:{...this.selection},reference:e.reference,price:e.priceCents,currency:this.pricing.currency,availability:e.availability}}},gt=class{send;dispatch;instance;focused=null;attributes=[];changeCallbacks=[];constructor(e,t,n){this.send=e,this.dispatch=t,this.instance=n}get current(){return this.focused}set(e){if(typeof e!=`string`||e.length===0)throw w.invalidParameter(`set() requires a non-empty component name, got ${String(e)}`);this.send({type:t.FOCUS,instance:this.instance,action:r.FOCUS,component:e})}clear(){this.send({type:t.FOCUS,instance:this.instance,action:r.UNFOCUS})}onChange(e){this.changeCallbacks.push(e)}handleStateReceived(e){e.state===i.FOCUSED&&e.component!==void 0?(this.focused=e.component,this.attributes=e.attributes??[]):(this.focused=null,this.attributes=[]);let t=this.focused===null?null:{component:this.focused,attributes:this.attributes};for(let e of this.changeCallbacks)e(t);this.dispatch(t)}},_t=class{filename;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())}},vt=3e4,yt=class{send;validExtensions=[`.png`];pendingPhotos=new Map;constructor(e){this.send=e}take(e){return this.request(e,void 0)}takeOf(e,t){return this.request(e,t)}request(e,n){this.validateFilename(e),A.debug(`Taking snapshot`,{filename:e});let r=new _t(e),i=setTimeout(()=>{this.pendingPhotos.delete(e),A.warn(`Snapshot timed out`,{filename:e}),r.fail(new w(`Snapshot timed out: the viewer did not respond within ${vt}ms`,C.SNAPSHOT_FAILED))},vt);return this.pendingPhotos.set(e,{photo:r,timeout:i}),this.send({type:t.SNAPSHOT,filename:e,...n!==void 0&&{subject:n}}),r}handleSnapshotResult(e){let t=this.pendingPhotos.get(e.filename);if(t===void 0){A.warn(`No pending photo found for filename`,{filename:e.filename,pendingFilenames:Array.from(this.pendingPhotos.keys())});return}clearTimeout(t.timeout),this.pendingPhotos.delete(e.filename);let{photo:n}=t;e.error===void 0?e.data!==void 0&&n.develop({filename:e.filename,data:e.data}):n.fail(new w(e.error,C.SNAPSHOT_FAILED))}clear(){if(this.pendingPhotos.size===0)return;let e=new w(`Client destroyed before snapshot completed`,C.SNAPSHOT_FAILED);for(let{photo:t,timeout:n}of this.pendingPhotos.values())clearTimeout(n),t.fail(e);this.pendingPhotos.clear()}validateFilename(e){if(e===``||typeof e!=`string`)throw new w(`Filename must be a non-empty string`,C.INVALID_PARAMETER);if(!this.validExtensions.some(t=>e.toLowerCase().endsWith(t)))throw new w(`Invalid filename: "${e}". Filename must end with one of: ${this.validExtensions.join(`, `)}`,C.INVALID_PARAMETER);if(e.includes(`..`)||e.includes(`/`)||e.includes(`\\`))throw new w(`Filename cannot contain path separators or ".."`,C.INVALID_PARAMETER)}},bt=class{container=null;attach(e){this.container=e}dispatch(e,t,n=!1){let r=new CustomEvent(e,{detail:t,cancelable:n});return this.container?.dispatchEvent(r),r}on(e,t){let n=e=>{let n=e;t({...n.detail,preventDefault:()=>{n.preventDefault()}})};return this.container?.addEventListener(e,n),()=>{this.container?.removeEventListener(e,n)}}},xt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Bezig…`:n===`de`?`Läuft…`:`Working…`}),St=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Mislukt`:n===`de`?`Fehlgeschlagen`:`Failed`}),Ct=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Gelukt`:n===`de`?`Fertig`:`Done`}),wt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Annotaties`:n===`de`?`Anmerkungen`:`Annotations`}),Tt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`AR activeren`:n===`de`?`AR aktivieren`:`Activate AR`}),Et=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Camera resetten`:n===`de`?`Kamera zurücksetzen`:`Reset camera`}),Dt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Naar links draaien`:n===`de`?`Nach links drehen`:`Rotate left`}),Ot=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Naar rechts draaien`:n===`de`?`Nach rechts drehen`:`Rotate right`}),kt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Omlaag kantelen`:n===`de`?`Nach unten kippen`:`Tilt down`}),At=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Omhoog kantelen`:n===`de`?`Nach oben kippen`:`Tilt up`}),jt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Inzoomen`:n===`de`?`Hineinzoomen`:`Zoom in`}),Mt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Uitzoomen`:n===`de`?`Herauszoomen`:`Zoom out`}),Nt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Sluiten`:n===`de`?`Schließen`:`Close`}),Pt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Configureren`:n===`de`?`Konfigurieren`:`Configure`}),Ft=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Volledig scherm`:n===`de`?`Vollbild`:`Fullscreen`}),It=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Sluiten`:n===`de`?`Schließen`:`Close`}),Lt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`QR-code`:n===`de`?`QR-Code`:`QR code`}),Rt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Gebruik de camera van je smartphone om deze QR-code te scannen`:n===`de`?`Verwende die Kamera deines Smartphones, um diesen QR-Code zu scannen`:`Use your smartphone camera to scan this QR code`}),zt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Je telefoon opent het 3D-model in AR-modus.`:n===`de`?`Dein Telefon öffnet das 3D-Modell im AR-Modus.`:`Your phone will open the 3D model in AR mode.`}),Bt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Scan om in AR te bekijken`:n===`de`?`Scannen für AR-Ansicht`:`Scan to view in AR`}),Vt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`We kunnen de QR-code nu niet tonen. Open deze link op je telefoon:`:n===`de`?`Wir können den QR-Code gerade nicht anzeigen. Öffne diesen Link auf deinem Handy:`:`We can't show the QR code right now. Open this link on your phone:`}),Ht=((e={},t={})=>(t.locale??v(),`Screenshot`)),Ut=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Downloaden`:n===`de`?`Herunterladen`:`Downloading`}),Wt=((e={},t={})=>{let n=t.locale??v();return n===`nl`?`Laden mislukt. Ververs de pagina om het opnieuw te proberen.`:n===`de`?`Laden fehlgeschlagen. Lade die Seite neu, um es erneut zu versuchen.`:`Load failed. Refresh the page to try again.`}),Gt={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`},Kt=([e,t,n])=>{let r=document.createElementNS(`http://www.w3.org/2000/svg`,e);return Object.keys(t).forEach(e=>{r.setAttribute(e,String(t[e]))}),n?.length&&n.forEach(e=>{let t=Kt(e);r.appendChild(t)}),r},qt=(e,t={})=>Kt([`svg`,{...Gt,...t},e]),Jt=[[`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`}]],Yt=[[`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`}]],Xt=[[`path`,{d:`m6 9 6 6 6-6`}]],Zt=[[`path`,{d:`m15 18-6-6 6-6`}]],Qt=[[`path`,{d:`m9 18 6-6-6-6`}]],$t=[[`path`,{d:`m18 15-6-6-6 6`}]],en=[[`path`,{d:`M12.75 7.09a3 3 0 0 1 2.16 2.16`}],[`path`,{d:`M17.072 17.072c-1.634 2.17-3.527 3.912-4.471 4.727a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 1.432-4.568`}],[`path`,{d:`m2 2 20 20`}],[`path`,{d:`M8.475 2.818A8 8 0 0 1 20 10c0 1.183-.31 2.377-.81 3.533`}],[`path`,{d:`M9.13 9.13a3 3 0 0 0 3.74 3.74`}]],tn=[[`path`,{d:`M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0`}],[`circle`,{cx:`12`,cy:`10`,r:`3`}]],nn=[[`path`,{d:`M15 3h6v6`}],[`path`,{d:`m21 3-7 7`}],[`path`,{d:`m3 21 7-7`}],[`path`,{d:`M9 21H3v-6`}]],rn=[[`path`,{d:`m14 10 7-7`}],[`path`,{d:`M20 10h-6V4`}],[`path`,{d:`m3 21 7-7`}],[`path`,{d:`M4 14h6v6`}]],an=[[`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`}]],on=[[`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`}]],sn=[[`path`,{d:`M18 6 6 18`}],[`path`,{d:`m6 6 12 12`}]],cn=[[`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`}]],ln=[[`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`}]];function j(e,{size:t=20,strokeWidth:n=1.75}={}){return qt(e,{width:t,height:t,"stroke-width":n})}var M={ar:e=>j(Jt,e),annotations:e=>j(tn,e),annotationsOff:e=>j(en,e),fullscreen:e=>j(nn,e),exitFullscreen:e=>j(rn,e),screenshot:e=>j(Yt,e),tiltUp:e=>j($t,e),tiltDown:e=>j(Xt,e),rotateLeft:e=>j(Zt,e),rotateRight:e=>j(Qt,e),zoomIn:e=>j(cn,e),zoomOut:e=>j(ln,e),reset:e=>j(an,e),configurator:e=>j(on,e),close:e=>j(sn,e)},N=class{element;constructor({variant:e=`default`,size:t=`default`,label:n,icon:r,onClick:i,disabled:a=!1}={}){this.element=document.createElement(`button`),this.element.className=`ui-btn ui-btn--${e} ui-btn--size-${t}`,n!==void 0&&(this.element.setAttribute(`aria-label`,n),this.element.title=n),r===void 0?n!==void 0&&(this.element.textContent=n):this.element.appendChild(r),i&&this.element.addEventListener(`click`,i),this.element.disabled=a}setIcon(e){let t=this.element.querySelector(`svg`);t===null?this.element.appendChild(e):t.replaceWith(e)}},un=class{element;selectCallback=null;constructor(e,t,n){this.element=document.createElement(`div`),this.element.className=`ui-toggle-group`;for(let r=0;r<e.length;r++){let i=e[r],a=document.createElement(`button`);a.className=`ui-toggle-group-item`,a.dataset.value=i,a.textContent=n?.[r]??i,a.dataset.state=i===t?`on`:`off`,a.setAttribute(`aria-pressed`,i===t?`true`:`false`),a.addEventListener(`click`,()=>{this.selectCallback?.(i)}),this.element.appendChild(a)}}setSelected(e){for(let t of this.element.querySelectorAll(`.ui-toggle-group-item`)){let n=t.dataset.value===e;t.dataset.state=n?`on`:`off`,t.setAttribute(`aria-pressed`,n?`true`:`false`)}}onSelect(e){this.selectCallback=e}setEnabled(e){for(let t of this.element.querySelectorAll(`.ui-toggle-group-item`)){let n=e===null||e.includes(t.dataset.value??``);t.disabled=!n,t.setAttribute(`aria-disabled`,n?`false`:`true`)}}},dn=class{element;select;constructor(e,t,n,r,i){this.select=document.createElement(`select`),this.select.className=`ui-native-select`,this.select.dataset.name=e,this.select.setAttribute(`aria-label`,n);let a=document.createElement(`option`);a.value=``,a.disabled=!0,a.textContent=n,this.select.appendChild(a);let o=!1;for(let e=0;e<t.length;e++){let n=t[e],a=document.createElement(`option`);a.value=n,a.textContent=i?.[e]??n,n===r&&(a.selected=!0,o=!0),this.select.appendChild(a)}o||(a.selected=!0);let s=qt(Xt,{width:16,height:16,"stroke-width":2});s.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(s)}setSelected(e){this.select.value=e}onSelect(e){this.select.addEventListener(`change`,()=>{e(this.select.value)})}setEnabled(e){for(let t of this.select.options)t.value!==``&&(t.disabled=e!==null&&!e.includes(t.value))}},fn=class{element;input;valueText;values;options;selectCallback=null;settleCallback=null;constructor(e,t){if(e.length===0)throw Error(`Virtualdisplay: Slider needs at least one value`);this.values=e,this.options=t,this.input=document.createElement(`input`),this.input.type=`range`,this.input.className=`ui-slider-input`,this.input.min=`0`,this.input.max=String(e.length-1),this.input.step=`1`,this.input.setAttribute(`aria-label`,t.label),this.valueText=document.createElement(`span`),this.valueText.className=`ui-slider-value`,this.valueText.setAttribute(`aria-hidden`,`true`);let n=document.createElement(`div`);n.className=`ui-slider-track`,n.appendChild(this.input),n.appendChild(this.buildEnds()),this.element=document.createElement(`div`),this.element.className=`ui-slider`,this.element.appendChild(n),this.element.appendChild(this.valueText);let r=t.initialSelected===void 0?0:e.indexOf(t.initialSelected);this.applyIndex(r===-1?0:r),this.listen()}setSelected(e){let t=this.values.indexOf(e);t!==-1&&this.applyIndex(t)}onSelect(e){this.selectCallback=e}onSettle(e){this.settleCallback=e}listen(){this.input.addEventListener(`input`,()=>{let e=this.values[this.currentIndex];e!==void 0&&(this.applyIndex(this.currentIndex),this.selectCallback?.(e))}),this.input.addEventListener(`change`,()=>{let e=this.values[this.currentIndex];e!==void 0&&this.settleCallback?.(e)})}get currentIndex(){return Number(this.input.value)}applyIndex(e){this.input.value=String(e);let t=this.displayAt(e);this.valueText.textContent=t,this.input.setAttribute(`aria-valuetext`,t);let n=this.values.length===1?100:e/(this.values.length-1)*100;this.element.style.setProperty(`--ui-slider-pct`,`${n}%`)}buildEnds(){let e=document.createElement(`div`);e.className=`ui-slider-ends`,e.setAttribute(`aria-hidden`,`true`);for(let t of[0,this.values.length-1]){let n=document.createElement(`span`);n.textContent=this.labelAt(t),e.appendChild(n)}return e}labelAt(e){return this.options.labels?.[e]??this.values[e]??``}displayAt(e){let t=this.labelAt(e);return this.options.unit===void 0?t:`${t} ${this.options.unit}`}},P={neutral:{50:`oklch(98.5% 0 0)`,100:`oklch(96.5% 0 0)`,200:`oklch(92% 0 0)`,300:`oklch(82% 0 0)`,400:`oklch(70% 0 0)`,500:`oklch(55.5% 0 0)`,600:`oklch(44.5% 0 0)`,700:`oklch(37% 0 0)`,800:`oklch(27% 0 0)`,900:`oklch(21% 0 0)`,950:`oklch(14.5% 0 0)`},white:`oklch(100% 0 0)`,semantic:{error:`oklch(47% 0.17 25)`}},F={px:`1px`,0:`0`,.5:`0.125rem`,1:`0.25rem`,1.5:`0.375rem`,2:`0.5rem`,2.5:`0.625rem`,3:`0.75rem`,3.5:`0.875rem`,4:`1rem`,5:`1.25rem`,6:`1.5rem`,7:`1.75rem`,8:`2rem`,9:`2.25rem`,10:`2.5rem`,12:`3rem`,14:`3.5rem`,16:`4rem`,20:`5rem`,24:`6rem`},I={fontFamily:{sans:[`Mona Sans`,`ui-sans-serif`,`system-ui`,`sans-serif`,`Apple Color Emoji`,`Segoe UI Emoji`,`Segoe UI Symbol`,`Noto Color Emoji`],mono:[`JetBrains Mono`,`ui-monospace`,`monospace`]},fontSize:{xs:`0.75rem`,sm:`0.875rem`,base:`1rem`,lg:`1.125rem`,xl:`1.25rem`,"2xl":`1.5rem`,"3xl":`1.875rem`,"4xl":`2.25rem`},fontWeight:{normal:`400`,medium:`500`,semibold:`600`,bold:`700`},lineHeight:{tight:`1.25`,normal:`1.5`,relaxed:`1.75`}},pn=class{element;constructor(){this.element=document.createElement(`div`),Object.assign(this.element.style,{background:P.white,borderRadius:`var(--radius)`,padding:F[6],boxShadow:`0 ${F[2]} ${F[8]} oklch(0% 0 0 / 20%)`,maxWidth:`20rem`,width:`100%`})}},mn=class{options;card;backdrop;keyHandler=null;constructor(e={}){this.options=e,this.card=new pn,this.backdrop=this.createBackdrop(),this.backdrop.appendChild(this.card.element)}get content(){return this.card.element}open(){document.body.appendChild(this.backdrop),this.keyHandler=e=>{e.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(){let e=document.createElement(`div`);return Object.assign(e.style,{position:`fixed`,inset:F[0],background:`oklch(0% 0 0 / 50%)`,zIndex:`9999`,display:`flex`,alignItems:`center`,justifyContent:`center`}),e.addEventListener(`click`,t=>{t.target===e&&this.close()}),e}},L=I.fontFamily.sans.join(`, `),hn=`
2
+ :root {
3
+ --primary: oklch(5% 0 0);
4
+ --primary-foreground: oklch(100% 0 0);
5
+ --secondary: oklch(92% 0 0);
6
+ --secondary-foreground: oklch(5% 0 0);
7
+ --background: oklch(100% 0 0);
8
+ --foreground: oklch(5% 0 0);
9
+ --border: oklch(92% 0 0);
10
+ --ring: oklch(44% 0 0);
11
+ --radius: 0.625rem;
12
+ --accent: oklch(92% 0 0);
13
+ --accent-foreground: oklch(5% 0 0);
14
+ --muted-foreground: oklch(44% 0 0);
15
+ }
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: ${L};
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: ${L};
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:disabled { opacity: 0.4; cursor: not-allowed; }
92
+ .ui-toggle-group-item:disabled:hover { background: var(--background); border-color: var(--border); }
93
+ .ui-toggle-group-item:active { transform: scale(0.98); }
94
+ .ui-toggle-group-item:focus-visible {
95
+ outline: none;
96
+ border-color: var(--ring);
97
+ box-shadow: 0 0 0 3px oklch(5% 0 0 / 12%);
98
+ }
99
+ .ui-toggle-group-item[data-state="on"] {
100
+ background: var(--primary);
101
+ color: var(--primary-foreground);
102
+ border-color: var(--primary);
103
+ }
104
+ .ui-toggle-group-item[data-state="on"]:hover { background: oklch(10% 0 0); }
105
+
106
+ /* ── Native select ───────────────────────────────────────── */
107
+ .ui-native-select-wrap {
108
+ position: relative;
109
+ display: inline-flex;
110
+ min-inline-size: 8rem;
111
+ }
112
+
113
+ .ui-native-select {
114
+ display: block;
115
+ inline-size: 100%;
116
+ block-size: 2.25rem;
117
+ padding: 0 2.25rem 0 0.75rem;
118
+ border: 1px solid var(--border);
119
+ border-radius: var(--radius);
120
+ background: var(--background);
121
+ appearance: none;
122
+ color: var(--foreground);
123
+ font-family: ${L};
124
+ font-size: 0.875rem;
125
+ font-weight: 400;
126
+ cursor: pointer;
127
+ transition: color 200ms, box-shadow 200ms, border-color 200ms;
128
+ box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
129
+ }
130
+ .ui-native-select:hover { border-color: oklch(85% 0 0); }
131
+ .ui-native-select:focus-visible {
132
+ outline: none;
133
+ border-color: var(--ring);
134
+ box-shadow: 0 0 0 3px oklch(5% 0 0 / 12%);
135
+ }
136
+
137
+ .ui-native-select-icon {
138
+ position: absolute;
139
+ inset-block-start: 50%;
140
+ inset-inline-end: 0.625rem;
141
+ transform: translateY(-50%);
142
+ color: var(--muted-foreground);
143
+ pointer-events: none;
144
+ }
145
+
146
+ /* ── Slider ──────────────────────────────────────────────── */
147
+ .ui-slider {
148
+ display: flex;
149
+ align-items: center;
150
+ gap: 0.75rem;
151
+ inline-size: 100%;
152
+ }
153
+
154
+ .ui-slider-track {
155
+ flex: 1;
156
+ min-inline-size: 0;
157
+ }
158
+
159
+ /* Tabular figures keep the readout and layout steady mid-drag. */
160
+ .ui-slider-value {
161
+ font-family: ${L};
162
+ font-size: 0.875rem;
163
+ font-weight: 600;
164
+ color: var(--foreground);
165
+ font-variant-numeric: tabular-nums;
166
+ white-space: nowrap;
167
+ }
168
+
169
+ .ui-slider-ends {
170
+ display: flex;
171
+ justify-content: space-between;
172
+ font-family: ${L};
173
+ font-size: 0.75rem;
174
+ color: var(--muted-foreground);
175
+ font-variant-numeric: tabular-nums;
176
+ }
177
+
178
+ /* 2.75rem tall: the whole input is the touch target (44px). */
179
+ .ui-slider-input {
180
+ appearance: none;
181
+ display: block;
182
+ inline-size: 100%;
183
+ block-size: 2.75rem;
184
+ margin: 0;
185
+ padding: 0;
186
+ background: transparent;
187
+ cursor: pointer;
188
+ }
189
+ .ui-slider-input:focus-visible { outline: none; }
190
+
191
+ /* --ui-slider-pct is set by the component; it fills the track up to the thumb. */
192
+ .ui-slider-input::-webkit-slider-runnable-track {
193
+ block-size: 0.375rem;
194
+ border-radius: 9999px;
195
+ background: linear-gradient(to right, var(--primary) var(--ui-slider-pct, 0%), var(--secondary) var(--ui-slider-pct, 0%));
196
+ }
197
+ .ui-slider-input::-webkit-slider-thumb {
198
+ appearance: none;
199
+ inline-size: 1.25rem;
200
+ block-size: 1.25rem;
201
+ margin-block-start: -0.4375rem; /* centre the 1.25rem thumb on the 0.375rem track */
202
+ border-radius: 50%;
203
+ border: 2px solid var(--primary);
204
+ background: var(--background);
205
+ box-shadow: 0 1px 3px oklch(5% 0 0 / 20%);
206
+ transition: box-shadow 200ms, border-color 200ms;
207
+ }
208
+ .ui-slider-input:focus-visible::-webkit-slider-thumb {
209
+ border-color: var(--ring);
210
+ box-shadow: 0 0 0 3px oklch(5% 0 0 / 12%);
211
+ }
212
+
213
+ .ui-slider-input::-moz-range-track {
214
+ block-size: 0.375rem;
215
+ border-radius: 9999px;
216
+ background: var(--secondary);
217
+ }
218
+ .ui-slider-input::-moz-range-progress {
219
+ block-size: 0.375rem;
220
+ border-radius: 9999px;
221
+ background: var(--primary);
222
+ }
223
+ .ui-slider-input::-moz-range-thumb {
224
+ inline-size: 1.25rem;
225
+ block-size: 1.25rem;
226
+ border-radius: 50%;
227
+ border: 2px solid var(--primary);
228
+ background: var(--background);
229
+ box-shadow: 0 1px 3px oklch(5% 0 0 / 20%);
230
+ transition: box-shadow 200ms, border-color 200ms;
231
+ }
232
+ .ui-slider-input:focus-visible::-moz-range-thumb {
233
+ border-color: var(--ring);
234
+ box-shadow: 0 0 0 3px oklch(5% 0 0 / 12%);
235
+ }
236
+
237
+ /* ── Annotation layer ───────────────────────────────────── */
238
+ .vd-annotations-layer {
239
+ position: absolute;
240
+ inset-block-start: 0;
241
+ inset-inline-start: 0;
242
+ inline-size: 100%;
243
+ block-size: 100%;
244
+ pointer-events: none;
245
+ overflow: visible !important; /* override CSS2DRenderer inline style */
246
+ }
247
+
248
+ .vd-annotation-anchor {
249
+ position: relative;
250
+ }
251
+
252
+ /* A pin stands on its point: the number on top, a stick down, and a ring on
253
+ the spot. Open, a card with the number and the title takes the number's
254
+ place at the top of the stick. */
255
+ .vd-annotation-anchor--pin {
256
+ display: flex;
257
+ flex-direction: column;
258
+ align-items: center;
259
+ }
260
+ .vd-annotation-head {
261
+ position: relative;
262
+ display: flex;
263
+ justify-content: center;
264
+ }
265
+ /* A light edge around the stick and the ring, as the dot has one, so a pin
266
+ stays visible on a dark surface. */
267
+ .vd-annotation-stick {
268
+ inline-size: 2px;
269
+ block-size: 2rem;
270
+ background: var(--primary);
271
+ box-shadow: 0 0 0 1px var(--background);
272
+ }
273
+ /* Half its height below the anchor's edge, so the ring's centre is the point. */
274
+ .vd-annotation-point {
275
+ box-sizing: border-box;
276
+ inline-size: 0.625rem;
277
+ block-size: 0.625rem;
278
+ margin-block-end: -0.3125rem;
279
+ border-radius: 50%;
280
+ border: 2px solid var(--primary);
281
+ background: var(--background);
282
+ box-shadow: 0 0 0 1px var(--background), 0 1px 2px oklch(5% 0 0 / 20%);
283
+ }
284
+ .vd-annotation-anchor--pin .vd-annotation-marker--open {
285
+ visibility: hidden;
286
+ }
287
+ .vd-annotation-anchor--pin .vd-annotation-popup {
288
+ inset-block-start: auto;
289
+ inset-block-end: 0;
290
+ }
291
+ /* Too close to the top edge, the card hangs down from the head over the
292
+ stick, where above it would be clipped by the frame. */
293
+ .vd-annotation-anchor--pin .vd-annotation-popup--below {
294
+ inset-block-start: 0;
295
+ inset-block-end: auto;
296
+ }
297
+
298
+ .vd-annotation-marker {
299
+ display: flex;
300
+ align-items: center;
301
+ justify-content: center;
302
+ inline-size: 1.75rem;
303
+ block-size: 1.75rem;
304
+ border-radius: 50%;
305
+ border: 2px solid oklch(100% 0 0);
306
+ background: var(--primary);
307
+ color: var(--primary-foreground);
308
+ font-family: ${L};
309
+ font-size: 0.8125rem;
310
+ font-weight: 600;
311
+ cursor: pointer;
312
+ pointer-events: auto;
313
+ box-shadow: 0 2px 8px oklch(5% 0 0 / 20%);
314
+ transition: transform 100ms ease;
315
+ position: relative;
316
+ }
317
+ .vd-annotation-marker:hover { transform: scale(1.1); }
318
+ .vd-annotation-marker:focus-visible {
319
+ outline: 2px solid var(--ring);
320
+ outline-offset: 2px;
321
+ }
322
+
323
+ .vd-annotation-popup {
324
+ position: absolute;
325
+ inset-block-end: calc(100% + 0.5rem);
326
+ inset-inline-start: 50%;
327
+ transform: translateX(-50%);
328
+ background: var(--background);
329
+ color: var(--foreground);
330
+ border: 1px solid var(--border);
331
+ border-radius: var(--radius);
332
+ padding: 0.75rem 1rem;
333
+ /* The popup is absolutely positioned inside the ~28px marker anchor, so
334
+ without an explicit width it shrink-to-fits against that anchor and
335
+ collapses to one word per line. max-content sizes it by its own text,
336
+ capped below. */
337
+ inline-size: max-content;
338
+ max-inline-size: 15rem;
339
+ box-shadow: 0 4px 6px oklch(5% 0 0 / 8%), 0 2px 4px oklch(5% 0 0 / 6%);
340
+ pointer-events: auto;
341
+ white-space: normal;
342
+ }
343
+ .vd-annotation-popup:focus { outline: none; }
344
+
345
+ /* Flipped below the marker when the popup would clip the container's top
346
+ edge; the layer positions it at open time and on the render cadence. */
347
+ .vd-annotation-popup--below {
348
+ inset-block-end: auto;
349
+ inset-block-start: calc(100% + 0.5rem);
350
+ }
351
+
352
+ .vd-annotation-popup-close {
353
+ position: absolute;
354
+ inset-block-start: 0.375rem;
355
+ inset-inline-end: 0.375rem;
356
+ display: flex;
357
+ align-items: center;
358
+ justify-content: center;
359
+ inline-size: 1.25rem;
360
+ block-size: 1.25rem;
361
+ padding: 0;
362
+ border: none;
363
+ border-radius: calc(var(--radius) - 4px);
364
+ background: transparent;
365
+ color: var(--muted-foreground);
366
+ cursor: pointer;
367
+ pointer-events: auto;
368
+ }
369
+ .vd-annotation-popup-close:hover {
370
+ color: var(--foreground);
371
+ background: var(--secondary);
372
+ }
373
+ .vd-annotation-popup-close:focus-visible {
374
+ outline: 2px solid var(--ring);
375
+ outline-offset: 1px;
376
+ }
377
+ .vd-annotation-popup-close svg {
378
+ inline-size: 0.875rem;
379
+ block-size: 0.875rem;
380
+ }
381
+
382
+ @media (prefers-reduced-motion: no-preference) {
383
+ .vd-annotation-popup {
384
+ animation: vd-popup-in 150ms ease;
385
+ }
386
+ }
387
+
388
+ /* Opacity only: the layer sets the popup's transform inline to clamp it
389
+ inside the container, and a keyframe animating transform would override
390
+ that for its duration and make the popup jump at the end. */
391
+ @keyframes vd-popup-in {
392
+ from { opacity: 0; }
393
+ to { opacity: 1; }
394
+ }
395
+
396
+ .vd-annotation-popup-title {
397
+ font-family: ${L};
398
+ font-size: 0.875rem;
399
+ font-weight: 600;
400
+ line-height: 1.25rem;
401
+ /* Keep the title clear of the absolutely positioned close button. */
402
+ padding-inline-end: 1.5rem;
403
+ }
404
+
405
+ .vd-annotation-popup-number {
406
+ display: inline-flex;
407
+ align-items: center;
408
+ justify-content: center;
409
+ inline-size: 1.25rem;
410
+ block-size: 1.25rem;
411
+ margin-inline-end: 0.5rem;
412
+ border-radius: 50%;
413
+ background: var(--primary);
414
+ color: var(--primary-foreground);
415
+ font-size: 0.75rem;
416
+ font-weight: 600;
417
+ vertical-align: middle;
418
+ }
419
+
420
+ /* A brief card shows its title, a button that opens the description. */
421
+ .vd-annotation-popup--brief .vd-annotation-popup-description {
422
+ display: none;
423
+ }
424
+ button.vd-annotation-popup-title {
425
+ display: block;
426
+ inline-size: 100%;
427
+ margin: 0;
428
+ /* A button's own padding would set the title off the description below it;
429
+ the end keeps the room the close button needs. */
430
+ padding-block: 0;
431
+ padding-inline-start: 0;
432
+ border: none;
433
+ background: none;
434
+ color: inherit;
435
+ text-align: start;
436
+ cursor: pointer;
437
+ }
438
+ button.vd-annotation-popup-title:focus-visible {
439
+ outline: 2px solid var(--ring);
440
+ outline-offset: 2px;
441
+ border-radius: calc(var(--radius) - 4px);
442
+ }
443
+
444
+ .vd-annotation-popup-description {
445
+ font-family: ${L};
446
+ font-size: 0.8125rem;
447
+ font-weight: 400;
448
+ line-height: 1.125rem;
449
+ color: var(--muted-foreground);
450
+ margin-block-start: 0.25rem;
451
+ }
452
+
453
+ /* ── QR modal ────────────────────────────────────────────── */
454
+ /* The slot the QR renders into. While loading it is a calm pulsing
455
+ placeholder of the same size, so the modal opens instantly and the QR
456
+ swaps in without any layout shift. */
457
+ .ui-qr-slot {
458
+ inline-size: 6rem;
459
+ block-size: 6rem;
460
+ border-radius: 0.25rem;
461
+ overflow: hidden;
462
+ }
463
+
464
+ .ui-qr-slot img {
465
+ inline-size: 100%;
466
+ block-size: 100%;
467
+ display: block;
468
+ }
469
+
470
+ .ui-qr-slot--loading {
471
+ background: var(--secondary);
472
+ }
473
+
474
+ @media (prefers-reduced-motion: no-preference) {
475
+ .ui-qr-slot--loading {
476
+ animation: vd-qr-pulse 1.6s ease-in-out infinite;
477
+ }
478
+ }
479
+
480
+ @keyframes vd-qr-pulse {
481
+ 0%, 100% { opacity: 1; }
482
+ 50% { opacity: 0.55; }
483
+ }
484
+ `,gn=!1;function _n(){if(gn||typeof document>`u`)return;gn=!0;let e=document.createElement(`style`);e.id=`vd-ui-vanilla`,e.textContent=hn,document.head.appendChild(e)}var vn=I.fontFamily.sans.join(`, `),yn=class{qrLib=null;dialog=null;qrSlot=null;show(){this.hide(),_n(),this.dialog=new mn({onClose:()=>{this.dialog=null,this.qrSlot=null}}),Object.assign(this.dialog.content.style,{display:`flex`,flexDirection:`column`,alignItems:`center`,gap:F[3],fontFamily:vn}),this.dialog.content.appendChild(this.createText(Bt(),{fontSize:I.fontSize.base,fontWeight:I.fontWeight.semibold,color:P.neutral[900]})),this.dialog.content.appendChild(this.createText(Rt(),{fontSize:I.fontSize.sm,color:P.neutral[600]})),this.qrSlot=this.createQrSlot(),this.dialog.content.appendChild(this.qrSlot),this.dialog.content.appendChild(this.createText(zt(),{fontSize:I.fontSize.xs,color:P.neutral[500]}));let e=new N({variant:`outline`,label:It(),onClick:()=>{this.hide()}});this.dialog.content.appendChild(e.element),this.dialog.open()}async update(t){let n;try{this.qrLib??=await Promise.resolve().then(()=>e.n(require("./browser-7qZ1KQYo.cjs").default,1)),n=await this.qrLib.toDataURL(t,{width:256,margin:4,errorCorrectionLevel:`M`,color:{dark:`#000000`,light:`#ffffff`}})}catch(e){throw this.showLink(t),e}return this.qrSlot!==null&&(this.qrSlot.classList.remove(`ui-qr-slot--loading`),this.qrSlot.replaceChildren(this.createQrImage(n)),!0)}showLink(e){this.qrSlot!==null&&(this.qrSlot.classList.remove(`ui-qr-slot--loading`),this.qrSlot.replaceChildren(this.createText(Vt(),{fontSize:I.fontSize.sm,color:P.neutral[600]}),this.createText(e,{fontSize:I.fontSize.xs,color:P.neutral[900],overflowWrap:`anywhere`,userSelect:`all`})))}hide(){this.dialog?.close(),this.dialog=null,this.qrSlot=null}createText(e,t){let n=document.createElement(`p`);return n.textContent=e,Object.assign(n.style,{margin:`0`,textAlign:`center`,...t}),n}createQrSlot(){let e=document.createElement(`div`);return e.className=`ui-qr-slot ui-qr-slot--loading`,e}createQrImage(e){let t=document.createElement(`img`);return t.src=e,t.alt=Lt(),t}};function bn(e){let t=Math.max(0,Math.min(1,e));return t*t*(3-2*t)}function xn(e,t,n,r,i,a){let[o,s,c]=e,l=Math.cos(t),u=Math.sin(t),ee=l*o+u*c,d=-u*o+l*c,f=Math.cos(n),p=Math.sin(n),te=f*s-p*d,ne=p*s+f*d,m=.55;return[r+ee*a*m,i-te*a*m,ne]}function Sn(e,t,n){e.beginPath(),e.moveTo(t[0],t[1]),e.lineTo(n[0],n[1]),e.strokeStyle=`#000`,e.lineWidth=2,e.stroke()}function Cn(e,t,n,r,i){let a=t(n),o=t(r);Sn(e,a,[a[0]+(o[0]-a[0])*i,a[1]+(o[1]-a[1])*i,a[2]])}var R=[-1,-1,1],z=[1,-1,1],B=[1,-1,-1],V=[-1,-1,-1],H=[-1,1,1],U=[1,1,1],W=[1,1,-1],G=[-1,1,-1],K=[[R,z],[z,B],[B,V],[V,R],[R,H],[z,U],[B,W],[V,G],[H,U],[U,W],[W,G],[G,H]];function wn(e){let t=e%6/6,n=K.length;return t<.35?bn(t/.35)*n:t<.55?n:t<.9?(1-bn((t-.55)/.35))*n:0}function Tn(e,{width:t,height:n},r){let i=t/2,a=n*.44,o=Math.min(t,n)*.08,s=e=>xn(e,.785,.615,i,a,o),c=wn(r);e.shadowBlur=5,e.shadowColor=`rgba(30,30,30,0.08)`;for(let t=0;t<K.length&&!(t>=c);t++){let n=K[t];if(n===void 0)continue;let r=Math.min(1,c-t);Cn(e,s,n[0],n[1],r)}e.shadowBlur=0}var En=400,Dn=3e4,On=`-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif`;function kn(){let e=document.createElement(`div`);Object.assign(e.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`});let t=document.createElement(`canvas`);Object.assign(t.style,{width:`100%`,height:`100%`,position:`absolute`,inset:`0`});let n=document.createElement(`div`);Object.assign(n.style,{position:`absolute`,top:`56%`,left:`0`,right:`0`,textAlign:`center`,pointerEvents:`none`});let r=document.createElement(`span`);Object.assign(r.style,{fontSize:`13px`,fontWeight:`400`,color:`#000`,fontVariantNumeric:`tabular-nums`,fontFamily:On});let i=document.createElement(`span`);return Object.assign(i.style,{fontSize:`13px`,color:`#000`,fontFamily:On}),i.textContent=Ut(),n.appendChild(r),n.appendChild(i),e.appendChild(t),e.appendChild(n),{overlay:e,canvas:t,pctEl:r,phaseEl:i}}var An=class{overlay;canvas;ctx;pctEl;phaseEl;animationId=null;showTimerId=null;noSignalTimerId=null;startTime;hidden=!1;visible=!1;errored=!1;noSignalErrored=!1;constructor(e){this.startTime=performance.now();let t=kn();this.overlay=t.overlay,this.canvas=t.canvas,this.pctEl=t.pctEl,this.phaseEl=t.phaseEl,e.appendChild(this.overlay),this.ctx=this.canvas.getContext(`2d`),this.ctx!==null&&(this.sizeCanvas(),this.tick()),this.showTimerId=setTimeout(()=>{this.reveal()},En),this.noSignalTimerId=setTimeout(()=>{this.hidden||(this.noSignalErrored=!0,this.showError(Wt()))},Dn)}viewerAlive(){this.cancelNoSignalTimer(),this.noSignalErrored&&this.recoverFromNoSignal()}recoverFromNoSignal(){this.noSignalErrored=!1,this.errored=!1,this.pctEl.textContent=``,this.phaseEl.textContent=Ut(),this.phaseEl.style.color=`#000`,this.ctx!==null&&this.animationId===null&&!this.hidden&&this.tick()}updateProgress(e,t){this.cancelNoSignalTimer(),!(this.hidden||this.errored)&&(this.pctEl.textContent=`${Math.round(e)}%`,this.phaseEl.textContent=t===``?``:` \u00B7 ${t}`)}showError(e){if(this.cancelNoSignalTimer(),this.hidden=!1,this.errored=!0,this.animationId!==null&&(cancelAnimationFrame(this.animationId),this.animationId=null),this.ctx!==null){let e=Math.min(devicePixelRatio,2),t=this.canvas.width/e,n=this.canvas.height/e;this.ctx.fillStyle=`#fff`,this.ctx.fillRect(0,0,t*e,n*e)}this.pctEl.textContent=``,this.phaseEl.textContent=e,this.phaseEl.style.color=`#b91c1c`,this.reveal()}hide(){this.hidden||(this.hidden=!0,this.cancelShowTimer(),this.visible?(this.overlay.style.opacity=`0`,this.overlay.addEventListener(`transitionend`,()=>{this.destroy()},{once:!0}),setTimeout(()=>{this.destroy()},500)):this.destroy())}destroy(){this.cancelShowTimer(),this.cancelNoSignalTimer(),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)}cancelNoSignalTimer(){this.noSignalTimerId!==null&&(clearTimeout(this.noSignalTimerId),this.noSignalTimerId=null)}sizeCanvas(){if(this.ctx===null)return;let e=Math.min(devicePixelRatio,2),t=this.overlay.clientWidth||440,n=this.overlay.clientHeight||360;this.canvas.width=t*e,this.canvas.height=n*e,this.ctx.scale(e,e),this.ctx.lineCap=`round`,this.ctx.lineJoin=`round`}tick=()=>{this.hidden||(this.drawFrame(),this.animationId=requestAnimationFrame(this.tick))};drawFrame(){if(this.ctx===null)return;let e=this.canvas.width/Math.min(devicePixelRatio,2),t=this.canvas.height/Math.min(devicePixelRatio,2),n=(performance.now()-this.startTime)/1e3;this.ctx.fillStyle=`#fff`,this.ctx.fillRect(0,0,e,t),Tn(this.ctx,{width:e,height:t},n)}},jn=class{options;element;arBtn=null;fullscreenBtn=null;annotationsBtn=null;annotationsShown=!1;onFullscreenChange;constructor(e){this.options=e,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)}setFullscreenIcon(e){this.fullscreenBtn!==null&&this.fullscreenBtn.setIcon(e?M.exitFullscreen():M.fullscreen())}syncButton(e,t,n){if(t&&e===null){let e=n();return this.element.appendChild(e.element),e}return!t&&e!==null?(e.element.remove(),null):e}applySettings(e){this.arBtn=this.syncButton(this.arBtn,e.ar!==!1&&this.options.onAr!==void 0,()=>new N({variant:`outline`,size:`icon`,label:Tt(),icon:M.ar(),onClick:()=>{this.options.onAr?.()}})),this.fullscreenBtn=this.syncButton(this.fullscreenBtn,e.fullscreen!==!1&&this.options.onFullscreen!==void 0,()=>new N({variant:`outline`,size:`icon`,label:Ft(),icon:M.fullscreen(),onClick:()=>{this.options.onFullscreen?.()}}));let t=e.annotations===`toggle-shown`||e.annotations===`toggle-hidden`;this.annotationsBtn=this.syncButton(this.annotationsBtn,t&&this.options.onAnnotationsToggle!==void 0,()=>{this.annotationsShown=e.annotations===`toggle-shown`;let t=new N({variant:`outline`,size:`icon`,label:wt(),icon:this.annotationsShown?M.annotations():M.annotationsOff(),onClick:()=>{this.flipAnnotations()}});return t.element.setAttribute(`aria-pressed`,String(this.annotationsShown)),t})}flipAnnotations(){this.annotationsShown=!this.annotationsShown,this.annotationsBtn?.element.setAttribute(`aria-pressed`,String(this.annotationsShown)),this.annotationsBtn?.setIcon(this.annotationsShown?M.annotations():M.annotationsOff()),this.options.onAnnotationsToggle?.(this.annotationsShown)}destroy(){document.removeEventListener(`fullscreenchange`,this.onFullscreenChange)}},q=.5,Mn=class e{element;constructor(t,n){this.element=Object.assign(document.createElement(`div`),{className:`vd-camera-controls`});let r={targetRotation:n.rotation,targetTilt:n.tilt,targetZoom:n.zoom,thetaOffset:0},i=Ln(t,n,r);n.onChange(e=>{r.targetRotation=e.rotation-r.thetaOffset,r.targetTilt=e.tilt,r.targetZoom=e.zoom,Rn(i,n,e)}),this.element.appendChild(e.buildZoom(i.zoomOut,i.zoomIn)),this.element.appendChild(e.buildDpad(i.tiltUp,i.rotateLeft,i.reset,i.rotateRight,i.tiltDown))}static buildZoom(e,t){let n=document.createElement(`div`);return n.className=`vd-zoom`,n.appendChild(e.element),n.appendChild(t.element),n}static buildDpad(e,t,n,r,i){let a=document.createElement(`div`);a.className=`vd-dpad`;for(let[o,s]of[[e,`up`],[t,`left`],[n,`center`],[r,`right`],[i,`down`]])o.element.classList.add(`vd-dpad-${s}`),a.appendChild(o.element);return a}};function Nn(e,t){let n=e;for(;n<t;)n+=360;for(;n>=t+360;)n-=360;return n}function Pn(e,t,n){let r=Nn(e,t);return r<=n?r:r-n<=t+360-r?n:t}function J(e,t,n){return new N({variant:`outline`,size:`icon`,label:e,icon:t,onClick:n})}function Fn(e,t){return Math.max(e.limits?.minZoom??1,Math.min(e.limits?.maxZoom??1/0,t))}function In(e,t){let n=e.limits?.minRotate,r=e.limits?.maxRotate;return n===void 0||r===void 0||r-n>=360?t:Pn(t,n,r)}function Y(e,t,n,r){let i=t.limits?.minTilt,a=t.limits?.maxTilt;if(i!==void 0||a!==void 0){n.targetTilt=Math.max(i??0,Math.min(a??180,n.targetTilt+r)),e.tilt(n.targetTilt).set();return}let o=n.targetTilt+r;o>180||o<0?(n.targetTilt=o>180?360-o:-o,n.thetaOffset=(n.thetaOffset+180)%360,e.tilt(n.targetTilt).rotate(n.targetRotation+n.thetaOffset).set()):(n.targetTilt=o,e.tilt(n.targetTilt).set())}function Ln(e,t,n){let r=r=>{n.targetZoom=Fn(t,n.targetZoom+r),e.zoom(n.targetZoom).set()},i=r=>{n.targetRotation=In(t,n.targetRotation+r),e.rotate(n.targetRotation+n.thetaOffset).set()};return{zoomOut:J(Mt(),M.zoomOut(),()=>{r(-10)}),zoomIn:J(jt(),M.zoomIn(),()=>{r(10)}),tiltUp:J(At(),M.tiltUp(),()=>{Y(e,t,n,-15)}),rotateLeft:J(Dt(),M.rotateLeft(),()=>{i(-15)}),reset:J(Et(),M.reset(),()=>{n.thetaOffset=0,e.reset()}),rotateRight:J(Ot(),M.rotateRight(),()=>{i(15)}),tiltDown:J(kt(),M.tiltDown(),()=>{Y(e,t,n,15)})}}function Rn(e,t,n){let r=t.limits;if(r===void 0)return;e.zoomOut.element.disabled=r.minZoom!==void 0&&n.zoom<=r.minZoom+q,e.zoomIn.element.disabled=r.maxZoom!==void 0&&n.zoom>=r.maxZoom-q,e.tiltUp.element.disabled=r.minTilt!==void 0&&n.tilt<=r.minTilt+q,e.tiltDown.element.disabled=r.maxTilt!==void 0&&n.tilt>=r.maxTilt-q;let{minRotate:i,maxRotate:a}=r;if(i===void 0||a===void 0||a-i>=360){e.rotateLeft.element.disabled=!1,e.rotateRight.element.disabled=!1;return}let o=Nn(n.rotation,i);e.rotateLeft.element.disabled=o<=i+q,e.rotateRight.element.disabled=o>=a-q}var X={SELECT:`vd:select`,SELECTED:`vd:selected`,FOCUS_CHANGE:`vd:focus-change`,CONFIGURATION_CHANGE:`vd:configuration-change`,CONFIGURATION_SUBMIT:`vd:configuration-submit`},zn={mm:1,cm:10,m:1e3,in:25.4},Bn=3;function Vn(e){let t=e.stepMm/zn[e.displayUnit];for(let e=0;e<=Bn;e++){let n=t*10**e;if(Math.abs(n-Math.round(n))<1e-9)return e}return Bn}function Hn(e,t,n){let r=Vn(t),i=e/zn[t.displayUnit];return new Intl.NumberFormat(n,{minimumFractionDigits:r,maximumFractionDigits:r}).format(i)}function Un(e,t,n,r,i,a,o){let s=v(),c=e.values.map(e=>Hn(Number(e),t,s)),l=e.values.find(t=>n.getValue(e.name,t)?.isSelected===!0)??e.defaultValue,u=new fn(e.values,{label:e.name,labels:c,unit:t.displayUnit,...l!==void 0&&{initialSelected:l}});return u.onSelect(t=>{i(e.name,t)}),u.onSettle(t=>{r.dispatch(X.SELECT,{attribute:e.name,value:t},!0).defaultPrevented||a(e.name,t)}),o(e.name,t=>{u.setSelected(t.value),r.dispatch(X.SELECTED,{attribute:e.name,value:t.value})}),{element:u.element,setSelectable:()=>{}}}var Wn=5,Gn=0;function Kn(e,t,n,r,i,a){let o=document.createElement(`div`);o.className=`vd-attribute`,o.dataset.name=e.name;let s=document.createElement(`span`);s.className=`vd-attribute-label`,s.textContent=S(e.name),s.id=`vd-attribute-label-${Gn++}`,o.appendChild(s),o.setAttribute(`role`,`group`),o.setAttribute(`aria-labelledby`,s.id);let c=e=>{o.style.display=e?`none`:``},l=e.dimension===void 0?qn(e,t,n,r,a):Un(e,e.dimension,t,n,i,r,a);return o.appendChild(l.element),{element:o,setSelectable:l.setSelectable,setHidden:c}}function qn(e,t,n,r,i){let a=e.values.find(n=>t.getValue(e.name,n)?.isSelected===!0),o=e.values.map(t=>Fe(t,e.labels)),s=e.values.length<=Wn?new un(e.values,a,o):new dn(e.name,e.values,S(e.name),a,o);return s.onSelect(t=>{n.dispatch(X.SELECT,{attribute:e.name,value:t},!0).defaultPrevented||r(e.name,t)}),i(e.name,t=>{s.setSelected(t.value),n.dispatch(X.SELECTED,{attribute:e.name,value:t.value})}),{element:s.element,setSelectable:e=>{s.setEnabled(e)}}}var Jn=80,Yn=2500,Xn=class{configuration;element;priceEl;vatEl;button;unsubscribe;state=`idle`;resetTimer;constructor(e){this.configuration=e,this.element=document.createElement(`div`),this.element.className=`vd-commerce vd-hidden`;let t=document.createElement(`div`);t.className=`vd-commerce-price`,this.priceEl=document.createElement(`span`),this.priceEl.className=`vd-price`,this.vatEl=document.createElement(`span`),this.vatEl.className=`vd-vat`,t.append(this.priceEl,this.vatEl),this.button=new N({variant:`default`,onClick:()=>{this.handleSubmit()}}),this.button.element.classList.add(`vd-cta`,`vd-hidden`),this.element.append(t,this.button.element),this.unsubscribe=this.configuration.onRender(()=>{this.update()}),this.update()}update(){this.renderPrice(this.configuration.current),this.renderButton();let e=this.configuration.current!==void 0||this.configuration.submitEnabled;this.element.classList.toggle(`vd-hidden`,!e)}destroy(){this.unsubscribe(),this.resetTimer!==void 0&&clearTimeout(this.resetTimer),this.element.remove()}renderPrice(e){e===void 0?(this.priceEl.textContent=``,this.vatEl.textContent=``):(this.priceEl.textContent=Zn(e.price,e.currency),this.vatEl.textContent=Z(this.configuration.vatDisplay))}renderButton(){let e=this.configuration.submitEnabled;this.button.element.classList.toggle(`vd-hidden`,!e),e&&this.state===`idle`&&this.setButtonText(Z(this.configuration.buttonLabel))}async handleSubmit(){if(this.state!==`busy`){this.setState(`busy`,xt());try{await this.configuration.submit(),this.setState(`success`,Ct())}catch(e){if(e instanceof DOMException&&e.name===`AbortError`){this.setState(`idle`,Z(this.configuration.buttonLabel));return}A.warn(`Commerce submit failed`,{error:e}),this.setState(`failed`,St())}this.scheduleReset()}}scheduleReset(){this.resetTimer!==void 0&&clearTimeout(this.resetTimer),this.resetTimer=setTimeout(()=>{this.state=`idle`,this.update()},Yn)}setState(e,t){this.state=e,this.element.dataset.submit=e,this.button.element.disabled=e===`busy`,this.setButtonText(t)}setButtonText(e){this.button.element.textContent=e,this.button.element.setAttribute(`aria-label`,e)}};function Z(e){return(e??``).slice(0,Jn)}function Zn(e,t){try{let n=new Intl.NumberFormat(v(),{style:`currency`,currency:t}),r=n.resolvedOptions().maximumFractionDigits??2;return n.format(e/10**r)}catch{return`${t} ${(e/100).toFixed(2)}`}}var Qn=class{slot=null;panel=null;attach(e,t){this.panel=t,t.style.display=`none`,this.slot=document.createElement(`div`),this.slot.className=`vd-slot-bottom-left`,this.slot.appendChild(t),e.appendChild(this.slot)}setVisible(e){this.panel!==null&&(this.panel.style.display=e?`flex`:`none`)}destroy(){this.slot?.remove(),this.slot=null,this.panel=null}},$n=572,er=class{actionBarSlot;element=null;body=null;openButton=null;closeButton=null;container=null;observer=null;collapsible=!1;expanded=!0;visible=!1;constructor(e){this.actionBarSlot=e}attach(e,t){this.container=e,t.classList.add(`vd-attributes-sidebar`),this.closeButton=new N({variant:`ghost`,size:`icon-sm`,label:Nt(),icon:M.close({size:18}),onClick:()=>{this.expanded=!1,this.render()}});let n=document.createElement(`div`);n.className=`vd-sidebar-header`,n.appendChild(this.closeButton.element),this.body=document.createElement(`div`),this.body.className=`vd-sidebar-body`,this.body.appendChild(t),this.element=document.createElement(`div`),this.element.className=`vd-sidebar vd-hidden`,this.element.append(n,this.body),e.appendChild(this.element),this.openButton=new N({variant:`outline`,size:`icon`,label:Pt(),icon:M.configurator({size:18}),onClick:()=>{this.expanded=!0,this.render()}}),this.openButton.element.classList.add(`vd-configurator-toggle`,`vd-hidden`),this.actionBarSlot.appendChild(this.openButton.element),this.observe()}setVisible(e){this.visible=e,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-permanent`),this.container=null}observe(){typeof ResizeObserver<`u`&&this.container!==null&&(this.observer=new ResizeObserver(e=>{let t=e[0]?.contentRect.width??0;this.setCollapsible(t>0&&t<$n)}),this.observer.observe(this.container))}setCollapsible(e){e!==this.collapsible&&(this.collapsible=e,this.expanded=!e,this.render())}render(){if(this.element===null||this.openButton===null||this.closeButton===null||this.container===null)return;let e=this.visible&&this.expanded,t=this.visible&&!this.expanded;this.element.classList.toggle(`vd-hidden`,!this.visible),this.element.classList.toggle(`vd-sidebar-collapsed`,t),this.openButton.element.classList.toggle(`vd-hidden`,!t),this.closeButton.element.style.display=this.collapsible?``:`none`,this.container.classList.toggle(`vd-layout-sidebar-right`,e),this.container.classList.toggle(`vd-layout-sidebar-permanent`,e&&!this.collapsible)}},tr=class{attach(e,t){}setVisible(e){}destroy(){}},nr={"inframe-bottom-left":()=>new Qn,"sidebar-right":e=>new er(e),hidden:()=>new tr};function rr(e,t){return(nr[e??``]??(()=>new Qn))(t)}var Q=I.fontFamily.sans.join(`, `),$=`
485
+ position: absolute;
486
+ display: flex;
487
+ z-index: 10;
488
+ transition: inset-inline-end 0.18s ease;
489
+ `,ir=`
490
+ /* Override browser's default black fullscreen backdrop */
491
+ .vd-container:fullscreen {
492
+ background: oklch(100% 0 0);
493
+ }
494
+
495
+ /* Layout slots — four corners */
496
+ .vd-slot-top-right {
497
+ ${$}
498
+ inset-block-start: ${F[3]};
499
+ inset-inline-end: ${F[3]};
500
+ flex-direction: column;
501
+ align-items: flex-end;
502
+ gap: ${F[1.5]};
503
+ }
504
+
505
+ .vd-slot-bottom-left {
506
+ ${$}
507
+ inset-block-end: ${F[3]};
508
+ inset-inline-start: ${F[3]};
509
+ flex-direction: column;
510
+ align-items: flex-start;
511
+ gap: ${F[1.5]};
512
+ }
513
+
514
+ .vd-slot-bottom-right {
515
+ ${$}
516
+ inset-block-end: ${F[3]};
517
+ inset-inline-end: ${F[3]};
518
+ flex-direction: row;
519
+ gap: ${F[1.5]};
520
+ }
521
+
522
+ /* Component styles — no positioning */
523
+ .vd-camera-controls {
524
+ display: flex;
525
+ flex-direction: column;
526
+ gap: ${F[1]};
527
+ background: color-mix(in oklch, ${P.white} 85%, transparent);
528
+ backdrop-filter: blur(8px);
529
+ border-radius: ${F[2]};
530
+ padding: ${F[2]};
531
+ }
532
+
533
+ .vd-zoom {
534
+ display: flex;
535
+ gap: ${F[.5]};
536
+ }
537
+
538
+ .vd-dpad {
539
+ display: grid;
540
+ grid-template-columns: repeat(3, ${F[9]});
541
+ grid-template-rows: repeat(3, ${F[9]});
542
+ gap: ${F[.5]};
543
+ }
544
+
545
+ .vd-dpad-up { grid-column: 2; grid-row: 1; }
546
+ .vd-dpad-left { grid-column: 1; grid-row: 2; }
547
+ .vd-dpad-center { grid-column: 2; grid-row: 2; }
548
+ .vd-dpad-right { grid-column: 3; grid-row: 2; }
549
+ .vd-dpad-down { grid-column: 2; grid-row: 3; }
550
+
551
+ .vd-attributes {
552
+ display: flex;
553
+ flex-direction: column;
554
+ gap: ${F[3]};
555
+ background: color-mix(in oklch, ${P.white} 85%, transparent);
556
+ backdrop-filter: blur(8px);
557
+ border: 1px solid color-mix(in oklch, ${P.neutral[900]} 8%, transparent);
558
+ border-radius: ${F[3]};
559
+ padding: ${F[3]};
560
+ box-shadow: 0 ${F[1]} ${F[4]} color-mix(in oklch, ${P.neutral[900]} 6%, transparent);
561
+ font-family: ${Q};
562
+ }
563
+
564
+ .vd-attribute {
565
+ display: flex;
566
+ flex-direction: column;
567
+ gap: ${F[1.5]};
568
+ }
569
+
570
+ /* Micro-label: recedes so the controls lead. */
571
+ .vd-attribute-label {
572
+ font-size: ${I.fontSize.xs};
573
+ font-weight: ${I.fontWeight.medium};
574
+ color: ${P.neutral[500]};
575
+ text-transform: uppercase;
576
+ letter-spacing: 0.05em;
577
+ font-family: ${Q};
578
+ }
579
+
580
+ /* sidebar-right layout — a docked, full-height right panel */
581
+ .vd-container { --vd-sidebar-width: 300px; }
582
+
583
+ .vd-container > iframe {
584
+ width: 100%;
585
+ height: 100%;
586
+ border: none;
587
+ display: block;
588
+ }
589
+
590
+ /* Permanently docked panel (wide embeds, not collapsible): the viewer fills the
591
+ remaining width instead of the panel floating over it. On narrow embeds the
592
+ panel is a temporary tap-to-reveal overlay instead (vd-layout-sidebar-right
593
+ without -permanent), where covering part of the model briefly is expected. */
594
+ .vd-container.vd-layout-sidebar-permanent > iframe {
595
+ width: calc(100% - var(--vd-sidebar-width));
596
+ }
597
+
598
+ .vd-hidden { display: none !important; }
599
+
600
+ /* the "open configurator" toggle joins the shared bottom-right slot as a flex child;
601
+ order pins it after AR/fullscreen regardless of DOM insertion order (MAPPING data,
602
+ which mounts this button, always arrives before the toolbar mounts on ready). */
603
+ .vd-configurator-toggle { order: 1; }
604
+
605
+ .vd-sidebar {
606
+ position: absolute;
607
+ inset-block: 0;
608
+ inset-inline-end: 0;
609
+ inline-size: var(--vd-sidebar-width);
610
+ z-index: 11;
611
+ display: flex;
612
+ flex-direction: column;
613
+ background: color-mix(in oklch, ${P.white} 90%, transparent);
614
+ backdrop-filter: blur(10px);
615
+ border-inline-start: 1px solid color-mix(in oklch, ${P.neutral[900]} 8%, transparent);
616
+ box-shadow: -${F[1]} 0 ${F[4]} color-mix(in oklch, ${P.neutral[900]} 5%, transparent);
617
+ }
618
+
619
+ @media (prefers-reduced-motion: no-preference) {
620
+ .vd-sidebar { transition: transform 0.18s ease; }
621
+ }
622
+
623
+ .vd-sidebar-collapsed { transform: translateX(100%); }
624
+
625
+ .vd-sidebar-header {
626
+ display: flex;
627
+ justify-content: flex-end;
628
+ padding: ${F[1.5]} ${F[1.5]} 0;
629
+ }
630
+
631
+ .vd-sidebar-body {
632
+ flex: 1;
633
+ overflow-y: auto;
634
+ padding: ${F[4]};
635
+ }
636
+
637
+ /* attributes inside the sidebar: flat and full-width — the panel provides the frosting */
638
+ .vd-attributes.vd-attributes-sidebar {
639
+ background: transparent;
640
+ backdrop-filter: none;
641
+ border: none;
642
+ border-radius: 0;
643
+ padding: 0;
644
+ box-shadow: none;
645
+ gap: ${F[5]};
646
+ }
647
+
648
+ /* while the panel is open, keep the corner controls clear of it */
649
+ .vd-layout-sidebar-right .vd-slot-top-right { inset-inline-end: calc(var(--vd-sidebar-width) + ${F[3]}); }
650
+ .vd-layout-sidebar-right .vd-slot-bottom-right { inset-inline-end: calc(var(--vd-sidebar-width) + ${F[3]}); }
651
+
652
+ /* Price + CTA — sit under the attribute controls, separated by a hairline */
653
+ .vd-commerce {
654
+ display: flex;
655
+ flex-direction: column;
656
+ gap: ${F[2]};
657
+ padding-block-start: ${F[3]};
658
+ border-block-start: 1px solid color-mix(in oklch, ${P.neutral[900]} 8%, transparent);
659
+ font-family: ${Q};
660
+ }
661
+
662
+ .vd-commerce-price {
663
+ display: flex;
664
+ align-items: baseline;
665
+ gap: ${F[1.5]};
666
+ }
667
+
668
+ .vd-price {
669
+ font-size: ${I.fontSize.lg};
670
+ font-weight: ${I.fontWeight.semibold};
671
+ color: ${P.neutral[900]};
672
+ }
673
+
674
+ .vd-vat {
675
+ font-size: ${I.fontSize.xs};
676
+ color: ${P.neutral[500]};
677
+ }
678
+
679
+ .vd-cta {
680
+ inline-size: 100%;
681
+ justify-content: center;
682
+ }
683
+
684
+ /* Failed submit is the one place red belongs: a clear, recoverable error state. */
685
+ .vd-commerce[data-submit="failed"] .vd-cta {
686
+ background: ${P.semantic.error};
687
+ border-color: ${P.semantic.error};
688
+ color: ${P.white};
689
+ }
690
+
691
+ `;function ar(){if(_n(),document.getElementById(`vd-styles`)!==null)return;let e=document.createElement(`style`);e.id=`vd-styles`,e.textContent=ir,document.head.appendChild(e)}function or(e,t){let n=document.createElement(`a`);n.href=`data:image/png;base64,${e}`,n.download=t,n.click()}var sr=class{options;settings={};container=null;loading=null;slots={topRight:null,bottomRight:null};screenshotBtn=null;actionBar=null;cameraControls=null;attributes=null;groupHandles=new Map;lastSelectable=null;layout=null;commerce=null;constructor(e){this.options=e}attach(e){ar(),this.container=e,this.loading=new An(e),this.slots.topRight=this.createSlot(e,`vd-slot-top-right`),this.slots.bottomRight=this.createSlot(e,`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;let e=typeof this.container.requestFullscreen==`function`&&document.fullscreenEnabled!==!1;this.actionBar=new jn({onAr:this.options.onAr,onFullscreen:e?()=>{this.toggleFullscreen()}:void 0,onAnnotationsToggle:this.options.onAnnotationsToggle}),this.actionBar.applySettings(this.settings),this.slots.bottomRight.appendChild(this.actionBar.element),this.syncScreenshotButton(),this.placeScreenshotButton()}toggleFullscreen(){this.container!==null&&(document.fullscreenElement===null?(this.options.onFullscreenEnter?.(),this.container.requestFullscreen().catch(e=>{A.warn(`Fullscreen request refused`,{error:e})})):document.exitFullscreen())}updateProgress(e,t){this.loading?.updateProgress(e,t)}showError(e){this.loading?.showError(e)}viewerAlive(){this.loading?.viewerAlive()}applyViewerSettings(e){this.settings=e,e.language!==void 0&&ye(e.language,{reload:!1}),this.syncScreenshotButton(),this.actionBar?.applySettings(e),this.cameraControls!==null&&(this.cameraControls.element.style.display=e.cameraControls===!0?`flex`:`none`),this.placeScreenshotButton()}renderModelControls(e,t){if(this.container!==null&&this.slots.topRight!==null&&this.slots.bottomRight!==null&&(this.cameraControls?.element.remove(),this.cameraControls=null,this.teardownConfigurator(),this.settings.cameraControls===!0&&(this.cameraControls=new Mn(this.options.cameraApi,this.options.cameraPositionApi),this.cameraControls.element.style.display=`none`,this.slots.topRight.appendChild(this.cameraControls.element)),this.placeScreenshotButton(),t.length!==0)){this.attributes=document.createElement(`div`),this.attributes.className=`vd-attributes`,this.groupHandles=new Map;for(let n of t){let t=Kn(n,e,this.options.eventBus,this.options.onSelect,this.options.onSelectTransient,this.options.onSubscribe);this.groupHandles.set(n.name,t),this.attributes.appendChild(t.element)}this.commerce=new Xn(this.options.configuration),this.attributes.appendChild(this.commerce.element),this.layout=rr(this.settings.configuratorLayout,this.slots.bottomRight),this.layout.attach(this.container,this.attributes),this.lastSelectable!==null&&this.applySelectable(this.lastSelectable)}}applySelectable(e){this.lastSelectable=e;for(let[t,n]of this.groupHandles){let r=e.find(e=>e.name===t);n.setSelectable(r?.selectable??null),n.setHidden(r?.hidden===!0)}}get viewerSettings(){return this.settings}teardownConfigurator(){this.commerce?.destroy(),this.commerce=null,this.attributes?.remove(),this.attributes=null,this.groupHandles=new Map,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(let e of Object.values(this.slots))e?.remove();this.container=null}createSlot(e,t){let n=document.createElement(`div`);return n.className=t,e.appendChild(n),n}syncScreenshotButton(){let e=this.settings.screenshot===!0;e&&this.screenshotBtn===null&&(this.screenshotBtn=new N({variant:`outline`,size:`icon`,label:Ht(),icon:M.screenshot(),onClick:()=>{this.takeScreenshot()}})),!e&&this.screenshotBtn!==null&&(this.screenshotBtn.element.remove(),this.screenshotBtn=null)}takeScreenshot(){let e=this.screenshotBtn;e===null||e.element.disabled||(e.element.disabled=!0,this.options.snapshotApi.take(`snapshot.png`).onDeveloped(({data:t,filename:n})=>{e.element.disabled=!1,or(t,n)}).onError(t=>{e.element.disabled=!1,A.warn(`Screenshot failed`,{error:t})}))}placeScreenshotButton(){this.screenshotBtn!==null&&this.slots.topRight!==null&&(this.cameraControls===null?this.slots.topRight.appendChild(this.screenshotBtn.element):this.cameraControls.element.appendChild(this.screenshotBtn.element))}},cr=class{defaultServer=`https://server.virtualdisplay.io`;options;serverHost;extraParams;constructor(e,t,n){this.options=e,this.serverHost=t,this.extraParams=n}create(){let e=this.createContainer(),t=this.createIframe();return e.appendChild(t),this.attachToParent(e),{container:e,iframe:t}}createContainer(){let e=document.createElement(`div`);return e.className=`vd-container`,Object.assign(e.style,{position:`relative`,width:`100%`,height:`100%`,overflow:`hidden`}),e}createIframe(){let e=document.createElement(`iframe`);return e.src=this.buildUrl(),e.setAttribute(`allow`,`xr-spatial-tracking; fullscreen`),e}attachToParent(e){this.getParentElement().appendChild(e)}buildUrl(){let e=this.getServerUrl(),t=new URL(e);this.setAddressParams(t),this.options.language!==void 0&&t.searchParams.set(`language`,this.options.language),this.options.session!==void 0&&t.searchParams.set(`session`,this.options.session),this.options.debug===!0&&t.searchParams.set(`debug`,`true`),this.options.traceparent!==void 0&&t.searchParams.set(`traceparent`,this.options.traceparent);for(let[e,n]of Object.entries(this.extraParams??{}))t.searchParams.set(e,n);return t.toString()}setAddressParams(e){this.options.app===void 0?(e.searchParams.set(`license`,this.options.license),e.searchParams.set(`model`,this.options.model)):(e.searchParams.set(`app`,this.options.app),(this.options.license!==void 0||this.options.model!==void 0)&&A.warn("Both `app` and `license`/`model` were supplied: `app` wins, the pair was ignored"))}getServerUrl(){return this.serverHost===void 0?this.defaultServer:this.serverHost}getParentElement(){if(typeof this.options.parent!=`string`)return this.options.parent;let e=document.querySelector(this.options.parent);if(e===null)throw w.parentNotFound(this.options.parent);return e}};function lr(e){let{messenger:n}=e;n.on(t.HANDSHAKE,t=>{l(t)&&(A.info(`Server handshake received, flushing publisher queue`),n.markReady(),e.ui.viewerAlive())}),n.on(t.SESSION,t=>{u(t)&&e.onSession(t.sessionId)}),n.on(t.MUTATION,t=>{d(t)&&(e.attributes.handleMutationResult(t),e.configuration.handleSelectionChanged(e.attributes.getSelection()))}),n.on(t.SNAPSHOT,t=>{f(t)&&e.snapshot.handleSnapshotResult(t)}),n.on(t.CAMERA,t=>{p(t)&&e.cameraPosition.handlePositionUpdate(t)}),n.on(t.LOADING_INDICATOR,t=>{ne(t)&&(t.error===void 0?e.ui.updateProgress(t.progress,t.phase):e.ui.showError(t.error))}),n.on(t.CONFIG,t=>{ie(t)&&e.applyConfig(t)}),n.on(t.MAPPING,t=>{te(t)&&(e.attributes.handleMappingReceived(t),e.configuration.handleSelectionChanged(e.attributes.getSelection()),e.ui.renderModelControls(e.attributes,t.attributes),e.readyStateTracker.handleMappingReceived())}),ur(e)}function ur(e){let{messenger:n}=e;n.on(t.FOCUS,t=>{ae(t)&&e.focus.handleStateReceived(t)}),n.on(t.PRICING,t=>{oe(t)&&e.configuration.handlePricingReceived(t.pricing)}),n.on(t.SYNC,t=>{m(t)&&e.onSync(t.connected)}),n.on(t.SELECTABLE,t=>{re(t)&&(e.selectable.handleSnapshot(t),e.ui.applySelectable(t.attributes))}),n.on(t.APP_RESOLVED,t=>{ee(t)&&e.onAppResolved(t)})}var dr=class{ready=!1;onReady;constructor(e){this.onReady=e}handleMappingReceived(){this.ready||(this.ready=!0,A.info(`Mapping received from server, client is now ready`),this.onReady?.())}get isReady(){return this.ready}clear(){this.ready=!1}};function fr(e){if(e===void 0)return;let{annotations:t,...n}=e;return t===void 0?n:t===!0?{...n,annotations:`show`}:t===!1?{...n,annotations:`hide`}:{...n,annotations:t}}function pr(e){if(!Array.isArray(e))return{};let t=e.filter(e=>typeof e==`string`);return t.length>0?{features:t}:{}}var mr=class{attributes;selectableState;readyStateTracker;messenger;cameraApi;cameraPositionApi;focusApi;configurationApi;snapshotApi;annotationsApi;eventBus;ui;options;serverHost;iframeParams;arActivation;syncTracker;iframe;container;readyCallbacks=[];mutationFailedCallbacks=[];viewerSessionId;resolvedApp;appResolvedCallbacks=[];constructor(e,t){this.options=e;let r=t??{};this.serverHost=r.serverHost,this.iframeParams=r.iframeParams,this.initializeLogging(),this.messenger=new ce(()=>this.iframe?.contentWindow??null,{onHandlerError:(e,t)=>A.error(`Error handling ${e.type}`,t),...r.messengerOptions});let i=e=>{this.messenger.send(e)};this.attributes=new ct(i,n,(e,t)=>{this.notifyMutationFailed(e,t)}),this.selectableState=new lt,this.snapshotApi=new yt(i),this.annotationsApi=new ue(i,n),this.cameraApi=new ut(i),this.cameraPositionApi=new dt,this.focusApi=new gt(i,e=>{this.dispatchFocusChange(e)},n),this.configurationApi=new ht(e=>{this.dispatchConfigurationChange(e)},e=>{this.dispatchConfigurationSubmit(e)}),this.eventBus=new bt,this.arActivation=r.createArActivation?.(i),this.syncTracker=r.createSyncTracker?.(),this.readyStateTracker=new dr(()=>{this.notifyReady()}),this.ui=this.createStandardInterface(),this.wireIncomingMessages(),r.registerHandlers?.(this.messenger,i),this.messenger.start(),this.mountIframe()}createStandardInterface(){let e=this.arActivation;return new sr({snapshotApi:this.snapshotApi,cameraApi:this.cameraApi,cameraPositionApi:this.cameraPositionApi,eventBus:this.eventBus,configuration:this.configurationApi,onSelect:(e,t)=>this.attributes.select(e,t),onSelectTransient:(e,t)=>this.attributes.selectTransient(e,t),onSubscribe:(e,t)=>this.attributes.onChange(e,t),...e!==void 0&&{onAr:()=>{e.activate()}},onFullscreenEnter:()=>{this.trackFullscreen()},onAnnotationsToggle:e=>{this.sendControlAnnotationToggle(e)}})}sendControlAnnotationToggle(e){this.sendAnnotationToggle(e,`control`)}sendAnnotationToggle(e,n){this.messenger.send({type:t.ANNOTATION_TOGGLE,enabled:e,...n!==void 0&&{origin:n}})}wireIncomingMessages(){lr({messenger:this.messenger,attributes:this.attributes,selectable:this.selectableState,configuration:this.configurationApi,snapshot:this.snapshotApi,cameraPosition:this.cameraPositionApi,focus:this.focusApi,ui:this.ui,readyStateTracker:this.readyStateTracker,applyConfig:e=>{this.handleConfig(e)},onSession:e=>{this.handleSession(e)},onSync:e=>{this.syncTracker?.handleSync(e)},onAppResolved:e=>{this.handleAppResolved({appType:e.appType,name:e.name,...e.slug!==void 0&&{slug:e.slug},...e.submit!==void 0&&{submit:e.submit},...pr(e.features)})}})}handleAppResolved(e){this.resolvedApp=e;for(let t of this.appResolvedCallbacks)t(e)}handleSession(e){this.viewerSessionId=e,this.arActivation?.onSession(e)}notifyMutationFailed(e,t){for(let n of this.mutationFailedCallbacks)n({attribute:e,value:t})}notifyReady(){let e=this.readyCallbacks;this.readyCallbacks=[];for(let t of e)t(this);this.ui.onReady()}dispatchFocusChange(e){this.container?.dispatchEvent(new CustomEvent(X.FOCUS_CHANGE,{detail:e,bubbles:!0}))}dispatchConfigurationChange(e){this.container?.dispatchEvent(new CustomEvent(X.CONFIGURATION_CHANGE,{detail:e??null,bubbles:!0}))}dispatchConfigurationSubmit(e){this.container?.dispatchEvent(new CustomEvent(X.CONFIGURATION_SUBMIT,{detail:e,bubbles:!0}))}handleConfig(e){let t=e.viewerSettings,n=fr(this.options.viewerSettings);if(t!==void 0||n!==void 0){let e=n===void 0?t:{...t??{},...n};if(n!==void 0&&t!==void 0){let e=Object.entries(n).filter(([e,n])=>t[e]!==n).map(([e,n])=>`${e} (metadata: ${t[e]??`undefined`}, override: ${n})`);e.length>0&&A.warn(`Viewer settings override active: ${e.join(`, `)}`)}this.ui.applyViewerSettings(e),this.echoAnnotationsDifference(t?.annotations,e.annotations)}this.cameraPositionApi.applyLimits(e.cameraLimits)}echoAnnotationsDifference(e,t){t!==void 0&&t!==e&&this.sendAnnotationToggle(t===`show`||t===`toggle-shown`)}trackFullscreen(){this.messenger.send({type:t.FULLSCREEN})}initializeLogging(){this.options.debug===!0&&ot(),A.info(`Initializing Virtualdisplay client`,{...this.options.app===void 0?{model:this.options.model}:{app:this.options.app}})}mountIframe(){let e=new cr(this.options,this.serverHost,this.iframeParams).create();this.container=e.container,this.iframe=e.iframe,this.eventBus.attach(this.container),this.ui.attach(this.container);try{let e=new URL(this.iframe.src).origin;this.messenger.setTargetOrigin(e)}catch{}}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){this.readyStateTracker.isReady?e(this):this.readyCallbacks.push(e)}onMutationFailed(e){this.mutationFailedCallbacks.push(e)}onSelectableChange(e){this.selectableState.onChange(e)}onAppResolved(e){this.appResolvedCallbacks.push(e),this.resolvedApp!==void 0&&e(this.resolvedApp)}getSelectable(e){return this.selectableState.selectableFor(e)}activateAr(){this.arActivation?.activate()}on(e,t){this.eventBus.on(e,t)}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.arActivation?.destroy(),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}},hr=`ar.virtualdisplay.io`;function gr(e){let t=new URL(`https://${hr}/go`);return e.sessionId===void 0?e.app===void 0?e.license!==void 0&&e.model!==void 0&&(t.searchParams.set(`license`,e.license),t.searchParams.set(`model`,e.model)):t.searchParams.set(`app`,e.app):t.searchParams.set(`session`,e.sessionId),t.toString()}var _r=1500,vr=class{options;qrModal=new yn;sessionId;waiters=[];pendingTimers=new Set;destroyed=!1;constructor(e){this.options=e}onSession(e){this.sessionId=e;let t=this.waiters;this.waiters=[];for(let n of t)n(e)}activate(){tt()?this.options.send({type:t.AR_ACTIVATE}):this.showQrCode()}destroy(){this.destroyed=!0;for(let e of this.pendingTimers)clearTimeout(e);this.pendingTimers.clear(),this.waiters=[],this.qrModal.hide()}async showQrCode(){this.qrModal.show();let e=await this.waitForSessionId();if(this.destroyed)return;let n=gr({sessionId:e,app:this.options.app,license:this.options.license,model:this.options.model}),r;try{r=await this.qrModal.update(n)}catch(e){A.warn(`AR QR code could not be rendered`,{error:e});return}this.destroyed?this.qrModal.hide():r&&this.options.send({type:t.QR_SHOWN})}waitForSessionId(){return this.sessionId===void 0?new Promise(e=>{let t=setTimeout(()=>{this.pendingTimers.delete(t),e(void 0)},_r);this.pendingTimers.add(t),this.waiters.push(n=>{this.pendingTimers.delete(t),clearTimeout(t),e(n)})}):Promise.resolve(this.sessionId)}},yr=class{callbacks=[];lastKnown;handleSync(e){this.lastKnown=e;for(let t of this.callbacks)t(e)}onChange(e){this.callbacks.push(e),this.lastKnown!==void 0&&e(this.lastKnown)}},br=class extends mr{syncStatusTracker;constructor(e){let t=new yr;super(e,{createArActivation:t=>new vr({app:e.app,license:e.license,model:e.model,send:t}),createSyncTracker:()=>t}),this.syncStatusTracker=t}onSyncChange(e){this.syncStatusTracker.onChange(e)}};exports.AVAILABILITY=a,exports.Annotations=ue,exports.Attribute=Le,exports.AttributeValue=de,exports.Camera=ut,exports.CameraPosition=dt,exports.Configuration=ht,exports.ERROR_CODES=C,exports.Focus=gt,exports.Photo=_t,exports.Snapshot=yt,exports.VD_EVENTS=X,exports.VirtualdisplayClient=br,exports.VirtualdisplayError=w,exports.enableDebugMode=ot,exports.isDebugMode=st,Object.defineProperty(exports,"logger",{enumerable:!0,get:function(){return A}});