@playcanvas/web-components 0.1.3 → 0.1.5

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 (43) hide show
  1. package/README.md +12 -24
  2. package/dist/app.d.ts +11 -4
  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/collision-component.d.ts +9 -1
  7. package/dist/components/component.d.ts +4 -2
  8. package/dist/components/element-component.d.ts +1 -1
  9. package/dist/components/render-component.d.ts +2 -2
  10. package/dist/components/script-component.d.ts +1 -1
  11. package/dist/components/sound-slot.d.ts +2 -1
  12. package/dist/entity.d.ts +2 -1
  13. package/dist/index.d.ts +10 -1
  14. package/dist/model.d.ts +2 -1
  15. package/dist/pwc.cjs +259 -119
  16. package/dist/pwc.cjs.map +1 -1
  17. package/dist/pwc.js +259 -119
  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 +260 -121
  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/dist/utils.d.ts +8 -1
  26. package/package.json +13 -12
  27. package/src/app.ts +13 -16
  28. package/src/asset.ts +1 -3
  29. package/src/async-element.ts +45 -0
  30. package/src/components/camera-component.ts +23 -2
  31. package/src/components/collision-component.ts +37 -3
  32. package/src/components/component.ts +15 -26
  33. package/src/components/element-component.ts +15 -4
  34. package/src/components/render-component.ts +1 -6
  35. package/src/components/screen-component.ts +1 -1
  36. package/src/components/script-component.ts +1 -3
  37. package/src/components/sound-slot.ts +7 -10
  38. package/src/entity.ts +25 -15
  39. package/src/index.ts +11 -0
  40. package/src/model.ts +20 -15
  41. package/src/scene.ts +6 -11
  42. package/src/sky.ts +82 -40
  43. package/src/utils.ts +14 -1
@@ -1,7 +1,7 @@
1
- import { CollisionComponent, Vec3 } from 'playcanvas';
1
+ import { CollisionComponent, Quat, Vec3 } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
- import { parseVec3 } from '../utils';
4
+ import { parseQuat, parseVec3 } from '../utils';
5
5
 
6
6
  /**
7
7
  * Represents a collision component in the PlayCanvas engine.
@@ -9,6 +9,8 @@ import { parseVec3 } from '../utils';
9
9
  * @category Components
10
10
  */
11
11
  class CollisionComponentElement extends ComponentElement {
12
+ private _angularOffset: Quat = new Quat();
13
+
12
14
  private _axis: number = 1;
13
15
 
14
16
  private _convexHull: boolean = false;
@@ -17,6 +19,8 @@ class CollisionComponentElement extends ComponentElement {
17
19
 
18
20
  private _height: number = 2;
19
21
 
22
+ private _linearOffset: Vec3 = new Vec3();
23
+
20
24
  private _radius: number = 0.5;
21
25
 
22
26
  private _type: string = 'box';
@@ -31,9 +35,11 @@ class CollisionComponentElement extends ComponentElement {
31
35
  getInitialComponentData() {
32
36
  return {
33
37
  axis: this._axis,
38
+ angularOffset: this._angularOffset,
34
39
  convexHull: this._convexHull,
35
40
  halfExtents: this._halfExtents,
36
41
  height: this._height,
42
+ linearOffset: this._linearOffset,
37
43
  radius: this._radius,
38
44
  type: this._type
39
45
  };
@@ -47,6 +53,17 @@ class CollisionComponentElement extends ComponentElement {
47
53
  return super.component as CollisionComponent | null;
48
54
  }
49
55
 
56
+ set angularOffset(value: Quat) {
57
+ this._angularOffset = value;
58
+ if (this.component) {
59
+ this.component.angularOffset = value;
60
+ }
61
+ }
62
+
63
+ get angularOffset() {
64
+ return this._angularOffset;
65
+ }
66
+
50
67
  set axis(value: number) {
51
68
  this._axis = value;
52
69
  if (this.component) {
@@ -91,6 +108,17 @@ class CollisionComponentElement extends ComponentElement {
91
108
  return this._height;
92
109
  }
93
110
 
111
+ set linearOffset(value: Vec3) {
112
+ this._linearOffset = value;
113
+ if (this.component) {
114
+ this.component.linearOffset = value;
115
+ }
116
+ }
117
+
118
+ get linearOffset() {
119
+ return this._linearOffset;
120
+ }
121
+
94
122
  set radius(value: number) {
95
123
  this._radius = value;
96
124
  if (this.component) {
@@ -114,13 +142,16 @@ class CollisionComponentElement extends ComponentElement {
114
142
  }
115
143
 
116
144
  static get observedAttributes() {
117
- return [...super.observedAttributes, 'axis', 'convex-hull', 'half-extents', 'height', 'radius', 'type'];
145
+ return [...super.observedAttributes, 'angular-offset', 'axis', 'convex-hull', 'half-extents', 'height', 'linear-offset', 'radius', 'type'];
118
146
  }
119
147
 
120
148
  attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
121
149
  super.attributeChangedCallback(name, _oldValue, newValue);
122
150
 
123
151
  switch (name) {
152
+ case 'angular-offset':
153
+ this.angularOffset = parseQuat(newValue);
154
+ break;
124
155
  case 'axis':
125
156
  this.axis = parseInt(newValue, 10);
126
157
  break;
@@ -133,6 +164,9 @@ class CollisionComponentElement extends ComponentElement {
133
164
  case 'height':
134
165
  this.height = parseFloat(newValue);
135
166
  break;
167
+ case 'linear-offset':
168
+ this.linearOffset = parseVec3(newValue);
169
+ break;
136
170
  case 'radius':
137
171
  this.radius = parseFloat(newValue);
138
172
  break;
@@ -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
  }
@@ -127,7 +127,7 @@ class ScreenComponentElement extends ComponentElement {
127
127
 
128
128
  switch (name) {
129
129
  case 'priority':
130
- this.priority = parseInt(newValue);
130
+ this.priority = parseInt(newValue, 10);
131
131
  break;
132
132
  case 'reference-resolution':
133
133
  this.referenceResolution = parseVec2(newValue);
@@ -42,9 +42,7 @@ class ScriptComponentElement extends ComponentElement {
42
42
  this.addEventListener('scriptenablechange', this.handleScriptEnableChange.bind(this));
43
43
  }
44
44
 
45
- async connectedCallback() {
46
- await super.connectedCallback();
47
-
45
+ initComponent() {
48
46
  // Handle initial script elements
49
47
  this.querySelectorAll<ScriptElement>(':scope > pc-script').forEach((scriptElement) => {
50
48
  const scriptName = scriptElement.getAttribute('name');
@@ -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
  */
@@ -43,24 +43,17 @@ class EntityElement extends HTMLElement {
43
43
  entity: Entity | null = null;
44
44
 
45
45
  async connectedCallback() {
46
- // Get the application
47
- const appElement = this.closest('pc-app') as AppElement;
48
- if (!appElement) {
49
- console.warn(`${this.tagName} must be a child of pc-app`);
50
- return;
51
- }
46
+ const closestApp = this.closestApp;
47
+ if (!closestApp) return;
48
+
49
+ // Wait for the app to complete initialization
50
+ await closestApp.ready();
52
51
 
53
- const app = await appElement.getApplication();
52
+ const app = closestApp.app!;
54
53
 
55
54
  // Create a new entity
56
55
  this.entity = new Entity(this._name, app);
57
56
 
58
- if (this.parentElement && this.parentElement.tagName.toLowerCase() === 'pc-entity' && (this.parentElement as EntityElement).entity) {
59
- (this.parentElement as EntityElement).entity!.addChild(this.entity);
60
- } else {
61
- app.root.addChild(this.entity);
62
- }
63
-
64
57
  // Initialize from attributes
65
58
  const nameAttr = this.getAttribute('name');
66
59
  const positionAttr = this.getAttribute('position');
@@ -73,10 +66,27 @@ class EntityElement extends HTMLElement {
73
66
  if (rotationAttr) this.rotation = parseVec3(rotationAttr);
74
67
  if (scaleAttr) this.scale = parseVec3(scaleAttr);
75
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
+ }
76
80
  }
77
81
 
78
82
  disconnectedCallback() {
79
83
  if (this.entity) {
84
+ // Notify all children that their entities are about to become invalid
85
+ const children = this.querySelectorAll('pc-entity');
86
+ children.forEach((child) => {
87
+ (child as EntityElement).entity = null;
88
+ });
89
+
80
90
  this.entity.destroy();
81
91
  this.entity = null;
82
92
  }
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/scene.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { Color, Scene } from 'playcanvas';
2
2
 
3
- import { AppElement } from './app';
3
+ import { AsyncElement } from './async-element';
4
4
  import { parseColor } from './utils';
5
5
 
6
6
  /**
7
7
  * Represents a scene in the PlayCanvas engine.
8
8
  */
9
- class SceneElement extends HTMLElement {
9
+ class SceneElement extends AsyncElement {
10
10
  /**
11
11
  * The fog type of the scene.
12
12
  */
@@ -38,17 +38,12 @@ class SceneElement extends HTMLElement {
38
38
  scene: Scene | null = null;
39
39
 
40
40
  async connectedCallback() {
41
- // Get the application
42
- const appElement = this.closest('pc-app') as AppElement;
43
- if (!appElement) {
44
- console.warn(`${this.tagName} must be a child of pc-app`);
45
- return;
46
- }
47
-
48
- const app = await appElement.getApplication();
41
+ await this.closestApp?.ready();
49
42
 
50
- this.scene = app.scene;
43
+ this.scene = this.closestApp!.app!.scene;
51
44
  this.updateSceneSettings();
45
+
46
+ this._onReady();
52
47
  }
53
48
 
54
49
  updateSceneSettings() {