@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
@@ -0,0 +1,45 @@
1
+ import { AppElement } from './app';
2
+ import { EntityElement } from './entity';
3
+
4
+ /**
5
+ * Base class for all PlayCanvas web components that initialize asynchronously.
6
+ */
7
+ class AsyncElement extends HTMLElement {
8
+ private _readyPromise: Promise<void>;
9
+
10
+ private _readyResolve!: () => void;
11
+
12
+ constructor() {
13
+ super();
14
+ this._readyPromise = new Promise<void>((resolve) => {
15
+ this._readyResolve = resolve;
16
+ });
17
+ }
18
+
19
+ get closestApp(): AppElement {
20
+ return this.parentElement?.closest('pc-app') as AppElement;
21
+ }
22
+
23
+ get closestEntity(): EntityElement {
24
+ return this.parentElement?.closest('pc-entity') as EntityElement;
25
+ }
26
+
27
+ /**
28
+ * Called when the element is fully initialized and ready.
29
+ * Subclasses should call this when they're ready.
30
+ */
31
+ protected _onReady() {
32
+ this._readyResolve();
33
+ this.dispatchEvent(new CustomEvent('ready'));
34
+ }
35
+
36
+ /**
37
+ * Returns a promise that resolves with this element when it's ready.
38
+ * @returns A promise that resolves with this element when it's ready.
39
+ */
40
+ ready(): Promise<this> {
41
+ return this._readyPromise.then(() => this);
42
+ }
43
+ }
44
+
45
+ export { AsyncElement };
@@ -1,4 +1,4 @@
1
- import { PROJECTION_ORTHOGRAPHIC, PROJECTION_PERSPECTIVE, CameraComponent, Color, Vec4 } from 'playcanvas';
1
+ import { PROJECTION_ORTHOGRAPHIC, PROJECTION_PERSPECTIVE, CameraComponent, Color, Vec4, XRTYPE_VR } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
4
  import { parseColor, parseVec4 } from '../utils';
@@ -66,6 +66,27 @@ class CameraComponentElement extends ComponentElement {
66
66
  };
67
67
  }
68
68
 
69
+ get xrAvailable() {
70
+ const xrManager = this.component?.system.app.xr;
71
+ return xrManager && xrManager.supported && xrManager.isAvailable(XRTYPE_VR);
72
+ }
73
+
74
+ startXr(type: 'immersive-ar' | 'immersive-vr', space: 'bounded-floor' | 'local' | 'local-floor' | 'unbounded' | 'viewer') {
75
+ if (this.component && this.xrAvailable) {
76
+ this.component.startXr(type, space, {
77
+ callback: (err: any) => {
78
+ if (err) console.error(`WebXR Immersive VR failed to start: ${err.message}`);
79
+ }
80
+ });
81
+ }
82
+ }
83
+
84
+ endXr() {
85
+ if (this.component) {
86
+ this.component.endXr();
87
+ }
88
+ }
89
+
69
90
  /**
70
91
  * Gets the camera component.
71
92
  * @returns The camera component.
@@ -1,14 +1,13 @@
1
1
  import { Component } from 'playcanvas';
2
2
 
3
- import { AppElement } from '../app';
4
- import { EntityElement } from '../entity';
3
+ import { AsyncElement } from '../async-element';
5
4
 
6
5
  /**
7
6
  * Represents a component in the PlayCanvas engine.
8
7
  *
9
8
  * @category Components
10
9
  */
11
- class ComponentElement extends HTMLElement {
10
+ class ComponentElement extends AsyncElement {
12
11
  private _componentName: string;
13
12
 
14
13
  private _enabled = true;
@@ -30,33 +29,23 @@ class ComponentElement extends HTMLElement {
30
29
  return {};
31
30
  }
32
31
 
33
- async connectedCallback() {
34
- const appElement = this.closest('pc-app') as AppElement | null;
35
- if (!appElement) {
36
- console.error(`${this.tagName.toLowerCase()} should be a descendant of pc-app`);
37
- return;
32
+ async addComponent() {
33
+ const entityElement = this.closestEntity;
34
+ if (entityElement) {
35
+ await entityElement.ready();
36
+ // Add the component to the entity
37
+ const data = this.getInitialComponentData();
38
+ this._component = entityElement.entity!.addComponent(this._componentName, data);
38
39
  }
39
-
40
- await appElement.getApplication();
41
-
42
- this.addComponent();
43
40
  }
44
41
 
45
- addComponent() {
46
- // Access the parent pc-entity's 'entity' property
47
- const entityElement = this.closest('pc-entity') as EntityElement | null;
48
- if (!entityElement) {
49
- console.error(`${this.tagName.toLowerCase()} should be a child of pc-entity`);
50
- return;
51
- }
42
+ initComponent() {}
52
43
 
53
- if (entityElement && entityElement.entity) {
54
- // Add the component to the entity
55
- this._component = entityElement.entity.addComponent(
56
- this._componentName,
57
- this.getInitialComponentData()
58
- );
59
- }
44
+ async connectedCallback() {
45
+ await this.closestApp?.ready();
46
+ await this.addComponent();
47
+ this.initComponent();
48
+ this._onReady();
60
49
  }
61
50
 
62
51
  disconnectedCallback() {
@@ -37,9 +37,7 @@ class ElementComponentElement extends ComponentElement {
37
37
  super('element');
38
38
  }
39
39
 
40
- async connectedCallback() {
41
- await super.connectedCallback();
42
-
40
+ initComponent() {
43
41
  this.component!._text._material.useFog = true;
44
42
  }
45
43
 
@@ -198,7 +196,20 @@ class ElementComponentElement extends ComponentElement {
198
196
  }
199
197
 
200
198
  static get observedAttributes() {
201
- return [...super.observedAttributes, 'anchor', 'asset', 'auto-width', 'color', 'font-size', 'line-height', 'pivot', 'text', 'type', 'width', 'wrap-lines'];
199
+ return [
200
+ ...super.observedAttributes,
201
+ 'anchor',
202
+ 'asset',
203
+ 'auto-width',
204
+ 'color',
205
+ 'font-size',
206
+ 'line-height',
207
+ 'pivot',
208
+ 'text',
209
+ 'type',
210
+ 'width',
211
+ 'wrap-lines'
212
+ ];
202
213
  }
203
214
 
204
215
  attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
@@ -21,16 +21,11 @@ class RenderComponentElement extends ComponentElement {
21
21
  super('render');
22
22
  }
23
23
 
24
- async connectedCallback() {
25
- await super.connectedCallback();
26
-
27
- this.material = this._material;
28
- }
29
-
30
24
  getInitialComponentData() {
31
25
  return {
32
26
  type: this._type,
33
27
  castShadows: this._castShadows,
28
+ material: MaterialElement.get(this._material),
34
29
  receiveShadows: this._receiveShadows
35
30
  };
36
31
  }
@@ -1,8 +1,12 @@
1
- import { ScriptComponent, ScriptType } from 'playcanvas';
1
+ import { ScriptComponent, Script, Vec2, Vec3, Vec4 } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
4
  import { ScriptElement } from './script';
5
5
 
6
+ const tmpV2 = new Vec2();
7
+ const tmpV3 = new Vec3();
8
+ const tmpV4 = new Vec4();
9
+
6
10
  // Add these interfaces at the top of the file, after the imports
7
11
  interface ScriptAttributesChangeEvent extends CustomEvent {
8
12
  detail: { attributes: any };
@@ -42,9 +46,7 @@ class ScriptComponentElement extends ComponentElement {
42
46
  this.addEventListener('scriptenablechange', this.handleScriptEnableChange.bind(this));
43
47
  }
44
48
 
45
- async connectedCallback() {
46
- await super.connectedCallback();
47
-
49
+ initComponent() {
48
50
  // Handle initial script elements
49
51
  this.querySelectorAll<ScriptElement>(':scope > pc-script').forEach((scriptElement) => {
50
52
  const scriptName = scriptElement.getAttribute('name');
@@ -55,11 +57,27 @@ class ScriptComponentElement extends ComponentElement {
55
57
  });
56
58
  }
57
59
 
58
- private applyAttributes(script: ScriptType, attributes: string | null) {
60
+ private applyAttributes(script: any, attributes: string | null) {
59
61
  try {
60
62
  // Parse the attributes string into an object and set them on the script
61
63
  const attributesObject = attributes ? JSON.parse(attributes) : {};
62
- Object.assign(script, attributesObject);
64
+ for (const key in attributesObject) {
65
+ const value = attributesObject[key];
66
+ if (Array.isArray(value) && script[key] instanceof Vec2) {
67
+ script[key] = tmpV2.set(value[0], value[1]);
68
+ continue;
69
+ }
70
+ if (Array.isArray(value) && script[key] instanceof Vec3) {
71
+ script[key] = tmpV3.set(value[0], value[1], value[2]);
72
+ continue;
73
+ }
74
+ if (Array.isArray(value) && script[key] instanceof Vec4) {
75
+ script[key] = tmpV4.set(value[0], value[1], value[2], value[3]);
76
+ continue;
77
+ }
78
+
79
+ script[key] = value;
80
+ }
63
81
  } catch (error) {
64
82
  console.error(`Error parsing attributes JSON string ${attributes}:`, error);
65
83
  }
@@ -87,7 +105,7 @@ class ScriptComponentElement extends ComponentElement {
87
105
  }
88
106
  }
89
107
 
90
- private createScript(name: string, attributes: string | null): ScriptType | null {
108
+ private createScript(name: string, attributes: string | null): Script | null {
91
109
  if (!this.component) return null;
92
110
 
93
111
  this.component.on(`create:${name}`, (script) => {
@@ -8,10 +8,18 @@ import { ComponentElement } from './component';
8
8
  * @category Components
9
9
  */
10
10
  class SoundComponentElement extends ComponentElement {
11
+ private _distanceModel: 'exponential' | 'inverse' | 'linear' = 'linear';
12
+
13
+ private _maxDistance: number = 10000;
14
+
11
15
  private _pitch: number = 1;
12
16
 
13
17
  private _positional: boolean = false;
14
18
 
19
+ private _refDistance: number = 1;
20
+
21
+ private _rollOffFactor: number = 1;
22
+
15
23
  private _volume: number = 1;
16
24
 
17
25
  constructor() {
@@ -20,8 +28,12 @@ class SoundComponentElement extends ComponentElement {
20
28
 
21
29
  getInitialComponentData() {
22
30
  return {
31
+ distanceModel: this._distanceModel,
32
+ maxDistance: this._maxDistance,
23
33
  pitch: this._pitch,
24
34
  positional: this._positional,
35
+ refDistance: this._refDistance,
36
+ rollOffFactor: this._rollOffFactor,
25
37
  volume: this._volume
26
38
  };
27
39
  }
@@ -34,6 +46,44 @@ class SoundComponentElement extends ComponentElement {
34
46
  return super.component as SoundComponent | null;
35
47
  }
36
48
 
49
+ /**
50
+ * Sets which algorithm to use to reduce the volume of the sound as it moves away from the listener.
51
+ * @param value - The distance model.
52
+ */
53
+ set distanceModel(value: 'exponential' | 'inverse' | 'linear') {
54
+ this._distanceModel = value;
55
+ if (this.component) {
56
+ this.component.distanceModel = value;
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Gets which algorithm to use to reduce the volume of the sound as it moves away from the listener.
62
+ * @returns The distance model.
63
+ */
64
+ get distanceModel(): 'exponential' | 'inverse' | 'linear' {
65
+ return this._distanceModel;
66
+ }
67
+
68
+ /**
69
+ * Sets the maximum distance from the listener at which audio falloff stops.
70
+ * @param value - The max distance.
71
+ */
72
+ set maxDistance(value: number) {
73
+ this._maxDistance = value;
74
+ if (this.component) {
75
+ this.component.maxDistance = value;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Gets the maximum distance from the listener at which audio falloff stops.
81
+ * @returns The max distance.
82
+ */
83
+ get maxDistance() {
84
+ return this._maxDistance;
85
+ }
86
+
37
87
  /**
38
88
  * Sets the pitch of the sound.
39
89
  * @param value - The pitch.
@@ -72,6 +122,44 @@ class SoundComponentElement extends ComponentElement {
72
122
  return this._positional;
73
123
  }
74
124
 
125
+ /**
126
+ * Sets the reference distance for reducing volume as the sound source moves further from the listener. Defaults to 1.
127
+ * @param value - The ref distance.
128
+ */
129
+ set refDistance(value: number) {
130
+ this._refDistance = value;
131
+ if (this.component) {
132
+ this.component.refDistance = value;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Gets the reference distance for reducing volume as the sound source moves further from the listener.
138
+ * @returns The ref distance.
139
+ */
140
+ get refDistance() {
141
+ return this._refDistance;
142
+ }
143
+
144
+ /**
145
+ * Sets the factor used in the falloff equation. Defaults to 1.
146
+ * @param value - The roll-off factor.
147
+ */
148
+ set rollOffFactor(value: number) {
149
+ this._rollOffFactor = value;
150
+ if (this.component) {
151
+ this.component.rollOffFactor = value;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Gets the factor used in the falloff equation.
157
+ * @returns The roll-off factor.
158
+ */
159
+ get rollOffFactor() {
160
+ return this._rollOffFactor;
161
+ }
162
+
75
163
  /**
76
164
  * Sets the volume of the sound.
77
165
  * @param value - The volume.
@@ -92,19 +180,40 @@ class SoundComponentElement extends ComponentElement {
92
180
  }
93
181
 
94
182
  static get observedAttributes() {
95
- return [...super.observedAttributes, 'pitch', 'positional', 'volume'];
183
+ return [
184
+ ...super.observedAttributes,
185
+ 'distance-model',
186
+ 'max-distance',
187
+ 'pitch',
188
+ 'positional',
189
+ 'ref-distance',
190
+ 'roll-off-factor',
191
+ 'volume'
192
+ ];
96
193
  }
97
194
 
98
195
  attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
99
196
  super.attributeChangedCallback(name, _oldValue, newValue);
100
197
 
101
198
  switch (name) {
199
+ case 'distance-model':
200
+ this.distanceModel = newValue as 'exponential' | 'inverse' | 'linear';
201
+ break;
202
+ case 'max-distance':
203
+ this.maxDistance = parseFloat(newValue);
204
+ break;
102
205
  case 'pitch':
103
206
  this.pitch = parseFloat(newValue);
104
207
  break;
105
208
  case 'positional':
106
209
  this.positional = this.hasAttribute('positional');
107
210
  break;
211
+ case 'ref-distance':
212
+ this.refDistance = parseFloat(newValue);
213
+ break;
214
+ case 'roll-off-factor':
215
+ this.rollOffFactor = parseFloat(newValue);
216
+ break;
108
217
  case 'volume':
109
218
  this.volume = parseFloat(newValue);
110
219
  break;
@@ -1,13 +1,13 @@
1
1
  import { SoundSlot } from 'playcanvas';
2
2
 
3
- import { AppElement } from '../app';
4
- import { SoundComponentElement } from './sound-component';
5
3
  import { AssetElement } from '../asset';
4
+ import { AsyncElement } from '../async-element';
5
+ import { SoundComponentElement } from './sound-component';
6
6
 
7
7
  /**
8
8
  * Represents a sound slot in the PlayCanvas engine.
9
9
  */
10
- class SoundSlotElement extends HTMLElement {
10
+ class SoundSlotElement extends AsyncElement {
11
11
  private _asset: string = '';
12
12
 
13
13
  private _autoPlay: boolean = false;
@@ -32,13 +32,7 @@ class SoundSlotElement extends HTMLElement {
32
32
  soundSlot: SoundSlot | null = null;
33
33
 
34
34
  async connectedCallback() {
35
- const appElement = this.closest('pc-app') as AppElement | null;
36
- if (!appElement) {
37
- console.error(`${this.tagName.toLowerCase()} should be a descendant of pc-app`);
38
- return;
39
- }
40
-
41
- await appElement.getApplication();
35
+ await this.soundElement?.ready();
42
36
 
43
37
  const options = {
44
38
  autoPlay: this._autoPlay,
@@ -51,9 +45,12 @@ class SoundSlotElement extends HTMLElement {
51
45
  if (this._duration) {
52
46
  options.duration = this._duration;
53
47
  }
48
+
54
49
  this.soundSlot = this.soundElement!.component!.addSlot(this._name, options);
55
50
  this.asset = this._asset;
56
51
  this.soundSlot!.play();
52
+
53
+ this._onReady();
57
54
  }
58
55
 
59
56
  disconnectedCallback() {
package/src/entity.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { Entity, Vec3 } from 'playcanvas';
2
2
 
3
- import { AppElement } from './app';
3
+ import { AsyncElement } from './async-element';
4
4
  import { parseVec3 } from './utils';
5
5
 
6
6
  /**
7
7
  * Represents an entity in the PlayCanvas engine.
8
8
  */
9
- class EntityElement extends HTMLElement {
9
+ class EntityElement extends AsyncElement {
10
10
  /**
11
11
  * Whether the entity is enabled.
12
12
  */
@@ -37,38 +37,22 @@ class EntityElement extends HTMLElement {
37
37
  */
38
38
  private _tags: string[] = [];
39
39
 
40
- private _resolveEntity!: (entity: Entity) => void;
41
-
42
- private _entityReady = new Promise<Entity>((resolve) => {
43
- this._resolveEntity = resolve;
44
- });
45
-
46
40
  /**
47
41
  * The PlayCanvas entity instance.
48
42
  */
49
43
  entity: Entity | null = null;
50
44
 
51
45
  async connectedCallback() {
52
- // Get the application
53
- const appElement = this.closest('pc-app') as AppElement;
54
- if (!appElement) {
55
- console.warn(`${this.tagName} must be a child of pc-app`);
56
- return;
57
- }
46
+ const closestApp = this.closestApp;
47
+ if (!closestApp) return;
48
+
49
+ // Wait for the app to complete initialization
50
+ await closestApp.ready();
58
51
 
59
- const app = await appElement.getApplication();
52
+ const app = closestApp.app!;
60
53
 
61
54
  // Create a new entity
62
55
  this.entity = new Entity(this._name, app);
63
- this._resolveEntity(this.entity);
64
-
65
- if (this.parentElement &&
66
- this.parentElement.tagName.toLowerCase() === 'pc-entity') {
67
- const parentEntity = await (this.parentElement as EntityElement)._entityReady;
68
- parentEntity.addChild(this.entity);
69
- } else {
70
- app.root.addChild(this.entity);
71
- }
72
56
 
73
57
  // Initialize from attributes
74
58
  const nameAttr = this.getAttribute('name');
@@ -82,6 +66,17 @@ class EntityElement extends HTMLElement {
82
66
  if (rotationAttr) this.rotation = parseVec3(rotationAttr);
83
67
  if (scaleAttr) this.scale = parseVec3(scaleAttr);
84
68
  if (tagsAttr) this.tags = tagsAttr.split(',').map(tag => tag.trim());
69
+
70
+ const closestEntity = this.closestEntity;
71
+ if (closestEntity) {
72
+ closestEntity.ready().then(() => {
73
+ closestEntity.entity!.addChild(this.entity!);
74
+ this._onReady();
75
+ });
76
+ } else {
77
+ app.root.addChild(this.entity);
78
+ this._onReady();
79
+ }
85
80
  }
86
81
 
87
82
  disconnectedCallback() {
@@ -95,11 +90,6 @@ class EntityElement extends HTMLElement {
95
90
  this.entity.destroy();
96
91
  this.entity = null;
97
92
  }
98
-
99
- // Reset the promise for potential reconnection
100
- this._entityReady = new Promise<Entity>((resolve) => {
101
- this._resolveEntity = resolve;
102
- });
103
93
  }
104
94
 
105
95
  /**
package/src/index.ts CHANGED
@@ -1,6 +1,16 @@
1
+ /**
2
+ * The Engine Web Components module provides a set of Web Components for the PlayCanvas Engine.
3
+ * While these components are normally instantiated in a declarative fashion using HTML, this
4
+ * reference covers the TypeScript/JavaScript API that allows these components to be created
5
+ * programmatically.
6
+ *
7
+ * @module EngineWebComponents
8
+ */
9
+
1
10
  /* eslint-disable import/order */
2
11
 
3
12
  // Note that order matters here (e.g. pc-entity must be defined before components)
13
+ import { AsyncElement } from './async-element';
4
14
  import { ModuleElement } from './module';
5
15
  import { AppElement } from './app';
6
16
  import { EntityElement } from './entity';
@@ -25,6 +35,7 @@ import { SceneElement } from './scene';
25
35
  import { SkyElement } from './sky';
26
36
 
27
37
  export {
38
+ AsyncElement,
28
39
  ModuleElement,
29
40
  AppElement,
30
41
  EntityElement,
package/src/model.ts CHANGED
@@ -1,27 +1,21 @@
1
- import { AppElement } from './app';
2
1
  import { AssetElement } from './asset';
3
- import { EntityElement } from './entity';
2
+ import { AsyncElement } from './async-element';
4
3
 
5
4
  /**
6
5
  * Represents a model in the PlayCanvas engine.
7
6
  */
8
- class ModelElement extends HTMLElement {
7
+ class ModelElement extends AsyncElement {
9
8
  private _asset: string = '';
10
9
 
11
10
  async connectedCallback() {
12
- // Get the application
13
- const appElement = this.closest('pc-app') as AppElement;
14
- if (!appElement) {
15
- console.warn(`${this.tagName} must be a child of pc-app`);
16
- return;
17
- }
18
-
19
- await appElement.getApplication();
11
+ await this.closestApp?.ready();
20
12
 
21
13
  const asset = this.getAttribute('asset');
22
14
  if (asset) {
23
15
  this.asset = asset;
24
16
  }
17
+
18
+ this._onReady();
25
19
  }
26
20
 
27
21
  _loadModel() {
@@ -31,12 +25,23 @@ class ModelElement extends HTMLElement {
31
25
  }
32
26
  const entity = asset.resource.instantiateRenderEntity();
33
27
 
34
- const parentEntityElement = this.closest('pc-entity') as EntityElement | null;
28
+ if (asset.resource.animations.length > 0) {
29
+ entity.addComponent('anim');
30
+ entity.anim.assignAnimation('animation', asset.resource.animations[0].resource);
31
+ }
32
+
33
+ const parentEntityElement = this.closestEntity;
35
34
  if (parentEntityElement) {
36
- parentEntityElement.entity!.addChild(entity);
35
+ parentEntityElement.ready().then(() => {
36
+ parentEntityElement.entity!.addChild(entity);
37
+ });
37
38
  } else {
38
- const appElement = this.closest('pc-app') as AppElement;
39
- appElement.app!.root.addChild(entity);
39
+ const appElement = this.closestApp;
40
+ if (appElement) {
41
+ appElement.ready().then(() => {
42
+ appElement.app!.root.addChild(entity);
43
+ });
44
+ }
40
45
  }
41
46
  }
42
47
 
package/src/module.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { WasmModule } from 'playcanvas';
1
+ import { basisInitialize, WasmModule } from 'playcanvas';
2
2
 
3
3
  class ModuleElement extends HTMLElement {
4
4
  private loadPromise: Promise<void>;
@@ -14,15 +14,23 @@ class ModuleElement extends HTMLElement {
14
14
  const wasm = this.getAttribute('wasm')!;
15
15
  const fallback = this.getAttribute('fallback')!;
16
16
 
17
- WasmModule.setConfig(name, {
18
- glueUrl: glue,
19
- wasmUrl: wasm,
20
- fallbackUrl: fallback
21
- });
22
-
23
- await new Promise<void>((resolve) => {
24
- WasmModule.getInstance(name, () => resolve());
25
- });
17
+ if (name === 'Basis') {
18
+ basisInitialize({
19
+ glueUrl: glue,
20
+ wasmUrl: wasm,
21
+ fallbackUrl: fallback
22
+ });
23
+ } else {
24
+ WasmModule.setConfig(name, {
25
+ glueUrl: glue,
26
+ wasmUrl: wasm,
27
+ fallbackUrl: fallback
28
+ });
29
+
30
+ await new Promise<void>((resolve) => {
31
+ WasmModule.getInstance(name, () => resolve());
32
+ });
33
+ }
26
34
  }
27
35
 
28
36
  public getLoadPromise(): Promise<void> {