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