@playcanvas/web-components 0.16.0 → 0.18.0

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 (126) hide show
  1. package/README.md +5 -3
  2. package/dist/app.d.cts +18 -13
  3. package/dist/app.d.ts +18 -13
  4. package/dist/asset.d.cts +13 -3
  5. package/dist/asset.d.ts +13 -3
  6. package/dist/async-element.d.cts +13 -13
  7. package/dist/async-element.d.ts +13 -13
  8. package/dist/components/anim-clip.d.cts +4 -0
  9. package/dist/components/anim-clip.d.ts +4 -0
  10. package/dist/components/anim-component.d.cts +38 -5
  11. package/dist/components/anim-component.d.ts +38 -5
  12. package/dist/components/audio-listener-component.d.cts +26 -0
  13. package/dist/components/audio-listener-component.d.ts +26 -0
  14. package/dist/components/button-component.d.cts +10 -1
  15. package/dist/components/button-component.d.ts +10 -1
  16. package/dist/components/camera-component.d.cts +37 -1
  17. package/dist/components/camera-component.d.ts +37 -1
  18. package/dist/components/collision-component.d.cts +9 -1
  19. package/dist/components/collision-component.d.ts +9 -1
  20. package/dist/components/component.d.cts +3 -2
  21. package/dist/components/component.d.ts +3 -2
  22. package/dist/components/element-component.d.cts +11 -0
  23. package/dist/components/element-component.d.ts +11 -0
  24. package/dist/components/gsplat-component.d.cts +6 -0
  25. package/dist/components/gsplat-component.d.ts +6 -0
  26. package/dist/components/joint-component.d.cts +14 -2
  27. package/dist/components/joint-component.d.ts +14 -2
  28. package/dist/components/{layoutchild-component.d.cts → layout-child-component.d.cts} +7 -1
  29. package/dist/components/{layoutchild-component.d.ts → layout-child-component.d.ts} +7 -1
  30. package/dist/components/{layoutgroup-component.d.cts → layout-group-component.d.cts} +7 -1
  31. package/dist/components/{layoutgroup-component.d.ts → layout-group-component.d.ts} +7 -1
  32. package/dist/components/light-component.d.cts +52 -1
  33. package/dist/components/light-component.d.ts +52 -1
  34. package/dist/components/{particlesystem-component.d.cts → particle-system-component.d.cts} +7 -1
  35. package/dist/components/{particlesystem-component.d.ts → particle-system-component.d.ts} +7 -1
  36. package/dist/components/render-component.d.cts +7 -0
  37. package/dist/components/render-component.d.ts +7 -0
  38. package/dist/components/{rigidbody-component.d.cts → rigid-body-component.d.cts} +8 -1
  39. package/dist/components/{rigidbody-component.d.ts → rigid-body-component.d.ts} +8 -1
  40. package/dist/components/screen-component.d.cts +6 -0
  41. package/dist/components/screen-component.d.ts +6 -0
  42. package/dist/components/script-component.d.cts +26 -12
  43. package/dist/components/script-component.d.ts +26 -12
  44. package/dist/components/{script.d.cts → script-instance.d.cts} +11 -7
  45. package/dist/components/{script.d.ts → script-instance.d.ts} +11 -7
  46. package/dist/components/{scrollview-component.d.cts → scroll-view-component.d.cts} +7 -1
  47. package/dist/components/{scrollview-component.d.ts → scroll-view-component.d.ts} +7 -1
  48. package/dist/components/scrollbar-component.d.cts +6 -0
  49. package/dist/components/scrollbar-component.d.ts +6 -0
  50. package/dist/components/sound-component.d.cts +7 -1
  51. package/dist/components/sound-component.d.ts +7 -1
  52. package/dist/components/sound-slot.d.cts +5 -2
  53. package/dist/components/sound-slot.d.ts +5 -2
  54. package/dist/custom-elements.json +1852 -974
  55. package/dist/entity-base.d.cts +7 -6
  56. package/dist/entity-base.d.ts +7 -6
  57. package/dist/entity-owner.d.cts +118 -0
  58. package/dist/entity-owner.d.ts +118 -0
  59. package/dist/entity.d.cts +14 -102
  60. package/dist/entity.d.ts +14 -102
  61. package/dist/index.d.cts +26 -22
  62. package/dist/index.d.ts +26 -22
  63. package/dist/material.d.cts +18 -7
  64. package/dist/material.d.ts +18 -7
  65. package/dist/model.d.cts +72 -24
  66. package/dist/model.d.ts +72 -24
  67. package/dist/node.d.cts +6 -1
  68. package/dist/node.d.ts +6 -1
  69. package/dist/pwc.cjs +807 -293
  70. package/dist/pwc.cjs.map +1 -1
  71. package/dist/pwc.js +807 -293
  72. package/dist/pwc.js.map +1 -1
  73. package/dist/pwc.min.js +1 -1
  74. package/dist/pwc.min.js.map +1 -1
  75. package/dist/pwc.min.mjs +1 -1
  76. package/dist/pwc.min.mjs.map +1 -1
  77. package/dist/pwc.mjs +805 -292
  78. package/dist/pwc.mjs.map +1 -1
  79. package/dist/scene.d.cts +3 -0
  80. package/dist/scene.d.ts +3 -0
  81. package/dist/sky.d.cts +4 -0
  82. package/dist/sky.d.ts +4 -0
  83. package/dist/vscode.html-custom-data.json +351 -121
  84. package/dist/{module.d.cts → wasm.d.cts} +10 -6
  85. package/dist/{module.d.ts → wasm.d.ts} +10 -6
  86. package/dist/web-types.json +465 -291
  87. package/package.json +7 -7
  88. package/src/app.ts +49 -35
  89. package/src/asset.ts +13 -4
  90. package/src/async-element.ts +14 -14
  91. package/src/components/anim-clip.ts +4 -0
  92. package/src/components/anim-component.ts +89 -14
  93. package/src/components/audio-listener-component.ts +36 -0
  94. package/src/components/button-component.ts +10 -1
  95. package/src/components/camera-component.ts +65 -6
  96. package/src/components/collision-component.ts +9 -1
  97. package/src/components/component.ts +4 -3
  98. package/src/components/element-component.ts +11 -0
  99. package/src/components/gsplat-component.ts +6 -0
  100. package/src/components/joint-component.ts +14 -2
  101. package/src/components/{layoutchild-component.ts → layout-child-component.ts} +8 -2
  102. package/src/components/{layoutgroup-component.ts → layout-group-component.ts} +8 -2
  103. package/src/components/light-component.ts +110 -17
  104. package/src/components/{particlesystem-component.ts → particle-system-component.ts} +8 -2
  105. package/src/components/render-component.ts +7 -0
  106. package/src/components/{rigidbody-component.ts → rigid-body-component.ts} +9 -2
  107. package/src/components/screen-component.ts +6 -0
  108. package/src/components/script-component.ts +66 -42
  109. package/src/components/{script.ts → script-instance.ts} +18 -14
  110. package/src/components/{scrollview-component.ts → scroll-view-component.ts} +8 -2
  111. package/src/components/scrollbar-component.ts +6 -0
  112. package/src/components/sound-component.ts +8 -2
  113. package/src/components/sound-slot.ts +7 -4
  114. package/src/entity-base.ts +8 -7
  115. package/src/entity-owner.ts +298 -0
  116. package/src/entity.ts +21 -271
  117. package/src/index.ts +38 -25
  118. package/src/material.ts +19 -8
  119. package/src/model.ts +164 -72
  120. package/src/node.ts +15 -6
  121. package/src/scene.ts +3 -0
  122. package/src/sky.ts +4 -0
  123. package/src/{module.ts → wasm.ts} +12 -8
  124. package/dist/components/listener-component.d.cts +0 -20
  125. package/dist/components/listener-component.d.ts +0 -20
  126. package/src/components/listener-component.ts +0 -30
@@ -0,0 +1,298 @@
1
+ import type { AppBase } from 'playcanvas';
2
+ import { Entity, Vec3 } from 'playcanvas';
3
+
4
+ import { EntityBaseElement } from './entity-base';
5
+
6
+ /**
7
+ * Creates and parents the entities of every descendant entity-owning element of `root`, in two
8
+ * passes so that no parent's existence depends on document order. Called wherever a subtree could
9
+ * not build itself: an element inserted into an application that is already running, and a
10
+ * `<pc-node>` whose children waited for it to bind.
11
+ *
12
+ * Descendants that are not yet custom elements are skipped, because there is nothing useful to do
13
+ * for them and reaching for `_createEntity` would throw. A subtree cloned from a `<template>`
14
+ * arrives entirely unupgraded — template content lives in an inert document, where custom element
15
+ * definitions are never looked up — and appending the clone upgrades its elements in tree order,
16
+ * an element before its descendants. So a sweep from an element's own `connectedCallback` sees
17
+ * plain `HTMLElement`s below it. Each becomes an entity-owning element moments later and its own
18
+ * `connectedCallback` creates and parents it, by which time the ancestor it parents under has its
19
+ * entity — the same guarantee tree order gives this sweep.
20
+ *
21
+ * @param root - The element whose descendant entities to build.
22
+ * @param app - The application to create the entities in.
23
+ * @internal
24
+ */
25
+ export const buildDescendantEntities = (root: Element, app: AppBase) => {
26
+ const children = Array.from(root.querySelectorAll('pc-entity, pc-model')).filter(
27
+ (child): child is EntityOwnerElement => child instanceof EntityOwnerElement
28
+ );
29
+ children.forEach((child) => child._createEntity(app));
30
+ children.forEach((child) => child._buildHierarchy(app));
31
+ };
32
+
33
+ /**
34
+ * The base class for elements that create and own their backing entity: `<pc-entity>` and
35
+ * `<pc-model>`, whose host entity carries the same authored properties. It carries the cached
36
+ * property state, entity creation and parenting, and the reset that follows the entity's
37
+ * destruction. `<pc-node>` sits outside this class: it borrows an entity a model instantiated,
38
+ * and its properties are nullable overrides rather than owned values.
39
+ */
40
+ class EntityOwnerElement extends EntityBaseElement {
41
+ /**
42
+ * Whether the entity is enabled.
43
+ */
44
+ private _enabled = true;
45
+
46
+ /**
47
+ * The name of the entity.
48
+ */
49
+ private _name = 'Untitled';
50
+
51
+ /**
52
+ * The position of the entity.
53
+ */
54
+ private _position = new Vec3();
55
+
56
+ /**
57
+ * The rotation of the entity.
58
+ */
59
+ private _rotation = new Vec3();
60
+
61
+ /**
62
+ * The scale of the entity.
63
+ */
64
+ private _scale = new Vec3(1, 1, 1);
65
+
66
+ /**
67
+ * The tags of the entity.
68
+ */
69
+ private _tags: string[] = [];
70
+
71
+ /**
72
+ * Whether the hierarchy has been built for this entity — set once `_buildHierarchy` has
73
+ * parented it. Read by subclasses that gate work on the entity being in the scene graph.
74
+ */
75
+ protected _built = false;
76
+
77
+ /**
78
+ * Creates the backing entity. Called by the containing `<pc-app>` element during its boot
79
+ * sweep, and on connection for elements inserted while the application is already running.
80
+ *
81
+ * @param app - The application to create the entity in.
82
+ * @internal
83
+ */
84
+ _createEntity(app: AppBase) {
85
+ // Guard against double creation. When a subtree is inserted at runtime (e.g. cloning a
86
+ // `<template>`), an ancestor's connectedCallback eagerly creates descendant entities; the
87
+ // descendants' own connectedCallbacks would otherwise create them a second time.
88
+ if (this._entity) {
89
+ return;
90
+ }
91
+
92
+ // Seed from the cached fields rather than re-reading the attributes. Every observed
93
+ // attribute is routed through its property setter by attributeChangedCallback, so the field
94
+ // already holds the parsed attribute value - and it also holds anything assigned through the
95
+ // property API before the app booted, which reading the attribute back would discard.
96
+ const entity = new Entity(this._name, app);
97
+ this._entity = entity;
98
+
99
+ entity.enabled = this._enabled;
100
+ entity.setLocalPosition(this._position);
101
+ entity.setLocalEulerAngles(this._rotation);
102
+ entity.setLocalScale(this._scale);
103
+
104
+ if (this._tags.length > 0) {
105
+ entity.tags.add(this._tags);
106
+ }
107
+
108
+ // Register with the owning application and hook the entity's destruction. The engine
109
+ // fires 'destroy' for every entity in a destroyed subtree, so the element learns of its
110
+ // entity's death no matter who causes it: this element, an ancestor, the whole
111
+ // application, or a user script calling entity.destroy().
112
+ this._registerEntity(entity);
113
+ entity.once('destroy', this._onEntityDestroy, this);
114
+ }
115
+
116
+ /**
117
+ * Handles the destruction of the backing entity. Resets the element so a later re-insertion
118
+ * starts clean: `_built` must be cleared alongside `_entity`, or _buildHierarchy would bail
119
+ * and a re-created entity would never be parented. Readiness is re-armed for the same
120
+ * reason — with the entity gone, a resolved ready promise would resume its awaiters against
121
+ * a null `entity`.
122
+ *
123
+ * @param entity - The entity that was destroyed.
124
+ */
125
+ protected _onEntityDestroy(entity: Entity) {
126
+ this._unregisterEntity(entity);
127
+ this._entity = null;
128
+ this._built = false;
129
+ this._resetReady();
130
+ }
131
+
132
+ /**
133
+ * Parents the backing entity: under the entity of the nearest ancestor `<pc-entity>`,
134
+ * `<pc-model>` or `<pc-node>` when there is one, and under the application root otherwise.
135
+ * Called by the containing `<pc-app>` element once a sweep has created every entity, so a
136
+ * parent's existence never depends on document order.
137
+ *
138
+ * @param app - The application whose root adopts parentless entities.
139
+ * @internal
140
+ */
141
+ _buildHierarchy(app: AppBase) {
142
+ if (!this.entity || this._built) return;
143
+
144
+ const closestEntity = this.closestEntity;
145
+
146
+ // A host element without an entity is an unresolved `<pc-node>`: building now would
147
+ // mis-anchor this entity to the application root while the host is still resolving.
148
+ // Stay unbuilt - the host drives this subtree itself once it binds.
149
+ if (closestEntity && !closestEntity.entity) {
150
+ return;
151
+ }
152
+
153
+ // An owner that exists but is not yet parented is itself deferred behind an unresolved
154
+ // node further up. Building beneath it would announce readiness for an entity that is
155
+ // not in the scene graph; stay unbuilt with it - the node's bind sweeps the whole
156
+ // subtree, ancestors before descendants.
157
+ if (closestEntity instanceof EntityOwnerElement && !closestEntity._built) {
158
+ return;
159
+ }
160
+
161
+ this._built = true;
162
+
163
+ if (closestEntity?.entity) {
164
+ closestEntity.entity.addChild(this.entity);
165
+ } else {
166
+ app.root.addChild(this.entity);
167
+ }
168
+
169
+ this._onBuilt();
170
+ }
171
+
172
+ /**
173
+ * Called by `_buildHierarchy` once the backing entity has been parented — exactly once
174
+ * per build cycle. The default announces readiness, which is what a parented `<pc-entity>`
175
+ * means; `<pc-model>` overrides it to start loading content instead, because its readiness
176
+ * tracks the content settling rather than the host entering the scene graph.
177
+ */
178
+ protected _onBuilt() {
179
+ this._onReady();
180
+ }
181
+
182
+ /**
183
+ * Sets the enabled state of the entity.
184
+ * @param value - Whether the entity is enabled.
185
+ */
186
+ set enabled(value) {
187
+ this._enabled = value;
188
+ if (this.entity) {
189
+ this.entity.enabled = value;
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Gets the enabled state of the entity.
195
+ * @returns Whether the entity is enabled.
196
+ */
197
+ get enabled() {
198
+ return this._enabled;
199
+ }
200
+
201
+ /**
202
+ * Sets the name of the entity.
203
+ * @param value - The name of the entity.
204
+ */
205
+ set name(value) {
206
+ this._name = value;
207
+ if (this.entity) {
208
+ this.entity.name = value;
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Gets the name of the entity.
214
+ * @returns The name of the entity.
215
+ */
216
+ get name() {
217
+ return this._name;
218
+ }
219
+
220
+ /**
221
+ * Sets the position of the entity.
222
+ * @param value - The position of the entity.
223
+ */
224
+ set position(value) {
225
+ this._position = value;
226
+ if (this.entity) {
227
+ this.entity.setLocalPosition(this._position);
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Gets the position of the entity.
233
+ * @returns The position of the entity.
234
+ */
235
+ get position() {
236
+ return this._position;
237
+ }
238
+
239
+ /**
240
+ * Sets the rotation of the entity.
241
+ * @param value - The rotation of the entity.
242
+ */
243
+ set rotation(value) {
244
+ this._rotation = value;
245
+ if (this.entity) {
246
+ this.entity.setLocalEulerAngles(this._rotation);
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Gets the rotation of the entity.
252
+ * @returns The rotation of the entity.
253
+ */
254
+ get rotation() {
255
+ return this._rotation;
256
+ }
257
+
258
+ /**
259
+ * Sets the scale of the entity.
260
+ * @param value - The scale of the entity.
261
+ */
262
+ set scale(value) {
263
+ this._scale = value;
264
+ if (this.entity) {
265
+ this.entity.setLocalScale(this._scale);
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Gets the scale of the entity.
271
+ * @returns The scale of the entity.
272
+ */
273
+ get scale() {
274
+ return this._scale;
275
+ }
276
+
277
+ /**
278
+ * Sets the tags of the entity.
279
+ * @param value - The tags of the entity.
280
+ */
281
+ set tags(value) {
282
+ this._tags = value;
283
+ if (this.entity) {
284
+ this.entity.tags.clear();
285
+ this.entity.tags.add(this._tags);
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Gets the tags of the entity.
291
+ * @returns The tags of the entity.
292
+ */
293
+ get tags() {
294
+ return this._tags;
295
+ }
296
+ }
297
+
298
+ export { EntityOwnerElement };
package/src/entity.ts CHANGED
@@ -1,36 +1,9 @@
1
- import type { AppBase } from 'playcanvas';
2
- import { Entity, Vec3 } from 'playcanvas';
1
+ import { Vec3 } from 'playcanvas';
3
2
 
4
- import { EntityBaseElement, POINTER_ATTRIBUTES } from './entity-base';
3
+ import { POINTER_ATTRIBUTES } from './entity-base';
4
+ import { buildDescendantEntities, EntityOwnerElement } from './entity-owner';
5
5
  import { parseBool, parseTags, parseVec3 } from './parse';
6
6
 
7
- /**
8
- * Creates and parents the entities of every descendant `<pc-entity>` of `root`, in two passes so
9
- * that no parent's existence depends on document order. Called wherever a subtree could not build
10
- * itself: an element inserted into an application that is already running, and a `<pc-node>` whose
11
- * children waited for it to bind.
12
- *
13
- * Descendants that are not yet custom elements are skipped, because there is nothing useful to do
14
- * for them and reaching for `_createEntity` would throw. A subtree cloned from a `<template>`
15
- * arrives entirely unupgraded — template content lives in an inert document, where custom element
16
- * definitions are never looked up — and appending the clone upgrades its elements in tree order,
17
- * an element before its descendants. So a sweep from an element's own `connectedCallback` sees
18
- * plain `HTMLElement`s below it. Each becomes an `EntityElement` moments later and its own
19
- * `connectedCallback` creates and parents it, by which time the ancestor it parents under has its
20
- * entity — the same guarantee tree order gives this sweep.
21
- *
22
- * @param root - The element whose descendant entities to build.
23
- * @param app - The application to create the entities in.
24
- * @internal
25
- */
26
- export const buildDescendantEntities = (root: Element, app: AppBase) => {
27
- const children = Array.from(root.querySelectorAll('pc-entity')).filter(
28
- (child): child is EntityElement => child instanceof EntityElement
29
- );
30
- children.forEach((child) => child._createEntity(app));
31
- children.forEach((child) => child._buildHierarchy(app));
32
- };
33
-
34
7
  /**
35
8
  * The EntityElement interface provides properties and methods for manipulating
36
9
  * {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-entity/ | `<pc-entity>`} elements.
@@ -39,9 +12,20 @@ export const buildDescendantEntities = (root: Element, app: AppBase) => {
39
12
  *
40
13
  * The pointer events below are dispatched by the containing `<pc-app>` element when the pointer
41
14
  * intersects this entity's geometry. They are only generated while the entity has a listener for
42
- * them, registered either with {@link addEventListener} or with the matching inline `onpointer*`
15
+ * them, registered either with {@link EventTarget.addEventListener} or with the matching inline `onpointer*`
43
16
  * attribute.
44
17
  *
18
+ * @elementSummary The `<pc-entity>` element creates an entity: a named, transformable node of the
19
+ * scene hierarchy, and the host for component elements such as `<pc-camera>`, `<pc-light>` and
20
+ * `<pc-render>`. Place it in the `<pc-scene>`, or nest it under another `<pc-entity>`, a
21
+ * `<pc-model>` or a `<pc-node>` to parent it there.
22
+ *
23
+ * @attribute {boolean} enabled - The enabled state of the entity.
24
+ * @attribute {string} name - The name of the entity.
25
+ * @attribute {string} position - The position of the entity.
26
+ * @attribute {string} rotation - The rotation of the entity.
27
+ * @attribute {string} scale - The scale of the entity.
28
+ * @attribute {string} tags - The tags of the entity.
45
29
  * @attribute {string} onpointerenter - Script to run when the pointer moves onto the entity.
46
30
  * @attribute {string} onpointerleave - Script to run when the pointer moves off the entity.
47
31
  * @attribute {string} onpointermove - Script to run when the pointer moves over the entity.
@@ -55,129 +39,7 @@ export const buildDescendantEntities = (root: Element, app: AppBase) => {
55
39
  * @fires {PointerEvent} pointerdown - Fired when a pointer button is pressed over the entity.
56
40
  * @fires {PointerEvent} pointerup - Fired when a pointer button is released over the entity.
57
41
  */
58
- class EntityElement extends EntityBaseElement {
59
- /**
60
- * Whether the entity is enabled.
61
- */
62
- private _enabled = true;
63
-
64
- /**
65
- * The name of the entity.
66
- */
67
- private _name = 'Untitled';
68
-
69
- /**
70
- * The position of the entity.
71
- */
72
- private _position = new Vec3();
73
-
74
- /**
75
- * The rotation of the entity.
76
- */
77
- private _rotation = new Vec3();
78
-
79
- /**
80
- * The scale of the entity.
81
- */
82
- private _scale = new Vec3(1, 1, 1);
83
-
84
- /**
85
- * The tags of the entity.
86
- */
87
- private _tags: string[] = [];
88
-
89
- /**
90
- * Whether the hierarchy has been built for this entity.
91
- */
92
- private _built = false;
93
-
94
- /**
95
- * Creates the backing entity. Called by the containing `<pc-app>` element during its boot
96
- * sweep, and on connection for elements inserted while the application is already running.
97
- *
98
- * @param app - The application to create the entity in.
99
- * @internal
100
- */
101
- _createEntity(app: AppBase) {
102
- // Guard against double creation. When a subtree is inserted at runtime (e.g. cloning a
103
- // `<template>`), an ancestor's connectedCallback eagerly creates descendant entities; the
104
- // descendants' own connectedCallbacks would otherwise create them a second time.
105
- if (this._entity) {
106
- return;
107
- }
108
-
109
- // Seed from the cached fields rather than re-reading the attributes. Every observed
110
- // attribute is routed through its property setter by attributeChangedCallback, so the field
111
- // already holds the parsed attribute value - and it also holds anything assigned through the
112
- // property API before the app booted, which reading the attribute back would discard.
113
- const entity = new Entity(this._name, app);
114
- this._entity = entity;
115
-
116
- entity.enabled = this._enabled;
117
- entity.setLocalPosition(this._position);
118
- entity.setLocalEulerAngles(this._rotation);
119
- entity.setLocalScale(this._scale);
120
-
121
- if (this._tags.length > 0) {
122
- entity.tags.add(this._tags);
123
- }
124
-
125
- // Register with the owning application and hook the entity's destruction. The engine
126
- // fires 'destroy' for every entity in a destroyed subtree, so the element learns of its
127
- // entity's death no matter who causes it: this element, an ancestor, the whole
128
- // application, or a user script calling entity.destroy().
129
- this._registerEntity(entity);
130
- entity.once('destroy', this._onEntityDestroy, this);
131
- }
132
-
133
- /**
134
- * Handles the destruction of the backing entity. Resets the element so a later re-insertion
135
- * starts clean: `_built` must be cleared alongside `_entity`, or _buildHierarchy would bail
136
- * and a re-created entity would never be parented. Readiness is re-armed for the same
137
- * reason — with the entity gone, a resolved ready promise would resume its awaiters against
138
- * a null `entity`.
139
- *
140
- * @param entity - The entity that was destroyed.
141
- */
142
- private _onEntityDestroy(entity: Entity) {
143
- this._unregisterEntity(entity);
144
- this._entity = null;
145
- this._built = false;
146
- this._resetReady();
147
- }
148
-
149
- /**
150
- * Parents the backing entity: under the entity of the nearest ancestor `<pc-entity>` or
151
- * `<pc-node>` when there is one, and under the application root otherwise. Called by the
152
- * containing `<pc-app>` element once a sweep has created every entity, so a parent's
153
- * existence never depends on document order.
154
- *
155
- * @param app - The application whose root adopts parentless entities.
156
- * @internal
157
- */
158
- _buildHierarchy(app: AppBase) {
159
- if (!this.entity || this._built) return;
160
-
161
- const closestEntity = this.closestEntity;
162
-
163
- // A host element without an entity is an unresolved `<pc-node>`: building now would
164
- // mis-anchor this entity to the application root while the host is still resolving.
165
- // Stay unbuilt - the host drives this subtree itself once it binds.
166
- if (closestEntity && !closestEntity.entity) {
167
- return;
168
- }
169
-
170
- this._built = true;
171
-
172
- if (closestEntity?.entity) {
173
- closestEntity.entity.addChild(this.entity);
174
- } else {
175
- app.root.addChild(this.entity);
176
- }
177
-
178
- this._onReady();
179
- }
180
-
42
+ class EntityElement extends EntityOwnerElement {
181
43
  connectedCallback() {
182
44
  // Wait for app to be ready
183
45
  const closestApp = this.closestApp;
@@ -198,8 +60,11 @@ class EntityElement extends EntityBaseElement {
198
60
  this._createEntity(app);
199
61
  this._buildHierarchy(app);
200
62
 
201
- // Handle any child entities that might exist
202
- buildDescendantEntities(this, app);
63
+ // Handle any child entities that might exist. A build that deferred (an unresolved
64
+ // pc-node above) defers the whole subtree with it - the node's bind sweeps it.
65
+ if (this._built) {
66
+ buildDescendantEntities(this, app);
67
+ }
203
68
  }
204
69
  }
205
70
 
@@ -211,121 +76,6 @@ class EntityElement extends EntityBaseElement {
211
76
  this._entity?.destroy();
212
77
  }
213
78
 
214
- /**
215
- * Sets the enabled state of the entity.
216
- * @param value - Whether the entity is enabled.
217
- */
218
- set enabled(value) {
219
- this._enabled = value;
220
- if (this.entity) {
221
- this.entity.enabled = value;
222
- }
223
- }
224
-
225
- /**
226
- * Gets the enabled state of the entity.
227
- * @returns Whether the entity is enabled.
228
- */
229
- get enabled() {
230
- return this._enabled;
231
- }
232
-
233
- /**
234
- * Sets the name of the entity.
235
- * @param value - The name of the entity.
236
- */
237
- set name(value) {
238
- this._name = value;
239
- if (this.entity) {
240
- this.entity.name = value;
241
- }
242
- }
243
-
244
- /**
245
- * Gets the name of the entity.
246
- * @returns The name of the entity.
247
- */
248
- get name() {
249
- return this._name;
250
- }
251
-
252
- /**
253
- * Sets the position of the entity.
254
- * @param value - The position of the entity.
255
- */
256
- set position(value) {
257
- this._position = value;
258
- if (this.entity) {
259
- this.entity.setLocalPosition(this._position);
260
- }
261
- }
262
-
263
- /**
264
- * Gets the position of the entity.
265
- * @returns The position of the entity.
266
- */
267
- get position() {
268
- return this._position;
269
- }
270
-
271
- /**
272
- * Sets the rotation of the entity.
273
- * @param value - The rotation of the entity.
274
- */
275
- set rotation(value) {
276
- this._rotation = value;
277
- if (this.entity) {
278
- this.entity.setLocalEulerAngles(this._rotation);
279
- }
280
- }
281
-
282
- /**
283
- * Gets the rotation of the entity.
284
- * @returns The rotation of the entity.
285
- */
286
- get rotation() {
287
- return this._rotation;
288
- }
289
-
290
- /**
291
- * Sets the scale of the entity.
292
- * @param value - The scale of the entity.
293
- */
294
- set scale(value) {
295
- this._scale = value;
296
- if (this.entity) {
297
- this.entity.setLocalScale(this._scale);
298
- }
299
- }
300
-
301
- /**
302
- * Gets the scale of the entity.
303
- * @returns The scale of the entity.
304
- */
305
- get scale() {
306
- return this._scale;
307
- }
308
-
309
- /**
310
- * Sets the tags of the entity.
311
- * @param value - The tags of the entity.
312
- */
313
- set tags(value) {
314
- this._tags = value;
315
- if (this.entity) {
316
- this.entity.tags.clear();
317
- this.entity.tags.add(this._tags);
318
- }
319
- }
320
-
321
- /**
322
- * Gets the tags of the entity.
323
- * @returns The tags of the entity.
324
- */
325
- get tags() {
326
- return this._tags;
327
- }
328
-
329
79
  static get observedAttributes() {
330
80
  return ['enabled', 'name', 'position', 'rotation', 'scale', 'tags', ...POINTER_ATTRIBUTES];
331
81
  }