@virtualdisplay.io/client 4.0.0-alpha.6 → 4.0.0-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { n as e } from "./chunk-efA98nb6.js";
1
+ import { n as e } from "./chunk-C_CI6nMA.js";
2
2
  //#region src/client/error.ts
3
3
  var t = {
4
4
  NO_MAPPING: "NO_MAPPING",
@@ -66,7 +66,7 @@ var t = {
66
66
  }
67
67
  buildUrl() {
68
68
  let e = this.getServerUrl(), t = new URL(e);
69
- return t.searchParams.set("license", this.options.license), t.searchParams.set("model", this.options.model), this.options.language !== void 0 && t.searchParams.set("language", this.options.language), this.options.debug === !0 && t.searchParams.set("debug", "true"), t.toString();
69
+ return t.searchParams.set("license", this.options.license), t.searchParams.set("model", this.options.model), this.options.language !== void 0 && t.searchParams.set("language", this.options.language), this.options.debug === !0 && t.searchParams.set("debug", "true"), this.options.traceparent !== void 0 && t.searchParams.set("traceparent", this.options.traceparent), t.toString();
70
70
  }
71
71
  getServerUrl() {
72
72
  return this.defaultServer;
@@ -101,28 +101,48 @@ function o(e, t) {
101
101
  e.level === "error" ? console.error(n) : e.level === "warn" ? console.warn(n) : console.log(n);
102
102
  }
103
103
  //#endregion
104
+ //#region ../logger/src/serialise.ts
105
+ function s(e, t = 0) {
106
+ let n = {
107
+ name: e.name,
108
+ message: e.message
109
+ };
110
+ e.stack !== void 0 && (n.stack = e.stack);
111
+ for (let t of Object.getOwnPropertyNames(e)) {
112
+ if (t === "name" || t === "message" || t === "stack" || t === "cause") continue;
113
+ let r = e[t];
114
+ r !== void 0 && (n[t] = r);
115
+ }
116
+ return e.cause !== void 0 && e.cause !== null && (n.cause = e.cause instanceof Error && t < 5 ? s(e.cause, t + 1) : String(e.cause)), n;
117
+ }
118
+ function c(e) {
119
+ let t = {};
120
+ for (let [n, r] of Object.entries(e)) t[n] = r instanceof Error ? s(r) : r;
121
+ return t;
122
+ }
123
+ //#endregion
104
124
  //#region ../utils/src/date.ts
105
- function s() {
125
+ function l() {
106
126
  return /* @__PURE__ */ new Date();
107
127
  }
108
- function c(e) {
128
+ function u(e) {
109
129
  return e.toISOString();
110
130
  }
111
131
  //#endregion
112
132
  //#region ../logger/src/logger.ts
113
- var l = class e {
133
+ var d = class e {
114
134
  constructor(e) {
115
135
  this.config = e;
116
136
  }
117
137
  log(e, t, n = {}) {
118
138
  let r = this.config.traceProvider?.() ?? {};
119
139
  o({
120
- timestamp: c(s()),
140
+ timestamp: u(l()),
121
141
  level: e,
122
142
  msg: t,
123
143
  service: this.config.service,
124
144
  ...r,
125
- ...n
145
+ ...c(n)
126
146
  }, this.config.isDev);
127
147
  }
128
148
  debug(e, t) {
@@ -147,8 +167,8 @@ var l = class e {
147
167
  }).bind(this), n;
148
168
  }
149
169
  };
150
- function u(e, t) {
151
- return new l({
170
+ function f(e, t) {
171
+ return new d({
152
172
  service: e,
153
173
  isDev: t?.isDev === void 0 ? typeof process < "u" ? process.env.NODE_ENV !== "production" : !0 : t.isDev,
154
174
  traceProvider: t?.traceProvider
@@ -156,34 +176,34 @@ function u(e, t) {
156
176
  }
157
177
  //#endregion
158
178
  //#region src/utils/logger.ts
159
- function d(e) {
179
+ function p(e) {
160
180
  if (e !== void 0) return typeof e == "object" && e && !Array.isArray(e) && !(e instanceof Error) ? e : e instanceof Error ? { error: e.message } : { value: e };
161
181
  }
162
- function f(e) {
182
+ function m(e) {
163
183
  return {
164
- debug: (t, n) => e.debug(t, d(n)),
165
- info: (t, n) => e.info(t, d(n)),
166
- warn: (t, n) => e.warn(t, d(n)),
167
- error: (t, n) => e.error(t, d(n))
184
+ debug: (t, n) => e.debug(t, p(n)),
185
+ info: (t, n) => e.info(t, p(n)),
186
+ warn: (t, n) => e.warn(t, p(n)),
187
+ error: (t, n) => e.error(t, p(n))
168
188
  };
169
189
  }
170
- var p = !1, m = f(u("client", { isDev: !1 }));
171
- function h() {
172
- p = !0, m = f(u("client", { isDev: !0 }));
190
+ var h = !1, g = m(f("client", { isDev: !1 }));
191
+ function _() {
192
+ h = !0, g = m(f("client", { isDev: !0 }));
173
193
  }
174
- function g() {
175
- return p;
194
+ function ee() {
195
+ return h;
176
196
  }
177
197
  //#endregion
178
198
  //#region src/client/ready-state-tracker.ts
179
- var _ = class {
199
+ var te = class {
180
200
  ready = !1;
181
201
  onReady;
182
202
  constructor(e) {
183
203
  this.onReady = e;
184
204
  }
185
205
  handleMappingReceived() {
186
- this.ready || (this.ready = !0, m.info("Mapping received from server, client is now ready"), this.onReady?.());
206
+ this.ready || (this.ready = !0, g.info("Mapping received from server, client is now ready"), this.onReady?.());
187
207
  }
188
208
  get isReady() {
189
209
  return this.ready;
@@ -191,102 +211,7 @@ var _ = class {
191
211
  clear() {
192
212
  this.ready = !1;
193
213
  }
194
- }, v = class {
195
- isSelectedValue = !1;
196
- constructor(e, t) {
197
- this.value = e, this.attribute = t;
198
- }
199
- get isSelected() {
200
- return this.isSelectedValue;
201
- }
202
- setSelected(e) {
203
- this.isSelectedValue = e;
204
- }
205
- }, ee = class {
206
- name;
207
- defaultValue;
208
- values;
209
- onSelect;
210
- onChangeCallback;
211
- constructor(e) {
212
- this.name = e.name, this.defaultValue = e.defaultValue, this.onSelect = e.onSelect, this.values = this.createValues(e.values);
213
- }
214
- select(e) {
215
- if (!this.values.has(e)) throw n.valueNotFound(this.name, e);
216
- this.onSelect(this.name, e);
217
- }
218
- getValues() {
219
- return Array.from(this.values.values());
220
- }
221
- getValue(e) {
222
- return this.values.get(e);
223
- }
224
- onChange(e) {
225
- this.onChangeCallback = e;
226
- }
227
- handleResult(e) {
228
- let t;
229
- for (let n of this.values.values()) {
230
- let r = n.value === e;
231
- n.setSelected(r), r && (t = n);
232
- }
233
- t !== void 0 && this.onChangeCallback !== void 0 && this.onChangeCallback(t);
234
- }
235
- createValues(e) {
236
- let t = /* @__PURE__ */ new Map();
237
- for (let n of e) {
238
- let e = new v(n, this.name);
239
- n === this.defaultValue && e.setSelected(!0), t.set(n, e);
240
- }
241
- return t;
242
- }
243
- }, te = class {
244
- attributes = /* @__PURE__ */ new Map();
245
- constructor(e, t, n) {
246
- for (let n of e) {
247
- let e = this.buildOptions(n, t);
248
- this.attributes.set(n.name, new ee(e));
249
- }
250
- this.onMutationFailed = n;
251
- }
252
- onMutationFailed;
253
- get(e) {
254
- return this.attributes.get(e);
255
- }
256
- defaults() {
257
- let e = [];
258
- for (let t of this.attributes.values()) t.defaultValue !== void 0 && e.push({
259
- name: t.name,
260
- value: t.defaultValue
261
- });
262
- return e;
263
- }
264
- handleResults(e) {
265
- for (let t of e) {
266
- if (!t.success) {
267
- this.onMutationFailed?.(t.name, t.value);
268
- continue;
269
- }
270
- this.get(t.name)?.handleResult(t.value);
271
- }
272
- }
273
- buildOptions(e, t) {
274
- let n = {
275
- name: e.name,
276
- values: e.values,
277
- onSelect: (e, n) => {
278
- t([{
279
- name: e,
280
- value: n
281
- }], !1);
282
- }
283
- };
284
- return e.defaultValue === void 0 ? n : {
285
- ...n,
286
- defaultValue: e.defaultValue
287
- };
288
- }
289
- }, y = {
214
+ }, v = {
290
215
  HANDSHAKE: "handshake",
291
216
  MUTATION: "mutation",
292
217
  STATE: "state",
@@ -296,47 +221,54 @@ var _ = class {
296
221
  MAPPING: "mapping",
297
222
  AR_ACTIVATE: "ar_activate",
298
223
  CONFIG: "config",
299
- INTERACTION: "interaction"
300
- }, ne = new Set(Object.values(y));
224
+ INTERACTION: "interaction",
225
+ ANNOTATION_PLACE_MODE: "annotation_place_mode",
226
+ ANNOTATION_PLACED: "annotation_placed",
227
+ ANNOTATION_TOGGLE: "annotation_toggle"
228
+ }, ne = new Set(Object.values(v));
301
229
  function re(e) {
302
230
  if (typeof e != "object" || !e) return !1;
303
231
  let t = e;
304
232
  return typeof t.target == "string" ? !1 : typeof t.type == "string" && ne.has(t.type);
305
233
  }
306
234
  function ie(e) {
307
- let t = b(e);
308
- return t !== null && t.type === y.HANDSHAKE;
235
+ let t = y(e);
236
+ return t !== null && t.type === v.HANDSHAKE;
309
237
  }
310
238
  function ae(e) {
311
- let t = b(e);
312
- return t !== null && t.type === y.MUTATION && Array.isArray(t.results);
239
+ let t = y(e);
240
+ return t !== null && t.type === v.MUTATION && Array.isArray(t.results);
313
241
  }
314
242
  function oe(e) {
315
- let t = b(e);
316
- return t !== null && t.type === y.SNAPSHOT && ("data" in t || "error" in t);
243
+ let t = y(e);
244
+ return t !== null && t.type === v.SNAPSHOT && ("data" in t || "error" in t);
317
245
  }
318
246
  function se(e) {
319
- let t = b(e);
320
- return t !== null && t.type === y.CAMERA && Array.isArray(t.transforms);
247
+ let t = y(e);
248
+ return t !== null && t.type === v.CAMERA && Array.isArray(t.transforms);
321
249
  }
322
250
  function ce(e) {
323
- let t = b(e);
324
- return t !== null && t.type === y.MAPPING && Array.isArray(t.attributes);
251
+ let t = y(e);
252
+ return t !== null && t.type === v.MAPPING && Array.isArray(t.attributes);
325
253
  }
326
254
  function le(e) {
327
- let t = b(e);
328
- return t !== null && t.type === y.LOADING_INDICATOR && typeof t.progress == "number";
255
+ let t = y(e);
256
+ return t !== null && t.type === v.LOADING_INDICATOR && typeof t.progress == "number";
329
257
  }
330
258
  function ue(e) {
331
- let t = b(e);
332
- return t !== null && t.type === y.CONFIG && typeof t.viewerSettings == "object";
259
+ let t = y(e);
260
+ return t !== null && t.type === v.CONFIG && typeof t.viewerSettings == "object";
333
261
  }
334
- function b(e) {
262
+ function de(e) {
263
+ let t = y(e);
264
+ return t !== null && t.type === v.ANNOTATION_PLACED && typeof t.position == "object" && t.position !== null;
265
+ }
266
+ function y(e) {
335
267
  return typeof e != "object" || !e ? null : e;
336
268
  }
337
269
  //#endregion
338
270
  //#region ../messaging/src/queue.ts
339
- var de = class {
271
+ var b = class {
340
272
  pending = [];
341
273
  isReady = !1;
342
274
  constructor(e) {
@@ -374,8 +306,9 @@ var de = class {
374
306
  shouldBuffer;
375
307
  listener = null;
376
308
  sourceId;
309
+ targetOrigin;
377
310
  constructor(e, t) {
378
- this.getTarget = e, this.sourceId = `vd-${Math.random().toString(36).slice(2, 8)}`, this.publisher = new de((e) => this.post(e)), this.consumer = new de((e) => this.routeToHandler(e)), this.shouldBuffer = t?.shouldBuffer ?? null, t?.bufferIncoming !== !0 && this.consumer.markReady();
311
+ this.getTarget = e, this.sourceId = `vd-${Math.random().toString(36).slice(2, 8)}`, this.targetOrigin = t?.targetOrigin ?? "*", this.publisher = new b((e) => this.post(e)), this.consumer = new b((e) => this.routeToHandler(e)), this.shouldBuffer = t?.shouldBuffer ?? null, t?.bufferIncoming !== !0 && this.consumer.markReady();
379
312
  }
380
313
  on(e, t) {
381
314
  this.handlers.set(e, t);
@@ -383,6 +316,9 @@ var de = class {
383
316
  off(e) {
384
317
  this.handlers.delete(e);
385
318
  }
319
+ setTargetOrigin(e) {
320
+ this.targetOrigin = e;
321
+ }
386
322
  send(e) {
387
323
  this.publisher.enqueue(e);
388
324
  }
@@ -421,7 +357,7 @@ var de = class {
421
357
  t !== null && t.postMessage({
422
358
  ...e,
423
359
  _source: this.sourceId
424
- }, "*");
360
+ }, this.targetOrigin);
425
361
  }
426
362
  routeToHandler(e) {
427
363
  let t = this.handlers.get(e.type);
@@ -433,17 +369,141 @@ var de = class {
433
369
  });
434
370
  }
435
371
  };
436
- new Set([y.CAMERA]);
372
+ new Set([v.CAMERA]);
437
373
  //#endregion
438
- //#region src/attributes/attributes.ts
374
+ //#region src/annotations/annotations.ts
439
375
  var pe = class {
376
+ placedCallbacks = [];
377
+ constructor(e) {
378
+ this.send = e;
379
+ }
380
+ setEnabled(e) {
381
+ this.send({
382
+ type: v.ANNOTATION_TOGGLE,
383
+ enabled: e
384
+ });
385
+ }
386
+ startPlacing() {
387
+ this.send({
388
+ type: v.ANNOTATION_PLACE_MODE,
389
+ enabled: !0
390
+ });
391
+ }
392
+ stopPlacing() {
393
+ this.send({
394
+ type: v.ANNOTATION_PLACE_MODE,
395
+ enabled: !1
396
+ });
397
+ }
398
+ onPlaced(e) {
399
+ this.placedCallbacks.push(e);
400
+ }
401
+ handlePlaced(e) {
402
+ for (let t of this.placedCallbacks) t(e);
403
+ }
404
+ }, me = class {
405
+ isSelectedValue = !1;
406
+ constructor(e, t) {
407
+ this.value = e, this.attribute = t;
408
+ }
409
+ get isSelected() {
410
+ return this.isSelectedValue;
411
+ }
412
+ setSelected(e) {
413
+ this.isSelectedValue = e;
414
+ }
415
+ }, x = class {
416
+ name;
417
+ defaultValue;
418
+ values;
419
+ onSelect;
420
+ onChangeCallback;
421
+ constructor(e) {
422
+ this.name = e.name, this.defaultValue = e.defaultValue, this.onSelect = e.onSelect, this.values = this.createValues(e.values);
423
+ }
424
+ select(e) {
425
+ if (!this.values.has(e)) throw n.valueNotFound(this.name, e);
426
+ this.onSelect(this.name, e);
427
+ }
428
+ getValues() {
429
+ return Array.from(this.values.values());
430
+ }
431
+ getValue(e) {
432
+ return this.values.get(e);
433
+ }
434
+ onChange(e) {
435
+ this.onChangeCallback = e;
436
+ }
437
+ handleResult(e) {
438
+ let t;
439
+ for (let n of this.values.values()) {
440
+ let r = n.value === e;
441
+ n.setSelected(r), r && (t = n);
442
+ }
443
+ t !== void 0 && this.onChangeCallback !== void 0 && this.onChangeCallback(t);
444
+ }
445
+ createValues(e) {
446
+ let t = /* @__PURE__ */ new Map();
447
+ for (let n of e) {
448
+ let e = new me(n, this.name);
449
+ n === this.defaultValue && e.setSelected(!0), t.set(n, e);
450
+ }
451
+ return t;
452
+ }
453
+ }, he = class {
454
+ attributes = /* @__PURE__ */ new Map();
455
+ constructor(e, t, n) {
456
+ for (let n of e) {
457
+ let e = this.buildOptions(n, t);
458
+ this.attributes.set(n.name, new x(e));
459
+ }
460
+ this.onMutationFailed = n;
461
+ }
462
+ onMutationFailed;
463
+ get(e) {
464
+ return this.attributes.get(e);
465
+ }
466
+ defaults() {
467
+ let e = [];
468
+ for (let t of this.attributes.values()) t.defaultValue !== void 0 && e.push({
469
+ name: t.name,
470
+ value: t.defaultValue
471
+ });
472
+ return e;
473
+ }
474
+ handleResults(e) {
475
+ for (let t of e) {
476
+ if (!t.success) {
477
+ this.onMutationFailed?.(t.name, t.value);
478
+ continue;
479
+ }
480
+ this.get(t.name)?.handleResult(t.value);
481
+ }
482
+ }
483
+ buildOptions(e, t) {
484
+ let n = {
485
+ name: e.name,
486
+ values: e.values,
487
+ onSelect: (e, n) => {
488
+ t([{
489
+ name: e,
490
+ value: n
491
+ }], !1);
492
+ }
493
+ };
494
+ return e.defaultValue === void 0 ? n : {
495
+ ...n,
496
+ defaultValue: e.defaultValue
497
+ };
498
+ }
499
+ }, ge = class {
440
500
  registry;
441
501
  pendingCallbacks = [];
442
502
  constructor(e, t) {
443
503
  this.send = e, this.onMutationFailed = t;
444
504
  }
445
505
  handleMappingReceived(e) {
446
- m.debug("Initializing from server mapping", { attributeCount: e.attributes.length }), this.registry = new te(e.attributes, (e, t) => this.sendMutation(e, t), this.onMutationFailed), this.replayPendingCallbacks();
506
+ g.debug("Initializing from server mapping", { attributeCount: e.attributes.length }), this.registry = new he(e.attributes, (e, t) => this.sendMutation(e, t), this.onMutationFailed), this.replayPendingCallbacks();
447
507
  }
448
508
  handleMutationResult(e) {
449
509
  this.registry?.handleResults(e.results);
@@ -470,7 +530,7 @@ var pe = class {
470
530
  }
471
531
  let n = this.registry.get(e);
472
532
  if (n === void 0) {
473
- m.warn(`onChange: attribute "${e}" not found — callback will not fire`);
533
+ g.warn(`onChange: attribute "${e}" not found — callback will not fire`);
474
534
  return;
475
535
  }
476
536
  n.onChange(t);
@@ -483,7 +543,7 @@ var pe = class {
483
543
  }
484
544
  sendMutation(e, t) {
485
545
  let n = {
486
- type: y.MUTATION,
546
+ type: v.MUTATION,
487
547
  mutations: e,
488
548
  isInitial: t
489
549
  };
@@ -492,11 +552,11 @@ var pe = class {
492
552
  replayPendingCallbacks() {
493
553
  for (let { name: e, callback: t } of this.pendingCallbacks) {
494
554
  let n = this.registry?.get(e);
495
- n === void 0 && m.warn(`onChange: attribute "${e}" not found — buffered callback will not fire`), n?.onChange(t);
555
+ n === void 0 && g.warn(`onChange: attribute "${e}" not found — buffered callback will not fire`), n?.onChange(t);
496
556
  }
497
557
  this.pendingCallbacks.length = 0;
498
558
  }
499
- }, me = class {
559
+ }, _e = class {
500
560
  commands = [];
501
561
  constructor(e) {
502
562
  this.send = e;
@@ -522,7 +582,7 @@ var pe = class {
522
582
  set() {
523
583
  if (this.commands.length === 0) throw n.invalidParameter("No camera commands to execute. Call rotate(), tilt(), or zoom() before set().");
524
584
  let e = {
525
- type: y.CAMERA,
585
+ type: v.CAMERA,
526
586
  commands: this.commands
527
587
  };
528
588
  this.send(e), this.commands = [];
@@ -532,12 +592,12 @@ var pe = class {
532
592
  }
533
593
  reset() {
534
594
  let e = {
535
- type: y.CAMERA,
595
+ type: v.CAMERA,
536
596
  commands: [{ action: "reset" }]
537
597
  };
538
598
  this.send(e);
539
599
  }
540
- }, he = class {
600
+ }, ve = class {
541
601
  state;
542
602
  limitsState;
543
603
  changeCallbacks = [];
@@ -598,7 +658,7 @@ var pe = class {
598
658
  for (let t of this.changeCallbacks) t(e);
599
659
  }
600
660
  }
601
- }, ge = class {
661
+ }, ye = class {
602
662
  developedCallbacks = /* @__PURE__ */ new Set();
603
663
  errorCallbacks = /* @__PURE__ */ new Set();
604
664
  developed = !1;
@@ -626,24 +686,24 @@ var pe = class {
626
686
  t(e);
627
687
  }), this.developedCallbacks.clear(), this.errorCallbacks.clear());
628
688
  }
629
- }, _e = class {
689
+ }, S = class {
630
690
  validExtensions = [".png"];
631
691
  pendingPhotos = /* @__PURE__ */ new Map();
632
692
  constructor(e) {
633
693
  this.send = e;
634
694
  }
635
695
  take(e) {
636
- this.validateFilename(e), m.debug("Taking snapshot", { filename: e });
637
- let t = new ge(e);
696
+ this.validateFilename(e), g.debug("Taking snapshot", { filename: e });
697
+ let t = new ye(e);
638
698
  return this.pendingPhotos.set(t.getFilename(), t), this.send({
639
- type: y.SNAPSHOT,
699
+ type: v.SNAPSHOT,
640
700
  filename: e
641
701
  }), t;
642
702
  }
643
703
  handleSnapshotResult(e) {
644
704
  let r = this.pendingPhotos.get(e.filename);
645
705
  if (r === void 0) {
646
- m.warn("No pending photo found for filename", {
706
+ g.warn("No pending photo found for filename", {
647
707
  filename: e.filename,
648
708
  pendingFilenames: Array.from(this.pendingPhotos.keys())
649
709
  });
@@ -663,7 +723,7 @@ var pe = class {
663
723
  if (!this.validExtensions.some((t) => e.toLowerCase().endsWith(t))) throw new n(`Invalid filename: "${e}". Filename must end with one of: ${this.validExtensions.join(", ")}`, t.INVALID_PARAMETER);
664
724
  if (e.includes("..") || e.includes("/") || e.includes("\\")) throw new n("Filename cannot contain path separators or \"..\"", t.INVALID_PARAMETER);
665
725
  }
666
- }, ve = class {
726
+ }, be = class {
667
727
  container = null;
668
728
  attach(e) {
669
729
  this.container = e;
@@ -689,70 +749,70 @@ var pe = class {
689
749
  this.container?.removeEventListener(e, n);
690
750
  };
691
751
  }
692
- }, ye = {}, be = [
752
+ }, xe = {}, C = [
693
753
  "en",
694
754
  "nl",
695
755
  "de"
696
- ], x = ["baseLocale"], S = [], C, w;
697
- function xe(e) {
698
- if (S.length === 0) return;
756
+ ], w = ["baseLocale"], T = [], E, D;
757
+ function Se(e) {
758
+ if (T.length === 0) return;
699
759
  let t = typeof e == "string" ? e : e.href;
700
- if (C === t) return w;
760
+ if (E === t) return D;
701
761
  let n = new URL(t, "http://dummy.com"), r;
702
- for (let e of S) if (new ye(e.match, n.href).exec(n.href)) {
762
+ for (let e of T) if (new xe(e.match, n.href).exec(n.href)) {
703
763
  r = e;
704
764
  break;
705
765
  }
706
- return C = t, w = r, r;
766
+ return E = t, D = r, r;
707
767
  }
708
- function T(e) {
709
- let t = xe(e);
710
- return t && t.exclude !== !0 && Array.isArray(t.strategy) ? t.strategy : x;
768
+ function O(e) {
769
+ let t = Se(e);
770
+ return t && t.exclude !== !0 && Array.isArray(t.strategy) ? t.strategy : w;
711
771
  }
712
- var E = void 0, D = typeof window > "u";
772
+ var k = void 0, A = typeof window > "u";
713
773
  globalThis.__paraglide = globalThis.__paraglide ?? {}, globalThis.__paraglide.ssr = globalThis.__paraglide.ssr ?? {};
714
- var O = !1, k = () => {
715
- if (E) {
716
- let e = E?.getStore()?.locale;
774
+ var j = !1, M = () => {
775
+ if (k) {
776
+ let e = k?.getStore()?.locale;
717
777
  if (e) return e;
718
778
  }
719
- let e = x;
720
- !D && typeof window < "u" && window.location?.href && (e = T(window.location.href));
721
- let t = Se(e, typeof window < "u" ? window.location?.href : void 0);
722
- if (t) return O || (O = !0, A(t, { reload: !1 })), t;
779
+ let e = w;
780
+ !A && typeof window < "u" && window.location?.href && (e = O(window.location.href));
781
+ let t = Ce(e, typeof window < "u" ? window.location?.href : void 0);
782
+ if (t) return j || (j = !0, N(t, { reload: !1 })), t;
723
783
  throw Error("No locale found. Read the docs https://inlang.com/m/gerre34r/library-inlang-paraglideJs/errors#no-locale-found");
724
784
  };
725
- function Se(e, t) {
785
+ function Ce(e, t) {
726
786
  let n;
727
787
  for (let t of e) {
728
788
  if (t === "baseLocale") n = "en";
729
- else if (N(t) && M.has(t)) {
730
- let e = M.get(t);
789
+ else if (Ee(t) && F.has(t)) {
790
+ let e = F.get(t);
731
791
  if (e) {
732
792
  let t = e.getLocale();
733
793
  if (t instanceof Promise) continue;
734
- if (t !== void 0) return we(t);
794
+ if (t !== void 0) return Te(t);
735
795
  }
736
796
  }
737
- let e = j(n);
797
+ let e = P(n);
738
798
  if (e) return e;
739
799
  }
740
800
  }
741
- var Ce = (e) => {
801
+ var we = (e) => {
742
802
  e ? window.location.href = e : window.location.reload();
743
- }, A = (e, t) => {
803
+ }, N = (e, t) => {
744
804
  let n = {
745
805
  reload: !0,
746
806
  ...t
747
807
  }, r;
748
808
  try {
749
- r = k();
809
+ r = M();
750
810
  } catch {}
751
- let i = [], a = x;
752
- !D && typeof window < "u" && window.location?.href && (a = T(window.location.href));
811
+ let i = [], a = w;
812
+ !A && typeof window < "u" && window.location?.href && (a = O(window.location.href));
753
813
  for (let t of a) if (t === "baseLocale") continue;
754
- else if (N(t) && M.has(t)) {
755
- let n = M.get(t);
814
+ else if (Ee(t) && F.has(t)) {
815
+ let n = F.get(t);
756
816
  if (n) {
757
817
  let r = n.setLocale(e);
758
818
  r instanceof Promise && (r = r.catch((e) => {
@@ -761,280 +821,78 @@ var Ce = (e) => {
761
821
  }
762
822
  }
763
823
  let o = () => {
764
- !D && n.reload && window.location && e !== r && Ce(void 0);
824
+ !A && n.reload && window.location && e !== r && we(void 0);
765
825
  };
766
826
  if (i.length) return Promise.all(i).then(() => {
767
827
  o();
768
828
  });
769
829
  o();
770
830
  };
771
- function j(e) {
831
+ function P(e) {
772
832
  if (typeof e != "string") return;
773
833
  let t = e.toLowerCase();
774
- for (let e of be) if (e.toLowerCase() === t) return e;
834
+ for (let e of C) if (e.toLowerCase() === t) return e;
775
835
  }
776
- function we(e) {
777
- let t = j(e);
836
+ function Te(e) {
837
+ let t = P(e);
778
838
  if (t) return t;
779
- throw Error(`Invalid locale: ${e}. Expected one of: ${be.join(", ")}`);
839
+ throw Error(`Invalid locale: ${e}. Expected one of: ${C.join(", ")}`);
780
840
  }
781
- var M = /* @__PURE__ */ new Map();
782
- function N(e) {
841
+ var F = /* @__PURE__ */ new Map();
842
+ function Ee(e) {
783
843
  return typeof e == "string" && /^custom-[A-Za-z0-9_-]+$/.test(e);
784
844
  }
785
845
  //#endregion
786
846
  //#region ../i18n/src/paraglide-viewer/messages/controls_ar_buttonlabel1.js
787
- var Te = () => "Activate AR", Ee = () => "AR activeren", De = () => "AR aktivieren", Oe = ((e = {}, t = {}) => {
788
- let n = t.locale ?? k();
789
- return n === "en" ? Te(e) : n === "nl" ? Ee(e) : De(e);
790
- }), ke = () => "Scan to view in AR", Ae = () => "Scan om in AR te bekijken", je = () => "Scannen für AR-Ansicht", Me = ((e = {}, t = {}) => {
791
- let n = t.locale ?? k();
792
- return n === "en" ? ke(e) : n === "nl" ? Ae(e) : je(e);
793
- }), Ne = () => "Use your smartphone camera to scan this QR code", Pe = () => "Gebruik de camera van uw smartphone om deze QR-code te scannen", Fe = () => "Verwenden Sie die Kamera Ihres Smartphones, um diesen QR-Code zu scannen", Ie = ((e = {}, t = {}) => {
794
- let n = t.locale ?? k();
795
- return n === "en" ? Ne(e) : n === "nl" ? Pe(e) : Fe(e);
796
- }), Le = () => "The 3D model will open in your phone's AR mode", Re = () => "Het 3D-model wordt geopend in de AR-modus van uw telefoon", ze = () => "Das 3D-Modell wird im AR-Modus Ihres Telefons geöffnet", Be = ((e = {}, t = {}) => {
797
- let n = t.locale ?? k();
798
- return n === "en" ? Le(e) : n === "nl" ? Re(e) : ze(e);
799
- }), Ve = () => "Close", He = () => "Sluiten", Ue = () => "Schließen", We = ((e = {}, t = {}) => {
800
- let n = t.locale ?? k();
801
- return n === "en" ? Ve(e) : n === "nl" ? He(e) : Ue(e);
802
- }), Ge = () => "Toggle fullscreen", Ke = () => "Volledig scherm", qe = () => "Vollbild umschalten", Je = ((e = {}, t = {}) => {
803
- let n = t.locale ?? k();
804
- return n === "en" ? Ge(e) : n === "nl" ? Ke(e) : qe(e);
805
- }), Ye = () => "Downloading", Xe = () => "Downloaden", Ze = () => "Herunterladen", P = ((e = {}, t = {}) => {
806
- let n = t.locale ?? k();
807
- return n === "en" ? Ye(e) : n === "nl" ? Xe(e) : Ze(e);
808
- }), Qe = () => "Rendering", $e = () => "Renderen", et = () => "Rendern", tt = ((e = {}, t = {}) => {
809
- let n = t.locale ?? k();
810
- return n === "en" ? Qe(e) : n === "nl" ? $e(e) : et(e);
811
- }), nt = () => "Screenshot", rt = () => "Screenshot", it = () => "Screenshot", at = ((e = {}, t = {}) => {
812
- let n = t.locale ?? k();
813
- return n === "en" ? nt(e) : n === "nl" ? rt(e) : it(e);
814
- }), ot = () => "Reset camera", st = () => "Camera resetten", ct = () => "Kamera zurücksetzen", lt = ((e = {}, t = {}) => {
815
- let n = t.locale ?? k();
816
- return n === "en" ? ot(e) : n === "nl" ? st(e) : ct(e);
817
- }), ut = () => "Zoom in", dt = () => "Inzoomen", ft = () => "Hineinzoomen", pt = ((e = {}, t = {}) => {
818
- let n = t.locale ?? k();
819
- return n === "en" ? ut(e) : n === "nl" ? dt(e) : ft(e);
820
- }), mt = () => "Zoom out", ht = () => "Uitzoomen", gt = () => "Herauszoomen", _t = ((e = {}, t = {}) => {
821
- let n = t.locale ?? k();
822
- return n === "en" ? mt(e) : n === "nl" ? ht(e) : gt(e);
823
- }), vt = () => "Rotate left", yt = () => "Naar links draaien", bt = () => "Nach links drehen", xt = ((e = {}, t = {}) => {
824
- let n = t.locale ?? k();
825
- return n === "en" ? vt(e) : n === "nl" ? yt(e) : bt(e);
826
- }), St = () => "Rotate right", Ct = () => "Naar rechts draaien", wt = () => "Nach rechts drehen", Tt = ((e = {}, t = {}) => {
827
- let n = t.locale ?? k();
828
- return n === "en" ? St(e) : n === "nl" ? Ct(e) : wt(e);
829
- }), Et = () => "Tilt up", Dt = () => "Omhoog kantelen", Ot = () => "Nach oben kippen", kt = ((e = {}, t = {}) => {
830
- let n = t.locale ?? k();
831
- return n === "en" ? Et(e) : n === "nl" ? Dt(e) : Ot(e);
832
- }), At = () => "Tilt down", jt = () => "Omlaag kantelen", Mt = () => "Nach unten kippen", Nt = ((e = {}, t = {}) => {
833
- let n = t.locale ?? k();
834
- return n === "en" ? At(e) : n === "nl" ? jt(e) : Mt(e);
835
- });
836
- //#endregion
837
- //#region src/ui/loading.ts
838
- function F(e) {
839
- let t = Math.max(0, Math.min(1, e));
840
- return t * t * (3 - 2 * t);
841
- }
842
- function Pt(e, t, n, r, i, a) {
843
- let [o, s, c] = e, l = Math.cos(t), u = Math.sin(t), d = l * o + u * c, f = -u * o + l * c, p = Math.cos(n), m = Math.sin(n), h = p * s - m * f, g = m * s + p * f, _ = .55;
844
- return [
845
- r + d * a * _,
846
- i - h * a * _,
847
- g
848
- ];
849
- }
850
- function Ft(e, t, n) {
851
- e.beginPath(), e.moveTo(t[0], t[1]), e.lineTo(n[0], n[1]), e.strokeStyle = "#000", e.lineWidth = 2, e.stroke();
852
- }
853
- function It(e, t, n, r, i) {
854
- let a = t(n), o = t(r);
855
- Ft(e, a, [
856
- a[0] + (o[0] - a[0]) * i,
857
- a[1] + (o[1] - a[1]) * i,
858
- a[2]
859
- ]);
860
- }
861
- var I = [
862
- -1,
863
- -1,
864
- 1
865
- ], L = [
866
- 1,
867
- -1,
868
- 1
869
- ], R = [
870
- 1,
871
- -1,
872
- -1
873
- ], z = [
874
- -1,
875
- -1,
876
- -1
877
- ], B = [
878
- -1,
879
- 1,
880
- 1
881
- ], V = [
882
- 1,
883
- 1,
884
- 1
885
- ], H = [
886
- 1,
887
- 1,
888
- -1
889
- ], U = [
890
- -1,
891
- 1,
892
- -1
893
- ], Lt = [
894
- [I, L],
895
- [L, R],
896
- [R, z],
897
- [z, I],
898
- [I, B],
899
- [L, V],
900
- [R, H],
901
- [z, U],
902
- [B, V],
903
- [V, H],
904
- [H, U],
905
- [U, B]
906
- ], Rt = 400, zt = "-apple-system, BlinkMacSystemFont, \"Segoe UI\", system-ui, sans-serif";
907
- function Bt() {
908
- let e = document.createElement("div");
909
- Object.assign(e.style, {
910
- position: "absolute",
911
- inset: "0",
912
- display: "flex",
913
- flexDirection: "column",
914
- alignItems: "center",
915
- justifyContent: "center",
916
- background: "#fff",
917
- zIndex: "20",
918
- opacity: "0",
919
- transition: "opacity 0.3s ease-in-out"
920
- });
921
- let t = document.createElement("canvas");
922
- Object.assign(t.style, {
923
- width: "100%",
924
- height: "100%",
925
- position: "absolute",
926
- inset: "0"
927
- });
928
- let n = document.createElement("div");
929
- Object.assign(n.style, {
930
- position: "absolute",
931
- top: "56%",
932
- left: "0",
933
- right: "0",
934
- textAlign: "center",
935
- pointerEvents: "none"
936
- });
937
- let r = document.createElement("span");
938
- Object.assign(r.style, {
939
- fontSize: "13px",
940
- fontWeight: "400",
941
- color: "#000",
942
- fontVariantNumeric: "tabular-nums",
943
- fontFamily: zt
944
- });
945
- let i = document.createElement("span");
946
- return Object.assign(i.style, {
947
- fontSize: "13px",
948
- color: "#000",
949
- fontFamily: zt
950
- }), i.textContent = P(), n.appendChild(r), n.appendChild(i), e.appendChild(t), e.appendChild(n), {
951
- overlay: e,
952
- canvas: t,
953
- pctEl: r,
954
- phaseEl: i
955
- };
956
- }
957
- var Vt = class {
958
- overlay;
959
- canvas;
960
- ctx;
961
- pctEl;
962
- phaseEl;
963
- animationId = null;
964
- showTimerId = null;
965
- startTime;
966
- hidden = !1;
967
- visible = !1;
968
- constructor(e, t = {}) {
969
- this.startTime = performance.now();
970
- let n = Bt();
971
- this.overlay = n.overlay, this.canvas = n.canvas, this.pctEl = n.pctEl, this.phaseEl = n.phaseEl, e.appendChild(this.overlay), this.ctx = this.canvas.getContext("2d"), this.ctx !== null && (this.sizeCanvas(), this.tick());
972
- let r = t.showDelay ?? Rt;
973
- this.showTimerId = setTimeout(() => {
974
- this.reveal();
975
- }, r);
976
- }
977
- get loadingTexts() {
978
- return {
979
- downloading: P(),
980
- rendering: tt()
981
- };
982
- }
983
- updateProgress(e, t) {
984
- this.hidden || (this.pctEl.textContent = `${Math.round(e)}%`, this.phaseEl.textContent = t === "" ? "" : ` \u00B7 ${t}`);
985
- }
986
- showError(e) {
987
- if (this.hidden = !1, this.animationId !== null && (cancelAnimationFrame(this.animationId), this.animationId = null), this.ctx !== null) {
988
- let e = Math.min(devicePixelRatio, 2), t = this.canvas.width / e, n = this.canvas.height / e;
989
- this.ctx.fillStyle = "#fff", this.ctx.fillRect(0, 0, t * e, n * e);
990
- }
991
- this.pctEl.textContent = "", this.phaseEl.textContent = e, this.phaseEl.style.color = "#b91c1c", this.reveal();
992
- }
993
- hide() {
994
- if (!this.hidden) {
995
- if (this.hidden = !0, this.cancelShowTimer(), !this.visible) {
996
- this.destroy();
997
- return;
998
- }
999
- this.overlay.style.opacity = "0", this.overlay.addEventListener("transitionend", () => {
1000
- this.destroy();
1001
- }, { once: !0 }), setTimeout(() => {
1002
- this.destroy();
1003
- }, 500);
1004
- }
1005
- }
1006
- destroy() {
1007
- this.cancelShowTimer(), this.animationId !== null && (cancelAnimationFrame(this.animationId), this.animationId = null), this.overlay.remove();
1008
- }
1009
- reveal() {
1010
- this.hidden || this.visible || (this.visible = !0, this.overlay.style.opacity = "1");
1011
- }
1012
- cancelShowTimer() {
1013
- this.showTimerId !== null && (clearTimeout(this.showTimerId), this.showTimerId = null);
1014
- }
1015
- sizeCanvas() {
1016
- if (this.ctx === null) return;
1017
- let e = Math.min(devicePixelRatio, 2), t = this.overlay.clientWidth || 440, n = this.overlay.clientHeight || 360;
1018
- this.canvas.width = t * e, this.canvas.height = n * e, this.ctx.scale(e, e), this.ctx.lineCap = "round", this.ctx.lineJoin = "round";
1019
- }
1020
- tick = () => {
1021
- this.hidden || (this.drawFrame(), this.animationId = requestAnimationFrame(this.tick));
1022
- };
1023
- drawFrame() {
1024
- if (this.ctx === null) return;
1025
- let e = this.canvas.width / Math.min(devicePixelRatio, 2), t = this.canvas.height / Math.min(devicePixelRatio, 2), n = (performance.now() - this.startTime) / 1e3;
1026
- this.ctx.fillStyle = "#fff", this.ctx.fillRect(0, 0, e, t);
1027
- let r = e / 2, i = t * .44, a = Math.min(e, t) * .08, o = (e) => Pt(e, .785, .615, r, i, a), s = n % 6 / 6, c = Lt.length, l;
1028
- l = s < .35 ? F(s / .35) * c : s < .55 ? c : s < .9 ? (1 - F((s - .55) / .35)) * c : 0, this.ctx.shadowBlur = 5, this.ctx.shadowColor = "rgba(30,30,30,0.08)";
1029
- for (let e = 0; e < c && !(e >= l); e++) {
1030
- let t = Lt[e];
1031
- if (t === void 0) continue;
1032
- let n = Math.min(1, l - e);
1033
- It(this.ctx, o, t[0], t[1], n);
1034
- }
1035
- this.ctx.shadowBlur = 0;
1036
- }
1037
- }, Ht = {
847
+ var De = () => "Activate AR", Oe = () => "AR activeren", ke = () => "AR aktivieren", Ae = ((e = {}, t = {}) => {
848
+ let n = t.locale ?? M();
849
+ return n === "en" ? De(e) : n === "nl" ? Oe(e) : ke(e);
850
+ }), je = () => "Scan to view in AR", Me = () => "Scan om in AR te bekijken", Ne = () => "Scannen für AR-Ansicht", Pe = ((e = {}, t = {}) => {
851
+ let n = t.locale ?? M();
852
+ return n === "en" ? je(e) : n === "nl" ? Me(e) : Ne(e);
853
+ }), Fe = () => "Use your smartphone camera to scan this QR code", Ie = () => "Gebruik de camera van je smartphone om deze QR-code te scannen", Le = () => "Verwenden Sie die Kamera Ihres Smartphones, um diesen QR-Code zu scannen", Re = ((e = {}, t = {}) => {
854
+ let n = t.locale ?? M();
855
+ return n === "en" ? Fe(e) : n === "nl" ? Ie(e) : Le(e);
856
+ }), ze = () => "The 3D model will open in your phone's AR mode", Be = () => "Het 3D-model wordt geopend in de AR-modus van je telefoon", Ve = () => "Das 3D-Modell wird im AR-Modus Ihres Telefons geöffnet", He = ((e = {}, t = {}) => {
857
+ let n = t.locale ?? M();
858
+ return n === "en" ? ze(e) : n === "nl" ? Be(e) : Ve(e);
859
+ }), Ue = () => "Close", We = () => "Sluiten", Ge = () => "Schließen", Ke = ((e = {}, t = {}) => {
860
+ let n = t.locale ?? M();
861
+ return n === "en" ? Ue(e) : n === "nl" ? We(e) : Ge(e);
862
+ }), qe = () => "Toggle fullscreen", Je = () => "Volledig scherm", Ye = () => "Vollbild umschalten", Xe = ((e = {}, t = {}) => {
863
+ let n = t.locale ?? M();
864
+ return n === "en" ? qe(e) : n === "nl" ? Je(e) : Ye(e);
865
+ }), Ze = () => "Downloading", Qe = () => "Downloaden", $e = () => "Herunterladen", et = ((e = {}, t = {}) => {
866
+ let n = t.locale ?? M();
867
+ return n === "en" ? Ze(e) : n === "nl" ? Qe(e) : $e(e);
868
+ }), tt = () => "Rendering", nt = () => "Renderen", rt = () => "Rendern", it = ((e = {}, t = {}) => {
869
+ let n = t.locale ?? M();
870
+ return n === "en" ? tt(e) : n === "nl" ? nt(e) : rt(e);
871
+ }), at = () => "Screenshot", ot = () => "Screenshot", st = () => "Screenshot", ct = ((e = {}, t = {}) => {
872
+ let n = t.locale ?? M();
873
+ return n === "en" ? at(e) : n === "nl" ? ot(e) : st(e);
874
+ }), lt = () => "Reset camera", ut = () => "Camera resetten", dt = () => "Kamera zurücksetzen", ft = ((e = {}, t = {}) => {
875
+ let n = t.locale ?? M();
876
+ return n === "en" ? lt(e) : n === "nl" ? ut(e) : dt(e);
877
+ }), pt = () => "Zoom in", mt = () => "Inzoomen", ht = () => "Hineinzoomen", gt = ((e = {}, t = {}) => {
878
+ let n = t.locale ?? M();
879
+ return n === "en" ? pt(e) : n === "nl" ? mt(e) : ht(e);
880
+ }), _t = () => "Zoom out", vt = () => "Uitzoomen", yt = () => "Herauszoomen", bt = ((e = {}, t = {}) => {
881
+ let n = t.locale ?? M();
882
+ return n === "en" ? _t(e) : n === "nl" ? vt(e) : yt(e);
883
+ }), xt = () => "Rotate left", St = () => "Naar links draaien", Ct = () => "Nach links drehen", wt = ((e = {}, t = {}) => {
884
+ let n = t.locale ?? M();
885
+ return n === "en" ? xt(e) : n === "nl" ? St(e) : Ct(e);
886
+ }), Tt = () => "Rotate right", Et = () => "Naar rechts draaien", Dt = () => "Nach rechts drehen", Ot = ((e = {}, t = {}) => {
887
+ let n = t.locale ?? M();
888
+ return n === "en" ? Tt(e) : n === "nl" ? Et(e) : Dt(e);
889
+ }), kt = () => "Tilt up", At = () => "Omhoog kantelen", jt = () => "Nach oben kippen", Mt = ((e = {}, t = {}) => {
890
+ let n = t.locale ?? M();
891
+ return n === "en" ? kt(e) : n === "nl" ? At(e) : jt(e);
892
+ }), Nt = () => "Tilt down", Pt = () => "Omlaag kantelen", Ft = () => "Nach unten kippen", It = ((e = {}, t = {}) => {
893
+ let n = t.locale ?? M();
894
+ return n === "en" ? Nt(e) : n === "nl" ? Pt(e) : Ft(e);
895
+ }), Lt = {
1038
896
  xmlns: "http://www.w3.org/2000/svg",
1039
897
  width: 24,
1040
898
  height: 24,
@@ -1044,40 +902,40 @@ var Vt = class {
1044
902
  "stroke-width": 2,
1045
903
  "stroke-linecap": "round",
1046
904
  "stroke-linejoin": "round"
1047
- }, Ut = ([e, t, n]) => {
905
+ }, Rt = ([e, t, n]) => {
1048
906
  let r = document.createElementNS("http://www.w3.org/2000/svg", e);
1049
907
  return Object.keys(t).forEach((e) => {
1050
908
  r.setAttribute(e, String(t[e]));
1051
909
  }), n?.length && n.forEach((e) => {
1052
- let t = Ut(e);
910
+ let t = Rt(e);
1053
911
  r.appendChild(t);
1054
912
  }), r;
1055
- }, Wt = (e, t = {}) => Ut([
913
+ }, zt = (e, t = {}) => Rt([
1056
914
  "svg",
1057
915
  {
1058
- ...Ht,
916
+ ...Lt,
1059
917
  ...t
1060
918
  },
1061
919
  e
1062
- ]), Gt = [
920
+ ]), Bt = [
1063
921
  ["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" }],
1064
922
  ["path", { d: "m3.3 7 8.7 5 8.7-5" }],
1065
923
  ["path", { d: "M12 22V12" }]
1066
- ], Kt = [["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", {
924
+ ], Vt = [["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", {
1067
925
  cx: "12",
1068
926
  cy: "13",
1069
927
  r: "3"
1070
- }]], qt = [["path", { d: "m6 9 6 6 6-6" }]], Jt = [["path", { d: "m15 18-6-6 6-6" }]], Yt = [["path", { d: "m9 18 6-6-6-6" }]], Xt = [["path", { d: "m18 15-6-6-6 6" }]], Zt = [
928
+ }]], Ht = [["path", { d: "m6 9 6 6 6-6" }]], Ut = [["path", { d: "m15 18-6-6 6-6" }]], Wt = [["path", { d: "m9 18 6-6-6-6" }]], Gt = [["path", { d: "m18 15-6-6-6 6" }]], Kt = [
1071
929
  ["path", { d: "M15 3h6v6" }],
1072
930
  ["path", { d: "m21 3-7 7" }],
1073
931
  ["path", { d: "m3 21 7-7" }],
1074
932
  ["path", { d: "M9 21H3v-6" }]
1075
- ], Qt = [
933
+ ], qt = [
1076
934
  ["path", { d: "m14 10 7-7" }],
1077
935
  ["path", { d: "M20 10h-6V4" }],
1078
936
  ["path", { d: "m3 21 7-7" }],
1079
937
  ["path", { d: "M4 14h6v6" }]
1080
- ], $t = [["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" }]], en = [
938
+ ], Jt = [["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" }]], Yt = [
1081
939
  ["circle", {
1082
940
  cx: "11",
1083
941
  cy: "11",
@@ -1101,7 +959,7 @@ var Vt = class {
1101
959
  y1: "11",
1102
960
  y2: "11"
1103
961
  }]
1104
- ], tn = [
962
+ ], Xt = [
1105
963
  ["circle", {
1106
964
  cx: "11",
1107
965
  cy: "11",
@@ -1122,26 +980,26 @@ var Vt = class {
1122
980
  ];
1123
981
  //#endregion
1124
982
  //#region ../ui/src/icons.ts
1125
- function W(e, { size: t = 20, strokeWidth: n = 1.75 } = {}) {
1126
- return Wt(e, {
983
+ function I(e, { size: t = 20, strokeWidth: n = 1.75 } = {}) {
984
+ return zt(e, {
1127
985
  width: t,
1128
986
  height: t,
1129
987
  "stroke-width": n
1130
988
  });
1131
989
  }
1132
- var G = {
1133
- ar: (e) => W(Gt, e),
1134
- fullscreen: (e) => W(Zt, e),
1135
- exitFullscreen: (e) => W(Qt, e),
1136
- screenshot: (e) => W(Kt, e),
1137
- tiltUp: (e) => W(Xt, e),
1138
- tiltDown: (e) => W(qt, e),
1139
- rotateLeft: (e) => W(Jt, e),
1140
- rotateRight: (e) => W(Yt, e),
1141
- zoomIn: (e) => W(en, e),
1142
- zoomOut: (e) => W(tn, e),
1143
- reset: (e) => W($t, e)
1144
- }, K = class {
990
+ var L = {
991
+ ar: (e) => I(Bt, e),
992
+ fullscreen: (e) => I(Kt, e),
993
+ exitFullscreen: (e) => I(qt, e),
994
+ screenshot: (e) => I(Vt, e),
995
+ tiltUp: (e) => I(Gt, e),
996
+ tiltDown: (e) => I(Ht, e),
997
+ rotateLeft: (e) => I(Ut, e),
998
+ rotateRight: (e) => I(Wt, e),
999
+ zoomIn: (e) => I(Yt, e),
1000
+ zoomOut: (e) => I(Xt, e),
1001
+ reset: (e) => I(Jt, e)
1002
+ }, R = class {
1145
1003
  element;
1146
1004
  constructor({ variant: e = "default", size: t = "default", label: n, icon: r, onClick: i, disabled: a = !1 } = {}) {
1147
1005
  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;
@@ -1150,7 +1008,7 @@ var G = {
1150
1008
  let t = this.element.querySelector("svg");
1151
1009
  t === null ? this.element.appendChild(e) : t.replaceWith(e);
1152
1010
  }
1153
- }, q = {
1011
+ }, z = {
1154
1012
  brand: {
1155
1013
  DEFAULT: "#171717",
1156
1014
  primary: "#171717",
@@ -1189,7 +1047,7 @@ var G = {
1189
1047
  },
1190
1048
  white: "#ffffff",
1191
1049
  black: "#000000"
1192
- }, J = {
1050
+ }, B = {
1193
1051
  px: "1px",
1194
1052
  0: "0",
1195
1053
  .5: "0.125rem",
@@ -1212,27 +1070,27 @@ var G = {
1212
1070
  20: "5rem",
1213
1071
  24: "6rem"
1214
1072
  };
1215
- J[1], J[2], J[4], J[6], J[8], J[12];
1073
+ B[1], B[2], B[4], B[6], B[8], B[12];
1216
1074
  //#endregion
1217
1075
  //#region ../ui/src/vanilla/components/card/index.ts
1218
- var nn = class {
1076
+ var Zt = class {
1219
1077
  element;
1220
1078
  constructor() {
1221
1079
  this.element = document.createElement("div"), Object.assign(this.element.style, {
1222
- background: q.white,
1223
- borderRadius: J[3],
1224
- padding: J[6],
1225
- boxShadow: `0 ${J[2]} ${J[8]} oklch(0% 0 0 / 20%)`,
1080
+ background: z.white,
1081
+ borderRadius: B[3],
1082
+ padding: B[6],
1083
+ boxShadow: `0 ${B[2]} ${B[8]} oklch(0% 0 0 / 20%)`,
1226
1084
  maxWidth: "20rem",
1227
1085
  width: "100%"
1228
1086
  });
1229
1087
  }
1230
- }, rn = class {
1088
+ }, Qt = class {
1231
1089
  card;
1232
1090
  backdrop;
1233
1091
  keyHandler = null;
1234
1092
  constructor(e = {}) {
1235
- this.options = e, this.card = new nn(), this.backdrop = this.createBackdrop(), this.backdrop.appendChild(this.card.element);
1093
+ this.options = e, this.card = new Zt(), this.backdrop = this.createBackdrop(), this.backdrop.appendChild(this.card.element);
1236
1094
  }
1237
1095
  open() {
1238
1096
  document.body.appendChild(this.backdrop), this.keyHandler = (e) => {
@@ -1246,7 +1104,7 @@ var nn = class {
1246
1104
  let e = document.createElement("div");
1247
1105
  return Object.assign(e.style, {
1248
1106
  position: "fixed",
1249
- inset: J[0],
1107
+ inset: B[0],
1250
1108
  background: "oklch(0% 0 0 / 50%)",
1251
1109
  zIndex: "9999",
1252
1110
  display: "flex",
@@ -1256,7 +1114,7 @@ var nn = class {
1256
1114
  t.target === e && this.close();
1257
1115
  }), e;
1258
1116
  }
1259
- }, an = class {
1117
+ }, $t = class {
1260
1118
  element;
1261
1119
  selectCallback = null;
1262
1120
  constructor(e, t, n) {
@@ -1274,7 +1132,7 @@ var nn = class {
1274
1132
  onSelect(e) {
1275
1133
  this.selectCallback = e;
1276
1134
  }
1277
- }, on = class {
1135
+ }, en = class {
1278
1136
  element;
1279
1137
  select;
1280
1138
  constructor(e, t, n, r, i) {
@@ -1287,7 +1145,7 @@ var nn = class {
1287
1145
  a.value = n, a.textContent = i?.[e] ?? n, n === r && (a.selected = !0, o = !0), this.select.appendChild(a);
1288
1146
  }
1289
1147
  o || (a.selected = !0);
1290
- let s = Wt(qt, {
1148
+ let s = zt(Ht, {
1291
1149
  width: 16,
1292
1150
  height: 16,
1293
1151
  "stroke-width": 2
@@ -1302,7 +1160,7 @@ var nn = class {
1302
1160
  e(this.select.value);
1303
1161
  });
1304
1162
  }
1305
- }, Y = {
1163
+ }, V = {
1306
1164
  fontFamily: {
1307
1165
  sans: [
1308
1166
  "Mona Sans",
@@ -1341,42 +1199,42 @@ var nn = class {
1341
1199
  normal: "1.5",
1342
1200
  relaxed: "1.75"
1343
1201
  }
1344
- }, sn = Y.fontFamily.sans.join(", "), cn = class {
1202
+ }, tn = V.fontFamily.sans.join(", "), nn = class {
1345
1203
  qrLib = null;
1346
1204
  dialog = null;
1347
1205
  async show(t) {
1348
- this.hide(), this.qrLib ??= await import("./browser-DbgxVbZp.js").then((t) => /* @__PURE__ */ e(t.default, 1));
1206
+ this.hide(), this.qrLib ??= await import("./browser-DxtIwHNu.js").then((t) => /* @__PURE__ */ e(t.default, 1));
1349
1207
  let n = await this.qrLib.toDataURL(t, {
1350
1208
  width: 256,
1351
1209
  margin: 4,
1352
1210
  errorCorrectionLevel: "M",
1353
1211
  color: {
1354
- dark: q.black,
1355
- light: q.white
1212
+ dark: z.black,
1213
+ light: z.white
1356
1214
  }
1357
1215
  });
1358
- this.dialog = new rn({ onClose: () => {
1216
+ this.dialog = new Qt({ onClose: () => {
1359
1217
  this.dialog = null;
1360
1218
  } }), Object.assign(this.dialog.card.element.style, {
1361
1219
  display: "flex",
1362
1220
  flexDirection: "column",
1363
1221
  alignItems: "center",
1364
- gap: J[3],
1365
- fontFamily: sn
1366
- }), this.dialog.card.element.appendChild(this.createText(Me(), {
1367
- fontSize: Y.fontSize.base,
1368
- fontWeight: Y.fontWeight.semibold,
1369
- color: q.neutral[900]
1370
- })), this.dialog.card.element.appendChild(this.createText(Ie(), {
1371
- fontSize: Y.fontSize.sm,
1372
- color: q.neutral[600]
1373
- })), this.dialog.card.element.appendChild(this.createQrImage(n)), this.dialog.card.element.appendChild(this.createText(Be(), {
1374
- fontSize: Y.fontSize.xs,
1375
- color: q.neutral[500]
1222
+ gap: B[3],
1223
+ fontFamily: tn
1224
+ }), this.dialog.card.element.appendChild(this.createText(Pe(), {
1225
+ fontSize: V.fontSize.base,
1226
+ fontWeight: V.fontWeight.semibold,
1227
+ color: z.neutral[900]
1228
+ })), this.dialog.card.element.appendChild(this.createText(Re(), {
1229
+ fontSize: V.fontSize.sm,
1230
+ color: z.neutral[600]
1231
+ })), this.dialog.card.element.appendChild(this.createQrImage(n)), this.dialog.card.element.appendChild(this.createText(He(), {
1232
+ fontSize: V.fontSize.xs,
1233
+ color: z.neutral[500]
1376
1234
  }));
1377
- let r = new K({
1235
+ let r = new R({
1378
1236
  variant: "outline",
1379
- label: We(),
1237
+ label: Ke(),
1380
1238
  onClick: () => {
1381
1239
  this.hide();
1382
1240
  }
@@ -1397,12 +1255,12 @@ var nn = class {
1397
1255
  createQrImage(e) {
1398
1256
  let t = document.createElement("img");
1399
1257
  return t.src = e, t.alt = "QR code", Object.assign(t.style, {
1400
- width: J[24],
1401
- height: J[24],
1402
- borderRadius: J[1]
1258
+ width: B[24],
1259
+ height: B[24],
1260
+ borderRadius: B[1]
1403
1261
  }), t;
1404
1262
  }
1405
- }, X = Y.fontFamily.sans.join(", "), ln = `
1263
+ }, H = V.fontFamily.sans.join(", "), rn = `
1406
1264
  :root {
1407
1265
  --primary: oklch(5% 0 0);
1408
1266
  --primary-foreground: oklch(100% 0 0);
@@ -1426,7 +1284,7 @@ var nn = class {
1426
1284
  gap: 0.5rem;
1427
1285
  border: 1px solid transparent;
1428
1286
  border-radius: var(--radius);
1429
- font-family: ${X};
1287
+ font-family: ${H};
1430
1288
  font-size: 0.875rem;
1431
1289
  font-weight: 600;
1432
1290
  white-space: nowrap;
@@ -1483,7 +1341,7 @@ var nn = class {
1483
1341
  border-radius: var(--radius);
1484
1342
  background: var(--background);
1485
1343
  color: var(--foreground);
1486
- font-family: ${X};
1344
+ font-family: ${H};
1487
1345
  font-size: 0.875rem;
1488
1346
  font-weight: 600;
1489
1347
  cursor: pointer;
@@ -1517,7 +1375,7 @@ var nn = class {
1517
1375
  background: var(--background);
1518
1376
  appearance: none;
1519
1377
  color: var(--foreground);
1520
- font-family: ${X};
1378
+ font-family: ${H};
1521
1379
  font-size: 0.875rem;
1522
1380
  font-weight: 400;
1523
1381
  cursor: pointer;
@@ -1539,55 +1397,302 @@ var nn = class {
1539
1397
  color: var(--muted-foreground);
1540
1398
  pointer-events: none;
1541
1399
  }
1542
- `, Z = !1;
1543
- function un() {
1544
- if (Z || typeof document > "u") return;
1545
- Z = !0;
1400
+
1401
+ /* ── Annotation layer ───────────────────────────────────── */
1402
+ .vd-annotations-layer {
1403
+ position: absolute;
1404
+ inset-block-start: 0;
1405
+ inset-inline-start: 0;
1406
+ inline-size: 100%;
1407
+ block-size: 100%;
1408
+ pointer-events: none;
1409
+ overflow: visible !important; /* override CSS2DRenderer inline style */
1410
+ }
1411
+
1412
+ .vd-annotation-marker {
1413
+ display: flex;
1414
+ align-items: center;
1415
+ justify-content: center;
1416
+ inline-size: 1.75rem;
1417
+ block-size: 1.75rem;
1418
+ border-radius: 50%;
1419
+ border: 2px solid oklch(100% 0 0);
1420
+ background: var(--primary);
1421
+ color: var(--primary-foreground);
1422
+ font-family: ${H};
1423
+ font-size: 0.8125rem;
1424
+ font-weight: 600;
1425
+ cursor: pointer;
1426
+ pointer-events: auto;
1427
+ box-shadow: 0 2px 8px oklch(5% 0 0 / 20%);
1428
+ transition: transform 100ms ease;
1429
+ position: relative;
1430
+ }
1431
+ .vd-annotation-marker:hover { transform: scale(1.1); }
1432
+
1433
+ .vd-annotation-popup {
1434
+ position: absolute;
1435
+ inset-block-end: calc(100% + 0.5rem);
1436
+ inset-inline-start: 50%;
1437
+ transform: translateX(-50%);
1438
+ background: var(--background);
1439
+ color: var(--foreground);
1440
+ border: 1px solid var(--border);
1441
+ border-radius: var(--radius);
1442
+ padding: 0.75rem 1rem;
1443
+ max-inline-size: 15rem;
1444
+ box-shadow: 0 4px 6px oklch(5% 0 0 / 8%), 0 2px 4px oklch(5% 0 0 / 6%);
1445
+ pointer-events: auto;
1446
+ white-space: normal;
1447
+ }
1448
+
1449
+ @media (prefers-reduced-motion: no-preference) {
1450
+ .vd-annotation-popup {
1451
+ animation: vd-popup-in 150ms ease;
1452
+ }
1453
+ }
1454
+
1455
+ @keyframes vd-popup-in {
1456
+ from { opacity: 0; transform: translateX(-50%) translateY(4px); }
1457
+ to { opacity: 1; transform: translateX(-50%) translateY(0); }
1458
+ }
1459
+
1460
+ .vd-annotation-popup-title {
1461
+ font-family: ${H};
1462
+ font-size: 0.875rem;
1463
+ font-weight: 600;
1464
+ line-height: 1.25rem;
1465
+ }
1466
+
1467
+ .vd-annotation-popup-description {
1468
+ font-family: ${H};
1469
+ font-size: 0.8125rem;
1470
+ font-weight: 400;
1471
+ line-height: 1.125rem;
1472
+ color: var(--muted-foreground);
1473
+ margin-block-start: 0.25rem;
1474
+ }
1475
+ `, an = !1;
1476
+ function on() {
1477
+ if (an || typeof document > "u") return;
1478
+ an = !0;
1546
1479
  let e = document.createElement("style");
1547
- e.id = "vd-ui-vanilla", e.textContent = ln, document.head.appendChild(e);
1480
+ e.id = "vd-ui-vanilla", e.textContent = rn, document.head.appendChild(e);
1548
1481
  }
1549
1482
  //#endregion
1550
- //#region src/ui/toolbar.ts
1551
- function dn(e, t) {
1552
- let n = document.createElement("a");
1553
- n.href = `data:image/png;base64,${e}`, n.download = t, n.click();
1483
+ //#region src/ui/loading.ts
1484
+ function sn(e) {
1485
+ let t = Math.max(0, Math.min(1, e));
1486
+ return t * t * (3 - 2 * t);
1554
1487
  }
1555
- var fn = class {
1556
- element;
1557
- screenshotBtn = null;
1558
- constructor(e) {
1559
- this.options = e, this.element = document.createElement("div"), this.element.className = "vd-toolbar";
1488
+ function cn(e, t, n, r, i, a) {
1489
+ let [o, s, c] = e, l = Math.cos(t), u = Math.sin(t), d = l * o + u * c, f = -u * o + l * c, p = Math.cos(n), m = Math.sin(n), h = p * s - m * f, g = m * s + p * f, _ = .55;
1490
+ return [
1491
+ r + d * a * _,
1492
+ i - h * a * _,
1493
+ g
1494
+ ];
1495
+ }
1496
+ function ln(e, t, n) {
1497
+ e.beginPath(), e.moveTo(t[0], t[1]), e.lineTo(n[0], n[1]), e.strokeStyle = "#000", e.lineWidth = 2, e.stroke();
1498
+ }
1499
+ function un(e, t, n, r, i) {
1500
+ let a = t(n), o = t(r);
1501
+ ln(e, a, [
1502
+ a[0] + (o[0] - a[0]) * i,
1503
+ a[1] + (o[1] - a[1]) * i,
1504
+ a[2]
1505
+ ]);
1506
+ }
1507
+ var U = [
1508
+ -1,
1509
+ -1,
1510
+ 1
1511
+ ], W = [
1512
+ 1,
1513
+ -1,
1514
+ 1
1515
+ ], G = [
1516
+ 1,
1517
+ -1,
1518
+ -1
1519
+ ], K = [
1520
+ -1,
1521
+ -1,
1522
+ -1
1523
+ ], q = [
1524
+ -1,
1525
+ 1,
1526
+ 1
1527
+ ], J = [
1528
+ 1,
1529
+ 1,
1530
+ 1
1531
+ ], Y = [
1532
+ 1,
1533
+ 1,
1534
+ -1
1535
+ ], X = [
1536
+ -1,
1537
+ 1,
1538
+ -1
1539
+ ], dn = [
1540
+ [U, W],
1541
+ [W, G],
1542
+ [G, K],
1543
+ [K, U],
1544
+ [U, q],
1545
+ [W, J],
1546
+ [G, Y],
1547
+ [K, X],
1548
+ [q, J],
1549
+ [J, Y],
1550
+ [Y, X],
1551
+ [X, q]
1552
+ ], fn = 400, pn = "-apple-system, BlinkMacSystemFont, \"Segoe UI\", system-ui, sans-serif";
1553
+ function mn() {
1554
+ let e = document.createElement("div");
1555
+ Object.assign(e.style, {
1556
+ position: "absolute",
1557
+ inset: "0",
1558
+ display: "flex",
1559
+ flexDirection: "column",
1560
+ alignItems: "center",
1561
+ justifyContent: "center",
1562
+ background: "#fff",
1563
+ zIndex: "20",
1564
+ opacity: "0",
1565
+ transition: "opacity 0.3s ease-in-out"
1566
+ });
1567
+ let t = document.createElement("canvas");
1568
+ Object.assign(t.style, {
1569
+ width: "100%",
1570
+ height: "100%",
1571
+ position: "absolute",
1572
+ inset: "0"
1573
+ });
1574
+ let n = document.createElement("div");
1575
+ Object.assign(n.style, {
1576
+ position: "absolute",
1577
+ top: "56%",
1578
+ left: "0",
1579
+ right: "0",
1580
+ textAlign: "center",
1581
+ pointerEvents: "none"
1582
+ });
1583
+ let r = document.createElement("span");
1584
+ Object.assign(r.style, {
1585
+ fontSize: "13px",
1586
+ fontWeight: "400",
1587
+ color: "#000",
1588
+ fontVariantNumeric: "tabular-nums",
1589
+ fontFamily: pn
1590
+ });
1591
+ let i = document.createElement("span");
1592
+ return Object.assign(i.style, {
1593
+ fontSize: "13px",
1594
+ color: "#000",
1595
+ fontFamily: pn
1596
+ }), i.textContent = et(), n.appendChild(r), n.appendChild(i), e.appendChild(t), e.appendChild(n), {
1597
+ overlay: e,
1598
+ canvas: t,
1599
+ pctEl: r,
1600
+ phaseEl: i
1601
+ };
1602
+ }
1603
+ var hn = class {
1604
+ overlay;
1605
+ canvas;
1606
+ ctx;
1607
+ pctEl;
1608
+ phaseEl;
1609
+ animationId = null;
1610
+ showTimerId = null;
1611
+ startTime;
1612
+ hidden = !1;
1613
+ visible = !1;
1614
+ constructor(e, t = {}) {
1615
+ this.startTime = performance.now();
1616
+ let n = mn();
1617
+ this.overlay = n.overlay, this.canvas = n.canvas, this.pctEl = n.pctEl, this.phaseEl = n.phaseEl, e.appendChild(this.overlay), this.ctx = this.canvas.getContext("2d"), this.ctx !== null && (this.sizeCanvas(), this.tick());
1618
+ let r = t.showDelay ?? fn;
1619
+ this.showTimerId = setTimeout(() => {
1620
+ this.reveal();
1621
+ }, r);
1560
1622
  }
1561
- syncButton(e, t, n) {
1562
- if (t && e === null) {
1563
- let e = n();
1564
- return this.element.appendChild(e.element), e;
1623
+ get loadingTexts() {
1624
+ return {
1625
+ downloading: et(),
1626
+ rendering: it()
1627
+ };
1628
+ }
1629
+ updateProgress(e, t) {
1630
+ this.hidden || (this.pctEl.textContent = `${Math.round(e)}%`, this.phaseEl.textContent = t === "" ? "" : ` \u00B7 ${t}`);
1631
+ }
1632
+ showError(e) {
1633
+ if (this.hidden = !1, this.animationId !== null && (cancelAnimationFrame(this.animationId), this.animationId = null), this.ctx !== null) {
1634
+ let e = Math.min(devicePixelRatio, 2), t = this.canvas.width / e, n = this.canvas.height / e;
1635
+ this.ctx.fillStyle = "#fff", this.ctx.fillRect(0, 0, t * e, n * e);
1565
1636
  }
1566
- return !t && e !== null ? (e.element.remove(), null) : e;
1637
+ this.pctEl.textContent = "", this.phaseEl.textContent = e, this.phaseEl.style.color = "#b91c1c", this.reveal();
1567
1638
  }
1568
- applySettings(e) {
1569
- this.screenshotBtn = this.syncButton(this.screenshotBtn, e.screenshot === !0, () => new K({
1570
- variant: "outline",
1571
- size: "icon",
1572
- label: at(),
1573
- icon: G.screenshot(),
1574
- onClick: () => {
1575
- this.options.snapshotApi.take("snapshot.png").onDeveloped(({ data: e, filename: t }) => {
1576
- dn(e, t);
1577
- });
1639
+ hide() {
1640
+ if (!this.hidden) {
1641
+ if (this.hidden = !0, this.cancelShowTimer(), !this.visible) {
1642
+ this.destroy();
1643
+ return;
1578
1644
  }
1579
- }));
1645
+ this.overlay.style.opacity = "0", this.overlay.addEventListener("transitionend", () => {
1646
+ this.destroy();
1647
+ }, { once: !0 }), setTimeout(() => {
1648
+ this.destroy();
1649
+ }, 500);
1650
+ }
1651
+ }
1652
+ destroy() {
1653
+ this.cancelShowTimer(), this.animationId !== null && (cancelAnimationFrame(this.animationId), this.animationId = null), this.overlay.remove();
1654
+ }
1655
+ reveal() {
1656
+ this.hidden || this.visible || (this.visible = !0, this.overlay.style.opacity = "1");
1657
+ }
1658
+ cancelShowTimer() {
1659
+ this.showTimerId !== null && (clearTimeout(this.showTimerId), this.showTimerId = null);
1580
1660
  }
1581
- }, pn = class {
1661
+ sizeCanvas() {
1662
+ if (this.ctx === null) return;
1663
+ let e = Math.min(devicePixelRatio, 2), t = this.overlay.clientWidth || 440, n = this.overlay.clientHeight || 360;
1664
+ this.canvas.width = t * e, this.canvas.height = n * e, this.ctx.scale(e, e), this.ctx.lineCap = "round", this.ctx.lineJoin = "round";
1665
+ }
1666
+ tick = () => {
1667
+ this.hidden || (this.drawFrame(), this.animationId = requestAnimationFrame(this.tick));
1668
+ };
1669
+ drawFrame() {
1670
+ if (this.ctx === null) return;
1671
+ let e = this.canvas.width / Math.min(devicePixelRatio, 2), t = this.canvas.height / Math.min(devicePixelRatio, 2), n = (performance.now() - this.startTime) / 1e3;
1672
+ this.ctx.fillStyle = "#fff", this.ctx.fillRect(0, 0, e, t);
1673
+ let r = e / 2, i = t * .44, a = Math.min(e, t) * .08, o = (e) => cn(e, .785, .615, r, i, a), s = n % 6 / 6, c = dn.length, l;
1674
+ l = s < .35 ? sn(s / .35) * c : s < .55 ? c : s < .9 ? (1 - sn((s - .55) / .35)) * c : 0, this.ctx.shadowBlur = 5, this.ctx.shadowColor = "rgba(30,30,30,0.08)";
1675
+ for (let e = 0; e < c && !(e >= l); e++) {
1676
+ let t = dn[e];
1677
+ if (t === void 0) continue;
1678
+ let n = Math.min(1, l - e);
1679
+ un(this.ctx, o, t[0], t[1], n);
1680
+ }
1681
+ this.ctx.shadowBlur = 0;
1682
+ }
1683
+ }, gn = class {
1582
1684
  element;
1583
1685
  arBtn = null;
1584
1686
  fullscreenBtn = null;
1585
1687
  onFullscreenChange;
1586
1688
  constructor(e) {
1587
- this.options = e, this.element = document.createElement("div"), this.element.className = "vd-action-bar", this.onFullscreenChange = () => {
1689
+ this.options = e, this.element = document.createElement("div"), Object.assign(this.element.style, {
1690
+ display: "flex",
1691
+ gap: "0.375rem"
1692
+ }), this.onFullscreenChange = () => {
1588
1693
  if (this.fullscreenBtn === null) return;
1589
1694
  let e = document.fullscreenElement !== null;
1590
- this.fullscreenBtn.setIcon(e ? G.exitFullscreen() : G.fullscreen());
1695
+ this.fullscreenBtn.setIcon(e ? L.exitFullscreen() : L.fullscreen());
1591
1696
  }, document.addEventListener("fullscreenchange", this.onFullscreenChange);
1592
1697
  }
1593
1698
  syncButton(e, t, n) {
@@ -1598,19 +1703,19 @@ var fn = class {
1598
1703
  return !t && e !== null ? (e.element.remove(), null) : e;
1599
1704
  }
1600
1705
  applySettings(e) {
1601
- this.arBtn = this.syncButton(this.arBtn, e.ar !== !1 && this.options.onAr !== void 0, () => new K({
1706
+ this.arBtn = this.syncButton(this.arBtn, e.ar !== !1 && this.options.onAr !== void 0, () => new R({
1602
1707
  variant: "outline",
1603
1708
  size: "icon",
1604
- label: Oe(),
1605
- icon: G.ar(),
1709
+ label: Ae(),
1710
+ icon: L.ar(),
1606
1711
  onClick: () => {
1607
1712
  this.options.onAr?.();
1608
1713
  }
1609
- })), this.fullscreenBtn = this.syncButton(this.fullscreenBtn, e.fullscreen !== !1 && this.options.onFullscreen !== void 0, () => new K({
1714
+ })), this.fullscreenBtn = this.syncButton(this.fullscreenBtn, e.fullscreen !== !1 && this.options.onFullscreen !== void 0, () => new R({
1610
1715
  variant: "outline",
1611
1716
  size: "icon",
1612
- label: Je(),
1613
- icon: G.fullscreen(),
1717
+ label: Xe(),
1718
+ icon: L.fullscreen(),
1614
1719
  onClick: () => {
1615
1720
  this.options.onFullscreen?.();
1616
1721
  }
@@ -1619,112 +1724,133 @@ var fn = class {
1619
1724
  destroy() {
1620
1725
  document.removeEventListener("fullscreenchange", this.onFullscreenChange);
1621
1726
  }
1622
- }, Q = .5, mn = class e {
1727
+ }, Z = .5, _n = class e {
1623
1728
  element;
1624
1729
  constructor(t, n) {
1625
1730
  this.element = Object.assign(document.createElement("div"), { className: "vd-camera-controls" });
1626
- let r = n.rotation, i = n.tilt, a = n.zoom, o = 0, s = (e) => Math.max(n.limits?.minZoom ?? 1, Math.min(n.limits?.maxZoom ?? Infinity, e)), c = (e) => {
1627
- let t = n.limits?.minRotate, r = n.limits?.maxRotate;
1628
- return t !== void 0 || r !== void 0 ? Math.max(t ?? -Infinity, Math.min(r ?? Infinity, e)) : e;
1629
- }, l = (e) => {
1630
- let a = n.limits?.minTilt, s = n.limits?.maxTilt;
1631
- if (a !== void 0 || s !== void 0) {
1632
- i = Math.max(a ?? 0, Math.min(s ?? 180, i + e)), t.tilt(i).set();
1633
- return;
1634
- }
1635
- let c = i + e;
1636
- c > 180 || c < 0 ? (i = c > 180 ? 360 - c : -c, o = (o + 180) % 360, t.tilt(i).rotate(r + o).set()) : (i = c, t.tilt(i).set());
1637
- }, u = new K({
1731
+ let r = {
1732
+ targetRotation: n.rotation,
1733
+ targetTilt: n.tilt,
1734
+ targetZoom: n.zoom,
1735
+ thetaOffset: 0
1736
+ }, i = vn(t, n, r);
1737
+ n.onChange((e) => {
1738
+ r.targetRotation = e.rotation - r.thetaOffset, r.targetTilt = e.tilt, r.targetZoom = e.zoom, yn(i, n, e);
1739
+ }), this.element.appendChild(e.buildZoom(i.zoomOut, i.zoomIn)), this.element.appendChild(e.buildDpad(i.tiltUp, i.rotateLeft, i.reset, i.rotateRight, i.tiltDown));
1740
+ }
1741
+ static buildZoom(e, t) {
1742
+ let n = document.createElement("div");
1743
+ return n.className = "vd-zoom", n.appendChild(e.element), n.appendChild(t.element), n;
1744
+ }
1745
+ static buildDpad(e, t, n, r, i) {
1746
+ let a = document.createElement("div");
1747
+ a.className = "vd-dpad";
1748
+ for (let [o, s] of [
1749
+ [e, "up"],
1750
+ [t, "left"],
1751
+ [n, "center"],
1752
+ [r, "right"],
1753
+ [i, "down"]
1754
+ ]) o.element.classList.add(`vd-dpad-${s}`), a.appendChild(o.element);
1755
+ return a;
1756
+ }
1757
+ };
1758
+ function vn(e, t, n) {
1759
+ let r = (e) => Math.max(t.limits?.minZoom ?? 1, Math.min(t.limits?.maxZoom ?? Infinity, e)), i = (e) => {
1760
+ let n = t.limits?.minRotate, r = t.limits?.maxRotate;
1761
+ return n !== void 0 || r !== void 0 ? Math.max(n ?? -Infinity, Math.min(r ?? Infinity, e)) : e;
1762
+ }, a = (r) => {
1763
+ let i = t.limits?.minTilt, a = t.limits?.maxTilt;
1764
+ if (i !== void 0 || a !== void 0) {
1765
+ n.targetTilt = Math.max(i ?? 0, Math.min(a ?? 180, n.targetTilt + r)), e.tilt(n.targetTilt).set();
1766
+ return;
1767
+ }
1768
+ let o = n.targetTilt + r;
1769
+ 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());
1770
+ };
1771
+ return {
1772
+ zoomOut: new R({
1638
1773
  variant: "outline",
1639
1774
  size: "icon",
1640
- label: _t(),
1641
- icon: G.zoomOut(),
1775
+ label: bt(),
1776
+ icon: L.zoomOut(),
1642
1777
  onClick: () => {
1643
- a = s(a - 10), t.zoom(a).set();
1778
+ n.targetZoom = r(n.targetZoom - 10), e.zoom(n.targetZoom).set();
1644
1779
  }
1645
- }), d = new K({
1780
+ }),
1781
+ zoomIn: new R({
1646
1782
  variant: "outline",
1647
1783
  size: "icon",
1648
- label: pt(),
1649
- icon: G.zoomIn(),
1784
+ label: gt(),
1785
+ icon: L.zoomIn(),
1650
1786
  onClick: () => {
1651
- a = s(a + 10), t.zoom(a).set();
1787
+ n.targetZoom = r(n.targetZoom + 10), e.zoom(n.targetZoom).set();
1652
1788
  }
1653
- }), f = new K({
1789
+ }),
1790
+ tiltUp: new R({
1654
1791
  variant: "outline",
1655
1792
  size: "icon",
1656
- label: kt(),
1657
- icon: G.tiltUp(),
1793
+ label: Mt(),
1794
+ icon: L.tiltUp(),
1658
1795
  onClick: () => {
1659
- l(-15);
1796
+ a(-15);
1660
1797
  }
1661
- }), p = new K({
1798
+ }),
1799
+ rotateLeft: new R({
1662
1800
  variant: "outline",
1663
1801
  size: "icon",
1664
- label: xt(),
1665
- icon: G.rotateLeft(),
1802
+ label: wt(),
1803
+ icon: L.rotateLeft(),
1666
1804
  onClick: () => {
1667
- r = c(r - 15), t.rotate(r + o).set();
1805
+ n.targetRotation = i(n.targetRotation - 15), e.rotate(n.targetRotation + n.thetaOffset).set();
1668
1806
  }
1669
- }), m = new K({
1807
+ }),
1808
+ reset: new R({
1670
1809
  variant: "outline",
1671
1810
  size: "icon",
1672
- label: lt(),
1673
- icon: G.reset(),
1811
+ label: ft(),
1812
+ icon: L.reset(),
1674
1813
  onClick: () => {
1675
- o = 0, t.reset();
1814
+ n.thetaOffset = 0, e.reset();
1676
1815
  }
1677
- }), h = new K({
1816
+ }),
1817
+ rotateRight: new R({
1678
1818
  variant: "outline",
1679
1819
  size: "icon",
1680
- label: Tt(),
1681
- icon: G.rotateRight(),
1820
+ label: Ot(),
1821
+ icon: L.rotateRight(),
1682
1822
  onClick: () => {
1683
- r = c(r + 15), t.rotate(r + o).set();
1823
+ n.targetRotation = i(n.targetRotation + 15), e.rotate(n.targetRotation + n.thetaOffset).set();
1684
1824
  }
1685
- }), g = new K({
1825
+ }),
1826
+ tiltDown: new R({
1686
1827
  variant: "outline",
1687
1828
  size: "icon",
1688
- label: Nt(),
1689
- icon: G.tiltDown(),
1829
+ label: It(),
1830
+ icon: L.tiltDown(),
1690
1831
  onClick: () => {
1691
- l(15);
1832
+ a(15);
1692
1833
  }
1693
- }), _ = (e) => {
1694
- let t = n.limits;
1695
- t !== void 0 && (u.element.disabled = t.minZoom !== void 0 && e.zoom <= t.minZoom + Q, d.element.disabled = t.maxZoom !== void 0 && e.zoom >= t.maxZoom - Q, f.element.disabled = t.minTilt !== void 0 && e.tilt <= t.minTilt + Q, g.element.disabled = t.maxTilt !== void 0 && e.tilt >= t.maxTilt - Q, p.element.disabled = t.minRotate !== void 0 && e.rotation <= t.minRotate + Q, h.element.disabled = t.maxRotate !== void 0 && e.rotation >= t.maxRotate - Q);
1696
- };
1697
- n.onChange((e) => {
1698
- r = e.rotation - o, i = e.tilt, a = e.zoom, _(e);
1699
- }), this.element.appendChild(e.buildZoom(u, d)), this.element.appendChild(e.buildDpad(f, p, m, h, g));
1700
- }
1701
- static buildZoom(e, t) {
1702
- let n = document.createElement("div");
1703
- return n.className = "vd-zoom", n.appendChild(e.element), n.appendChild(t.element), n;
1704
- }
1705
- static buildDpad(e, t, n, r, i) {
1706
- let a = document.createElement("div");
1707
- a.className = "vd-dpad";
1708
- for (let [o, s] of [
1709
- [e, "up"],
1710
- [t, "left"],
1711
- [n, "center"],
1712
- [r, "right"],
1713
- [i, "down"]
1714
- ]) o.element.classList.add(`vd-dpad-${s}`), a.appendChild(o.element);
1715
- return a;
1716
- }
1717
- }, hn = 5;
1718
- function $(e) {
1834
+ })
1835
+ };
1836
+ }
1837
+ function yn(e, t, n) {
1838
+ let r = t.limits;
1839
+ r !== void 0 && (e.zoomOut.element.disabled = r.minZoom !== void 0 && n.zoom <= r.minZoom + Z, e.zoomIn.element.disabled = r.maxZoom !== void 0 && n.zoom >= r.maxZoom - Z, e.tiltUp.element.disabled = r.minTilt !== void 0 && n.tilt <= r.minTilt + Z, e.tiltDown.element.disabled = r.maxTilt !== void 0 && n.tilt >= r.maxTilt - Z, e.rotateLeft.element.disabled = r.minRotate !== void 0 && n.rotation <= r.minRotate + Z, e.rotateRight.element.disabled = r.maxRotate !== void 0 && n.rotation >= r.maxRotate - Z);
1840
+ }
1841
+ //#endregion
1842
+ //#region src/ui/controls/attribute-group.ts
1843
+ var bn = 5;
1844
+ function Q(e) {
1719
1845
  let t = e.replace(/([A-Z])/g, " $1").trim();
1720
1846
  return t.charAt(0).toUpperCase() + t.slice(1).toLowerCase();
1721
1847
  }
1722
- function gn(e, t, n, r, i) {
1848
+ function xn(e, t, n, r, i) {
1723
1849
  let a = document.createElement("div");
1724
1850
  a.className = "vd-attribute", a.dataset.name = e.name;
1725
1851
  let o = document.createElement("span");
1726
- o.className = "vd-attribute-label", o.textContent = $(e.name), a.appendChild(o);
1727
- let s = e.values.find((n) => t.getValue(e.name, n)?.isSelected === !0), c = e.values.map($), l = e.values.length <= hn ? new an(e.values, s, c) : new on(e.name, e.values, $(e.name), s, c);
1852
+ o.className = "vd-attribute-label", o.textContent = Q(e.name), a.appendChild(o);
1853
+ let s = e.values.find((n) => t.getValue(e.name, n)?.isSelected === !0), c = e.values.map(Q), l = e.values.length <= bn ? new $t(e.values, s, c) : new en(e.name, e.values, Q(e.name), s, c);
1728
1854
  return l.onSelect((t) => {
1729
1855
  n.dispatch("ui:select", {
1730
1856
  attribute: e.name,
@@ -1739,56 +1865,60 @@ function gn(e, t, n, r, i) {
1739
1865
  }
1740
1866
  //#endregion
1741
1867
  //#region src/ui/styles.ts
1742
- var _n = Y.fontFamily.sans.join(", "), vn = `
1868
+ var Sn = V.fontFamily.sans.join(", "), $ = "\n position: absolute;\n display: flex;\n z-index: 10;\n", Cn = `
1743
1869
  /* Override browser's default black fullscreen backdrop */
1744
1870
  .vd-container:fullscreen {
1745
1871
  background: oklch(100% 0 0);
1746
1872
  }
1747
1873
 
1748
- /* Top-right: screenshot + camera controls */
1749
- .vd-toolbar {
1750
- position: absolute;
1751
- inset-block-start: ${J[3]};
1752
- inset-inline-end: ${J[3]};
1753
- display: flex;
1874
+ /* Layout slots — four corners */
1875
+ .vd-slot-top-right {
1876
+ ${$}
1877
+ inset-block-start: ${B[3]};
1878
+ inset-inline-end: ${B[3]};
1754
1879
  flex-direction: column;
1755
1880
  align-items: flex-end;
1756
- gap: ${J[1.5]};
1757
- z-index: 10;
1881
+ gap: ${B[1.5]};
1758
1882
  }
1759
1883
 
1760
- /* Bottom-right: AR + fullscreen */
1761
- .vd-action-bar {
1762
- position: absolute;
1763
- inset-block-end: ${J[3]};
1764
- inset-inline-end: ${J[3]};
1765
- display: flex;
1884
+ .vd-slot-bottom-left {
1885
+ ${$}
1886
+ inset-block-end: ${B[3]};
1887
+ inset-inline-start: ${B[3]};
1888
+ flex-direction: column;
1889
+ align-items: flex-start;
1890
+ gap: ${B[1.5]};
1891
+ }
1892
+
1893
+ .vd-slot-bottom-right {
1894
+ ${$}
1895
+ inset-block-end: ${B[3]};
1896
+ inset-inline-end: ${B[3]};
1766
1897
  flex-direction: row;
1767
- gap: ${J[1.5]};
1768
- z-index: 10;
1898
+ gap: ${B[1.5]};
1769
1899
  }
1770
1900
 
1771
- /* Camera controls card inside .vd-toolbar */
1901
+ /* Component styles — no positioning */
1772
1902
  .vd-camera-controls {
1773
1903
  display: flex;
1774
1904
  flex-direction: column;
1775
- gap: ${J[1]};
1776
- background: color-mix(in oklch, ${q.white} 85%, transparent);
1905
+ gap: ${B[1]};
1906
+ background: color-mix(in oklch, ${z.white} 85%, transparent);
1777
1907
  backdrop-filter: blur(8px);
1778
- border-radius: ${J[2]};
1779
- padding: ${J[2]};
1908
+ border-radius: ${B[2]};
1909
+ padding: ${B[2]};
1780
1910
  }
1781
1911
 
1782
1912
  .vd-zoom {
1783
1913
  display: flex;
1784
- gap: ${J[.5]};
1914
+ gap: ${B[.5]};
1785
1915
  }
1786
1916
 
1787
1917
  .vd-dpad {
1788
1918
  display: grid;
1789
- grid-template-columns: repeat(3, ${J[9]});
1790
- grid-template-rows: repeat(3, ${J[9]});
1791
- gap: ${J[.5]};
1919
+ grid-template-columns: repeat(3, ${B[9]});
1920
+ grid-template-rows: repeat(3, ${B[9]});
1921
+ gap: ${B[.5]};
1792
1922
  }
1793
1923
 
1794
1924
  .vd-dpad-up { grid-column: 2; grid-row: 1; }
@@ -1797,49 +1927,53 @@ var _n = Y.fontFamily.sans.join(", "), vn = `
1797
1927
  .vd-dpad-right { grid-column: 3; grid-row: 2; }
1798
1928
  .vd-dpad-down { grid-column: 2; grid-row: 3; }
1799
1929
 
1800
- /* Bottom-left: attribute selectors */
1801
1930
  .vd-attributes {
1802
- position: absolute;
1803
- inset-block-end: ${J[3]};
1804
- inset-inline-start: ${J[3]};
1805
1931
  display: flex;
1806
1932
  flex-direction: column;
1807
- gap: ${J[2]};
1808
- background: color-mix(in oklch, ${q.white} 85%, transparent);
1933
+ gap: ${B[2]};
1934
+ background: color-mix(in oklch, ${z.white} 85%, transparent);
1809
1935
  backdrop-filter: blur(8px);
1810
- border-radius: ${J[2]};
1811
- padding: ${J[2]};
1812
- font-family: ${_n};
1813
- z-index: 10;
1936
+ border-radius: ${B[2]};
1937
+ padding: ${B[2]};
1938
+ font-family: ${Sn};
1814
1939
  }
1815
1940
 
1816
1941
  .vd-attribute {
1817
1942
  display: flex;
1818
1943
  flex-direction: column;
1819
- gap: ${J[1]};
1944
+ gap: ${B[1]};
1820
1945
  }
1821
1946
 
1822
1947
  .vd-attribute-label {
1823
- font-size: ${Y.fontSize.xs};
1824
- font-weight: ${Y.fontWeight.medium};
1825
- color: ${q.neutral[900]};
1826
- font-family: ${_n};
1948
+ font-size: ${V.fontSize.xs};
1949
+ font-weight: ${V.fontWeight.medium};
1950
+ color: ${z.neutral[900]};
1951
+ font-family: ${Sn};
1827
1952
  }
1828
1953
 
1829
1954
  `;
1830
- function yn() {
1831
- if (un(), document.getElementById("vd-styles") !== null) return;
1955
+ function wn() {
1956
+ if (on(), document.getElementById("vd-styles") !== null) return;
1832
1957
  let e = document.createElement("style");
1833
- e.id = "vd-styles", e.textContent = vn, document.head.appendChild(e);
1958
+ e.id = "vd-styles", e.textContent = Cn, document.head.appendChild(e);
1834
1959
  }
1835
1960
  //#endregion
1836
1961
  //#region src/ui/standard-interface.ts
1837
- var bn = class {
1962
+ function Tn(e, t) {
1963
+ let n = document.createElement("a");
1964
+ n.href = `data:image/png;base64,${e}`, n.download = t, n.click();
1965
+ }
1966
+ var En = class {
1838
1967
  options;
1839
1968
  settings = {};
1840
1969
  container = null;
1841
1970
  loading = null;
1842
- toolbar = null;
1971
+ slots = {
1972
+ topRight: null,
1973
+ bottomLeft: null,
1974
+ bottomRight: null
1975
+ };
1976
+ screenshotBtn = null;
1843
1977
  actionBar = null;
1844
1978
  cameraControls = null;
1845
1979
  attributes = null;
@@ -1847,15 +1981,18 @@ var bn = class {
1847
1981
  this.options = e;
1848
1982
  }
1849
1983
  attach(e) {
1850
- yn(), this.container = e, this.loading = new Vt(e), this.toolbar = new fn({ snapshotApi: this.options.snapshotApi }), this.toolbar.applySettings(this.settings), e.appendChild(this.toolbar.element), this.actionBar = new pn({
1984
+ wn(), this.container = e, this.loading = new hn(e), this.slots.topRight = this.createSlot(e, "vd-slot-top-right"), this.slots.bottomLeft = this.createSlot(e, "vd-slot-bottom-left"), this.slots.bottomRight = this.createSlot(e, "vd-slot-bottom-right");
1985
+ }
1986
+ onReady() {
1987
+ this.loading?.hide(), this.loading = null, this.mountToolbar(), this.cameraControls !== null && (this.cameraControls.element.style.display = "flex"), this.attributes !== null && (this.attributes.style.display = "flex");
1988
+ }
1989
+ mountToolbar() {
1990
+ this.actionBar !== null || this.slots.bottomRight === null || (this.actionBar = new gn({
1851
1991
  onAr: this.options.onAr,
1852
1992
  onFullscreen: () => {
1853
1993
  document.fullscreenElement === null ? this.container?.requestFullscreen() : document.exitFullscreen();
1854
1994
  }
1855
- }), this.actionBar.applySettings(this.settings), e.appendChild(this.actionBar.element);
1856
- }
1857
- onReady() {
1858
- this.loading?.hide(), this.loading = null, this.cameraControls !== null && (this.cameraControls.element.style.display = "flex"), this.attributes !== null && (this.attributes.style.display = "flex");
1995
+ }), this.actionBar.applySettings(this.settings), this.slots.bottomRight.appendChild(this.actionBar.element), this.syncScreenshotButton(), this.placeScreenshotButton());
1859
1996
  }
1860
1997
  updateProgress(e, t) {
1861
1998
  this.loading?.updateProgress(e, t);
@@ -1864,28 +2001,52 @@ var bn = class {
1864
2001
  this.loading?.showError(e);
1865
2002
  }
1866
2003
  applyViewerSettings(e) {
1867
- this.settings = e, e.language !== void 0 && A(e.language), this.toolbar?.applySettings(e), this.actionBar?.applySettings(e), this.cameraControls !== null && (this.cameraControls.element.style.display = e.cameraControls === !0 ? "flex" : "none");
2004
+ this.settings = e, e.language !== void 0 && N(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();
1868
2005
  }
1869
2006
  renderAttributeControls(e, t) {
1870
- if (!(this.container === null || this.toolbar === null) && (this.cameraControls?.element.remove(), this.cameraControls = null, this.attributes?.remove(), this.attributes = null, this.settings.cameraControls === !0 && (this.cameraControls = new mn(this.options.cameraApi, this.options.cameraPositionApi), this.cameraControls.element.style.display = "none", this.toolbar.element.appendChild(this.cameraControls.element)), t.length !== 0)) {
2007
+ if (!(this.container === null || this.slots.topRight === null) && (this.cameraControls?.element.remove(), this.cameraControls = null, this.attributes?.remove(), this.attributes = null, this.settings.cameraControls === !0 && (this.cameraControls = new _n(this.options.cameraApi, this.options.cameraPositionApi), this.cameraControls.element.style.display = "none", this.slots.topRight.appendChild(this.cameraControls.element)), this.placeScreenshotButton(), !(t.length === 0 || this.settings.attributeControls === !1))) {
1871
2008
  this.attributes = document.createElement("div"), this.attributes.className = "vd-attributes", this.attributes.style.display = "none";
1872
- for (let n of t) this.attributes.appendChild(gn(n, e, this.options.eventBus, this.options.onSelect, this.options.onSubscribe));
1873
- this.container.appendChild(this.attributes);
2009
+ for (let n of t) this.attributes.appendChild(xn(n, e, this.options.eventBus, this.options.onSelect, this.options.onSubscribe));
2010
+ this.slots.bottomLeft.appendChild(this.attributes);
1874
2011
  }
1875
2012
  }
1876
2013
  get viewerSettings() {
1877
2014
  return this.settings;
1878
2015
  }
1879
2016
  destroy() {
1880
- this.loading?.destroy(), this.toolbar?.element.remove(), this.actionBar?.destroy(), this.actionBar?.element.remove(), this.cameraControls?.element.remove(), this.attributes?.remove(), this.container = null;
2017
+ this.loading?.destroy(), this.screenshotBtn?.element.remove(), this.actionBar?.destroy(), this.actionBar?.element.remove(), this.cameraControls?.element.remove(), this.attributes?.remove();
2018
+ for (let e of Object.values(this.slots)) e?.remove();
2019
+ this.container = null;
1881
2020
  }
1882
- }, xn = class {
2021
+ createSlot(e, t) {
2022
+ let n = document.createElement("div");
2023
+ return n.className = t, e.appendChild(n), n;
2024
+ }
2025
+ syncScreenshotButton() {
2026
+ let e = this.settings.screenshot === !0;
2027
+ e && this.screenshotBtn === null && (this.screenshotBtn = new R({
2028
+ variant: "outline",
2029
+ size: "icon",
2030
+ label: ct(),
2031
+ icon: L.screenshot(),
2032
+ onClick: () => {
2033
+ this.options.snapshotApi.take("snapshot.png").onDeveloped(({ data: e, filename: t }) => {
2034
+ Tn(e, t);
2035
+ });
2036
+ }
2037
+ })), !e && this.screenshotBtn !== null && (this.screenshotBtn.element.remove(), this.screenshotBtn = null);
2038
+ }
2039
+ placeScreenshotButton() {
2040
+ this.screenshotBtn === null || this.slots.topRight === null || (this.cameraControls === null ? this.slots.topRight.appendChild(this.screenshotBtn.element) : this.cameraControls.element.appendChild(this.screenshotBtn.element));
2041
+ }
2042
+ }, Dn = class {
1883
2043
  attributes;
1884
2044
  readyStateTracker;
1885
2045
  messenger;
1886
2046
  cameraApi;
1887
2047
  cameraPositionApi;
1888
2048
  snapshotApi;
2049
+ annotationsApi;
1889
2050
  eventBus;
1890
2051
  ui;
1891
2052
  qrModal;
@@ -1899,17 +2060,17 @@ var bn = class {
1899
2060
  let t = (e) => {
1900
2061
  this.messenger.send(e);
1901
2062
  };
1902
- this.attributes = new pe(t, (e, t) => {
2063
+ this.attributes = new ge(t, (e, t) => {
1903
2064
  for (let n of this.mutationFailedCallbacks) n({
1904
2065
  attribute: e,
1905
2066
  value: t
1906
2067
  });
1907
- }), this.snapshotApi = new _e(t), this.cameraApi = new me(t), this.cameraPositionApi = new he(), this.eventBus = new ve(), this.qrModal = new cn(), this.readyStateTracker = new _(() => {
2068
+ }), this.snapshotApi = new S(t), this.annotationsApi = new pe(t), this.cameraApi = new _e(t), this.cameraPositionApi = new ve(), this.eventBus = new be(), this.qrModal = new nn(), this.readyStateTracker = new te(() => {
1908
2069
  let e = this.readyCallbacks;
1909
2070
  this.readyCallbacks = [];
1910
2071
  for (let t of e) t(this);
1911
2072
  this.ui.onReady();
1912
- }), this.ui = new bn({
2073
+ }), this.ui = new En({
1913
2074
  snapshotApi: this.snapshotApi,
1914
2075
  cameraApi: this.cameraApi,
1915
2076
  cameraPositionApi: this.cameraPositionApi,
@@ -1922,28 +2083,49 @@ var bn = class {
1922
2083
  }), this.registerHandlers(), this.messenger.start(), this.createAndConnectIframe();
1923
2084
  }
1924
2085
  registerHandlers() {
1925
- this.messenger.on(y.HANDSHAKE, (e) => {
1926
- ie(e) && (m.info("Server handshake received, flushing publisher queue"), this.messenger.markReady());
1927
- }), this.messenger.on(y.MUTATION, (e) => {
2086
+ this.messenger.on(v.HANDSHAKE, (e) => {
2087
+ ie(e) && (g.info("Server handshake received, flushing publisher queue"), this.messenger.markReady());
2088
+ }), this.messenger.on(v.MUTATION, (e) => {
1928
2089
  ae(e) && this.attributes.handleMutationResult(e);
1929
- }), this.messenger.on(y.SNAPSHOT, (e) => {
2090
+ }), this.messenger.on(v.SNAPSHOT, (e) => {
1930
2091
  oe(e) && this.snapshotApi.handleSnapshotResult(e);
1931
- }), this.messenger.on(y.CAMERA, (e) => {
2092
+ }), this.messenger.on(v.CAMERA, (e) => {
1932
2093
  se(e) && this.cameraPositionApi.handlePositionUpdate(e);
1933
- }), this.messenger.on(y.LOADING_INDICATOR, (e) => {
2094
+ }), this.messenger.on(v.LOADING_INDICATOR, (e) => {
1934
2095
  le(e) && (e.error === void 0 ? this.ui.updateProgress(e.progress, e.phase) : this.ui.showError(e.error));
1935
- }), this.messenger.on(y.CONFIG, (e) => {
1936
- ue(e) && (e.viewerSettings !== void 0 && this.ui.applyViewerSettings(e.viewerSettings), this.cameraPositionApi.applyLimits(e.cameraLimits));
1937
- }), this.messenger.on(y.MAPPING, (e) => {
2096
+ }), this.messenger.on(v.CONFIG, (e) => {
2097
+ ue(e) && this.handleConfig(e);
2098
+ }), this.messenger.on(v.ANNOTATION_PLACED, (e) => {
2099
+ de(e) && this.annotationsApi.handlePlaced(e.position);
2100
+ }), this.messenger.on(v.MAPPING, (e) => {
1938
2101
  ce(e) && (this.attributes.handleMappingReceived(e), this.ui.renderAttributeControls(this.attributes, e.attributes), this.readyStateTracker.handleMappingReceived());
1939
2102
  });
1940
2103
  }
2104
+ handleConfig(e) {
2105
+ let t = e.viewerSettings, n = this.options.viewerSettings;
2106
+ if (t !== void 0 || n !== void 0) {
2107
+ let e = n === void 0 ? t : {
2108
+ ...t ?? {},
2109
+ ...n
2110
+ };
2111
+ if (n !== void 0 && t !== void 0) {
2112
+ let e = Object.entries(n).filter(([e, n]) => t[e] !== n).map(([e, n]) => `${e} (metadata: ${t[e] ?? "undefined"}, override: ${n})`);
2113
+ e.length > 0 && g.warn(`Viewer settings override active: ${e.join(", ")}`);
2114
+ }
2115
+ this.ui.applyViewerSettings(e), this.annotationsApi.setEnabled(e.annotations !== !1);
2116
+ }
2117
+ this.cameraPositionApi.applyLimits(e.cameraLimits);
2118
+ }
1941
2119
  initializeLogging() {
1942
- this.options.debug === !0 && h(), m.info("Initializing Virtualdisplay client", { model: this.options.model });
2120
+ this.options.debug === !0 && _(), g.info("Initializing Virtualdisplay client", { model: this.options.model });
1943
2121
  }
1944
2122
  createAndConnectIframe() {
1945
2123
  let e = new r(this.options).create();
1946
2124
  this.container = e.container, this.iframe = e.iframe, this.eventBus.attach(this.container), this.ui.attach(this.container);
2125
+ try {
2126
+ let e = new URL(this.iframe.src).origin;
2127
+ this.messenger.setTargetOrigin(e);
2128
+ } catch {}
1947
2129
  }
1948
2130
  select(e, t) {
1949
2131
  this.attributes.select(e, t);
@@ -1976,6 +2158,9 @@ var bn = class {
1976
2158
  on(e, t) {
1977
2159
  this.eventBus.on(e, t);
1978
2160
  }
2161
+ get annotations() {
2162
+ return this.annotationsApi;
2163
+ }
1979
2164
  get camera() {
1980
2165
  return this.cameraApi;
1981
2166
  }
@@ -1993,4 +2178,4 @@ var bn = class {
1993
2178
  }
1994
2179
  };
1995
2180
  //#endregion
1996
- export { ee as Attribute, v as AttributeValue, me as Camera, t as ERROR_CODES, ge as Photo, _e as Snapshot, xn as VirtualdisplayClient, n as VirtualdisplayError, h as enableDebugMode, g as isDebugMode, m as logger };
2181
+ export { pe as Annotations, x as Attribute, me as AttributeValue, _e as Camera, t as ERROR_CODES, ye as Photo, S as Snapshot, Dn as VirtualdisplayClient, n as VirtualdisplayError, _ as enableDebugMode, ee as isDebugMode, g as logger };