@preference-sl/pref-viewer 2.10.0-beta.10 → 2.10.0-beta.11

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +18 -318
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preference-sl/pref-viewer",
3
- "version": "2.10.0-beta.10",
3
+ "version": "2.10.0-beta.11",
4
4
  "description": "Web Component to preview GLTF models with Babylon.js",
5
5
  "author": "Alex Moreno Palacio <amoreno@preference.es>",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -47,13 +47,7 @@ import { DracoCompression } from "@babylonjs/core/Meshes/Compression/dracoCompre
47
47
  import { initDb, loadModel } from "./gltf-storage.js";
48
48
 
49
49
  class PrefViewer extends HTMLElement {
50
- static LOG_PREFIX = "[PrefViewer]";
51
- static LOG_LEVELS = { none: 0, error: 1, warn: 2, info: 3, debug: 4 };
52
- // Por defecto NO loggear: control únicamente vía atributo `log-level`
53
- static DEFAULT_LOG_LEVEL = "none";
54
-
55
50
  #initialized = false;
56
- #logLevel = PrefViewer.DEFAULT_LOG_LEVEL;
57
51
 
58
52
  #data = {
59
53
  containers: {
@@ -119,67 +113,6 @@ class PrefViewer extends HTMLElement {
119
113
  },
120
114
  };
121
115
 
122
- #log(level, message, context) {
123
- const levels = PrefViewer.LOG_LEVELS;
124
- const current = levels[this.#logLevel] ?? levels[PrefViewer.DEFAULT_LOG_LEVEL];
125
- const incoming = levels[level] ?? levels.info;
126
- if (incoming > current || current === levels.none) return;
127
-
128
- const logger = console[level] ?? console.log;
129
- if (context !== undefined) {
130
- logger(`${PrefViewer.LOG_PREFIX}: ${message}`, context);
131
- } else {
132
- logger(`${PrefViewer.LOG_PREFIX}: ${message}`);
133
- }
134
- }
135
-
136
- #setLogLevel(level) {
137
- const value = String(level || "").toLowerCase();
138
- this.#logLevel = (value in PrefViewer.LOG_LEVELS) ? value : PrefViewer.DEFAULT_LOG_LEVEL;
139
- this.#logInfo("Log level set", { level: this.#logLevel });
140
- }
141
-
142
- #logDebug(message, context) {
143
- this.#log("debug", message, context);
144
- }
145
-
146
- #logInfo(message, context) {
147
- this.#log("info", message, context);
148
- }
149
-
150
- #logWarn(message, context) {
151
- this.#log("warn", message, context);
152
- }
153
-
154
- #logError(message, context) {
155
- this.#log("error", message, context);
156
- }
157
-
158
- #summarizeValue(value) {
159
- if (typeof value === "string" && value.length > 150) {
160
- return `${value.slice(0, 150)}… (${value.length} chars)`;
161
- }
162
- return value;
163
- }
164
-
165
- #describeStorage(storage) {
166
- if (!storage) {
167
- return "none";
168
- }
169
- if (storage.db && storage.table && storage.id) {
170
- return `IndexedDB(${storage.db}/${storage.table}#${storage.id})`;
171
- }
172
- if (typeof storage.url === "string") {
173
- return storage.url.startsWith("data:") ? "data-url" : storage.url;
174
- }
175
- return "unknown";
176
- }
177
-
178
- static get observedAttributes() {
179
- // Añadimos "log-level" para controlar logs fuera del objeto config
180
- return ["config", "model", "scene", "show-model", "show-scene", "log-level"];
181
- }
182
-
183
116
  // DOM elements
184
117
  #wrapper = null;
185
118
  #canvas = null;
@@ -196,7 +129,6 @@ class PrefViewer extends HTMLElement {
196
129
 
197
130
  constructor() {
198
131
  super();
199
- this.#logDebug("Constructing PrefViewer instance");
200
132
  this.attachShadow({ mode: "open" });
201
133
  this.#createCanvas();
202
134
  this.#wrapCanvas();
@@ -212,13 +144,11 @@ class PrefViewer extends HTMLElement {
212
144
  };
213
145
  }
214
146
 
215
- attributeChangedCallback(name, _old, value) {
216
- if (name === "log-level") {
217
- this.#setLogLevel(value);
218
- return;
219
- }
147
+ static get observedAttributes() {
148
+ return ["config", "model", "scene", "show-model", "show-scene"];
149
+ }
220
150
 
221
- this.#logDebug("Attribute change detected", { name, value: this.#summarizeValue(value) });
151
+ attributeChangedCallback(name, _old, value) {
222
152
  let data = null;
223
153
  switch (name) {
224
154
  case "config":
@@ -232,7 +162,6 @@ class PrefViewer extends HTMLElement {
232
162
  break;
233
163
  case "show-model":
234
164
  data = value.toLowerCase?.() === "true";
235
- this.#logDebug("Toggling model visibility from attribute", { visible: data, initialized: this.#initialized });
236
165
  if (this.#initialized) {
237
166
  data ? this.showModel() : this.hideModel();
238
167
  } else {
@@ -241,7 +170,6 @@ class PrefViewer extends HTMLElement {
241
170
  break;
242
171
  case "show-scene":
243
172
  data = value.toLowerCase?.() === "true";
244
- this.#logDebug("Toggling scene visibility from attribute", { visible: data, initialized: this.#initialized });
245
173
  if (this.#initialized) {
246
174
  data ? this.showScene() : this.hideScene();
247
175
  } else {
@@ -254,7 +182,7 @@ class PrefViewer extends HTMLElement {
254
182
  connectedCallback() {
255
183
  if (!this.hasAttribute("config")) {
256
184
  const error = 'PrefViewer: provide "models" as array of model and environment';
257
- this.#logError("Missing required config attribute", { error });
185
+ console.error(error);
258
186
  this.dispatchEvent(
259
187
  new CustomEvent("model-error", {
260
188
  detail: { error: new Error(error) },
@@ -265,22 +193,18 @@ class PrefViewer extends HTMLElement {
265
193
  return false;
266
194
  }
267
195
 
268
- this.#logDebug("Connected to DOM, initializing Babylon");
269
196
  this.#initializeBabylon();
270
197
  this.#loadContainers(true, true, true);
271
198
  this.#initialized = true;
272
- this.#logInfo("Initialization completed", { initialized: this.#initialized });
273
199
  }
274
200
 
275
201
  disconnectedCallback() {
276
- this.#logDebug("Disconnected from DOM, disposing resources");
277
202
  this.#disposeEngine();
278
203
  this.#canvasResizeObserver.disconnect();
279
204
  }
280
205
 
281
206
  // Web Component
282
207
  #createCanvas() {
283
- this.#logDebug("Creating rendering canvas");
284
208
  this.#canvas = document.createElement("canvas");
285
209
  Object.assign(this.#canvas.style, {
286
210
  width: "100%",
@@ -288,11 +212,9 @@ class PrefViewer extends HTMLElement {
288
212
  display: "block",
289
213
  outline: "none",
290
214
  });
291
- this.#logDebug("Canvas element created and styled");
292
215
  }
293
216
 
294
217
  #wrapCanvas() {
295
- this.#logDebug("Wrapping canvas inside container div");
296
218
  this.#wrapper = document.createElement("div");
297
219
  Object.assign(this.#wrapper.style, {
298
220
  width: "100%",
@@ -301,24 +223,20 @@ class PrefViewer extends HTMLElement {
301
223
  });
302
224
  this.#wrapper.appendChild(this.#canvas);
303
225
  this.shadowRoot.append(this.#wrapper);
304
- this.#logDebug("Canvas wrapper appended to shadow DOM");
305
226
  }
306
227
 
307
228
  // Data
308
229
  #checkCameraChanged(options) {
309
230
  if (!options || !options.camera) {
310
- this.#logDebug("Camera options not provided or unchanged");
311
231
  return false;
312
232
  }
313
233
  this.#data.options.camera.changed = options.camera && options.camera !== this.#data.options.camera.value ? true : false;
314
234
  this.#data.options.camera.value = this.#data.options.camera.changed ? options.camera : this.#data.options.camera.value;
315
- this.#logDebug("Camera option processed", { changed: this.#data.options.camera.changed, value: this.#data.options.camera.value });
316
235
  return this.#data.options.camera.changed;
317
236
  }
318
237
 
319
238
  #checkMaterialsChanged(options) {
320
239
  if (!options) {
321
- this.#logDebug("Material options not provided");
322
240
  return false;
323
241
  }
324
242
  let someChanged = false;
@@ -328,32 +246,22 @@ class PrefViewer extends HTMLElement {
328
246
  this.#data.options.materials[material].value = this.#data.options.materials[material].changed ? options[key] : this.#data.options.materials[material].value;
329
247
  someChanged = someChanged || this.#data.options.materials[material].changed;
330
248
  });
331
- this.#logDebug("Material options processed", {
332
- changed: someChanged,
333
- values: Object.entries(this.#data.options.materials).reduce((acc, [key, entry]) => {
334
- acc[key] = { value: entry.value, changed: entry.changed };
335
- return acc;
336
- }, {}),
337
- });
338
249
  return someChanged;
339
250
  }
340
251
 
341
252
  #storeChangedFlagsForContainer(container) {
342
253
  container.timestamp = container.changed.timestamp;
343
254
  container.size = container.changed.size;
344
- this.#logDebug("Stored change flags for container", { name: container.name, timestamp: container.timestamp, size: container.size });
345
255
  }
346
256
 
347
257
  #resetChangedFlags() {
348
258
  Object.values(this.#data.containers).forEach((container) => (container.changed = false));
349
259
  Object.values(this.#data.options.materials).forEach((material) => (material.changed = false));
350
260
  this.#data.options.camera.changed = false;
351
- this.#logDebug("Reset change flags across containers and options");
352
261
  }
353
262
 
354
263
  // Babylon.js
355
264
  async #initializeBabylon() {
356
- this.#logInfo("Initializing Babylon engine and scene");
357
265
  this.#engine = new Engine(this.#canvas, true, { alpha: true });
358
266
  this.#scene = new Scene(this.#engine);
359
267
  this.#scene.clearColor = new Color4(1, 1, 1, 1);
@@ -363,32 +271,26 @@ class PrefViewer extends HTMLElement {
363
271
 
364
272
  this.#engine.runRenderLoop(() => this.#scene && this.#scene.render());
365
273
  this.#canvasResizeObserver.observe(this.#canvas);
366
- this.#logDebug("Engine render loop started and resize observer attached");
367
274
 
368
275
  await this.#createXRExperience();
369
- this.#logInfo("Babylon initialization finished", { xrEnabled: !!this.#XRExperience });
370
276
  }
371
277
 
372
278
  addStylesToARButton() {
373
- this.#logDebug("Adding styles to AR button");
374
279
  const css = '.babylonVRicon { color: #868686; border-color: #868686; border-style: solid; margin-left: 10px; height: 50px; width: 80px; background-color: rgba(51,51,51,0.7); background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%222048%22%20height%3D%221152%22%20viewBox%3D%220%200%202048%201152%22%20version%3D%221.1%22%3E%3Cpath%20transform%3D%22rotate%28180%201024%2C576.0000000000001%29%22%20d%3D%22m1109%2C896q17%2C0%2030%2C-12t13%2C-30t-12.5%2C-30.5t-30.5%2C-12.5l-170%2C0q-18%2C0%20-30.5%2C12.5t-12.5%2C30.5t13%2C30t30%2C12l170%2C0zm-85%2C256q59%2C0%20132.5%2C-1.5t154.5%2C-5.5t164.5%2C-11.5t163%2C-20t150%2C-30t124.5%2C-41.5q23%2C-11%2042%2C-24t38%2C-30q27%2C-25%2041%2C-61.5t14%2C-72.5l0%2C-257q0%2C-123%20-47%2C-232t-128%2C-190t-190%2C-128t-232%2C-47l-81%2C0q-37%2C0%20-68.5%2C14t-60.5%2C34.5t-55.5%2C45t-53%2C45t-53%2C34.5t-55.5%2C14t-55.5%2C-14t-53%2C-34.5t-53%2C-45t-55.5%2C-45t-60.5%2C-34.5t-68.5%2C-14l-81%2C0q-123%2C0%20-232%2C47t-190%2C128t-128%2C190t-47%2C232l0%2C257q0%2C68%2038%2C115t97%2C73q54%2C24%20124.5%2C41.5t150%2C30t163%2C20t164.5%2C11.5t154.5%2C5.5t132.5%2C1.5zm939%2C-298q0%2C39%20-24.5%2C67t-58.5%2C42q-54%2C23%20-122%2C39.5t-143.5%2C28t-155.5%2C19t-157%2C11t-148.5%2C5t-129.5%2C1.5q-59%2C0%20-130%2C-1.5t-148%2C-5t-157%2C-11t-155.5%2C-19t-143.5%2C-28t-122%2C-39.5q-34%2C-14%20-58.5%2C-42t-24.5%2C-67l0%2C-257q0%2C-106%2040.5%2C-199t110%2C-162.5t162.5%2C-109.5t199%2C-40l81%2C0q27%2C0%2052%2C14t50%2C34.5t51%2C44.5t55.5%2C44.5t63.5%2C34.5t74%2C14t74%2C-14t63.5%2C-34.5t55.5%2C-44.5t51%2C-44.5t50%2C-34.5t52%2C-14l14%2C0q37%2C0%2070%2C0.5t64.5%2C4.5t63.5%2C12t68%2C23q71%2C30%20128.5%2C78.5t98.5%2C110t63.5%2C133.5t22.5%2C149l0%2C257z%22%20fill%3D%22white%22%20/%3E%3C/svg%3E%0A); background-size: 80%; background-repeat:no-repeat; background-position: center; border: none; outline: none; transition: transform 0.125s ease-out } .babylonVRicon:hover { transform: scale(1.05) } .babylonVRicon:active {background-color: rgba(51,51,51,1) } .babylonVRicon:focus {background-color: rgba(51,51,51,1) }.babylonVRicon.vrdisplaypresenting { background-image: none;} .vrdisplaypresenting::after { content: "EXIT"} .xr-error::after { content: "ERROR"}';
375
280
  const style = document.createElement("style");
376
281
  style.appendChild(document.createTextNode(css));
377
282
  this.#wrapper.appendChild(style);
378
- this.#logDebug("AR button styles applied");
379
283
  }
380
284
 
381
285
  async #createXRExperience() {
382
286
  if (this.#XRExperience) {
383
- this.#logDebug("XR experience already created, skipping");
384
287
  return true;
385
288
  }
386
289
 
387
- this.#logDebug("Attempting to create XR experience");
388
290
  const sessionMode = "immersive-ar";
389
291
  const sessionSupported = await WebXRSessionManager.IsSessionSupportedAsync(sessionMode);
390
292
  if (!sessionSupported) {
391
- this.#logInfo("WebXR session mode not supported", { sessionMode });
293
+ console.info("PrefViewer: WebXR in mode AR is not supported");
392
294
  return false;
393
295
  }
394
296
 
@@ -407,7 +309,6 @@ class PrefViewer extends HTMLElement {
407
309
  };
408
310
 
409
311
  this.#XRExperience = await WebXRDefaultExperience.CreateAsync(this.#scene, options);
410
- this.#logInfo("XR experience created successfully", { sessionMode });
411
312
 
412
313
  const featuresManager = this.#XRExperience.baseExperience.featuresManager;
413
314
  featuresManager.enableFeature(WebXRFeatureName.TELEPORTATION, "stable", {
@@ -415,32 +316,24 @@ class PrefViewer extends HTMLElement {
415
316
  floorMeshes: [ground],
416
317
  timeToTeleport: 1500,
417
318
  });
418
- this.#logDebug("XR teleportation feature enabled");
419
319
 
420
320
  this.#XRExperience.baseExperience.sessionManager.onXRReady.add(() => {
421
321
  // Set the initial position of xrCamera: use nonVRCamera, which contains a copy of the original this.#scene.activeCamera before entering XR
422
322
  this.#XRExperience.baseExperience.camera.setTransformationFromNonVRCamera(this.#XRExperience.baseExperience._nonVRCamera);
423
323
  this.#XRExperience.baseExperience.camera.setTarget(Vector3.Zero());
424
324
  this.#XRExperience.baseExperience.onInitialXRPoseSetObservable.notifyObservers(this.#XRExperience.baseExperience.camera);
425
- this.#logDebug("XR session ready and camera transformed");
426
325
  });
427
326
 
428
327
  this.addStylesToARButton();
429
328
  } catch (error) {
430
- this.#logWarn("Failed to create XR experience", { error });
329
+ console.warn("PrefViewer: failed to create WebXR experience", error);
431
330
  this.#XRExperience = null;
432
331
  }
433
332
  }
434
333
 
435
- #canvasResizeObserver = new ResizeObserver(() => {
436
- if (this.#engine) {
437
- this.#logDebug("Resize observer triggered");
438
- this.#engine.resize();
439
- }
440
- });
334
+ #canvasResizeObserver = new ResizeObserver(() => this.#engine && this.#engine.resize());
441
335
 
442
336
  #createCamera() {
443
- this.#logDebug("Creating default camera");
444
337
  this.#camera = new ArcRotateCamera("camera", (3 * Math.PI) / 2, Math.PI * 0.47, 10, Vector3.Zero(), this.#scene);
445
338
  this.#camera.upperBetaLimit = Math.PI * 0.48;
446
339
  this.#camera.lowerBetaLimit = Math.PI * 0.25;
@@ -449,16 +342,9 @@ class PrefViewer extends HTMLElement {
449
342
  this.#camera.metadata = { locked: false }
450
343
  this.#camera = this.#camera;
451
344
  this.#camera.attachControl(this.#canvas, true);
452
- this.#logDebug("Camera created", {
453
- upperBetaLimit: this.#camera.upperBetaLimit,
454
- lowerBetaLimit: this.#camera.lowerBetaLimit,
455
- lowerRadiusLimit: this.#camera.lowerRadiusLimit,
456
- upperRadiusLimit: this.#camera.upperRadiusLimit,
457
- });
458
345
  }
459
346
 
460
347
  #createLights() {
461
- this.#logDebug("Creating scene lights");
462
348
  // 1) Stronger ambient fill
463
349
  this.#hemiLight = new HemisphericLight("hemiLight", new Vector3(-10, 10, -10), this.#scene);
464
350
  this.#hemiLight.intensity = 0.6;
@@ -478,52 +364,32 @@ class PrefViewer extends HTMLElement {
478
364
  this.#cameraLight = new PointLight("pl", this.#camera.position, this.#scene);
479
365
  this.#cameraLight.parent = this.#camera;
480
366
  this.#cameraLight.intensity = 0.3;
481
- this.#logDebug("Scene lights configured", {
482
- hemiIntensity: this.#hemiLight.intensity,
483
- dirIntensity: this.#dirLight.intensity,
484
- pointIntensity: this.#cameraLight.intensity,
485
- shadowKernel: this.#shadowGen.blurKernel,
486
- });
487
367
  }
488
368
 
489
369
  #setupInteraction() {
490
- this.#logDebug("Setting up canvas interaction listeners");
491
370
  this.#canvas.addEventListener("wheel", (event) => {
492
371
  if (!this.#scene || !this.#camera) {
493
- this.#logWarn("Wheel interaction ignored; scene or camera missing");
494
372
  return false;
495
373
  }
496
374
  //const pick = this.#scene.pick(this.#scene.pointerX, this.#scene.pointerY);
497
375
  //this.#camera.target = pick.hit ? pick.pickedPoint.clone() : this.#camera.target;
498
376
  if (!this.#scene.activeCamera.metadata?.locked) {
499
377
  this.#scene.activeCamera.inertialRadiusOffset -= event.deltaY * this.#scene.activeCamera.wheelPrecision * 0.001;
500
- this.#logDebug("Processed wheel interaction", {
501
- deltaY: event.deltaY,
502
- inertialRadiusOffset: this.#scene.activeCamera.inertialRadiusOffset,
503
- });
504
- } else {
505
- this.#logDebug("Wheel interaction ignored because camera is locked");
506
378
  }
507
379
  event.preventDefault();
508
380
  });
509
381
  }
510
382
 
511
383
  #disposeEngine() {
512
- if (!this.#engine) {
513
- this.#logDebug("Dispose engine called but engine already null");
514
- return;
515
- }
516
- this.#logDebug("Disposing Babylon resources");
384
+ if (!this.#engine) return;
517
385
  this.#engine.dispose();
518
386
  this.#engine = this.#scene = this.#camera = null;
519
387
  this.#hemiLight = this.#dirLight = this.#cameraLight = null;
520
388
  this.#shadowGen = null;
521
- this.#logDebug("Babylon resources disposed");
522
389
  }
523
390
 
524
391
  // Utility methods for loading gltf/glb
525
392
  async #getServerFileDataHeader(uri) {
526
- this.#logDebug("Requesting server file header", { uri });
527
393
  return new Promise((resolve) => {
528
394
  const xhr = new XMLHttpRequest();
529
395
  xhr.open("HEAD", uri, true);
@@ -532,15 +398,12 @@ class PrefViewer extends HTMLElement {
532
398
  if (xhr.status === 200) {
533
399
  const size = parseInt(xhr.getResponseHeader("Content-Length"));
534
400
  const timestamp = new Date(xhr.getResponseHeader("Last-Modified")).toISOString();
535
- this.#logDebug("Received server file header", { uri, size, timestamp });
536
401
  resolve(size, timestamp);
537
402
  } else {
538
- this.#logWarn("Failed to retrieve server file header", { uri, status: xhr.status });
539
403
  resolve(0, null);
540
404
  }
541
405
  };
542
406
  xhr.onerror = () => {
543
- this.#logError("Error requesting server file header", { uri });
544
407
  resolve(0, null);
545
408
  };
546
409
  xhr.send();
@@ -549,14 +412,11 @@ class PrefViewer extends HTMLElement {
549
412
 
550
413
  #transformUrl(url) {
551
414
  return new Promise((resolve) => {
552
- const transformed = url.replace(/^blob:[^/]+\//i, "").replace(/\\/g, "/");
553
- this.#logDebug("Transformed URL", { original: url, transformed });
554
- resolve(transformed);
415
+ resolve(url.replace(/^blob:[^/]+\//i, "").replace(/\\/g, "/"));
555
416
  });
556
417
  }
557
418
 
558
419
  #decodeBase64(base64) {
559
- this.#logDebug("Decoding Base64 payload", { length: base64 ? base64.length : 0 });
560
420
  const [, payload] = base64.split(",");
561
421
  const raw = payload || base64;
562
422
  let decoded = "";
@@ -566,62 +426,44 @@ class PrefViewer extends HTMLElement {
566
426
  try {
567
427
  decoded = atob(raw);
568
428
  } catch {
569
- this.#logWarn("Failed to decode Base64 string");
570
429
  return { blob, extension, size };
571
430
  }
572
431
  let isJson = false;
573
432
  try {
574
433
  JSON.parse(decoded);
575
434
  isJson = true;
576
- } catch { }
435
+ } catch {}
577
436
  extension = isJson ? ".gltf" : ".glb";
578
437
  const type = isJson ? "model/gltf+json" : "model/gltf-binary";
579
438
  const array = Uint8Array.from(decoded, (c) => c.charCodeAt(0));
580
439
  blob = new Blob([array], { type });
581
- this.#logDebug("Decoded Base64 payload", { isJson, size, extension });
582
440
  return { blob, extension, size };
583
441
  }
584
442
 
585
443
  async #initStorage(db, table) {
586
- this.#logDebug("Initializing storage access", { db, table });
587
444
  if (window.gltfDB && window.gltfDB.name === db && window.gltfDB.objectStoreNames.contains(table)) {
588
- this.#logDebug("Reusing existing IndexedDB connection", { db, table });
589
445
  return true;
590
446
  }
591
447
  await initDb(db, table);
592
- this.#logDebug("IndexedDB initialized", { db, table });
593
448
  }
594
449
 
595
450
  // Methods for managing Asset Containers
596
451
  #setVisibilityOfWallAndFloorInModel(show) {
597
452
  if (!this.#data.containers.model.assetContainer || !this.#data.containers.model.visible) {
598
- this.#logDebug("Skipping wall/floor visibility update", {
599
- hasModel: !!this.#data.containers.model.assetContainer,
600
- modelVisible: this.#data.containers.model.visible,
601
- });
602
453
  return false;
603
454
  }
604
455
  show = show !== undefined ? show : this.#data.containers.environment.visible;
605
456
  const prefixes = Object.values(this.#data.options.materials).map((material) => material.prefix);
606
457
  this.#data.containers.model.assetContainer.meshes.filter((meshToFilter) => prefixes.some((prefix) => meshToFilter.name.startsWith(prefix))).forEach((mesh) => mesh.setEnabled(show));
607
- this.#logDebug("Updated wall and floor visibility", { show });
608
458
  }
609
459
 
610
460
  #setOptionsMaterial(optionMaterial) {
611
461
  if (!optionMaterial || !optionMaterial.prefix || !optionMaterial.value) {
612
- this.#logWarn("Material option invalid", { optionMaterial });
613
462
  return false;
614
463
  }
615
464
 
616
- this.#logDebug("Applying material option", {
617
- prefix: optionMaterial.prefix,
618
- value: optionMaterial.value,
619
- changed: optionMaterial.changed,
620
- });
621
-
622
465
  const material = this.#data.containers.materials.assetContainer?.materials.find((mat) => mat.name === optionMaterial.value) || null;
623
466
  if (!material) {
624
- this.#logWarn("Requested material not found", { value: optionMaterial.value });
625
467
  return false;
626
468
  }
627
469
 
@@ -633,7 +475,6 @@ class PrefViewer extends HTMLElement {
633
475
  containers.push(this.#data.containers.environment.assetContainer);
634
476
  }
635
477
  if (containers.length === 0) {
636
- this.#logDebug("No containers required material update", { prefix: optionMaterial.prefix });
637
478
  return false;
638
479
  }
639
480
 
@@ -644,61 +485,36 @@ class PrefViewer extends HTMLElement {
644
485
  .forEach((mesh) => {
645
486
  mesh.material = material;
646
487
  someSetted = true;
647
- this.#logDebug("Assigned material to mesh", { mesh: mesh.name, material: material.name });
648
488
  })
649
489
  );
650
490
 
651
- this.#logDebug("Material option applied", {
652
- prefix: optionMaterial.prefix,
653
- value: optionMaterial.value,
654
- applied: someSetted,
655
- containers: containers.map((container) => container.name),
656
- });
657
-
658
491
  return someSetted;
659
492
  }
660
493
 
661
494
  #setOptionsMaterials() {
662
- if (!this.#data.containers.materials.assetContainer) {
663
- this.#logDebug("Skipping materials update; materials container is missing");
664
- return false;
665
- }
666
-
667
- this.#logDebug("Applying material options batch");
668
495
  let someSetted = false;
669
496
  Object.values(this.#data.options.materials).forEach((material) => {
670
497
  let settedMaterial = this.#setOptionsMaterial(material);
671
498
  someSetted = someSetted || settedMaterial;
672
499
  });
673
- this.#logDebug("Material batch processing finished", { appliedAny: someSetted });
674
500
  return someSetted;
675
501
  }
676
502
 
677
503
  #setOptionsCamera() {
678
504
  if (!this.#data.options.camera.value || (!this.#data.options.camera.changed && !this.#data.containers.model.assetContainer.changed)) {
679
- this.#logDebug("No camera option update necessary", {
680
- value: this.#data.options.camera.value,
681
- changed: this.#data.options.camera.changed,
682
- modelChanged: this.#data.containers.model.assetContainer?.changed,
683
- });
684
505
  return false;
685
506
  }
686
507
 
687
508
  let camera = this.#data.containers.model.assetContainer?.cameras.find((cam) => cam.name === this.#data.options.camera.value) || null;
688
509
  if (!camera) {
689
- this.#logWarn("Requested camera not found", { name: this.#data.options.camera.value });
690
510
  return false;
691
511
  }
692
512
 
693
513
  camera.metadata = { locked: this.#data.options.camera.locked };
694
514
  if (!this.#data.options.camera.locked) {
695
515
  camera.attachControl(this.#canvas, true);
696
- this.#logDebug("Attached unlocked camera control", { camera: camera.name });
697
- } else {
698
- this.#logDebug("Using locked camera configuration", { camera: camera.name });
699
516
  }
700
517
  this.#scene.activeCamera = camera;
701
- this.#logDebug("Active camera set", { camera: camera.name });
702
518
 
703
519
  return true;
704
520
  }
@@ -707,14 +523,6 @@ class PrefViewer extends HTMLElement {
707
523
  if (container.assetContainer && !container.visible && container.show) {
708
524
  container.assetContainer.addAllToScene();
709
525
  container.visible = true;
710
- this.#logDebug("Added container to scene", { name: container.name });
711
- } else {
712
- this.#logDebug("Skipped adding container", {
713
- name: container?.name,
714
- hasAssetContainer: !!container?.assetContainer,
715
- visible: container?.visible,
716
- show: container?.show,
717
- });
718
526
  }
719
527
  }
720
528
 
@@ -722,67 +530,40 @@ class PrefViewer extends HTMLElement {
722
530
  if (container.assetContainer && container.visible) {
723
531
  container.assetContainer.removeAllFromScene();
724
532
  container.visible = false;
725
- this.#logDebug("Removed container from scene", { name: container.name });
726
- } else {
727
- this.#logDebug("Skipped removing container", {
728
- name: container?.name,
729
- hasAssetContainer: !!container?.assetContainer,
730
- visible: container?.visible,
731
- });
732
533
  }
733
534
  }
734
535
 
735
536
  #replaceContainer(container, newAssetContainer) {
736
- this.#logDebug("Replacing container asset", { name: container.name });
737
537
  this.#removeContainer(container);
738
538
  container.assetContainer = newAssetContainer;
739
539
  container.assetContainer.meshes.forEach((mesh) => {
740
540
  mesh.receiveShadows = true;
741
541
  this.#shadowGen.addShadowCaster(mesh, true);
742
- this.#logDebug("Configured mesh for shadows", { container: container.name, mesh: mesh.name });
743
542
  });
744
543
  this.#addContainer(container);
745
- this.#logDebug("Container replacement complete", {
746
- name: container.name,
747
- meshCount: container.assetContainer.meshes.length,
748
- });
749
544
  }
750
545
 
751
546
  async #loadAssetContainer(container) {
752
- const storage = container?.storage;
753
- this.#logDebug("Requested asset container load", {
754
- container: container?.name,
755
- storage: this.#describeStorage(storage),
756
- });
547
+ let storage = container?.storage;
757
548
 
758
549
  if (!storage) {
759
- this.#logWarn("No storage configuration provided for container", { container: container?.name });
760
550
  return false;
761
551
  }
762
552
 
763
553
  let source = storage.url || null;
764
554
 
765
555
  if (storage.db && storage.table && storage.id) {
766
- this.#logDebug("Loading container from IndexedDB", {
767
- container: container.name,
768
- db: storage.db,
769
- table: storage.table,
770
- id: storage.id,
771
- });
772
556
  await this.#initStorage(storage.db, storage.table);
773
557
  const object = await loadModel(storage.id, storage.table);
774
558
  source = object.data;
775
559
  if (object.timestamp === container.timestamp) {
776
- this.#logDebug("IndexedDB model unchanged; skipping reload", { container: container.name });
777
560
  return false;
778
561
  } else {
779
562
  container.changed = { timestamp: object.timestamp, size: object.size };
780
- this.#logDebug("IndexedDB model marked as changed", { container: container.name, metadata: container.changed });
781
563
  }
782
564
  }
783
565
 
784
566
  if (!source) {
785
- this.#logWarn("No source resolved for container", { container: container.name });
786
567
  return false;
787
568
  }
788
569
 
@@ -790,17 +571,14 @@ class PrefViewer extends HTMLElement {
790
571
 
791
572
  let { blob, extension, size } = this.#decodeBase64(source);
792
573
  if (blob && extension) {
793
- this.#logDebug("Source detected as Base64", { container: container.name, extension });
794
574
  file = new File([blob], `${container.name}${extension}`, {
795
575
  type: blob.type,
796
576
  });
797
577
  if (!container.changed) {
798
578
  if (container.timestamp === null && container.size === size) {
799
- this.#logDebug("Base64 model unchanged; skipping reload", { container: container.name, size });
800
579
  return false;
801
580
  } else {
802
581
  container.changed = { timestamp: null, size: size };
803
- this.#logDebug("Base64 model marked as changed", { container: container.name, size });
804
582
  }
805
583
  }
806
584
  } else {
@@ -808,15 +586,9 @@ class PrefViewer extends HTMLElement {
808
586
  extension = extMatch ? `.${extMatch[1].toLowerCase()}` : ".gltf";
809
587
  const { fileSize, fileTimestamp } = await this.#getServerFileDataHeader(source);
810
588
  if (container.timestamp === fileTimestamp && container.size === fileSize) {
811
- this.#logDebug("Remote model unchanged; skipping reload", {
812
- container: container.name,
813
- fileTimestamp,
814
- fileSize,
815
- });
816
589
  return false;
817
590
  } else {
818
591
  container.changed = { timestamp: fileTimestamp, size: fileSize };
819
- this.#logDebug("Remote model marked as changed", { container: container.name, metadata: container.changed });
820
592
  }
821
593
  }
822
594
 
@@ -830,12 +602,10 @@ class PrefViewer extends HTMLElement {
830
602
  },
831
603
  };
832
604
 
833
- this.#logInfo("Loading asset container", { container: container.name, extension });
834
605
  return LoadAssetContainerAsync(file || source, this.#scene, options);
835
606
  }
836
607
 
837
608
  async #loadContainers(loadModel = true, loadEnvironment = true, loadMaterials = true) {
838
- this.#logInfo("Starting container load", { loadModel, loadEnvironment, loadMaterials });
839
609
  const promiseArray = [];
840
610
  promiseArray.push(loadModel ? this.#loadAssetContainer(this.#data.containers.model) : false);
841
611
  promiseArray.push(loadEnvironment ? this.#loadAssetContainer(this.#data.containers.environment) : false);
@@ -850,27 +620,20 @@ class PrefViewer extends HTMLElement {
850
620
  if (modelContainer.status === "fulfilled" && modelContainer.value) {
851
621
  this.#replaceContainer(this.#data.containers.model, modelContainer.value);
852
622
  this.#storeChangedFlagsForContainer(this.#data.containers.model);
853
- this.#logInfo("Model container loaded successfully");
854
623
  } else {
855
624
  this.#data.containers.model.show ? this.#addContainer(this.#data.containers.model) : this.#removeContainer(this.#data.containers.model);
856
- this.#logDebug("Model container load skipped or failed", { status: modelContainer.status });
857
625
  }
858
626
 
859
627
  if (environmentContainer.status === "fulfilled" && environmentContainer.value) {
860
628
  this.#replaceContainer(this.#data.containers.environment, environmentContainer.value);
861
629
  this.#storeChangedFlagsForContainer(this.#data.containers.environment);
862
- this.#logInfo("Environment container loaded successfully");
863
630
  } else {
864
631
  this.#data.containers.environment.show ? this.#addContainer(this.#data.containers.environment) : this.#removeContainer(this.#data.containers.environment);
865
- this.#logDebug("Environment container load skipped or failed", { status: environmentContainer.status });
866
632
  }
867
633
 
868
634
  if (materialsContainer.status === "fulfilled" && materialsContainer.value) {
869
635
  this.#replaceContainer(this.#data.containers.materials, materialsContainer.value);
870
636
  this.#storeChangedFlagsForContainer(this.#data.containers.materials);
871
- this.#logInfo("Materials container loaded successfully");
872
- } else {
873
- this.#logDebug("Materials container load skipped or failed", { status: materialsContainer.status });
874
637
  }
875
638
 
876
639
  this.#setOptionsMaterials();
@@ -879,7 +642,6 @@ class PrefViewer extends HTMLElement {
879
642
 
880
643
  this.#resetChangedFlags();
881
644
 
882
- this.#logInfo("Containers load routine completed");
883
645
  this.dispatchEvent(
884
646
  new CustomEvent("model-loaded", {
885
647
  detail: { success: "" },
@@ -887,10 +649,9 @@ class PrefViewer extends HTMLElement {
887
649
  composed: true,
888
650
  })
889
651
  );
890
- this.#logDebug("Dispatched model-loaded event");
891
652
  })
892
653
  .catch((error) => {
893
- this.#logError("Failed to load containers", { error });
654
+ console.error("PrefViewer: failed to load model", error);
894
655
  this.dispatchEvent(
895
656
  new CustomEvent("model-error", {
896
657
  detail: { error: error },
@@ -903,17 +664,8 @@ class PrefViewer extends HTMLElement {
903
664
 
904
665
  // Public Methods
905
666
  loadConfig(config) {
906
- this.#logInfo("loadConfig called", { initialized: this.#initialized, inputType: typeof config });
907
- if (typeof config === "string") {
908
- try {
909
- config = JSON.parse(config);
910
- } catch (error) {
911
- this.#logError("Failed to parse config JSON", { error });
912
- throw error;
913
- }
914
- }
667
+ config = typeof config === "string" ? JSON.parse(config) : config;
915
668
  if (!config) {
916
- this.#logWarn("No config provided");
917
669
  return false;
918
670
  }
919
671
 
@@ -930,145 +682,93 @@ class PrefViewer extends HTMLElement {
930
682
  this.#checkMaterialsChanged(config.options);
931
683
  }
932
684
 
933
- this.#logDebug("Config applied", {
934
- modelStorage: this.#describeStorage(this.#data.containers.model.storage),
935
- environmentStorage: this.#describeStorage(this.#data.containers.environment.storage),
936
- });
937
-
938
685
  this.#initialized && this.#loadContainers(true, true, true);
939
686
  }
940
687
 
941
688
  setOptions(options) {
942
- this.#logInfo("setOptions called", { optionsProvided: !!options });
943
689
  if (!options) {
944
- this.#logWarn("setOptions called without options");
945
690
  return false;
946
691
  }
947
692
  let someSetted = false;
948
693
  if (this.#checkCameraChanged(options)) {
949
- this.#logDebug("Camera options changed via setOptions");
950
694
  someSetted = someSetted || this.#setOptionsCamera();
951
695
  }
952
696
  if (this.#checkMaterialsChanged(options)) {
953
- this.#logDebug("Material options changed via setOptions");
954
697
  someSetted = someSetted || this.#setOptionsMaterials();
955
698
  }
956
699
  this.#resetChangedFlags();
957
- this.#logDebug("setOptions completed", { appliedAny: someSetted });
958
700
  debugger;
959
701
  return someSetted;
960
702
  }
961
703
 
962
704
  loadModel(model) {
963
- this.#logInfo("loadModel called", { initialized: this.#initialized, inputType: typeof model });
964
- if (typeof model === "string") {
965
- try {
966
- model = JSON.parse(model);
967
- } catch (error) {
968
- this.#logError("Failed to parse model JSON", { error });
969
- throw error;
970
- }
971
- }
705
+ model = typeof model === "string" ? JSON.parse(model) : model;
972
706
  if (!model) {
973
- this.#logWarn("No model payload provided");
974
707
  return false;
975
708
  }
976
709
  this.#data.containers.model.storage = model.storage || null;
977
710
  this.#data.containers.model.show = model.visible !== undefined ? model.visible : this.#data.containers.model.show;
978
- this.#logDebug("Model configuration updated", {
979
- storage: this.#describeStorage(this.#data.containers.model.storage),
980
- show: this.#data.containers.model.show,
981
- });
982
711
  this.#initialized && this.#loadContainers(true, false, false);
983
712
  }
984
713
 
985
714
  loadScene(scene) {
986
- this.#logInfo("loadScene called", { initialized: this.#initialized, inputType: typeof scene });
987
- if (typeof scene === "string") {
988
- try {
989
- scene = JSON.parse(scene);
990
- } catch (error) {
991
- this.#logError("Failed to parse scene JSON", { error });
992
- throw error;
993
- }
994
- }
715
+ scene = typeof scene === "string" ? JSON.parse(scene) : scene;
995
716
  if (!scene) {
996
- this.#logWarn("No scene payload provided");
997
717
  return false;
998
718
  }
999
719
  this.#data.containers.environment.storage = scene.storage || null;
1000
720
  this.#data.containers.environment.show = scene.visible !== undefined ? scene.visible : this.#data.containers.environment.show;
1001
- this.#logDebug("Scene configuration updated", {
1002
- storage: this.#describeStorage(this.#data.containers.environment.storage),
1003
- show: this.#data.containers.environment.show,
1004
- });
1005
721
  this.#initialized && this.#loadContainers(false, true, false);
1006
722
  }
1007
723
 
1008
724
  showModel() {
1009
725
  this.#data.containers.model.show = true;
1010
726
  this.#addContainer(this.#data.containers.model);
1011
- this.#logInfo("Model visibility set to true");
1012
727
  }
1013
728
 
1014
729
  hideModel() {
1015
730
  this.#data.containers.model.show = false;
1016
731
  this.#removeContainer(this.#data.containers.model);
1017
- this.#logInfo("Model visibility set to false");
1018
732
  }
1019
733
 
1020
734
  showScene() {
1021
735
  this.#data.containers.environment.show = true;
1022
736
  this.#addContainer(this.#data.containers.environment);
1023
737
  this.#setVisibilityOfWallAndFloorInModel();
1024
- this.#logInfo("Scene visibility set to true");
1025
738
  }
1026
739
 
1027
740
  hideScene() {
1028
741
  this.#data.containers.environment.show = false;
1029
742
  this.#removeContainer(this.#data.containers.environment);
1030
743
  this.#setVisibilityOfWallAndFloorInModel();
1031
- this.#logInfo("Scene visibility set to false");
1032
744
  }
1033
745
 
1034
746
  downloadModelGLB() {
1035
747
  const fileName = "model";
1036
- this.#logInfo("Initiating GLB download for model", { fileName });
1037
- GLTF2Export.GLBAsync(this.#data.containers.model.assetContainer, fileName, { exportWithoutWaitingForScene: true }).then((glb) => {
1038
- this.#logDebug("Model GLB export ready", { fileName });
1039
- glb.downloadFiles();
1040
- });
748
+ GLTF2Export.GLBAsync(this.#data.containers.model.assetContainer, fileName, { exportWithoutWaitingForScene: true }).then((glb) => glb.downloadFiles());
1041
749
  }
1042
750
 
1043
751
  downloadModelUSDZ() {
1044
752
  const fileName = "model";
1045
- this.#logInfo("Initiating USDZ download for model", { fileName });
1046
753
  USDZExportAsync(this.#data.containers.model.assetContainer).then((response) => {
1047
754
  if (response) {
1048
755
  Tools.Download(new Blob([response], { type: "model/vnd.usdz+zip" }), `${fileName}.usdz`);
1049
- this.#logDebug("Model USDZ export ready", { fileName });
1050
756
  }
1051
757
  });
1052
758
  }
1053
759
 
1054
760
  downloadModelAndSceneUSDZ() {
1055
761
  const fileName = "scene";
1056
- this.#logInfo("Initiating USDZ download for scene", { fileName });
1057
762
  USDZExportAsync(this.#scene).then((response) => {
1058
763
  if (response) {
1059
764
  Tools.Download(new Blob([response], { type: "model/vnd.usdz+zip" }), `${fileName}.usdz`);
1060
- this.#logDebug("Scene USDZ export ready", { fileName });
1061
765
  }
1062
766
  });
1063
767
  }
1064
768
 
1065
769
  downloadModelAndSceneGLB() {
1066
770
  const fileName = "scene";
1067
- this.#logInfo("Initiating GLB download for scene", { fileName });
1068
- GLTF2Export.GLBAsync(this.#scene, fileName, { exportWithoutWaitingForScene: true }).then((glb) => {
1069
- this.#logDebug("Scene GLB export ready", { fileName });
1070
- glb.downloadFiles();
1071
- });
771
+ GLTF2Export.GLBAsync(this.#scene, fileName, { exportWithoutWaitingForScene: true }).then((glb) => glb.downloadFiles());
1072
772
  }
1073
773
  }
1074
774