@playcanvas/web-components 0.11.0 → 0.12.0

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 (82) hide show
  1. package/README.md +1 -1
  2. package/dist/app.d.ts +31 -49
  3. package/dist/asset.d.ts +152 -12
  4. package/dist/async-element.d.ts +26 -9
  5. package/dist/components/button-component.d.ts +3 -7
  6. package/dist/components/camera-component.d.ts +3 -7
  7. package/dist/components/collision-component.d.ts +19 -7
  8. package/dist/components/component.d.ts +41 -4
  9. package/dist/components/element-component.d.ts +4 -8
  10. package/dist/components/gsplat-component.d.ts +2 -7
  11. package/dist/components/layoutchild-component.d.ts +2 -7
  12. package/dist/components/layoutgroup-component.d.ts +3 -7
  13. package/dist/components/light-component.d.ts +3 -7
  14. package/dist/components/listener-component.d.ts +1 -6
  15. package/dist/components/particlesystem-component.d.ts +2 -7
  16. package/dist/components/render-component.d.ts +2 -7
  17. package/dist/components/rigidbody-component.d.ts +3 -7
  18. package/dist/components/screen-component.d.ts +3 -7
  19. package/dist/components/script-component.d.ts +8 -20
  20. package/dist/components/script.d.ts +2 -22
  21. package/dist/components/scrollbar-component.d.ts +2 -7
  22. package/dist/components/scrollview-component.d.ts +3 -7
  23. package/dist/components/sound-component.d.ts +2 -7
  24. package/dist/components/sound-slot.d.ts +8 -6
  25. package/dist/custom-elements.json +5824 -10581
  26. package/dist/entity-base.d.ts +67 -0
  27. package/dist/entity.d.ts +7 -48
  28. package/dist/index.d.ts +41 -1
  29. package/dist/material.d.ts +14 -13
  30. package/dist/model.d.ts +43 -5
  31. package/dist/module.d.ts +0 -6
  32. package/dist/node.d.ts +253 -0
  33. package/dist/parse.d.ts +2 -1
  34. package/dist/pwc.cjs +1830 -274
  35. package/dist/pwc.cjs.map +1 -1
  36. package/dist/pwc.js +1830 -274
  37. package/dist/pwc.js.map +1 -1
  38. package/dist/pwc.min.js +1 -1
  39. package/dist/pwc.min.js.map +1 -1
  40. package/dist/pwc.min.mjs +1 -1
  41. package/dist/pwc.min.mjs.map +1 -1
  42. package/dist/pwc.mjs +1830 -276
  43. package/dist/pwc.mjs.map +1 -1
  44. package/dist/scene.d.ts +4 -7
  45. package/dist/sky.d.ts +13 -5
  46. package/dist/vscode.html-custom-data.json +148 -26
  47. package/dist/web-types.json +894 -581
  48. package/package.json +9 -8
  49. package/src/app.ts +163 -88
  50. package/src/asset.ts +472 -36
  51. package/src/async-element.ts +39 -12
  52. package/src/components/button-component.ts +5 -9
  53. package/src/components/camera-component.ts +24 -10
  54. package/src/components/collision-component.ts +61 -15
  55. package/src/components/component.ts +151 -11
  56. package/src/components/element-component.ts +26 -30
  57. package/src/components/gsplat-component.ts +4 -9
  58. package/src/components/layoutchild-component.ts +4 -9
  59. package/src/components/layoutgroup-component.ts +14 -9
  60. package/src/components/light-component.ts +42 -12
  61. package/src/components/listener-component.ts +1 -7
  62. package/src/components/particlesystem-component.ts +7 -15
  63. package/src/components/render-component.ts +5 -10
  64. package/src/components/rigidbody-component.ts +23 -16
  65. package/src/components/screen-component.ts +5 -9
  66. package/src/components/script-component.ts +108 -46
  67. package/src/components/script.ts +38 -33
  68. package/src/components/scrollbar-component.ts +6 -16
  69. package/src/components/scrollview-component.ts +16 -11
  70. package/src/components/sound-component.ts +10 -15
  71. package/src/components/sound-slot.ts +30 -20
  72. package/src/entity-base.ts +136 -0
  73. package/src/entity.ts +47 -118
  74. package/src/index.ts +50 -1
  75. package/src/loading-bar.ts +8 -8
  76. package/src/material.ts +65 -39
  77. package/src/model.ts +140 -17
  78. package/src/module.ts +8 -7
  79. package/src/node.ts +715 -0
  80. package/src/parse.ts +62 -17
  81. package/src/scene.ts +12 -9
  82. package/src/sky.ts +50 -10
package/src/material.ts CHANGED
@@ -21,17 +21,26 @@ import {
21
21
  SPECOCC_GLOSSDEPENDENT,
22
22
  SPECOCC_NONE,
23
23
  StandardMaterial,
24
- Vec2,
25
- type EventHandle,
26
- type Texture
24
+ Vec2
27
25
  } from 'playcanvas';
26
+ import type { EventHandle, Texture } from 'playcanvas';
28
27
 
29
- import { AppElement } from './app';
28
+ import type { AppElement } from './app';
30
29
  import { AssetElement } from './asset';
31
30
  import { parseBool, parseColor, parseEnum, parseNumber, parseVec2 } from './parse';
32
31
 
33
- type BlendType = 'none' | 'normal' | 'additive' | 'additive-alpha' | 'premultiplied' |
34
- 'multiplicative' | 'multiplicative-2x' | 'screen' | 'min' | 'max' | 'subtractive';
32
+ type BlendType =
33
+ | 'none'
34
+ | 'normal'
35
+ | 'additive'
36
+ | 'additive-alpha'
37
+ | 'premultiplied'
38
+ | 'multiplicative'
39
+ | 'multiplicative-2x'
40
+ | 'screen'
41
+ | 'min'
42
+ | 'max'
43
+ | 'subtractive';
35
44
 
36
45
  const blendTypes = new Map<BlendType, number>([
37
46
  ['none', BLEND_NONE],
@@ -100,8 +109,8 @@ const roughnessAliases = ['roughness', 'roughness-map'];
100
109
  * The texture slots a `pc-material` can populate. Each is backed by a `pc-asset` id rather than a
101
110
  * `Texture`, so the element can be authored before the asset has loaded.
102
111
  */
103
- type TextureSlot = 'aoMap' | 'diffuseMap' | 'emissiveMap' | 'glossMap' | 'heightMap' |
104
- 'metalnessMap' | 'normalMap' | 'opacityMap';
112
+ type TextureSlot =
113
+ 'aoMap' | 'diffuseMap' | 'emissiveMap' | 'glossMap' | 'heightMap' | 'metalnessMap' | 'normalMap' | 'opacityMap';
105
114
 
106
115
  /**
107
116
  * The MaterialElement interface provides properties and methods for manipulating
@@ -286,7 +295,7 @@ class MaterialElement extends HTMLElement {
286
295
 
287
296
  private _useLighting = true;
288
297
 
289
- // Diverges from the engine default of false - see the class docblock and createMaterial()
298
+ // Diverges from the engine default of false - see the class docblock and _createMaterial()
290
299
  private _useMetalness = true;
291
300
 
292
301
  private _useMetalnessSpecularColor = false;
@@ -306,10 +315,14 @@ class MaterialElement extends HTMLElement {
306
315
 
307
316
  private _glossConflictWarned = false;
308
317
 
318
+ /**
319
+ * The material. `null` until the containing application has created it — an element present
320
+ * at startup has its material once the application is ready.
321
+ */
309
322
  material: StandardMaterial | null = null;
310
323
 
311
324
  async connectedCallback() {
312
- const appElement = this.parentElement?.closest('pc-app') as AppElement | null ?? null;
325
+ const appElement = (this.parentElement?.closest('pc-app') as AppElement | null) ?? null;
313
326
 
314
327
  // Materials must be direct children of pc-app (matches the boot query ':scope > pc-material')
315
328
  if (!appElement || this.parentElement !== appElement) {
@@ -326,11 +339,18 @@ class MaterialElement extends HTMLElement {
326
339
  // elements inserted (or re-inserted) after the app is already running
327
340
  if (!this.material) {
328
341
  if (!appElement.app) return; // pc-app is re-connecting; its own boot will create this
329
- this.createMaterial();
342
+ this._createMaterial();
330
343
  }
331
344
  }
332
345
 
333
- createMaterial() {
346
+ /**
347
+ * Creates the material from the element's cached properties. Called by the containing
348
+ * `<pc-app>` element during its boot sweep, and on connection for elements inserted while
349
+ * the application is already running.
350
+ *
351
+ * @internal
352
+ */
353
+ _createMaterial() {
334
354
  const material = new StandardMaterial();
335
355
  this.material = material;
336
356
 
@@ -464,10 +484,10 @@ class MaterialElement extends HTMLElement {
464
484
  * warning latches and reports once per episode, clearing when the clash is resolved.
465
485
  */
466
486
  private _warnGlossConflict() {
467
- const quote = (names: string[]) => `'${names.join('\', \'')}'`;
487
+ const quote = (names: string[]) => `'${names.join("', '")}'`;
468
488
 
469
- const roughness = roughnessAliases.filter(name => this.hasAttribute(name));
470
- const gloss = glossConflicts.filter(name => this.hasAttribute(name));
489
+ const roughness = roughnessAliases.filter((name) => this.hasAttribute(name));
490
+ const gloss = glossConflicts.filter((name) => this.hasAttribute(name));
471
491
 
472
492
  if (roughness.length === 0 || gloss.length === 0) {
473
493
  this._glossConflictWarned = false;
@@ -477,8 +497,10 @@ class MaterialElement extends HTMLElement {
477
497
  if (this._glossConflictWarned) return;
478
498
  this._glossConflictWarned = true;
479
499
 
480
- console.warn(`pc-material '${this.id}' sets both ${quote(roughness)} and ${quote(gloss)} - ` +
481
- 'the roughness-* attributes invert gloss, so the two families contradict each other. Use one or the other.');
500
+ console.warn(
501
+ `pc-material '${this.id}' sets both ${quote(roughness)} and ${quote(gloss)} - ` +
502
+ 'the roughness-* attributes invert gloss, so the two families contradict each other. Use one or the other.'
503
+ );
482
504
  }
483
505
 
484
506
  /**
@@ -488,7 +510,7 @@ class MaterialElement extends HTMLElement {
488
510
  * @param id - The id of the `pc-asset`, or an empty string to clear the slot.
489
511
  * @param slot - The material property to write.
490
512
  */
491
- setMap(id: string, slot: TextureSlot) {
513
+ private _setMap(id: string, slot: TextureSlot) {
492
514
  // Drop any load still pending for this slot - its texture is no longer the one we want
493
515
  this._mapHandles.get(slot)?.off();
494
516
  this._mapHandles.delete(slot);
@@ -509,20 +531,23 @@ class MaterialElement extends HTMLElement {
509
531
  return;
510
532
  }
511
533
 
512
- this._mapHandles.set(slot, asset.once('load', () => {
513
- this._mapHandles.delete(slot);
514
- this._applyMap(slot, asset.resource as Texture);
515
- }));
534
+ this._mapHandles.set(
535
+ slot,
536
+ asset.once('load', () => {
537
+ this._mapHandles.delete(slot);
538
+ this._applyMap(slot, asset.resource as Texture);
539
+ })
540
+ );
516
541
  }
517
542
 
518
543
  /**
519
544
  * @param slot - The material property to write.
520
- * @param texture - The loaded texture.
545
+ * @param texture - The loaded texture, applied with its sampler state untouched - anisotropy
546
+ * and friends belong to the `pc-asset`'s texture options.
521
547
  */
522
548
  private _applyMap(slot: TextureSlot, texture: Texture) {
523
549
  if (!this.material) return;
524
550
  this.material[slot] = texture;
525
- texture.anisotropy = 4;
526
551
  this._scheduleUpdate();
527
552
  }
528
553
 
@@ -592,7 +617,7 @@ class MaterialElement extends HTMLElement {
592
617
  */
593
618
  set aoMap(value: string) {
594
619
  this._aoMap = value;
595
- this.setMap(value, 'aoMap');
620
+ this._setMap(value, 'aoMap');
596
621
  }
597
622
 
598
623
  /**
@@ -850,7 +875,7 @@ class MaterialElement extends HTMLElement {
850
875
  */
851
876
  set diffuseMap(value: string) {
852
877
  this._diffuseMap = value;
853
- this.setMap(value, 'diffuseMap');
878
+ this._setMap(value, 'diffuseMap');
854
879
  }
855
880
 
856
881
  /**
@@ -1007,7 +1032,7 @@ class MaterialElement extends HTMLElement {
1007
1032
  */
1008
1033
  set emissiveMap(value: string) {
1009
1034
  this._emissiveMap = value;
1010
- this.setMap(value, 'emissiveMap');
1035
+ this._setMap(value, 'emissiveMap');
1011
1036
  }
1012
1037
 
1013
1038
  /**
@@ -1205,7 +1230,7 @@ class MaterialElement extends HTMLElement {
1205
1230
  */
1206
1231
  set glossMap(value: string) {
1207
1232
  this._glossMap = value;
1208
- this.setMap(value, 'glossMap');
1233
+ this._setMap(value, 'glossMap');
1209
1234
  }
1210
1235
 
1211
1236
  /**
@@ -1322,7 +1347,7 @@ class MaterialElement extends HTMLElement {
1322
1347
  */
1323
1348
  set heightMap(value: string) {
1324
1349
  this._heightMap = value;
1325
- this.setMap(value, 'heightMap');
1350
+ this._setMap(value, 'heightMap');
1326
1351
  }
1327
1352
 
1328
1353
  /**
@@ -1479,7 +1504,7 @@ class MaterialElement extends HTMLElement {
1479
1504
  */
1480
1505
  set metalnessMap(value: string) {
1481
1506
  this._metalnessMap = value;
1482
- this.setMap(value, 'metalnessMap');
1507
+ this._setMap(value, 'metalnessMap');
1483
1508
  }
1484
1509
 
1485
1510
  /**
@@ -1596,7 +1621,7 @@ class MaterialElement extends HTMLElement {
1596
1621
  */
1597
1622
  set normalMap(value: string) {
1598
1623
  this._normalMap = value;
1599
- this.setMap(value, 'normalMap');
1624
+ this._setMap(value, 'normalMap');
1600
1625
  }
1601
1626
 
1602
1627
  /**
@@ -1694,7 +1719,7 @@ class MaterialElement extends HTMLElement {
1694
1719
  set occludeDirect(value: boolean) {
1695
1720
  this._occludeDirect = value;
1696
1721
  if (this.material) {
1697
- // @ts-ignore see createMaterial() - the engine mistypes occludeDirect as a number
1722
+ // @ts-ignore see _createMaterial() - the engine mistypes occludeDirect as a number
1698
1723
  this.material.occludeDirect = value;
1699
1724
  this._scheduleUpdate();
1700
1725
  }
@@ -1796,7 +1821,7 @@ class MaterialElement extends HTMLElement {
1796
1821
  */
1797
1822
  set opacityMap(value: string) {
1798
1823
  this._opacityMap = value;
1799
- this.setMap(value, 'opacityMap');
1824
+ this._setMap(value, 'opacityMap');
1800
1825
  }
1801
1826
 
1802
1827
  /**
@@ -2150,6 +2175,13 @@ class MaterialElement extends HTMLElement {
2150
2175
  return this._useTonemap;
2151
2176
  }
2152
2177
 
2178
+ /**
2179
+ * Returns the {@link StandardMaterial} created by the `<pc-material>` element with the given
2180
+ * `id`, or `undefined` if there is no such element or its material has not been created yet.
2181
+ *
2182
+ * @param id - The `id` of the `<pc-material>` element.
2183
+ * @returns The material, or `undefined`.
2184
+ */
2153
2185
  static get(id: string) {
2154
2186
  const materialElement = document.querySelector<MaterialElement>(`pc-material[id="${id}"]`);
2155
2187
  return materialElement?.material;
@@ -2508,10 +2540,4 @@ class MaterialElement extends HTMLElement {
2508
2540
 
2509
2541
  customElements.define('pc-material', MaterialElement);
2510
2542
 
2511
- declare global {
2512
- interface HTMLElementTagNameMap {
2513
- 'pc-material': MaterialElement;
2514
- }
2515
- }
2516
-
2517
2543
  export { MaterialElement };
package/src/model.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ContainerResource, Entity } from 'playcanvas';
1
+ import type { ContainerResource, Entity, EventHandle } from 'playcanvas';
2
2
 
3
3
  import { AssetElement } from './asset';
4
4
  import { AsyncElement } from './async-element';
@@ -8,41 +8,123 @@ import { AsyncElement } from './async-element';
8
8
  * {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-model/ | `<pc-model>`} elements.
9
9
  * The ModelElement interface also inherits the properties and methods of the
10
10
  * {@link HTMLElement} interface.
11
+ *
12
+ * The element becomes ready once its container asset has loaded and the instantiated hierarchy has
13
+ * been added to the scene — `entity` is non-null by then. A failed load also settles readiness,
14
+ * with `entity` remaining `null`: readiness means the load settled, not that it succeeded — listen
15
+ * for `error`, or check `entity`, to tell the outcomes apart. Changing `asset` re-arms readiness
16
+ * and instantiates anew, so a `ready()` obtained after the change resolves against the new
17
+ * hierarchy. A `pc-model` outside a `pc-app`, or referencing an unknown asset id, warns and never
18
+ * becomes ready.
19
+ *
20
+ * @fires {Event} load - Fired each time a container asset finishes instantiating, including
21
+ * re-instantiation after `asset` changes. Does not bubble — listen on this element, or use a
22
+ * capture-phase listener on an ancestor.
23
+ * @fires {ErrorEvent} error - Fired when the container asset fails to load, with the engine's
24
+ * error in `message`. Does not bubble. The element still becomes ready — readiness means the load
25
+ * settled, not that it succeeded.
11
26
  */
12
27
  class ModelElement extends AsyncElement {
13
- private _asset: string = '';
28
+ private _asset = '';
14
29
 
15
30
  private _entity: Entity | null = null;
16
31
 
32
+ /**
33
+ * Incremented on every new load and on disconnect, and captured by a load when it starts. A
34
+ * load that resumes from an await or a load callback abandons itself if the value has moved
35
+ * on, so a superseded load can neither instantiate a second entity nor parent one that has
36
+ * since been destroyed.
37
+ */
38
+ private _loadGeneration = 0;
39
+
40
+ /**
41
+ * The pending asset subscriptions of the current load, if it is waiting for its asset. Held
42
+ * so that whatever supersedes the load can detach the handlers from the asset, rather than
43
+ * leave them registered until the asset settles (or forever, if it never does).
44
+ */
45
+ private _loadHandle: EventHandle | null = null;
46
+
47
+ private _errorHandle: EventHandle | null = null;
48
+
49
+ /**
50
+ * The root entity of the instantiated model. `null` until the container asset has loaded
51
+ * and been instantiated, and again once the element has been removed from the document.
52
+ * @returns The model's root entity, or `null`.
53
+ */
54
+ get entity(): Entity | null {
55
+ return this._entity;
56
+ }
57
+
17
58
  connectedCallback() {
59
+ // A model outside an application is inert and never becomes ready, so awaiting it hangs.
60
+ // Warn rather than fail silently, naming the parent it requires, as every other misplaced
61
+ // element does.
62
+ if (!this.closestApp) {
63
+ const label = this._asset ? ` '${this._asset}'` : '';
64
+ console.warn(`pc-model${label} must be a descendant of pc-app - model not created`);
65
+ return;
66
+ }
18
67
  this._loadModel();
19
- this._onReady();
20
68
  }
21
69
 
22
70
  disconnectedCallback() {
71
+ this._loadGeneration++;
72
+ this._detachLoadHandlers();
23
73
  this._unloadModel();
74
+ this._resetReady();
75
+ }
76
+
77
+ private _detachLoadHandlers() {
78
+ this._loadHandle?.off();
79
+ this._loadHandle = null;
80
+ this._errorHandle?.off();
81
+ this._errorHandle = null;
82
+ }
83
+
84
+ /**
85
+ * Resolves readiness and dispatches the `load` event. Called once the instantiated hierarchy
86
+ * has been parented — readiness means "in the scene graph", matching `pc-entity`, so a ready
87
+ * model's entity always has world transforms.
88
+ */
89
+ private _announceLoad() {
90
+ this._onReady();
91
+ this.dispatchEvent(new Event('load'));
24
92
  }
25
93
 
26
94
  private _instantiate(container: ContainerResource) {
27
- this._entity = container.instantiateRenderEntity();
95
+ const generation = this._loadGeneration;
96
+
97
+ const entity = container.instantiateRenderEntity();
98
+ this._entity = entity;
28
99
 
29
100
  // @ts-ignore
30
101
  if (container.animations.length > 0) {
31
- this._entity.addComponent('anim');
102
+ entity.addComponent('anim');
32
103
  // @ts-ignore
33
- this._entity.anim.assignAnimation('animation', container.animations[0].resource);
104
+ entity.anim.assignAnimation('animation', container.animations[0].resource);
34
105
  }
35
106
 
107
+ // The parent's readiness re-arms when it is torn down, so these can resume in a later
108
+ // connection cycle. The entity is captured above and the generation re-checked, so a
109
+ // stale resume cannot parent an entity a newer cycle has already destroyed.
36
110
  const parentEntityElement = this.closestEntity;
37
111
  if (parentEntityElement) {
38
112
  parentEntityElement.ready().then(() => {
39
- parentEntityElement.entity!.addChild(this._entity!);
113
+ if (generation !== this._loadGeneration) {
114
+ return;
115
+ }
116
+ parentEntityElement.entity!.addChild(entity);
117
+ this._announceLoad();
40
118
  });
41
119
  } else {
42
120
  const appElement = this.closestApp;
43
121
  if (appElement) {
44
122
  appElement.ready().then(() => {
45
- appElement.app!.root.addChild(this._entity!);
123
+ if (generation !== this._loadGeneration) {
124
+ return;
125
+ }
126
+ appElement.app!.root.addChild(entity);
127
+ this._announceLoad();
46
128
  });
47
129
  }
48
130
  }
@@ -51,20 +133,67 @@ class ModelElement extends AsyncElement {
51
133
  private async _loadModel() {
52
134
  this._unloadModel();
53
135
 
54
- const appElement = await this.closestApp?.ready();
55
- const app = appElement?.app;
136
+ // Supersede any load already in flight - only the newest load may instantiate
137
+ const generation = ++this._loadGeneration;
138
+ this._detachLoadHandlers();
139
+
140
+ // Re-arm readiness so a waiter obtained after an asset change resolves against the new
141
+ // hierarchy. A no-op on first connection, where readiness is still pending.
142
+ this._resetReady();
143
+
144
+ const appElement = this.closestApp;
145
+ if (!appElement) {
146
+ // Outside pc-app; connectedCallback already warned. Reached through the asset setter.
147
+ return;
148
+ }
149
+
150
+ await appElement.ready();
151
+
152
+ // The element may have been removed, or another load started, while we waited
153
+ if (generation !== this._loadGeneration) {
154
+ return;
155
+ }
156
+
157
+ const app = appElement.app;
56
158
 
57
159
  const asset = AssetElement.get(this._asset);
58
160
  if (!asset) {
161
+ // An empty id is a legitimate transient (the asset may be assigned later); a
162
+ // non-empty one that resolves to nothing is a dead end - say so rather than staying
163
+ // silently pending.
164
+ if (this._asset) {
165
+ console.warn(`pc-model could not find asset '${this._asset}' - model not created`);
166
+ }
59
167
  return;
60
168
  }
61
169
 
62
170
  if (asset.loaded) {
63
171
  this._instantiate(asset.resource as ContainerResource);
64
172
  } else {
65
- asset.once('load', () => {
173
+ // The generation is re-checked even though a superseded handler is detached: the
174
+ // detach relies on how the engine's event emitter treats removal, while the check
175
+ // holds on its own. Whichever of load/error fires first detaches the other.
176
+ this._loadHandle = asset.once('load', () => {
177
+ this._detachLoadHandlers();
178
+ if (generation !== this._loadGeneration) {
179
+ return;
180
+ }
66
181
  this._instantiate(asset.resource as ContainerResource);
67
182
  });
183
+ this._errorHandle = asset.once('error', (err: string | Error) => {
184
+ this._detachLoadHandlers();
185
+ if (generation !== this._loadGeneration) {
186
+ return;
187
+ }
188
+ // A failed load settles readiness with a null entity, mirroring pc-asset:
189
+ // readiness means the load settled, not that it succeeded.
190
+ this.dispatchEvent(
191
+ new ErrorEvent('error', {
192
+ message: err instanceof Error ? err.message : String(err)
193
+ })
194
+ );
195
+ this._onReady();
196
+ });
68
197
  app!.assets.load(asset);
69
198
  }
70
199
  }
@@ -108,10 +237,4 @@ class ModelElement extends AsyncElement {
108
237
 
109
238
  customElements.define('pc-model', ModelElement);
110
239
 
111
- declare global {
112
- interface HTMLElementTagNameMap {
113
- 'pc-model': ModelElement;
114
- }
115
- }
116
-
117
240
  export { ModelElement };
package/src/module.ts CHANGED
@@ -43,17 +43,18 @@ class ModuleElement extends HTMLElement {
43
43
  }
44
44
  }
45
45
 
46
- public getLoadPromise(): Promise<void> {
46
+ /**
47
+ * Returns the promise that settles when the module has loaded. Awaited by the containing
48
+ * `<pc-app>` element before it creates its graphics device.
49
+ *
50
+ * @returns The load promise.
51
+ * @internal
52
+ */
53
+ _getLoadPromise(): Promise<void> {
47
54
  return this.loadPromise;
48
55
  }
49
56
  }
50
57
 
51
58
  customElements.define('pc-module', ModuleElement);
52
59
 
53
- declare global {
54
- interface HTMLElementTagNameMap {
55
- 'pc-module': ModuleElement;
56
- }
57
- }
58
-
59
60
  export { ModuleElement };