@needle-tools/engine 4.11.5-next.9fa3148 → 4.11.5-next.a900688

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 (30) hide show
  1. package/dist/{needle-engine.bundle-D8QnRDOA.js → needle-engine.bundle-Bwinyjsh.js} +2338 -2373
  2. package/dist/{needle-engine.bundle-aQ4JfO6G.umd.cjs → needle-engine.bundle-Dsfd8BPk.umd.cjs} +113 -121
  3. package/dist/{needle-engine.bundle-BODHvc75.min.js → needle-engine.bundle-vPWPv18K.min.js} +108 -116
  4. package/dist/needle-engine.js +2 -2
  5. package/dist/needle-engine.min.js +1 -1
  6. package/dist/needle-engine.umd.cjs +1 -1
  7. package/lib/engine/engine_application.d.ts +0 -7
  8. package/lib/engine/engine_application.js +1 -8
  9. package/lib/engine/engine_application.js.map +1 -1
  10. package/lib/engine/engine_assetdatabase.d.ts +6 -0
  11. package/lib/engine/engine_assetdatabase.js +15 -0
  12. package/lib/engine/engine_assetdatabase.js.map +1 -1
  13. package/lib/engine/engine_context.d.ts +0 -1
  14. package/lib/engine/engine_context.js +2 -5
  15. package/lib/engine/engine_context.js.map +1 -1
  16. package/lib/engine/engine_loaders.js +25 -24
  17. package/lib/engine/engine_loaders.js.map +1 -1
  18. package/lib/engine-components/RendererInstancing.d.ts +3 -5
  19. package/lib/engine-components/RendererInstancing.js +31 -64
  20. package/lib/engine-components/RendererInstancing.js.map +1 -1
  21. package/package.json +1 -1
  22. package/src/engine/engine_application.ts +1 -16
  23. package/src/engine/engine_assetdatabase.ts +21 -0
  24. package/src/engine/engine_context.ts +2 -6
  25. package/src/engine/engine_loaders.ts +26 -24
  26. package/src/engine-components/RendererInstancing.ts +33 -69
  27. package/lib/engine/debug/debug_spector.d.ts +0 -16
  28. package/lib/engine/debug/debug_spector.js +0 -28
  29. package/lib/engine/debug/debug_spector.js.map +0 -1
  30. package/src/engine/debug/debug_spector.ts +0 -43
@@ -29,9 +29,8 @@ export class InstancingHandler {
29
29
  * (The instancing mesh renderer will grow x2 if the max instance count is reached)
30
30
  * @default 4
31
31
  * @returns The initial instance count
32
- */
33
- // @ts-ignore (ignore the unused parameter warning)
34
- static getStartInstanceCount = (obj: Object3D) => {
32
+ * */
33
+ static getStartInstanceCount = (_obj: Object3D) => {
35
34
  return 4;
36
35
  };
37
36
 
@@ -46,24 +45,20 @@ export class InstancingHandler {
46
45
  if (res) {
47
46
  if (handlesArray === null) handlesArray = [];
48
47
  handlesArray.push(res);
49
-
50
- // Load LOD for textures
51
- const mat = res.object.material;
52
- if(Array.isArray(mat)) {
53
- mat.forEach(m => NEEDLE_progressive.assignTextureLOD(m, 0));
54
- }
55
- else {
56
- NEEDLE_progressive.assignTextureLOD(mat, 0);
48
+ // load texture lods
49
+ NEEDLE_progressive.assignTextureLOD(res.renderer.material, 0);
50
+
51
+ // Load mesh lods
52
+ // TODO: technically for multi meshes we do this work multiple times (we search for meshes in children and then use the renderer sharedMeshes... that doesnt make sense)
53
+ for (let i = 0; i < renderer.sharedMeshes.length; i++) {
54
+ const mesh = renderer.sharedMeshes[i];
55
+ const geometry = mesh.geometry;
56
+ NEEDLE_progressive.assignMeshLOD(mesh, 0).then(lod => {
57
+ if (lod && renderer.activeAndEnabled && geometry != lod) {
58
+ res.setGeometry(lod);
59
+ }
60
+ });
57
61
  }
58
-
59
- // Load LOD for geometry
60
- const mesh = res.object;
61
- const geometry = mesh.geometry;
62
- NEEDLE_progressive.assignMeshLOD(mesh, 0).then(lod => {
63
- if (lod && geometry != lod) {
64
- res.setGeometry(lod);
65
- }
66
- });
67
62
  }
68
63
 
69
64
  else if (level <= 0 && obj.type !== "Mesh") {
@@ -354,7 +349,7 @@ class InstancedMeshRenderer {
354
349
  private _context: Context;
355
350
  private _batchedMesh: BatchedMesh;
356
351
  private _handles: (InstanceHandle | null)[] = [];
357
- private _geometryIds = new WeakMap<BufferGeometry, number>();
352
+ private readonly _geometryIds: Map<BufferGeometry, number> = new Map();
358
353
  private _maxInstanceCount: number;
359
354
 
360
355
  private _currentInstanceCount = 0;
@@ -444,10 +439,6 @@ class InstancedMeshRenderer {
444
439
  private _needUpdateBounds: boolean = false;
445
440
  private _debugMaterial: MeshStandardMaterial | null = null;
446
441
 
447
- private getBatchedMeshName() {
448
- return this.name ? `${this.name} (BatchedMesh)` : "BatchedMesh";
449
- }
450
-
451
442
  constructor(name: string, geo: BufferGeometry, material: Material, initialMaxCount: number, context: Context) {
452
443
  this.name = name;
453
444
  this.geometry = geo;
@@ -461,7 +452,6 @@ class InstancedMeshRenderer {
461
452
  this._maxVertexCount = estimate.vertexCount;
462
453
  this._maxIndexCount = estimate.indexCount;
463
454
  this._batchedMesh = new BatchedMesh(this._maxInstanceCount, this._maxVertexCount, this._maxIndexCount, this._debugMaterial ?? this.material);
464
- this._batchedMesh.name = this.getBatchedMeshName();
465
455
  // this.inst = new InstancedMesh(geo, material, count);
466
456
  this._batchedMesh[$instancingAutoUpdateBounds] = true;
467
457
  // this.inst.count = 0;
@@ -485,7 +475,7 @@ class InstancedMeshRenderer {
485
475
  context.post_render_callbacks.push(this.onAfterRender);
486
476
 
487
477
  if (debugInstancing) {
488
- console.log(`Instanced renderer (${this.name}) created with ${this._maxInstanceCount} instances, ${this._maxVertexCount} max vertices and ${this._maxIndexCount} max indices for \"${name}\"`)
478
+ console.log(`Instanced renderer created with ${this._maxInstanceCount} instances, ${this._maxVertexCount} max vertices and ${this._maxIndexCount} max indices for \"${name}\"`)
489
479
  }
490
480
  }
491
481
 
@@ -532,8 +522,7 @@ class InstancedMeshRenderer {
532
522
  return false;
533
523
  }
534
524
 
535
- const newInstanceCount = this._currentInstanceCount + 1;
536
- if (newInstanceCount > this._maxInstanceCount || this.mustGrow(geo)) {
525
+ if (this.mustGrow(geo)) {
537
526
  if (this.allowResize) {
538
527
  this.grow(geo);
539
528
  }
@@ -655,42 +644,34 @@ class InstancedMeshRenderer {
655
644
  private mustGrow(geo?: BufferGeometry): boolean {
656
645
  if (this.count >= this._maxInstanceCount) return true;
657
646
  if (!geo || !geo.attributes) return false;
658
-
659
- const isKnownGeometry = this._geometryIds.has(geo);
660
- if (isKnownGeometry) return false;
661
-
662
647
  const meshInfo = getMeshInformation(geo);
663
648
  const newVertexCount = meshInfo.vertexCount;
664
649
  const newIndexCount = meshInfo.indexCount;
665
650
  return this._currentVertexCount + newVertexCount > this._maxVertexCount || this._currentIndexCount + newIndexCount > this._maxIndexCount;
666
651
  }
667
652
 
668
- private _growId = 0;
669
653
  private grow(geometry: BufferGeometry) {
670
- const id = ++this._growId;
671
654
  const growFactor = 2;
672
655
  const newSize = Math.ceil(this._maxInstanceCount * growFactor);
673
656
 
674
657
  // create a new BatchedMesh instance
675
- // TODO: we should keep track of how many instances for each geometry we have and consider that when estimating new space
676
658
  const estimatedSpace = this.tryEstimateVertexCountSize(newSize, [geometry]);// geometry.attributes.position.count;
677
659
  // const indices = geometry.index ? geometry.index.count : 0;
678
660
  const newMaxVertexCount = Math.max(this._maxVertexCount, estimatedSpace.vertexCount);
679
- const newMaxIndexCount = Math.max(this._maxIndexCount, estimatedSpace.indexCount);//, Math.ceil(this._maxVertexCount * growFactor));
661
+ const newMaxIndexCount = Math.max(this._maxIndexCount, estimatedSpace.indexCount, Math.ceil(this._maxVertexCount * growFactor));
680
662
 
681
663
  if (debugInstancing) {
682
664
  const geometryInfo = getMeshInformation(geometry);
683
- console.warn(`[Instancing] Growing Buffer\nMesh: \"${this.name}${geometry.name?.length ? "/" + geometry.name : ""}\" (${geometryInfo.vertexCount.toLocaleString()} vertices, ${geometryInfo.indexCount.toLocaleString()} indices)\nMax count ${this._maxInstanceCount.toLocaleString()} → ${newSize.toLocaleString()}\nMax vertex count ${this._maxVertexCount.toLocaleString()} -> ${newMaxVertexCount.toLocaleString()}\nMax index count ${this._maxIndexCount.toLocaleString()} -> ${newMaxIndexCount.toLocaleString()}`);
665
+ console.warn(`[Instancing] Growing Buffer\nMesh: \"${this.name}${geometry.name?.length ? "/" + geometry.name : ""}\"\n${geometryInfo.vertexCount} vertices, ${geometryInfo.indexCount} indices\nMax count ${this._maxInstanceCount} → ${newSize}\nMax vertex count ${this._maxVertexCount} -> ${newMaxVertexCount}\nMax index count ${this._maxIndexCount} -> ${newMaxIndexCount}`);
684
666
  this._debugMaterial = createDebugMaterial();
685
667
  }
686
668
  else if (isDevEnvironment()) {
687
- console.debug(`[Instancing] Growing Buffer\nMesh: \"${this.name}${geometry.name?.length ? "/" + geometry.name : ""}\"\nMax count ${this._maxInstanceCount} → ${newSize}\nMax vertex count ${this._maxVertexCount.toLocaleString()} -> ${newMaxVertexCount.toLocaleString()}\nMax index count ${this._maxIndexCount.toLocaleString()} -> ${newMaxIndexCount.toLocaleString()}`);
669
+ console.debug(`[Instancing] Growing Buffer\nMesh: \"${this.name}${geometry.name?.length ? "/" + geometry.name : ""}\"\nMax count ${this._maxInstanceCount} → ${newSize}\nMax vertex count ${this._maxVertexCount} -> ${newMaxVertexCount}\nMax index count ${this._maxIndexCount} -> ${newMaxIndexCount}`);
688
670
  }
689
671
 
690
672
  this._maxVertexCount = newMaxVertexCount;
691
673
  this._maxIndexCount = newMaxIndexCount;
692
674
  const newInst = new BatchedMesh(newSize, this._maxVertexCount, this._maxIndexCount, this._debugMaterial ?? this.material);
693
- newInst.name = this.getBatchedMeshName();
694
675
  newInst.layers = this._batchedMesh.layers;
695
676
  newInst.castShadow = this._batchedMesh.castShadow;
696
677
  newInst.receiveShadow = this._batchedMesh.receiveShadow;
@@ -705,7 +686,7 @@ class InstancedMeshRenderer {
705
686
  // dispose the old batched mesh
706
687
  this._batchedMesh.dispose();
707
688
  this._batchedMesh.removeFromParent();
708
- this._geometryIds = new WeakMap<BufferGeometry, number>();
689
+ this._geometryIds.clear();
709
690
 
710
691
  this._batchedMesh = newInst;
711
692
  this._maxInstanceCount = newSize;
@@ -717,11 +698,6 @@ class InstancedMeshRenderer {
717
698
  const original = [...this._handles];
718
699
  this._handles = [];
719
700
  for (const handle of original) {
720
- if (id !== this._growId) {
721
- // another grow happened in the meantime
722
- if (debugInstancing) console.warn("[Instancing] Aborting grow since another grow happened in the meantime");
723
- return;
724
- }
725
701
  if (handle && handle.__instanceIndex >= 0) {
726
702
  this.addGeometry(handle);
727
703
  this._handles[handle.__instanceIndex] = handle;
@@ -746,31 +722,23 @@ class InstancedMeshRenderer {
746
722
  entry.count += 1;
747
723
  }
748
724
 
749
- if (_newGeometries && _newGeometries?.length > 0) {
750
- const index = _newGeometries.indexOf(handle.object.geometry as BufferGeometry);
751
- if (index !== -1) {
752
- _newGeometries.splice(index, 1);
753
- }
754
- }
755
725
  }
756
726
  }
757
727
 
758
728
  // then calculate the total vertex count
759
729
  let totalVertices = 0;
760
730
  let totalIndices = 0;
761
- let totalGeometries = 0;
762
731
  // let maxVertices = 0;
763
732
  for (const [_geo, data] of usedGeometries) {
764
- totalGeometries += 1;
765
- totalVertices += data.vertexCount;
766
- totalIndices += data.indexCount;
733
+ totalVertices += data.vertexCount * data.count;
734
+ totalIndices += data.indexCount * data.count;
767
735
  // maxVertices = Math.max(maxVertices, geo.attributes.position.count * count);
768
736
  }
769
737
  // we calculate the average to make an educated guess of how many vertices will be needed with the new buffer count
770
- const averageVerts = Math.ceil(totalVertices / Math.max(1, totalGeometries));
771
- let maxVertexCount = averageVerts * totalGeometries;
772
- const averageIndices = Math.ceil(totalIndices / Math.max(1, totalGeometries));
773
- let maxIndexCount = averageIndices * totalGeometries;
738
+ const averageVerts = Math.ceil(totalVertices / Math.max(1, this._currentInstanceCount));
739
+ let maxVertexCount = averageVerts * newMaxInstances;
740
+ const averageIndices = Math.ceil(totalIndices / Math.max(1, this._currentInstanceCount));
741
+ let maxIndexCount = averageIndices * newMaxInstances * 2;
774
742
 
775
743
  // if new geometries are provided we *know* that they will be added
776
744
  // so we make sure to include them in the calculation
@@ -785,10 +753,6 @@ class InstancedMeshRenderer {
785
753
  }
786
754
  }
787
755
 
788
- if (debugInstancing) {
789
- console.log(`[Instancing] Estimated size for new buffer ${this.name}\nGeometries: ${totalGeometries} (New: ${_newGeometries?.length || 0})\nInstances: ${newMaxInstances}\nEstimated Vertices: ${maxVertexCount.toLocaleString()}\nEstimated Indices: ${maxIndexCount.toLocaleString()}`);
790
- }
791
-
792
756
  return { vertexCount: maxVertexCount, indexCount: maxIndexCount };
793
757
  }
794
758
 
@@ -806,16 +770,16 @@ class InstancedMeshRenderer {
806
770
  let geometryId = this._geometryIds.get(geo);
807
771
  if (geometryId === undefined || geometryId === null) {
808
772
  if (debugInstancing)
809
- console.warn(`[Instancing] > ADD NEW GEOMETRY \"${handle.name} (${geo.name}; ${geo.uuid})\"\nCurrent Instances: ${this._currentInstanceCount}\nMax Vertices: ${handle.maxVertexCount.toLocaleString()}\nMax Indices: ${handle.maxIndexCount.toLocaleString()}\nMax Triangles: ${(handle.maxIndexCount / 3).toLocaleString()}`);
773
+ console.debug(`[Instancing] > ADD NEW GEOMETRY \"${handle.name} (${geo.name}; ${geo.uuid})\"\n${this._currentInstanceCount} instances, ${handle.maxVertexCount} max vertices, ${handle.maxIndexCount} max indices`);
810
774
 
811
775
  geometryId = this._batchedMesh.addGeometry(geo, handle.maxVertexCount, handle.maxIndexCount);
812
776
  this._geometryIds.set(geo, geometryId);
813
- this._currentVertexCount += handle.maxVertexCount;
814
- this._currentIndexCount += handle.maxIndexCount;
815
777
  }
816
778
  else {
817
779
  if (debugInstancing === "verbose") console.log(`[Instancing] > ADD INSTANCE \"${handle.name}\"\nGEOMETRY_ID=${geometryId}\n${this._currentInstanceCount} instances`);
818
780
  }
781
+ this._currentVertexCount += handle.maxVertexCount;
782
+ this._currentIndexCount += handle.maxIndexCount;
819
783
  const i = this._batchedMesh.addInstance(geometryId);
820
784
  handle.__geometryIndex = geometryId;
821
785
  handle.__instanceIndex = i;
@@ -823,7 +787,7 @@ class InstancedMeshRenderer {
823
787
  handle.__reservedIndexRange = handle.maxIndexCount;
824
788
  this._batchedMesh.setMatrixAt(i, handle.object.matrixWorld);
825
789
  if (debugInstancing)
826
- console.debug(`[Instancing] > ADDED INSTANCE \"${handle.name}\"\nGEOMETRY_ID=${geometryId}\n${this._currentInstanceCount} instances\nIndex: ${handle.__instanceIndex}\nVertices: ${this._currentVertexCount.toLocaleString()}/${this._maxVertexCount.toLocaleString()},\nIndices: ${this._currentIndexCount.toLocaleString()}/${this._maxIndexCount.toLocaleString()}`);
790
+ console.debug(`[Instancing] > ADDED INSTANCE \"${handle.name}\"\nGEOMETRY_ID=${geometryId}\n${this._currentInstanceCount} instances\nIndex: ${handle.__instanceIndex}`);
827
791
 
828
792
  }
829
793
 
@@ -839,7 +803,7 @@ class InstancedMeshRenderer {
839
803
  // this.inst.deleteGeometry(handle.__instanceIndex);
840
804
  // else
841
805
  // this._batchedMesh.setVisibleAt(handle.__instanceIndex, false);
842
- if (debugInstancing) {
806
+ if(debugInstancing) {
843
807
  console.debug(`[Instancing] < REMOVE INSTANCE \"${handle.name}\" at [${handle.__instanceIndex}]\nGEOMETRY_ID=${handle.__geometryIndex}\n${this._currentInstanceCount} instances\nIndex: ${handle.__instanceIndex}`);
844
808
  }
845
809
  this._batchedMesh.deleteInstance(handle.__instanceIndex);
@@ -1,16 +0,0 @@
1
- import type { Context } from "../engine_setup.js";
2
- declare global {
3
- interface Window {
4
- SPECTOR?: {
5
- Spector: new () => Spector;
6
- };
7
- }
8
- interface Spector {
9
- displayUI: () => void;
10
- setCanvas: (canvas: HTMLCanvasElement) => void;
11
- spyCanvases: boolean;
12
- startCaptureOnNextFrame: () => void;
13
- captureCanvas: (canvas: HTMLCanvasElement) => any;
14
- }
15
- }
16
- export declare function initSpectorIfAvailable(_context: Context, canvas: HTMLCanvasElement): void;
@@ -1,28 +0,0 @@
1
- import { isDevEnvironment } from "./debug.js";
2
- export function initSpectorIfAvailable(_context, canvas) {
3
- if (typeof window !== undefined && window.SPECTOR) {
4
- console.log(window.SPECTOR);
5
- const params = new URLSearchParams(window.location.search);
6
- if (params.has("spector")) {
7
- const frame = Number.parseInt(params.get("spector") || "0") || 0;
8
- console.log("Scheduled Spector capture at frame #" + frame);
9
- const spector = new window.SPECTOR.Spector();
10
- spector.spyCanvases = true;
11
- waitForFrameAndCapture();
12
- return;
13
- function waitForFrameAndCapture() {
14
- if (frame > _context.time.frame)
15
- return window.requestAnimationFrame(() => waitForFrameAndCapture());
16
- const res = spector.captureCanvas(canvas);
17
- if (res && res instanceof Promise)
18
- res.then(() => spector.displayUI());
19
- else
20
- spector.displayUI();
21
- }
22
- }
23
- else if (isDevEnvironment()) {
24
- console.debug("Spector available: Add '?spector=<frame>' to the URL to enable it and capture a frame.");
25
- }
26
- }
27
- }
28
- //# sourceMappingURL=debug_spector.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"debug_spector.js","sourceRoot":"","sources":["../../../src/engine/debug/debug_spector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAkB9C,MAAM,UAAU,sBAAsB,CAAC,QAAiB,EAAE,MAAyB;IAC/E,IAAI,OAAO,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO,EAAE;QAC/C,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3D,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;YACvB,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;YACjE,OAAO,CAAC,GAAG,CAAC,sCAAsC,GAAG,KAAK,CAAC,CAAC;YAC5D,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YAC7C,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;YAC3B,sBAAsB,EAAE,CAAC;YACzB,OAAO;YAEP,SAAS,sBAAsB;gBAC3B,IAAI,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK;oBAAE,OAAO,MAAM,CAAC,qBAAqB,CAAC,GAAG,EAAE,CAAC,sBAAsB,EAAE,CAAC,CAAC;gBACrG,MAAM,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;gBAC1C,IAAI,GAAG,IAAI,GAAG,YAAY,OAAO;oBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;;oBAClE,OAAO,CAAC,SAAS,EAAE,CAAC;YAC7B,CAAC;SACJ;aACI,IAAI,gBAAgB,EAAE,EAAE;YACzB,OAAO,CAAC,KAAK,CAAC,wFAAwF,CAAC,CAAC;SAC3G;KACJ;AACL,CAAC"}
@@ -1,43 +0,0 @@
1
- import type { Context } from "../engine_setup.js";
2
- import { isDevEnvironment } from "./debug.js";
3
-
4
- declare global {
5
- interface Window {
6
- SPECTOR?: {
7
- Spector: new () => Spector;
8
- }
9
- }
10
- interface Spector {
11
- displayUI: () => void;
12
- setCanvas: (canvas: HTMLCanvasElement) => void;
13
- spyCanvases: boolean;
14
- startCaptureOnNextFrame: () => void;
15
- captureCanvas: (canvas: HTMLCanvasElement) => any;
16
- }
17
- }
18
-
19
-
20
- export function initSpectorIfAvailable(_context: Context, canvas: HTMLCanvasElement): void {
21
- if (typeof window !== undefined && window.SPECTOR) {
22
- console.log(window.SPECTOR);
23
- const params = new URLSearchParams(window.location.search);
24
- if (params.has("spector")) {
25
- const frame = Number.parseInt(params.get("spector") || "0") || 0;
26
- console.log("Scheduled Spector capture at frame #" + frame);
27
- const spector = new window.SPECTOR.Spector();
28
- spector.spyCanvases = true;
29
- waitForFrameAndCapture();
30
- return;
31
-
32
- function waitForFrameAndCapture() {
33
- if (frame > _context.time.frame) return window.requestAnimationFrame(() => waitForFrameAndCapture());
34
- const res = spector.captureCanvas(canvas);
35
- if (res && res instanceof Promise) res.then(() => spector.displayUI());
36
- else spector.displayUI();
37
- }
38
- }
39
- else if (isDevEnvironment()) {
40
- console.debug("Spector available: Add '?spector=<frame>' to the URL to enable it and capture a frame.");
41
- }
42
- }
43
- }