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