@playcanvas/web-components 0.1.4 → 0.1.6

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 (41) hide show
  1. package/README.md +43 -61
  2. package/dist/app.d.ts +56 -5
  3. package/dist/asset.d.ts +0 -1
  4. package/dist/async-element.d.ts +23 -0
  5. package/dist/components/camera-component.d.ts +3 -0
  6. package/dist/components/component.d.ts +4 -2
  7. package/dist/components/element-component.d.ts +1 -1
  8. package/dist/components/render-component.d.ts +2 -2
  9. package/dist/components/script-component.d.ts +1 -1
  10. package/dist/components/sound-component.d.ts +48 -0
  11. package/dist/components/sound-slot.d.ts +2 -1
  12. package/dist/entity.d.ts +2 -3
  13. package/dist/index.d.ts +10 -1
  14. package/dist/model.d.ts +2 -1
  15. package/dist/pwc.cjs +426 -141
  16. package/dist/pwc.cjs.map +1 -1
  17. package/dist/pwc.js +426 -141
  18. package/dist/pwc.js.map +1 -1
  19. package/dist/pwc.min.js +1 -1
  20. package/dist/pwc.min.js.map +1 -1
  21. package/dist/pwc.mjs +427 -143
  22. package/dist/pwc.mjs.map +1 -1
  23. package/dist/scene.d.ts +2 -1
  24. package/dist/sky.d.ts +15 -6
  25. package/package.json +9 -8
  26. package/src/app.ts +103 -17
  27. package/src/asset.ts +1 -3
  28. package/src/async-element.ts +45 -0
  29. package/src/components/camera-component.ts +22 -1
  30. package/src/components/component.ts +15 -26
  31. package/src/components/element-component.ts +15 -4
  32. package/src/components/render-component.ts +1 -6
  33. package/src/components/script-component.ts +25 -7
  34. package/src/components/sound-component.ts +110 -1
  35. package/src/components/sound-slot.ts +7 -10
  36. package/src/entity.ts +19 -29
  37. package/src/index.ts +11 -0
  38. package/src/model.ts +20 -15
  39. package/src/module.ts +18 -10
  40. package/src/scene.ts +6 -11
  41. package/src/sky.ts +82 -40
package/dist/pwc.js CHANGED
@@ -4,6 +4,41 @@
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.pd = {}, global.pc));
5
5
  })(this, (function (exports, playcanvas) { 'use strict';
6
6
 
7
+ /**
8
+ * Base class for all PlayCanvas web components that initialize asynchronously.
9
+ */
10
+ class AsyncElement extends HTMLElement {
11
+ constructor() {
12
+ super();
13
+ this._readyPromise = new Promise((resolve) => {
14
+ this._readyResolve = resolve;
15
+ });
16
+ }
17
+ get closestApp() {
18
+ var _a;
19
+ return (_a = this.parentElement) === null || _a === void 0 ? void 0 : _a.closest('pc-app');
20
+ }
21
+ get closestEntity() {
22
+ var _a;
23
+ return (_a = this.parentElement) === null || _a === void 0 ? void 0 : _a.closest('pc-entity');
24
+ }
25
+ /**
26
+ * Called when the element is fully initialized and ready.
27
+ * Subclasses should call this when they're ready.
28
+ */
29
+ _onReady() {
30
+ this._readyResolve();
31
+ this.dispatchEvent(new CustomEvent('ready'));
32
+ }
33
+ /**
34
+ * Returns a promise that resolves with this element when it's ready.
35
+ * @returns A promise that resolves with this element when it's ready.
36
+ */
37
+ ready() {
38
+ return this._readyPromise.then(() => this);
39
+ }
40
+ }
41
+
7
42
  class ModuleElement extends HTMLElement {
8
43
  constructor() {
9
44
  super();
@@ -14,14 +49,23 @@
14
49
  const glue = this.getAttribute('glue');
15
50
  const wasm = this.getAttribute('wasm');
16
51
  const fallback = this.getAttribute('fallback');
17
- playcanvas.WasmModule.setConfig(name, {
18
- glueUrl: glue,
19
- wasmUrl: wasm,
20
- fallbackUrl: fallback
21
- });
22
- await new Promise((resolve) => {
23
- playcanvas.WasmModule.getInstance(name, () => resolve());
24
- });
52
+ if (name === 'Basis') {
53
+ playcanvas.basisInitialize({
54
+ glueUrl: glue,
55
+ wasmUrl: wasm,
56
+ fallbackUrl: fallback
57
+ });
58
+ }
59
+ else {
60
+ playcanvas.WasmModule.setConfig(name, {
61
+ glueUrl: glue,
62
+ wasmUrl: wasm,
63
+ fallbackUrl: fallback
64
+ });
65
+ await new Promise((resolve) => {
66
+ playcanvas.WasmModule.getInstance(name, () => resolve());
67
+ });
68
+ }
25
69
  }
26
70
  getLoadPromise() {
27
71
  return this.loadPromise;
@@ -32,7 +76,7 @@
32
76
  /**
33
77
  * The main application element.
34
78
  */
35
- class AppElement extends HTMLElement {
79
+ class AppElement extends AsyncElement {
36
80
  /**
37
81
  * Creates a new AppElement.
38
82
  */
@@ -42,6 +86,10 @@
42
86
  * The canvas element.
43
87
  */
44
88
  this._canvas = null;
89
+ this._alpha = true;
90
+ this._antialias = true;
91
+ this._depth = true;
92
+ this._stencil = true;
45
93
  this._highResolution = false;
46
94
  /**
47
95
  * The PlayCanvas application instance.
@@ -49,9 +97,6 @@
49
97
  this.app = null;
50
98
  // Bind methods to maintain 'this' context
51
99
  this._onWindowResize = this._onWindowResize.bind(this);
52
- this.appReadyPromise = new Promise((resolve) => {
53
- this.appReadyResolve = resolve;
54
- });
55
100
  }
56
101
  async connectedCallback() {
57
102
  // Get all pc-module elements that are direct children of the pc-app element
@@ -64,11 +109,15 @@
64
109
  // Initialize the PlayCanvas application
65
110
  this.app = new playcanvas.Application(this._canvas, {
66
111
  graphicsDeviceOptions: {
67
- devicePixelRatio: this._highResolution ? window.devicePixelRatio : 1
112
+ alpha: this._alpha,
113
+ antialias: this._antialias,
114
+ depth: this._depth,
115
+ stencil: this._stencil
68
116
  },
69
117
  keyboard: new playcanvas.Keyboard(window),
70
118
  mouse: new playcanvas.Mouse(this._canvas)
71
119
  });
120
+ this.app.graphicsDevice.maxPixelRatio = this._highResolution ? window.devicePixelRatio : 1;
72
121
  this.app.setCanvasFillMode(playcanvas.FILLMODE_FILL_WINDOW);
73
122
  this.app.setCanvasResolution(playcanvas.RESOLUTION_AUTO);
74
123
  // Get all pc-asset elements that are direct children of the pc-app element
@@ -91,7 +140,7 @@
91
140
  this.app.start();
92
141
  // Handle window resize to keep the canvas responsive
93
142
  window.addEventListener('resize', this._onWindowResize);
94
- this.appReadyResolve(this.app);
143
+ this._onReady();
95
144
  });
96
145
  }
97
146
  disconnectedCallback() {
@@ -108,31 +157,104 @@
108
157
  this._canvas = null;
109
158
  }
110
159
  }
111
- async getApplication() {
112
- await this.appReadyPromise;
113
- return this.app;
114
- }
115
160
  _onWindowResize() {
116
161
  if (this.app) {
117
162
  this.app.resizeCanvas();
118
163
  }
119
164
  }
165
+ /**
166
+ * Sets the alpha flag.
167
+ * @param value - The alpha flag.
168
+ */
169
+ set alpha(value) {
170
+ this._alpha = value;
171
+ }
172
+ /**
173
+ * Gets the alpha flag.
174
+ * @returns The alpha flag.
175
+ */
176
+ get alpha() {
177
+ return this._alpha;
178
+ }
179
+ /**
180
+ * Sets the antialias flag.
181
+ * @param value - The antialias flag.
182
+ */
183
+ set antialias(value) {
184
+ this._antialias = value;
185
+ }
186
+ /**
187
+ * Gets the antialias flag.
188
+ * @returns The antialias flag.
189
+ */
190
+ get antialias() {
191
+ return this._antialias;
192
+ }
193
+ /**
194
+ * Sets the depth flag.
195
+ * @param value - The depth flag.
196
+ */
197
+ set depth(value) {
198
+ this._depth = value;
199
+ }
200
+ /**
201
+ * Gets the depth flag.
202
+ * @returns The depth flag.
203
+ */
204
+ get depth() {
205
+ return this._depth;
206
+ }
207
+ /**
208
+ * Sets the high resolution flag. When true, the application will render at the device's
209
+ * physical resolution. When false, the application will render at CSS resolution.
210
+ * @param value - The high resolution flag.
211
+ */
120
212
  set highResolution(value) {
121
213
  this._highResolution = value;
122
214
  if (this.app) {
123
215
  this.app.graphicsDevice.maxPixelRatio = value ? window.devicePixelRatio : 1;
124
216
  }
125
217
  }
218
+ /**
219
+ * Gets the high resolution flag.
220
+ * @returns The high resolution flag.
221
+ */
126
222
  get highResolution() {
127
223
  return this._highResolution;
128
224
  }
225
+ /**
226
+ * Sets the stencil flag.
227
+ * @param value - The stencil flag.
228
+ */
229
+ set stencil(value) {
230
+ this._stencil = value;
231
+ }
232
+ /**
233
+ * Gets the stencil flag.
234
+ * @returns The stencil flag.
235
+ */
236
+ get stencil() {
237
+ return this._stencil;
238
+ }
129
239
  static get observedAttributes() {
130
- return ['high-resolution'];
240
+ return ['alpha', 'antialias', 'depth', 'stencil', 'high-resolution'];
131
241
  }
132
- attributeChangedCallback(name, _oldValue, _newValue) {
242
+ attributeChangedCallback(name, _oldValue, newValue) {
133
243
  switch (name) {
244
+ case 'alpha':
245
+ this.alpha = newValue !== 'false';
246
+ break;
247
+ case 'antialias':
248
+ this.antialias = newValue !== 'false';
249
+ break;
250
+ case 'depth':
251
+ this.depth = newValue !== 'false';
252
+ break;
134
253
  case 'high-resolution':
135
- this.highResolution = this.hasAttribute(name);
254
+ this.highResolution = newValue !== 'false';
255
+ break;
256
+ case 'stencil':
257
+ this.stencil = newValue !== 'false';
136
258
  break;
137
259
  }
138
260
  }
@@ -199,7 +321,7 @@
199
321
  /**
200
322
  * Represents an entity in the PlayCanvas engine.
201
323
  */
202
- class EntityElement extends HTMLElement {
324
+ class EntityElement extends AsyncElement {
203
325
  constructor() {
204
326
  super(...arguments);
205
327
  /**
@@ -226,33 +348,20 @@
226
348
  * The tags of the entity.
227
349
  */
228
350
  this._tags = [];
229
- this._entityReady = new Promise((resolve) => {
230
- this._resolveEntity = resolve;
231
- });
232
351
  /**
233
352
  * The PlayCanvas entity instance.
234
353
  */
235
354
  this.entity = null;
236
355
  }
237
356
  async connectedCallback() {
238
- // Get the application
239
- const appElement = this.closest('pc-app');
240
- if (!appElement) {
241
- console.warn(`${this.tagName} must be a child of pc-app`);
357
+ const closestApp = this.closestApp;
358
+ if (!closestApp)
242
359
  return;
243
- }
244
- const app = await appElement.getApplication();
360
+ // Wait for the app to complete initialization
361
+ await closestApp.ready();
362
+ const app = closestApp.app;
245
363
  // Create a new entity
246
364
  this.entity = new playcanvas.Entity(this._name, app);
247
- this._resolveEntity(this.entity);
248
- if (this.parentElement &&
249
- this.parentElement.tagName.toLowerCase() === 'pc-entity') {
250
- const parentEntity = await this.parentElement._entityReady;
251
- parentEntity.addChild(this.entity);
252
- }
253
- else {
254
- app.root.addChild(this.entity);
255
- }
256
365
  // Initialize from attributes
257
366
  const nameAttr = this.getAttribute('name');
258
367
  const positionAttr = this.getAttribute('position');
@@ -269,6 +378,17 @@
269
378
  this.scale = parseVec3(scaleAttr);
270
379
  if (tagsAttr)
271
380
  this.tags = tagsAttr.split(',').map(tag => tag.trim());
381
+ const closestEntity = this.closestEntity;
382
+ if (closestEntity) {
383
+ closestEntity.ready().then(() => {
384
+ closestEntity.entity.addChild(this.entity);
385
+ this._onReady();
386
+ });
387
+ }
388
+ else {
389
+ app.root.addChild(this.entity);
390
+ this._onReady();
391
+ }
272
392
  }
273
393
  disconnectedCallback() {
274
394
  if (this.entity) {
@@ -280,10 +400,6 @@
280
400
  this.entity.destroy();
281
401
  this.entity = null;
282
402
  }
283
- // Reset the promise for potential reconnection
284
- this._entityReady = new Promise((resolve) => {
285
- this._resolveEntity = resolve;
286
- });
287
403
  }
288
404
  /**
289
405
  * Sets the enabled state of the entity.
@@ -422,6 +538,7 @@
422
538
  ['frag', 'shader'],
423
539
  ['glb', 'container'],
424
540
  ['glsl', 'shader'],
541
+ ['hdr', 'texture'],
425
542
  ['html', 'html'],
426
543
  ['jpg', 'texture'],
427
544
  ['js', 'script'],
@@ -446,8 +563,6 @@
446
563
  */
447
564
  this.asset = null;
448
565
  }
449
- async connectedCallback() {
450
- }
451
566
  disconnectedCallback() {
452
567
  this.destroyAsset();
453
568
  }
@@ -511,7 +626,7 @@
511
626
  *
512
627
  * @category Components
513
628
  */
514
- class ComponentElement extends HTMLElement {
629
+ class ComponentElement extends AsyncElement {
515
630
  /**
516
631
  * Constructor for the ComponentElement.
517
632
  * @param componentName - The name of the component.
@@ -526,27 +641,23 @@
526
641
  getInitialComponentData() {
527
642
  return {};
528
643
  }
529
- async connectedCallback() {
530
- const appElement = this.closest('pc-app');
531
- if (!appElement) {
532
- console.error(`${this.tagName.toLowerCase()} should be a descendant of pc-app`);
533
- return;
534
- }
535
- await appElement.getApplication();
536
- this.addComponent();
537
- }
538
- addComponent() {
539
- // Access the parent pc-entity's 'entity' property
540
- const entityElement = this.closest('pc-entity');
541
- if (!entityElement) {
542
- console.error(`${this.tagName.toLowerCase()} should be a child of pc-entity`);
543
- return;
544
- }
545
- if (entityElement && entityElement.entity) {
644
+ async addComponent() {
645
+ const entityElement = this.closestEntity;
646
+ if (entityElement) {
647
+ await entityElement.ready();
546
648
  // Add the component to the entity
547
- this._component = entityElement.entity.addComponent(this._componentName, this.getInitialComponentData());
649
+ const data = this.getInitialComponentData();
650
+ this._component = entityElement.entity.addComponent(this._componentName, data);
548
651
  }
549
652
  }
653
+ initComponent() { }
654
+ async connectedCallback() {
655
+ var _a;
656
+ await ((_a = this.closestApp) === null || _a === void 0 ? void 0 : _a.ready());
657
+ await this.addComponent();
658
+ this.initComponent();
659
+ this._onReady();
660
+ }
550
661
  disconnectedCallback() {
551
662
  // Remove the component when the element is disconnected
552
663
  if (this.component && this.component.entity) {
@@ -651,6 +762,26 @@
651
762
  scissorRect: this._scissorRect
652
763
  };
653
764
  }
765
+ get xrAvailable() {
766
+ var _a;
767
+ const xrManager = (_a = this.component) === null || _a === void 0 ? void 0 : _a.system.app.xr;
768
+ return xrManager && xrManager.supported && xrManager.isAvailable(playcanvas.XRTYPE_VR);
769
+ }
770
+ startXr(type, space) {
771
+ if (this.component && this.xrAvailable) {
772
+ this.component.startXr(type, space, {
773
+ callback: (err) => {
774
+ if (err)
775
+ console.error(`WebXR Immersive VR failed to start: ${err.message}`);
776
+ }
777
+ });
778
+ }
779
+ }
780
+ endXr() {
781
+ if (this.component) {
782
+ this.component.endXr();
783
+ }
784
+ }
654
785
  /**
655
786
  * Gets the camera component.
656
787
  * @returns The camera component.
@@ -1152,8 +1283,7 @@
1152
1283
  this._width = 0;
1153
1284
  this._wrapLines = false;
1154
1285
  }
1155
- async connectedCallback() {
1156
- await super.connectedCallback();
1286
+ initComponent() {
1157
1287
  this.component._text._material.useFog = true;
1158
1288
  }
1159
1289
  getInitialComponentData() {
@@ -1287,7 +1417,20 @@
1287
1417
  return this._wrapLines;
1288
1418
  }
1289
1419
  static get observedAttributes() {
1290
- return [...super.observedAttributes, 'anchor', 'asset', 'auto-width', 'color', 'font-size', 'line-height', 'pivot', 'text', 'type', 'width', 'wrap-lines'];
1420
+ return [
1421
+ ...super.observedAttributes,
1422
+ 'anchor',
1423
+ 'asset',
1424
+ 'auto-width',
1425
+ 'color',
1426
+ 'font-size',
1427
+ 'line-height',
1428
+ 'pivot',
1429
+ 'text',
1430
+ 'type',
1431
+ 'width',
1432
+ 'wrap-lines'
1433
+ ];
1291
1434
  }
1292
1435
  attributeChangedCallback(name, _oldValue, newValue) {
1293
1436
  super.attributeChangedCallback(name, _oldValue, newValue);
@@ -1773,14 +1916,11 @@
1773
1916
  this._receiveShadows = true;
1774
1917
  this._type = 'asset';
1775
1918
  }
1776
- async connectedCallback() {
1777
- await super.connectedCallback();
1778
- this.material = this._material;
1779
- }
1780
1919
  getInitialComponentData() {
1781
1920
  return {
1782
1921
  type: this._type,
1783
1922
  castShadows: this._castShadows,
1923
+ material: MaterialElement.get(this._material),
1784
1924
  receiveShadows: this._receiveShadows
1785
1925
  };
1786
1926
  }
@@ -2192,6 +2332,9 @@
2192
2332
  }
2193
2333
  customElements.define('pc-screen', ScreenComponentElement);
2194
2334
 
2335
+ const tmpV2 = new playcanvas.Vec2();
2336
+ const tmpV3 = new playcanvas.Vec3();
2337
+ const tmpV4 = new playcanvas.Vec4();
2195
2338
  /**
2196
2339
  * Represents a script component in the PlayCanvas engine.
2197
2340
  *
@@ -2209,8 +2352,7 @@
2209
2352
  this.addEventListener('scriptattributeschange', this.handleScriptAttributesChange.bind(this));
2210
2353
  this.addEventListener('scriptenablechange', this.handleScriptEnableChange.bind(this));
2211
2354
  }
2212
- async connectedCallback() {
2213
- await super.connectedCallback();
2355
+ initComponent() {
2214
2356
  // Handle initial script elements
2215
2357
  this.querySelectorAll(':scope > pc-script').forEach((scriptElement) => {
2216
2358
  const scriptName = scriptElement.getAttribute('name');
@@ -2224,7 +2366,22 @@
2224
2366
  try {
2225
2367
  // Parse the attributes string into an object and set them on the script
2226
2368
  const attributesObject = attributes ? JSON.parse(attributes) : {};
2227
- Object.assign(script, attributesObject);
2369
+ for (const key in attributesObject) {
2370
+ const value = attributesObject[key];
2371
+ if (Array.isArray(value) && script[key] instanceof playcanvas.Vec2) {
2372
+ script[key] = tmpV2.set(value[0], value[1]);
2373
+ continue;
2374
+ }
2375
+ if (Array.isArray(value) && script[key] instanceof playcanvas.Vec3) {
2376
+ script[key] = tmpV3.set(value[0], value[1], value[2]);
2377
+ continue;
2378
+ }
2379
+ if (Array.isArray(value) && script[key] instanceof playcanvas.Vec4) {
2380
+ script[key] = tmpV4.set(value[0], value[1], value[2], value[3]);
2381
+ continue;
2382
+ }
2383
+ script[key] = value;
2384
+ }
2228
2385
  }
2229
2386
  catch (error) {
2230
2387
  console.error(`Error parsing attributes JSON string ${attributes}:`, error);
@@ -2388,14 +2545,22 @@
2388
2545
  class SoundComponentElement extends ComponentElement {
2389
2546
  constructor() {
2390
2547
  super('sound');
2548
+ this._distanceModel = 'linear';
2549
+ this._maxDistance = 10000;
2391
2550
  this._pitch = 1;
2392
2551
  this._positional = false;
2552
+ this._refDistance = 1;
2553
+ this._rollOffFactor = 1;
2393
2554
  this._volume = 1;
2394
2555
  }
2395
2556
  getInitialComponentData() {
2396
2557
  return {
2558
+ distanceModel: this._distanceModel,
2559
+ maxDistance: this._maxDistance,
2397
2560
  pitch: this._pitch,
2398
2561
  positional: this._positional,
2562
+ refDistance: this._refDistance,
2563
+ rollOffFactor: this._rollOffFactor,
2399
2564
  volume: this._volume
2400
2565
  };
2401
2566
  }
@@ -2406,6 +2571,40 @@
2406
2571
  get component() {
2407
2572
  return super.component;
2408
2573
  }
2574
+ /**
2575
+ * Sets which algorithm to use to reduce the volume of the sound as it moves away from the listener.
2576
+ * @param value - The distance model.
2577
+ */
2578
+ set distanceModel(value) {
2579
+ this._distanceModel = value;
2580
+ if (this.component) {
2581
+ this.component.distanceModel = value;
2582
+ }
2583
+ }
2584
+ /**
2585
+ * Gets which algorithm to use to reduce the volume of the sound as it moves away from the listener.
2586
+ * @returns The distance model.
2587
+ */
2588
+ get distanceModel() {
2589
+ return this._distanceModel;
2590
+ }
2591
+ /**
2592
+ * Sets the maximum distance from the listener at which audio falloff stops.
2593
+ * @param value - The max distance.
2594
+ */
2595
+ set maxDistance(value) {
2596
+ this._maxDistance = value;
2597
+ if (this.component) {
2598
+ this.component.maxDistance = value;
2599
+ }
2600
+ }
2601
+ /**
2602
+ * Gets the maximum distance from the listener at which audio falloff stops.
2603
+ * @returns The max distance.
2604
+ */
2605
+ get maxDistance() {
2606
+ return this._maxDistance;
2607
+ }
2409
2608
  /**
2410
2609
  * Sets the pitch of the sound.
2411
2610
  * @param value - The pitch.
@@ -2440,6 +2639,40 @@
2440
2639
  get positional() {
2441
2640
  return this._positional;
2442
2641
  }
2642
+ /**
2643
+ * Sets the reference distance for reducing volume as the sound source moves further from the listener. Defaults to 1.
2644
+ * @param value - The ref distance.
2645
+ */
2646
+ set refDistance(value) {
2647
+ this._refDistance = value;
2648
+ if (this.component) {
2649
+ this.component.refDistance = value;
2650
+ }
2651
+ }
2652
+ /**
2653
+ * Gets the reference distance for reducing volume as the sound source moves further from the listener.
2654
+ * @returns The ref distance.
2655
+ */
2656
+ get refDistance() {
2657
+ return this._refDistance;
2658
+ }
2659
+ /**
2660
+ * Sets the factor used in the falloff equation. Defaults to 1.
2661
+ * @param value - The roll-off factor.
2662
+ */
2663
+ set rollOffFactor(value) {
2664
+ this._rollOffFactor = value;
2665
+ if (this.component) {
2666
+ this.component.rollOffFactor = value;
2667
+ }
2668
+ }
2669
+ /**
2670
+ * Gets the factor used in the falloff equation.
2671
+ * @returns The roll-off factor.
2672
+ */
2673
+ get rollOffFactor() {
2674
+ return this._rollOffFactor;
2675
+ }
2443
2676
  /**
2444
2677
  * Sets the volume of the sound.
2445
2678
  * @param value - The volume.
@@ -2458,17 +2691,38 @@
2458
2691
  return this._volume;
2459
2692
  }
2460
2693
  static get observedAttributes() {
2461
- return [...super.observedAttributes, 'pitch', 'positional', 'volume'];
2694
+ return [
2695
+ ...super.observedAttributes,
2696
+ 'distance-model',
2697
+ 'max-distance',
2698
+ 'pitch',
2699
+ 'positional',
2700
+ 'ref-distance',
2701
+ 'roll-off-factor',
2702
+ 'volume'
2703
+ ];
2462
2704
  }
2463
2705
  attributeChangedCallback(name, _oldValue, newValue) {
2464
2706
  super.attributeChangedCallback(name, _oldValue, newValue);
2465
2707
  switch (name) {
2708
+ case 'distance-model':
2709
+ this.distanceModel = newValue;
2710
+ break;
2711
+ case 'max-distance':
2712
+ this.maxDistance = parseFloat(newValue);
2713
+ break;
2466
2714
  case 'pitch':
2467
2715
  this.pitch = parseFloat(newValue);
2468
2716
  break;
2469
2717
  case 'positional':
2470
2718
  this.positional = this.hasAttribute('positional');
2471
2719
  break;
2720
+ case 'ref-distance':
2721
+ this.refDistance = parseFloat(newValue);
2722
+ break;
2723
+ case 'roll-off-factor':
2724
+ this.rollOffFactor = parseFloat(newValue);
2725
+ break;
2472
2726
  case 'volume':
2473
2727
  this.volume = parseFloat(newValue);
2474
2728
  break;
@@ -2480,7 +2734,7 @@
2480
2734
  /**
2481
2735
  * Represents a sound slot in the PlayCanvas engine.
2482
2736
  */
2483
- class SoundSlotElement extends HTMLElement {
2737
+ class SoundSlotElement extends AsyncElement {
2484
2738
  constructor() {
2485
2739
  super(...arguments);
2486
2740
  this._asset = '';
@@ -2498,12 +2752,8 @@
2498
2752
  this.soundSlot = null;
2499
2753
  }
2500
2754
  async connectedCallback() {
2501
- const appElement = this.closest('pc-app');
2502
- if (!appElement) {
2503
- console.error(`${this.tagName.toLowerCase()} should be a descendant of pc-app`);
2504
- return;
2505
- }
2506
- await appElement.getApplication();
2755
+ var _a;
2756
+ await ((_a = this.soundElement) === null || _a === void 0 ? void 0 : _a.ready());
2507
2757
  const options = {
2508
2758
  autoPlay: this._autoPlay,
2509
2759
  loop: this._loop,
@@ -2518,6 +2768,7 @@
2518
2768
  this.soundSlot = this.soundElement.component.addSlot(this._name, options);
2519
2769
  this.asset = this._asset;
2520
2770
  this.soundSlot.play();
2771
+ this._onReady();
2521
2772
  }
2522
2773
  disconnectedCallback() {
2523
2774
  this.soundElement.component.removeSlot(this._name);
@@ -2724,23 +2975,19 @@
2724
2975
  /**
2725
2976
  * Represents a model in the PlayCanvas engine.
2726
2977
  */
2727
- class ModelElement extends HTMLElement {
2978
+ class ModelElement extends AsyncElement {
2728
2979
  constructor() {
2729
2980
  super(...arguments);
2730
2981
  this._asset = '';
2731
2982
  }
2732
2983
  async connectedCallback() {
2733
- // Get the application
2734
- const appElement = this.closest('pc-app');
2735
- if (!appElement) {
2736
- console.warn(`${this.tagName} must be a child of pc-app`);
2737
- return;
2738
- }
2739
- await appElement.getApplication();
2984
+ var _a;
2985
+ await ((_a = this.closestApp) === null || _a === void 0 ? void 0 : _a.ready());
2740
2986
  const asset = this.getAttribute('asset');
2741
2987
  if (asset) {
2742
2988
  this.asset = asset;
2743
2989
  }
2990
+ this._onReady();
2744
2991
  }
2745
2992
  _loadModel() {
2746
2993
  const asset = AssetElement.get(this._asset);
@@ -2748,13 +2995,23 @@
2748
2995
  return;
2749
2996
  }
2750
2997
  const entity = asset.resource.instantiateRenderEntity();
2751
- const parentEntityElement = this.closest('pc-entity');
2998
+ if (asset.resource.animations.length > 0) {
2999
+ entity.addComponent('anim');
3000
+ entity.anim.assignAnimation('animation', asset.resource.animations[0].resource);
3001
+ }
3002
+ const parentEntityElement = this.closestEntity;
2752
3003
  if (parentEntityElement) {
2753
- parentEntityElement.entity.addChild(entity);
3004
+ parentEntityElement.ready().then(() => {
3005
+ parentEntityElement.entity.addChild(entity);
3006
+ });
2754
3007
  }
2755
3008
  else {
2756
- const appElement = this.closest('pc-app');
2757
- appElement.app.root.addChild(entity);
3009
+ const appElement = this.closestApp;
3010
+ if (appElement) {
3011
+ appElement.ready().then(() => {
3012
+ appElement.app.root.addChild(entity);
3013
+ });
3014
+ }
2758
3015
  }
2759
3016
  }
2760
3017
  /**
@@ -2788,7 +3045,7 @@
2788
3045
  /**
2789
3046
  * Represents a scene in the PlayCanvas engine.
2790
3047
  */
2791
- class SceneElement extends HTMLElement {
3048
+ class SceneElement extends AsyncElement {
2792
3049
  constructor() {
2793
3050
  super(...arguments);
2794
3051
  /**
@@ -2817,15 +3074,11 @@
2817
3074
  this.scene = null;
2818
3075
  }
2819
3076
  async connectedCallback() {
2820
- // Get the application
2821
- const appElement = this.closest('pc-app');
2822
- if (!appElement) {
2823
- console.warn(`${this.tagName} must be a child of pc-app`);
2824
- return;
2825
- }
2826
- const app = await appElement.getApplication();
2827
- this.scene = app.scene;
3077
+ var _a;
3078
+ await ((_a = this.closestApp) === null || _a === void 0 ? void 0 : _a.ready());
3079
+ this.scene = this.closestApp.app.scene;
2828
3080
  this.updateSceneSettings();
3081
+ this._onReady();
2829
3082
  }
2830
3083
  updateSceneSettings() {
2831
3084
  if (this.scene) {
@@ -2951,57 +3204,71 @@
2951
3204
  /**
2952
3205
  * Represents a sky in the PlayCanvas engine.
2953
3206
  */
2954
- class SkyElement extends HTMLElement {
3207
+ class SkyElement extends AsyncElement {
2955
3208
  constructor() {
2956
3209
  super(...arguments);
2957
3210
  this._asset = '';
3211
+ this._center = new playcanvas.Vec3(0, 0.01, 0);
2958
3212
  this._intensity = 1;
2959
- this._rotation = [0, 0, 0];
3213
+ this._rotation = new playcanvas.Vec3();
2960
3214
  this._level = 0;
2961
- this._solidColor = false;
3215
+ this._scale = new playcanvas.Vec3(100, 100, 100);
3216
+ this._type = 'infinite';
2962
3217
  }
2963
3218
  async connectedCallback() {
2964
- // Get the application
2965
- const appElement = this.closest('pc-app');
2966
- if (!appElement) {
2967
- console.warn(`${this.tagName} must be a child of pc-app`);
2968
- return;
2969
- }
2970
- await appElement.getApplication();
3219
+ var _a;
3220
+ await ((_a = this.closestApp) === null || _a === void 0 ? void 0 : _a.ready());
2971
3221
  this.asset = this.getAttribute('asset') || '';
2972
- this.solidColor = this.hasAttribute('solid-color');
3222
+ this._onReady();
2973
3223
  }
2974
3224
  getScene() {
2975
- const appElement = this.closest('pc-app');
2976
- if (!appElement) {
2977
- return;
2978
- }
2979
- const app = appElement.app;
3225
+ const app = this.closestApp.app;
2980
3226
  if (!app) {
2981
3227
  return;
2982
3228
  }
2983
3229
  return app.scene;
2984
3230
  }
3231
+ initSkybox(source) {
3232
+ source.anisotropy = 4;
3233
+ const skybox = playcanvas.EnvLighting.generateSkyboxCubemap(source);
3234
+ const lighting = playcanvas.EnvLighting.generateLightingSource(source);
3235
+ const envAtlas = playcanvas.EnvLighting.generateAtlas(lighting);
3236
+ const app = this.closestApp.app;
3237
+ if (app) {
3238
+ app.scene.envAtlas = envAtlas;
3239
+ app.scene.skybox = skybox;
3240
+ const layer = app.scene.layers.getLayerById(playcanvas.LAYERID_SKYBOX);
3241
+ if (layer) {
3242
+ layer.enabled = this._type !== 'none';
3243
+ }
3244
+ app.scene.sky.type = this._type;
3245
+ app.scene.sky.node.setLocalScale(this._scale);
3246
+ app.scene.sky.center = this._center;
3247
+ }
3248
+ }
2985
3249
  set asset(value) {
2986
3250
  this._asset = value;
2987
3251
  const scene = this.getScene();
2988
3252
  if (scene) {
2989
3253
  const asset = AssetElement.get(value);
2990
3254
  if (asset) {
2991
- if (asset.resource) {
2992
- scene.envAtlas = asset.resource;
2993
- }
2994
- else {
2995
- asset.once('load', () => {
2996
- scene.envAtlas = asset.resource;
2997
- });
2998
- }
3255
+ this.initSkybox(asset.resource);
2999
3256
  }
3000
3257
  }
3001
3258
  }
3002
3259
  get asset() {
3003
3260
  return this._asset;
3004
3261
  }
3262
+ set center(value) {
3263
+ this._center = value;
3264
+ const scene = this.getScene();
3265
+ if (scene) {
3266
+ scene.sky.center = this._center;
3267
+ }
3268
+ }
3269
+ get center() {
3270
+ return this._center;
3271
+ }
3005
3272
  set intensity(value) {
3006
3273
  this._intensity = value;
3007
3274
  const scene = this.getScene();
@@ -3016,24 +3283,21 @@
3016
3283
  this._rotation = value;
3017
3284
  const scene = this.getScene();
3018
3285
  if (scene) {
3019
- scene.skyboxRotation = new playcanvas.Quat().setFromEulerAngles(this._rotation[0], this._rotation[1], this._rotation[2]);
3286
+ scene.skyboxRotation = new playcanvas.Quat().setFromEulerAngles(value);
3020
3287
  }
3021
3288
  }
3022
3289
  get rotation() {
3023
3290
  return this._rotation;
3024
3291
  }
3025
- set solidColor(value) {
3026
- this._solidColor = value;
3292
+ set scale(value) {
3293
+ this._scale = value;
3027
3294
  const scene = this.getScene();
3028
3295
  if (scene) {
3029
- const layer = scene.layers.getLayerById(playcanvas.LAYERID_SKYBOX);
3030
- if (layer) {
3031
- layer.enabled = !this._solidColor;
3032
- }
3296
+ scene.sky.node.setLocalScale(this._scale);
3033
3297
  }
3034
3298
  }
3035
- get solidColor() {
3036
- return this._solidColor;
3299
+ get scale() {
3300
+ return this._scale;
3037
3301
  }
3038
3302
  set level(value) {
3039
3303
  this._level = value;
@@ -3045,25 +3309,45 @@
3045
3309
  get level() {
3046
3310
  return this._level;
3047
3311
  }
3312
+ set type(value) {
3313
+ this._type = value;
3314
+ const scene = this.getScene();
3315
+ if (scene) {
3316
+ scene.sky.type = this._type;
3317
+ const layer = scene.layers.getLayerById(playcanvas.LAYERID_SKYBOX);
3318
+ if (layer) {
3319
+ layer.enabled = this._type !== 'none';
3320
+ }
3321
+ }
3322
+ }
3323
+ get type() {
3324
+ return this._type;
3325
+ }
3048
3326
  static get observedAttributes() {
3049
- return ['asset', 'intensity', 'level', 'rotation', 'solid-color'];
3327
+ return ['asset', 'center', 'intensity', 'level', 'rotation', 'scale', 'type'];
3050
3328
  }
3051
3329
  attributeChangedCallback(name, _oldValue, newValue) {
3052
3330
  switch (name) {
3053
3331
  case 'asset':
3054
3332
  this.asset = newValue;
3055
3333
  break;
3334
+ case 'center':
3335
+ this.center = parseVec3(newValue);
3336
+ break;
3056
3337
  case 'intensity':
3057
3338
  this.intensity = parseFloat(newValue);
3058
3339
  break;
3059
3340
  case 'rotation':
3060
- this.rotation = newValue.split(',').map(Number);
3341
+ this.rotation = parseVec3(newValue);
3061
3342
  break;
3062
3343
  case 'level':
3063
3344
  this.level = parseInt(newValue, 10);
3064
3345
  break;
3065
- case 'solid-color':
3066
- this.solidColor = this.hasAttribute('solid-color');
3346
+ case 'scale':
3347
+ this.scale = parseVec3(newValue);
3348
+ break;
3349
+ case 'type':
3350
+ this.type = newValue;
3067
3351
  break;
3068
3352
  }
3069
3353
  }
@@ -3072,6 +3356,7 @@
3072
3356
 
3073
3357
  exports.AppElement = AppElement;
3074
3358
  exports.AssetElement = AssetElement;
3359
+ exports.AsyncElement = AsyncElement;
3075
3360
  exports.CameraComponentElement = CameraComponentElement;
3076
3361
  exports.CollisionComponentElement = CollisionComponentElement;
3077
3362
  exports.ComponentElement = ComponentElement;