@preference-sl/pref-viewer 2.10.0-beta.13 → 2.10.0-beta.14

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 +15 -130
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preference-sl/pref-viewer",
3
- "version": "2.10.0-beta.13",
3
+ "version": "2.10.0-beta.14",
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
@@ -49,13 +49,6 @@ import { initDb, loadModel } from "./gltf-storage.js";
49
49
  class PrefViewer extends HTMLElement {
50
50
  #initialized = false;
51
51
 
52
- // --- logging helper (no functional change) ---
53
- #logNS = "PrefViewer";
54
- #log(method, ...args) {
55
- const fn = console[method] || console.log;
56
- fn(`[${this.#logNS}]`, ...args);
57
- }
58
-
59
52
  #data = {
60
53
  containers: {
61
54
  model: {
@@ -149,7 +142,6 @@ class PrefViewer extends HTMLElement {
149
142
  // JS fallback if WASM isn’t available
150
143
  fallbackUrl: `${DRACO_BASE}/draco_decoder_gltf.js`,
151
144
  };
152
- this.#log("info", "constructed");
153
145
  }
154
146
 
155
147
  static get observedAttributes() {
@@ -157,8 +149,6 @@ class PrefViewer extends HTMLElement {
157
149
  }
158
150
 
159
151
  attributeChangedCallback(name, _old, value) {
160
- this.#log("groupCollapsed", `attributeChanged: ${name}`);
161
- this.#log("info", "new value:", value);
162
152
  let data = null;
163
153
  switch (name) {
164
154
  case "config":
@@ -187,7 +177,6 @@ class PrefViewer extends HTMLElement {
187
177
  }
188
178
  break;
189
179
  }
190
- console.groupEnd();
191
180
  }
192
181
 
193
182
  connectedCallback() {
@@ -204,14 +193,12 @@ class PrefViewer extends HTMLElement {
204
193
  return false;
205
194
  }
206
195
 
207
- this.#log("info", "connectedCallback: initializing Babylon and starting initial load");
208
196
  this.#initializeBabylon();
209
197
  this.#loadContainers(true, true, true);
210
198
  this.#initialized = true;
211
199
  }
212
200
 
213
201
  disconnectedCallback() {
214
- this.#log("info", "disconnectedCallback: disposing engine and observers");
215
202
  this.#disposeEngine();
216
203
  this.#canvasResizeObserver.disconnect();
217
204
  }
@@ -241,47 +228,36 @@ class PrefViewer extends HTMLElement {
241
228
  // Data
242
229
  #checkCameraChanged(options) {
243
230
  if (!options || !options.camera) {
244
- this.#log("debug", "checkCameraChanged: no camera in options");
245
231
  return false;
246
232
  }
247
- const prev = this.#data.options.camera.value;
248
- const next = options.camera;
249
- this.#data.options.camera.changed = options.camera && options.camera !== prev ? true : false;
250
- this.#data.options.camera.value = this.#data.options.camera.changed ? next : prev;
251
- this.#log("info", "checkCameraChanged:", { prev, next, changed: this.#data.options.camera.changed });
233
+ this.#data.options.camera.changed = options.camera && options.camera !== this.#data.options.camera.value ? true : false;
234
+ this.#data.options.camera.value = this.#data.options.camera.changed ? options.camera : this.#data.options.camera.value;
252
235
  return this.#data.options.camera.changed;
253
236
  }
254
237
 
255
238
  #checkMaterialsChanged(options) {
256
239
  if (!options) {
257
- this.#log("debug", "checkMaterialsChanged: no options object");
258
240
  return false;
259
241
  }
260
242
  let someChanged = false;
261
243
  Object.keys(this.#data.options.materials).forEach((material) => {
262
244
  const key = `${material}Material`;
263
- const prev = this.#data.options.materials[material].value;
264
- const next = options[key];
265
- this.#data.options.materials[material].changed = next && next !== prev ? true : false;
266
- this.#data.options.materials[material].value = this.#data.options.materials[material].changed ? next : prev;
245
+ this.#data.options.materials[material].changed = options[key] && options[key] !== this.#data.options.materials[material].value ? true : false;
246
+ this.#data.options.materials[material].value = this.#data.options.materials[material].changed ? options[key] : this.#data.options.materials[material].value;
267
247
  someChanged = someChanged || this.#data.options.materials[material].changed;
268
- this.#log("info", "checkMaterialsChanged item:", { material, key, prev, next, changed: this.#data.options.materials[material].changed });
269
248
  });
270
- this.#log("info", "checkMaterialsChanged: someChanged =", someChanged);
271
249
  return someChanged;
272
250
  }
273
251
 
274
252
  #storeChangedFlagsForContainer(container) {
275
253
  container.timestamp = container.changed.timestamp;
276
254
  container.size = container.changed.size;
277
- this.#log("debug", "storeChangedFlagsForContainer:", { name: container.name, timestamp: container.timestamp, size: container.size });
278
255
  }
279
256
 
280
257
  #resetChangedFlags() {
281
258
  Object.values(this.#data.containers).forEach((container) => (container.changed = false));
282
259
  Object.values(this.#data.options.materials).forEach((material) => (material.changed = false));
283
260
  this.#data.options.camera.changed = false;
284
- this.#log("debug", "resetChangedFlags()");
285
261
  }
286
262
 
287
263
  // Babylon.js
@@ -296,7 +272,6 @@ class PrefViewer extends HTMLElement {
296
272
  this.#engine.runRenderLoop(() => this.#scene && this.#scene.render());
297
273
  this.#canvasResizeObserver.observe(this.#canvas);
298
274
 
299
- this.#log("info", "Babylon initialized: creating XR experience (if supported)...");
300
275
  await this.#createXRExperience();
301
276
  }
302
277
 
@@ -315,7 +290,7 @@ class PrefViewer extends HTMLElement {
315
290
  const sessionMode = "immersive-ar";
316
291
  const sessionSupported = await WebXRSessionManager.IsSessionSupportedAsync(sessionMode);
317
292
  if (!sessionSupported) {
318
- this.#log("info", "WebXR in mode AR is not supported");
293
+ console.info("PrefViewer: WebXR in mode AR is not supported");
319
294
  return false;
320
295
  }
321
296
 
@@ -350,7 +325,6 @@ class PrefViewer extends HTMLElement {
350
325
  });
351
326
 
352
327
  this.addStylesToARButton();
353
- this.#log("info", "WebXR experience created");
354
328
  } catch (error) {
355
329
  console.warn("PrefViewer: failed to create WebXR experience", error);
356
330
  this.#XRExperience = null;
@@ -368,7 +342,6 @@ class PrefViewer extends HTMLElement {
368
342
  this.#camera.metadata = { locked: false }
369
343
  this.#camera = this.#camera;
370
344
  this.#camera.attachControl(this.#canvas, true);
371
- this.#log("info", "Default camera created");
372
345
  }
373
346
 
374
347
  #createLights() {
@@ -391,8 +364,6 @@ class PrefViewer extends HTMLElement {
391
364
  this.#cameraLight = new PointLight("pl", this.#camera.position, this.#scene);
392
365
  this.#cameraLight.parent = this.#camera;
393
366
  this.#cameraLight.intensity = 0.3;
394
-
395
- this.#log("info", "Lights & shadows configured");
396
367
  }
397
368
 
398
369
  #setupInteraction() {
@@ -415,7 +386,6 @@ class PrefViewer extends HTMLElement {
415
386
  this.#engine = this.#scene = this.#camera = null;
416
387
  this.#hemiLight = this.#dirLight = this.#cameraLight = null;
417
388
  this.#shadowGen = null;
418
- this.#log("info", "Engine disposed");
419
389
  }
420
390
 
421
391
  // Utility methods for loading gltf/glb
@@ -459,7 +429,7 @@ class PrefViewer extends HTMLElement {
459
429
  return { blob, extension, size };
460
430
  }
461
431
  let isJson = false;
462
- try {
432
+ try {
463
433
  JSON.parse(decoded);
464
434
  isJson = true;
465
435
  } catch {}
@@ -484,20 +454,16 @@ class PrefViewer extends HTMLElement {
484
454
  }
485
455
  show = show !== undefined ? show : this.#data.containers.environment.visible;
486
456
  const prefixes = Object.values(this.#data.options.materials).map((material) => material.prefix);
487
- const meshes = this.#data.containers.model.assetContainer.meshes.filter((meshToFilter) => prefixes.some((prefix) => meshToFilter.name.startsWith(prefix)));
488
- this.#log("debug", "setVisibilityOfWallAndFloorInModel:", { show, affectedMeshes: meshes.map(m => m.name) });
489
- meshes.forEach((mesh) => mesh.setEnabled(show));
457
+ this.#data.containers.model.assetContainer.meshes.filter((meshToFilter) => prefixes.some((prefix) => meshToFilter.name.startsWith(prefix))).forEach((mesh) => mesh.setEnabled(show));
490
458
  }
491
459
 
492
460
  #setOptionsMaterial(optionMaterial) {
493
461
  if (!optionMaterial || !optionMaterial.prefix || !optionMaterial.value) {
494
- this.#log("debug", "setOptionsMaterial: missing data", optionMaterial);
495
462
  return false;
496
463
  }
497
464
 
498
465
  const material = this.#data.containers.materials.assetContainer?.materials.find((mat) => mat.name === optionMaterial.value) || null;
499
466
  if (!material) {
500
- this.#log("warn", `setOptionsMaterial: material "${optionMaterial.value}" not found in materials container`);
501
467
  return false;
502
468
  }
503
469
 
@@ -509,22 +475,20 @@ class PrefViewer extends HTMLElement {
509
475
  containers.push(this.#data.containers.environment.assetContainer);
510
476
  }
511
477
  if (containers.length === 0) {
512
- this.#log("debug", "setOptionsMaterial: no target containers (unchanged)");
513
478
  return false;
514
479
  }
515
480
 
516
- let count = 0;
481
+ let someSetted = false;
517
482
  containers.forEach((container) =>
518
483
  container.meshes
519
484
  .filter((meshToFilter) => meshToFilter.name.startsWith(optionMaterial.prefix))
520
485
  .forEach((mesh) => {
521
486
  mesh.material = material;
522
- count++;
487
+ someSetted = true;
523
488
  })
524
489
  );
525
490
 
526
- this.#log("info", "setOptionsMaterial applied", { prefix: optionMaterial.prefix, material: optionMaterial.value, meshesUpdated: count });
527
- return count > 0;
491
+ return someSetted;
528
492
  }
529
493
 
530
494
  #setOptionsMaterials() {
@@ -533,19 +497,16 @@ class PrefViewer extends HTMLElement {
533
497
  let settedMaterial = this.#setOptionsMaterial(material);
534
498
  someSetted = someSetted || settedMaterial;
535
499
  });
536
- this.#log("info", "setOptionsMaterials: anyApplied =", someSetted);
537
500
  return someSetted;
538
501
  }
539
502
 
540
503
  #setOptionsCamera() {
541
504
  if (!this.#data.options.camera.value || (!this.#data.options.camera.changed && !this.#data.containers.model.assetContainer.changed)) {
542
- this.#log("debug", "setOptionsCamera: skipped (no change or no camera specified)");
543
505
  return false;
544
506
  }
545
507
 
546
508
  let camera = this.#data.containers.model.assetContainer?.cameras.find((cam) => cam.name === this.#data.options.camera.value) || null;
547
509
  if (!camera) {
548
- this.#log("warn", `setOptionsCamera: camera "${this.#data.options.camera.value}" not found in model`);
549
510
  return false;
550
511
  }
551
512
 
@@ -554,7 +515,6 @@ class PrefViewer extends HTMLElement {
554
515
  camera.attachControl(this.#canvas, true);
555
516
  }
556
517
  this.#scene.activeCamera = camera;
557
- this.#log("info", "setOptionsCamera: activated", { name: camera.name, locked: this.#data.options.camera.locked });
558
518
 
559
519
  return true;
560
520
  }
@@ -563,7 +523,6 @@ class PrefViewer extends HTMLElement {
563
523
  if (container.assetContainer && !container.visible && container.show) {
564
524
  container.assetContainer.addAllToScene();
565
525
  container.visible = true;
566
- this.#log("debug", "addContainer -> visible", container.name);
567
526
  }
568
527
  }
569
528
 
@@ -571,7 +530,6 @@ class PrefViewer extends HTMLElement {
571
530
  if (container.assetContainer && container.visible) {
572
531
  container.assetContainer.removeAllFromScene();
573
532
  container.visible = false;
574
- this.#log("debug", "removeContainer -> hidden", container.name);
575
533
  }
576
534
  }
577
535
 
@@ -583,24 +541,15 @@ class PrefViewer extends HTMLElement {
583
541
  this.#shadowGen.addShadowCaster(mesh, true);
584
542
  });
585
543
  this.#addContainer(container);
586
- this.#log("debug", "replaceContainer:", container.name, {
587
- meshes: container.assetContainer.meshes?.length,
588
- materials: container.assetContainer.materials?.length,
589
- cameras: container.assetContainer.cameras?.length,
590
- });
591
544
  }
592
545
 
593
546
  async #loadAssetContainer(container) {
594
547
  let storage = container?.storage;
595
548
 
596
549
  if (!storage) {
597
- this.#log("debug", `loadAssetContainer(${container?.name}): no storage provided`);
598
550
  return false;
599
551
  }
600
552
 
601
- this.#log("groupCollapsed", `loadAssetContainer -> ${container.name}`);
602
- this.#log("info", "storage:", storage);
603
-
604
553
  let source = storage.url || null;
605
554
 
606
555
  if (storage.db && storage.table && storage.id) {
@@ -608,18 +557,13 @@ class PrefViewer extends HTMLElement {
608
557
  const object = await loadModel(storage.id, storage.table);
609
558
  source = object.data;
610
559
  if (object.timestamp === container.timestamp) {
611
- this.#log("info", "IndexedDB source unchanged (timestamp match). Skipping reload.");
612
- console.groupEnd();
613
560
  return false;
614
561
  } else {
615
562
  container.changed = { timestamp: object.timestamp, size: object.size };
616
- this.#log("info", "IndexedDB source changed:", container.changed);
617
563
  }
618
564
  }
619
565
 
620
566
  if (!source) {
621
- this.#log("warn", "no source (url/db) to load");
622
- console.groupEnd();
623
567
  return false;
624
568
  }
625
569
 
@@ -632,12 +576,9 @@ class PrefViewer extends HTMLElement {
632
576
  });
633
577
  if (!container.changed) {
634
578
  if (container.timestamp === null && container.size === size) {
635
- this.#log("info", "Base64 source unchanged (size match). Skipping reload.");
636
- console.groupEnd();
637
579
  return false;
638
580
  } else {
639
581
  container.changed = { timestamp: null, size: size };
640
- this.#log("info", "Base64 source changed (size):", container.changed);
641
582
  }
642
583
  }
643
584
  } else {
@@ -645,12 +586,9 @@ class PrefViewer extends HTMLElement {
645
586
  extension = extMatch ? `.${extMatch[1].toLowerCase()}` : ".gltf";
646
587
  const { fileSize, fileTimestamp } = await this.#getServerFileDataHeader(source);
647
588
  if (container.timestamp === fileTimestamp && container.size === fileSize) {
648
- this.#log("info", "URL source unchanged (HEAD size/timestamp). Skipping reload.");
649
- console.groupEnd();
650
589
  return false;
651
590
  } else {
652
591
  container.changed = { timestamp: fileTimestamp, size: fileSize };
653
- this.#log("info", "URL source changed:", container.changed);
654
592
  }
655
593
  }
656
594
 
@@ -664,19 +602,10 @@ class PrefViewer extends HTMLElement {
664
602
  },
665
603
  };
666
604
 
667
- this.#log("info", "Loading asset container with options:", options);
668
- const result = await LoadAssetContainerAsync(file || source, this.#scene, options);
669
- this.#log("info", "Asset container loaded:", {
670
- meshes: result.meshes?.length,
671
- materials: result.materials?.length,
672
- cameras: result.cameras?.length,
673
- });
674
- console.groupEnd();
675
- return result;
605
+ return LoadAssetContainerAsync(file || source, this.#scene, options);
676
606
  }
677
607
 
678
608
  async #loadContainers(loadModel = true, loadEnvironment = true, loadMaterials = true) {
679
- this.#log("groupCollapsed", "loadContainers flags", { loadModel, loadEnvironment, loadMaterials });
680
609
  const promiseArray = [];
681
610
  promiseArray.push(loadModel ? this.#loadAssetContainer(this.#data.containers.model) : false);
682
611
  promiseArray.push(loadEnvironment ? this.#loadAssetContainer(this.#data.containers.environment) : false);
@@ -688,12 +617,6 @@ class PrefViewer extends HTMLElement {
688
617
  const environmentContainer = values[1];
689
618
  const materialsContainer = values[2];
690
619
 
691
- this.#log("info", "loadContainers results:", {
692
- model: modelContainer?.status,
693
- environment: environmentContainer?.status,
694
- materials: materialsContainer?.status,
695
- });
696
-
697
620
  if (modelContainer.status === "fulfilled" && modelContainer.value) {
698
621
  this.#replaceContainer(this.#data.containers.model, modelContainer.value);
699
622
  this.#storeChangedFlagsForContainer(this.#data.containers.model);
@@ -713,12 +636,10 @@ class PrefViewer extends HTMLElement {
713
636
  this.#storeChangedFlagsForContainer(this.#data.containers.materials);
714
637
  }
715
638
 
716
- const materialsApplied = this.#setOptionsMaterials();
717
- const cameraApplied = this.#setOptionsCamera();
639
+ this.#setOptionsMaterials();
640
+ this.#setOptionsCamera();
718
641
  this.#setVisibilityOfWallAndFloorInModel();
719
642
 
720
- this.#log("info", "post-load options applied", { materialsApplied, cameraApplied });
721
-
722
643
  this.#resetChangedFlags();
723
644
 
724
645
  this.dispatchEvent(
@@ -728,8 +649,6 @@ class PrefViewer extends HTMLElement {
728
649
  composed: true,
729
650
  })
730
651
  );
731
- this.#log("info", "model-loaded event dispatched");
732
- console.groupEnd();
733
652
  })
734
653
  .catch((error) => {
735
654
  console.error("PrefViewer: failed to load model", error);
@@ -740,18 +659,13 @@ class PrefViewer extends HTMLElement {
740
659
  composed: true,
741
660
  })
742
661
  );
743
- this.#log("error", "model-error event dispatched");
744
- console.groupEnd();
745
662
  });
746
663
  }
747
664
 
748
665
  // Public Methods
749
666
  loadConfig(config) {
750
- this.#log("groupCollapsed", "loadConfig called with:", config);
751
667
  config = typeof config === "string" ? JSON.parse(config) : config;
752
668
  if (!config) {
753
- this.#log("warn", "loadConfig: no config provided");
754
- console.groupEnd();
755
669
  return false;
756
670
  }
757
671
 
@@ -762,30 +676,17 @@ class PrefViewer extends HTMLElement {
762
676
  this.#data.containers.environment.show = config.scene?.visible !== undefined ? config.scene.visible : this.#data.containers.environment.show;
763
677
  this.#data.containers.materials.storage = config.materials?.storage || null;
764
678
 
765
- this.#log("info", "containers set from config", {
766
- model: this.#data.containers.model,
767
- environment: this.#data.containers.environment,
768
- materials: this.#data.containers.materials,
769
- });
770
-
771
679
  // Options
772
680
  if (config.options) {
773
- const camChanged = this.#checkCameraChanged(config.options);
774
- const matsChanged = this.#checkMaterialsChanged(config.options);
775
- this.#log("info", "options parsed", { camChanged, matsChanged, options: this.#data.options });
776
- } else {
777
- this.#log("debug", "no options in config");
681
+ this.#checkCameraChanged(config.options);
682
+ this.#checkMaterialsChanged(config.options);
778
683
  }
779
684
 
780
685
  this.#initialized && this.#loadContainers(true, true, true);
781
- console.groupEnd();
782
686
  }
783
687
 
784
688
  setOptions(options) {
785
- this.#log("groupCollapsed", "setOptions called with:", options);
786
689
  if (!options) {
787
- this.#log("warn", "setOptions: no options");
788
- console.groupEnd();
789
690
  return false;
790
691
  }
791
692
  let someSetted = false;
@@ -796,63 +697,47 @@ class PrefViewer extends HTMLElement {
796
697
  someSetted = someSetted || this.#setOptionsMaterials();
797
698
  }
798
699
  this.#resetChangedFlags();
799
- this.#log("info", "setOptions result:", { applied: someSetted, currentOptions: this.#data.options });
800
700
  debugger;
801
- console.groupEnd();
802
701
  return someSetted;
803
702
  }
804
703
 
805
704
  loadModel(model) {
806
- this.#log("groupCollapsed", "loadModel called with:", model);
807
705
  model = typeof model === "string" ? JSON.parse(model) : model;
808
706
  if (!model) {
809
- this.#log("warn", "loadModel: no model object");
810
- console.groupEnd();
811
707
  return false;
812
708
  }
813
709
  this.#data.containers.model.storage = model.storage || null;
814
710
  this.#data.containers.model.show = model.visible !== undefined ? model.visible : this.#data.containers.model.show;
815
- this.#log("info", "model container updated", this.#data.containers.model);
816
711
  this.#initialized && this.#loadContainers(true, false, false);
817
- console.groupEnd();
818
712
  }
819
713
 
820
714
  loadScene(scene) {
821
- this.#log("groupCollapsed", "loadScene called with:", scene);
822
715
  scene = typeof scene === "string" ? JSON.parse(scene) : scene;
823
716
  if (!scene) {
824
- this.#log("warn", "loadScene: no scene object");
825
- console.groupEnd();
826
717
  return false;
827
718
  }
828
719
  this.#data.containers.environment.storage = scene.storage || null;
829
720
  this.#data.containers.environment.show = scene.visible !== undefined ? scene.visible : this.#data.containers.environment.show;
830
- this.#log("info", "environment container updated", this.#data.containers.environment);
831
721
  this.#initialized && this.#loadContainers(false, true, false);
832
- console.groupEnd();
833
722
  }
834
723
 
835
724
  showModel() {
836
- this.#log("info", "showModel()");
837
725
  this.#data.containers.model.show = true;
838
726
  this.#addContainer(this.#data.containers.model);
839
727
  }
840
728
 
841
729
  hideModel() {
842
- this.#log("info", "hideModel()");
843
730
  this.#data.containers.model.show = false;
844
731
  this.#removeContainer(this.#data.containers.model);
845
732
  }
846
733
 
847
734
  showScene() {
848
- this.#log("info", "showScene()");
849
735
  this.#data.containers.environment.show = true;
850
736
  this.#addContainer(this.#data.containers.environment);
851
737
  this.#setVisibilityOfWallAndFloorInModel();
852
738
  }
853
739
 
854
740
  hideScene() {
855
- this.#log("info", "hideScene()");
856
741
  this.#data.containers.environment.show = false;
857
742
  this.#removeContainer(this.#data.containers.environment);
858
743
  this.#setVisibilityOfWallAndFloorInModel();