@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.
- package/README.md +5 -3
- package/dist/app.d.cts +18 -13
- package/dist/app.d.ts +18 -13
- package/dist/asset.d.cts +13 -3
- package/dist/asset.d.ts +13 -3
- package/dist/async-element.d.cts +13 -13
- package/dist/async-element.d.ts +13 -13
- package/dist/components/anim-clip.d.cts +4 -0
- package/dist/components/anim-clip.d.ts +4 -0
- package/dist/components/anim-component.d.cts +38 -5
- package/dist/components/anim-component.d.ts +38 -5
- package/dist/components/audio-listener-component.d.cts +26 -0
- package/dist/components/audio-listener-component.d.ts +26 -0
- package/dist/components/button-component.d.cts +10 -1
- package/dist/components/button-component.d.ts +10 -1
- package/dist/components/camera-component.d.cts +37 -1
- package/dist/components/camera-component.d.ts +37 -1
- package/dist/components/collision-component.d.cts +9 -1
- package/dist/components/collision-component.d.ts +9 -1
- package/dist/components/component.d.cts +3 -2
- package/dist/components/component.d.ts +3 -2
- package/dist/components/element-component.d.cts +11 -0
- package/dist/components/element-component.d.ts +11 -0
- package/dist/components/gsplat-component.d.cts +6 -0
- package/dist/components/gsplat-component.d.ts +6 -0
- package/dist/components/joint-component.d.cts +14 -2
- package/dist/components/joint-component.d.ts +14 -2
- package/dist/components/{layoutchild-component.d.cts → layout-child-component.d.cts} +7 -1
- package/dist/components/{layoutchild-component.d.ts → layout-child-component.d.ts} +7 -1
- package/dist/components/{layoutgroup-component.d.cts → layout-group-component.d.cts} +7 -1
- package/dist/components/{layoutgroup-component.d.ts → layout-group-component.d.ts} +7 -1
- package/dist/components/light-component.d.cts +52 -1
- package/dist/components/light-component.d.ts +52 -1
- package/dist/components/{particlesystem-component.d.cts → particle-system-component.d.cts} +7 -1
- package/dist/components/{particlesystem-component.d.ts → particle-system-component.d.ts} +7 -1
- package/dist/components/render-component.d.cts +7 -0
- package/dist/components/render-component.d.ts +7 -0
- package/dist/components/{rigidbody-component.d.cts → rigid-body-component.d.cts} +8 -1
- package/dist/components/{rigidbody-component.d.ts → rigid-body-component.d.ts} +8 -1
- package/dist/components/screen-component.d.cts +6 -0
- package/dist/components/screen-component.d.ts +6 -0
- package/dist/components/script-component.d.cts +26 -12
- package/dist/components/script-component.d.ts +26 -12
- package/dist/components/{script.d.cts → script-instance.d.cts} +11 -7
- package/dist/components/{script.d.ts → script-instance.d.ts} +11 -7
- package/dist/components/{scrollview-component.d.cts → scroll-view-component.d.cts} +7 -1
- package/dist/components/{scrollview-component.d.ts → scroll-view-component.d.ts} +7 -1
- package/dist/components/scrollbar-component.d.cts +6 -0
- package/dist/components/scrollbar-component.d.ts +6 -0
- package/dist/components/sound-component.d.cts +7 -1
- package/dist/components/sound-component.d.ts +7 -1
- package/dist/components/sound-slot.d.cts +5 -2
- package/dist/components/sound-slot.d.ts +5 -2
- package/dist/custom-elements.json +1852 -974
- package/dist/entity-base.d.cts +7 -6
- package/dist/entity-base.d.ts +7 -6
- package/dist/entity-owner.d.cts +118 -0
- package/dist/entity-owner.d.ts +118 -0
- package/dist/entity.d.cts +14 -102
- package/dist/entity.d.ts +14 -102
- package/dist/index.d.cts +26 -22
- package/dist/index.d.ts +26 -22
- package/dist/material.d.cts +18 -7
- package/dist/material.d.ts +18 -7
- package/dist/model.d.cts +72 -24
- package/dist/model.d.ts +72 -24
- package/dist/node.d.cts +6 -1
- package/dist/node.d.ts +6 -1
- package/dist/pwc.cjs +807 -293
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +807 -293
- package/dist/pwc.js.map +1 -1
- package/dist/pwc.min.js +1 -1
- package/dist/pwc.min.js.map +1 -1
- package/dist/pwc.min.mjs +1 -1
- package/dist/pwc.min.mjs.map +1 -1
- package/dist/pwc.mjs +805 -292
- package/dist/pwc.mjs.map +1 -1
- package/dist/scene.d.cts +3 -0
- package/dist/scene.d.ts +3 -0
- package/dist/sky.d.cts +4 -0
- package/dist/sky.d.ts +4 -0
- package/dist/vscode.html-custom-data.json +351 -121
- package/dist/{module.d.cts → wasm.d.cts} +10 -6
- package/dist/{module.d.ts → wasm.d.ts} +10 -6
- package/dist/web-types.json +465 -291
- package/package.json +7 -7
- package/src/app.ts +49 -35
- package/src/asset.ts +13 -4
- package/src/async-element.ts +14 -14
- package/src/components/anim-clip.ts +4 -0
- package/src/components/anim-component.ts +89 -14
- package/src/components/audio-listener-component.ts +36 -0
- package/src/components/button-component.ts +10 -1
- package/src/components/camera-component.ts +65 -6
- package/src/components/collision-component.ts +9 -1
- package/src/components/component.ts +4 -3
- package/src/components/element-component.ts +11 -0
- package/src/components/gsplat-component.ts +6 -0
- package/src/components/joint-component.ts +14 -2
- package/src/components/{layoutchild-component.ts → layout-child-component.ts} +8 -2
- package/src/components/{layoutgroup-component.ts → layout-group-component.ts} +8 -2
- package/src/components/light-component.ts +110 -17
- package/src/components/{particlesystem-component.ts → particle-system-component.ts} +8 -2
- package/src/components/render-component.ts +7 -0
- package/src/components/{rigidbody-component.ts → rigid-body-component.ts} +9 -2
- package/src/components/screen-component.ts +6 -0
- package/src/components/script-component.ts +66 -42
- package/src/components/{script.ts → script-instance.ts} +18 -14
- package/src/components/{scrollview-component.ts → scroll-view-component.ts} +8 -2
- package/src/components/scrollbar-component.ts +6 -0
- package/src/components/sound-component.ts +8 -2
- package/src/components/sound-slot.ts +7 -4
- package/src/entity-base.ts +8 -7
- package/src/entity-owner.ts +298 -0
- package/src/entity.ts +21 -271
- package/src/index.ts +38 -25
- package/src/material.ts +19 -8
- package/src/model.ts +164 -72
- package/src/node.ts +15 -6
- package/src/scene.ts +3 -0
- package/src/sky.ts +4 -0
- package/src/{module.ts → wasm.ts} +12 -8
- package/dist/components/listener-component.d.cts +0 -20
- package/dist/components/listener-component.d.ts +0 -20
- package/src/components/listener-component.ts +0 -30
package/dist/pwc.js
CHANGED
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
return this.parentElement?.closest('pc-app') ?? null;
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
|
-
* The nearest ancestor element that fronts an entity — `<pc-entity
|
|
35
|
-
* `null` if this element has no such ancestor. The search starts at the
|
|
36
|
-
* never resolves to itself.
|
|
34
|
+
* The nearest ancestor element that fronts an entity — `<pc-entity>`, `<pc-model>` or
|
|
35
|
+
* `<pc-node>` — or `null` if this element has no such ancestor. The search starts at the
|
|
36
|
+
* parent, so an element never resolves to itself.
|
|
37
37
|
* @returns The closest entity-fronting element, or `null`.
|
|
38
38
|
*/
|
|
39
39
|
get closestEntity() {
|
|
40
|
-
return this.parentElement?.closest('pc-entity, pc-node') ?? null;
|
|
40
|
+
return this.parentElement?.closest('pc-entity, pc-model, pc-node') ?? null;
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
43
|
* Called when the element is fully initialized and ready. Subclasses should call this when
|
|
@@ -111,9 +111,9 @@
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
|
-
* The
|
|
115
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
116
|
-
* elements. The
|
|
114
|
+
* The WasmElement interface provides properties and methods for manipulating
|
|
115
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-wasm/ | `<pc-wasm>`}
|
|
116
|
+
* elements. The WasmElement interface also inherits the properties and methods of the
|
|
117
117
|
* {@link AsyncElement} interface.
|
|
118
118
|
*
|
|
119
119
|
* The attributes are read once, when the module starts loading - on the element's first
|
|
@@ -122,9 +122,13 @@
|
|
|
122
122
|
* modules configure engine-global state that never unloads, so readiness is not re-armed by
|
|
123
123
|
* removing the element, and a re-inserted element does not load again.
|
|
124
124
|
*
|
|
125
|
-
* A `<pc-
|
|
125
|
+
* A `<pc-wasm>` without a `name` warns and never becomes ready; a containing `<pc-app>` still
|
|
126
126
|
* boots.
|
|
127
127
|
*
|
|
128
|
+
* @elementSummary The `<pc-wasm>` element loads a WebAssembly module the engine needs before the
|
|
129
|
+
* application starts — `Ammo` for physics, `Basis` or `DracoDecoderModule` for compressed assets.
|
|
130
|
+
* Must be a direct child of `<pc-app>`.
|
|
131
|
+
*
|
|
128
132
|
* @attribute {string} name - The name of the WebAssembly module to configure, e.g. `Basis` or
|
|
129
133
|
* `Ammo`.
|
|
130
134
|
* @attribute {string} glue - The URL of the module's glue script.
|
|
@@ -132,7 +136,7 @@
|
|
|
132
136
|
* @attribute {string} fallback - The URL of the module's asm.js fallback script, used when
|
|
133
137
|
* WebAssembly is unavailable.
|
|
134
138
|
*/
|
|
135
|
-
class
|
|
139
|
+
class WasmElement extends AsyncElement {
|
|
136
140
|
_loadPromise = null;
|
|
137
141
|
connectedCallback() {
|
|
138
142
|
this._getLoadPromise();
|
|
@@ -140,7 +144,7 @@
|
|
|
140
144
|
async _loadModule() {
|
|
141
145
|
const name = this.getAttribute('name');
|
|
142
146
|
if (!name) {
|
|
143
|
-
console.warn("pc-
|
|
147
|
+
console.warn("pc-wasm requires a 'name' attribute - no module was configured");
|
|
144
148
|
return;
|
|
145
149
|
}
|
|
146
150
|
const config = {
|
|
@@ -175,7 +179,7 @@
|
|
|
175
179
|
return this._loadPromise;
|
|
176
180
|
}
|
|
177
181
|
}
|
|
178
|
-
customElements.define('pc-
|
|
182
|
+
customElements.define('pc-wasm', WasmElement);
|
|
179
183
|
|
|
180
184
|
/** Covers the 0.2s opacity transition; jsdom never fires transitionend, so removal is timed. */
|
|
181
185
|
const REMOVAL_DELAY_MS = 250;
|
|
@@ -732,6 +736,12 @@
|
|
|
732
736
|
|
|
733
737
|
/** The pointer event types the application synthesizes on `<pc-entity>` elements via picking. */
|
|
734
738
|
const pointerEventTypes = ['pointermove', 'pointerdown', 'pointerup', 'pointerenter', 'pointerleave'];
|
|
739
|
+
/**
|
|
740
|
+
* The event types whose listeners make an element a hover target. Hover resolution walks past
|
|
741
|
+
* elements listening for none of them, so a silent element never swallows an ancestor's
|
|
742
|
+
* enter/leave pair.
|
|
743
|
+
*/
|
|
744
|
+
const hoverEventTypes = ['pointerenter', 'pointerleave', 'pointermove'];
|
|
735
745
|
/**
|
|
736
746
|
* Gives `pc-app` the sizing contract of a replaced element (`<video>`, `<img>`): a block-level
|
|
737
747
|
* box that the page's CSS sizes, defaulting to the canvas's own 300x150 intrinsic size, with the
|
|
@@ -760,6 +770,10 @@
|
|
|
760
770
|
* tracked live via a ResizeObserver — so the element can be embedded at any size, resized by
|
|
761
771
|
* its container, or made fullscreen with ordinary CSS such as `width: 100vw; height: 100dvh`.
|
|
762
772
|
*
|
|
773
|
+
* @elementSummary The `<pc-app>` element creates a PlayCanvas application and the canvas it renders
|
|
774
|
+
* into, and is the root of every scene. It holds the `<pc-asset>`, `<pc-material>`, `<pc-wasm>` and
|
|
775
|
+
* `<pc-scene>` elements, and the page's CSS sizes it, as it would a `<video>`.
|
|
776
|
+
*
|
|
763
777
|
* @fires {ProgressEvent} progress - Fired while the application preloads its assets. `loaded` and
|
|
764
778
|
* `total` are asset counts, not bytes, and an asset that fails to load still counts as loaded.
|
|
765
779
|
* Fired at least once per boot, and the final event always has `loaded` equal to `total`. Does
|
|
@@ -806,9 +820,9 @@
|
|
|
806
820
|
_bootGeneration = 0;
|
|
807
821
|
/**
|
|
808
822
|
* The elements backing this application's entities, keyed by the entity itself. Registered
|
|
809
|
-
* by
|
|
810
|
-
*
|
|
811
|
-
* identity - never by name.
|
|
823
|
+
* by entity-owning elements at creation (pc-entity, and pc-model for its host) and by
|
|
824
|
+
* NodeElement at binding, and removed when an entity is destroyed or unbound, this joins
|
|
825
|
+
* engine scene nodes back to their owning elements by identity - never by name.
|
|
812
826
|
*/
|
|
813
827
|
_entityElements = new Map();
|
|
814
828
|
_picker = null;
|
|
@@ -887,7 +901,7 @@
|
|
|
887
901
|
// there, leaving the element permanently unready: no canvas, no entities, no application.
|
|
888
902
|
//
|
|
889
903
|
// Upgrading is the fix here rather than skipping whatever has not upgraded, because a
|
|
890
|
-
// <pc-
|
|
904
|
+
// <pc-wasm> is the one child that nothing else ever builds on its own behalf - skipping
|
|
891
905
|
// it would drop the wasm module the app asked for, silently and only for cloned apps.
|
|
892
906
|
// Upgrading runs each descendant's connectedCallback synchronously, a few lines earlier
|
|
893
907
|
// than the parser's path runs them but into the same state they see there: no application
|
|
@@ -896,10 +910,10 @@
|
|
|
896
910
|
// as any other disconnect is. An already-upgraded subtree - every other insertion path -
|
|
897
911
|
// is left completely untouched.
|
|
898
912
|
customElements.upgrade(this);
|
|
899
|
-
// Get all pc-
|
|
900
|
-
const
|
|
913
|
+
// Get all pc-wasm elements that are direct children of the pc-app element
|
|
914
|
+
const wasmElements = this.querySelectorAll(':scope > pc-wasm');
|
|
901
915
|
// Wait for all modules to load
|
|
902
|
-
await Promise.all(Array.from(
|
|
916
|
+
await Promise.all(Array.from(wasmElements).map((element) => element._getLoadPromise()));
|
|
903
917
|
// The element may have been removed while the modules loaded. Nothing beyond the loading
|
|
904
918
|
// bar exists yet, and disconnectedCallback has already destroyed that.
|
|
905
919
|
if (generation !== this._bootGeneration) {
|
|
@@ -1069,14 +1083,15 @@
|
|
|
1069
1083
|
Array.from(materialElements).forEach((materialElement) => {
|
|
1070
1084
|
materialElement._createMaterial();
|
|
1071
1085
|
});
|
|
1072
|
-
// Create all entities
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1086
|
+
// Create all entities. pc-model joins the sweep because it owns a host entity of its
|
|
1087
|
+
// own; its instantiated content arrives later, beneath that host.
|
|
1088
|
+
const ownerElements = this.querySelectorAll('pc-entity, pc-model');
|
|
1089
|
+
Array.from(ownerElements).forEach((ownerElement) => {
|
|
1090
|
+
ownerElement._createEntity(app);
|
|
1076
1091
|
});
|
|
1077
1092
|
// Build hierarchy
|
|
1078
|
-
|
|
1079
|
-
|
|
1093
|
+
ownerElements.forEach((ownerElement) => {
|
|
1094
|
+
ownerElement._buildHierarchy(app);
|
|
1080
1095
|
});
|
|
1081
1096
|
// Building the hierarchy dispatched each entity's ready event synchronously, and a
|
|
1082
1097
|
// listener may have removed the element. The sweep itself degrades safely - destroying
|
|
@@ -1187,7 +1202,7 @@
|
|
|
1187
1202
|
// created from onpointer* attributes when their elements were first upgraded, or
|
|
1188
1203
|
// listeners carried over from before a re-boot)
|
|
1189
1204
|
pointerEventTypes.forEach((type) => {
|
|
1190
|
-
const anyListeners = Array.from(this.querySelectorAll('pc-entity, pc-node')).some((entity) => entity._hasListeners(type));
|
|
1205
|
+
const anyListeners = Array.from(this.querySelectorAll('pc-entity, pc-model, pc-node')).some((entity) => entity._hasListeners(type));
|
|
1191
1206
|
if (anyListeners) {
|
|
1192
1207
|
this._onPointerListenerAdded(type);
|
|
1193
1208
|
}
|
|
@@ -1237,10 +1252,10 @@
|
|
|
1237
1252
|
this._entityElements.delete(entity);
|
|
1238
1253
|
}
|
|
1239
1254
|
/**
|
|
1240
|
-
* Returns the `<pc-entity>` or `<pc-node>` element whose backing entity is
|
|
1241
|
-
* `null` if the entity is not fronted by an element of this application - for
|
|
1242
|
-
* unbound node inside a model's instantiated hierarchy, or an entity created
|
|
1243
|
-
* engine API.
|
|
1255
|
+
* Returns the `<pc-entity>`, `<pc-model>` or `<pc-node>` element whose backing entity is
|
|
1256
|
+
* `entity`, or `null` if the entity is not fronted by an element of this application - for
|
|
1257
|
+
* example, an unbound node inside a model's instantiated hierarchy, or an entity created
|
|
1258
|
+
* through the engine API.
|
|
1244
1259
|
*
|
|
1245
1260
|
* @param entity - The entity to look up.
|
|
1246
1261
|
* @returns The element fronting the entity, or `null`.
|
|
@@ -1249,18 +1264,19 @@
|
|
|
1249
1264
|
return this._entityElements.get(entity) ?? null;
|
|
1250
1265
|
}
|
|
1251
1266
|
/**
|
|
1252
|
-
* Resolves the element that owns a picked node: the nearest node up the parent
|
|
1253
|
-
* starting with the node itself -
|
|
1254
|
-
*
|
|
1255
|
-
*
|
|
1267
|
+
* Resolves the element that owns hover for a picked node: the nearest node up the parent
|
|
1268
|
+
* chain - starting with the node itself - whose element listens for any of the hover event
|
|
1269
|
+
* types. Skipping silent elements matches {@link _elementWithListener}, so a registered
|
|
1270
|
+
* element with no hover listeners (a `<pc-model>` host, a plain child entity) is transparent
|
|
1271
|
+
* to hover rather than swallowing a listening ancestor's enter/leave pair.
|
|
1256
1272
|
*
|
|
1257
1273
|
* @param node - The picked node, or `null`.
|
|
1258
|
-
* @returns The owning element, or `null`.
|
|
1274
|
+
* @returns The hover-owning element, or `null`.
|
|
1259
1275
|
*/
|
|
1260
|
-
|
|
1276
|
+
_hoverTarget(node) {
|
|
1261
1277
|
while (node !== null) {
|
|
1262
1278
|
const element = this._entityElements.get(node);
|
|
1263
|
-
if (element) {
|
|
1279
|
+
if (element && hoverEventTypes.some((type) => element._hasListeners(type))) {
|
|
1264
1280
|
return element;
|
|
1265
1281
|
}
|
|
1266
1282
|
node = node.parent;
|
|
@@ -1396,9 +1412,10 @@
|
|
|
1396
1412
|
const node = await this._pickNode(event);
|
|
1397
1413
|
if (token !== this._pickToken || !this._picker)
|
|
1398
1414
|
return;
|
|
1399
|
-
// The hovered element is the nearest one up the node's parent chain
|
|
1400
|
-
//
|
|
1401
|
-
|
|
1415
|
+
// The hovered element is the nearest one up the node's parent chain with a hover
|
|
1416
|
+
// listener - the nearest-listener rule down/up use. Dispatch is still gated per event
|
|
1417
|
+
// type below: having any hover listener selects the target, each event needs its own.
|
|
1418
|
+
const newHoverEntity = this._hoverTarget(node);
|
|
1402
1419
|
// Handle enter/leave events
|
|
1403
1420
|
if (this._hoveredEntity !== newHoverEntity) {
|
|
1404
1421
|
if (this._hoveredEntity && this._hoveredEntity._hasListeners('pointerleave')) {
|
|
@@ -1450,7 +1467,7 @@
|
|
|
1450
1467
|
}
|
|
1451
1468
|
}
|
|
1452
1469
|
_onPointerListenerRemoved(type) {
|
|
1453
|
-
const hasListeners = Array.from(this.querySelectorAll('pc-entity, pc-node')).some((entity) => entity._hasListeners(type));
|
|
1470
|
+
const hasListeners = Array.from(this.querySelectorAll('pc-entity, pc-model, pc-node')).some((entity) => entity._hasListeners(type));
|
|
1454
1471
|
if (!hasListeners && this._canvas) {
|
|
1455
1472
|
this._hasPointerListeners[type] = false;
|
|
1456
1473
|
const handler = type === 'pointerenter' || type === 'pointerleave'
|
|
@@ -1641,11 +1658,12 @@
|
|
|
1641
1658
|
'onpointermove'
|
|
1642
1659
|
];
|
|
1643
1660
|
/**
|
|
1644
|
-
* The base class for elements that front an engine {@link Entity}: `<pc-entity
|
|
1645
|
-
* one, and `<pc-node>`, which binds to one inside a model's
|
|
1646
|
-
* what
|
|
1647
|
-
* picked scene nodes back to elements by identity,
|
|
1648
|
-
* bookkeeping that lets the application lazily attach
|
|
1661
|
+
* The base class for elements that front an engine {@link Entity}: `<pc-entity>` and
|
|
1662
|
+
* `<pc-model>`, which create one, and `<pc-node>`, which binds to one inside a model's
|
|
1663
|
+
* instantiated hierarchy. It carries what all of them need — the `entity` contract, registration
|
|
1664
|
+
* with the owning application (which joins picked scene nodes back to elements by identity,
|
|
1665
|
+
* never by name), and the pointer listener bookkeeping that lets the application lazily attach
|
|
1666
|
+
* its canvas handlers.
|
|
1649
1667
|
*/
|
|
1650
1668
|
class EntityBaseElement extends AsyncElement {
|
|
1651
1669
|
_entity = null;
|
|
@@ -1694,7 +1712,7 @@
|
|
|
1694
1712
|
* Tracks whether an inline `onpointer*` attribute is present. The browser itself compiles and
|
|
1695
1713
|
* runs these attributes — they are standard `GlobalEventHandlers`, so setting one replaces
|
|
1696
1714
|
* the previous handler and removing it removes the handler, exactly like `onclick` on any
|
|
1697
|
-
* HTML element. But because they bypass {@link addEventListener}, the connect/disconnect
|
|
1715
|
+
* HTML element. But because they bypass {@link EventTarget.addEventListener}, the connect/disconnect
|
|
1698
1716
|
* bookkeeping that lets the application lazily attach its canvas pointer handlers must be
|
|
1699
1717
|
* kept in sync here.
|
|
1700
1718
|
*
|
|
@@ -1735,7 +1753,7 @@
|
|
|
1735
1753
|
}
|
|
1736
1754
|
/**
|
|
1737
1755
|
* Whether the element has a listener for an event type, registered either with
|
|
1738
|
-
* {@link addEventListener} or with the matching inline `onpointer*` attribute. Read by the
|
|
1756
|
+
* {@link EventTarget.addEventListener} or with the matching inline `onpointer*` attribute. Read by the
|
|
1739
1757
|
* containing `<pc-app>` element to gate pointer event synthesis.
|
|
1740
1758
|
*
|
|
1741
1759
|
* @param type - The event type.
|
|
@@ -1748,17 +1766,17 @@
|
|
|
1748
1766
|
}
|
|
1749
1767
|
|
|
1750
1768
|
/**
|
|
1751
|
-
* Creates and parents the entities of every descendant
|
|
1752
|
-
* that no parent's existence depends on document order. Called wherever a subtree could
|
|
1753
|
-
* itself: an element inserted into an application that is already running, and a
|
|
1754
|
-
* children waited for it to bind.
|
|
1769
|
+
* Creates and parents the entities of every descendant entity-owning element of `root`, in two
|
|
1770
|
+
* passes so that no parent's existence depends on document order. Called wherever a subtree could
|
|
1771
|
+
* not build itself: an element inserted into an application that is already running, and a
|
|
1772
|
+
* `<pc-node>` whose children waited for it to bind.
|
|
1755
1773
|
*
|
|
1756
1774
|
* Descendants that are not yet custom elements are skipped, because there is nothing useful to do
|
|
1757
1775
|
* for them and reaching for `_createEntity` would throw. A subtree cloned from a `<template>`
|
|
1758
1776
|
* arrives entirely unupgraded — template content lives in an inert document, where custom element
|
|
1759
1777
|
* definitions are never looked up — and appending the clone upgrades its elements in tree order,
|
|
1760
1778
|
* an element before its descendants. So a sweep from an element's own `connectedCallback` sees
|
|
1761
|
-
* plain `HTMLElement`s below it. Each becomes an
|
|
1779
|
+
* plain `HTMLElement`s below it. Each becomes an entity-owning element moments later and its own
|
|
1762
1780
|
* `connectedCallback` creates and parents it, by which time the ancestor it parents under has its
|
|
1763
1781
|
* entity — the same guarantee tree order gives this sweep.
|
|
1764
1782
|
*
|
|
@@ -1767,35 +1785,18 @@
|
|
|
1767
1785
|
* @internal
|
|
1768
1786
|
*/
|
|
1769
1787
|
const buildDescendantEntities = (root, app) => {
|
|
1770
|
-
const children = Array.from(root.querySelectorAll('pc-entity')).filter((child) => child instanceof
|
|
1788
|
+
const children = Array.from(root.querySelectorAll('pc-entity, pc-model')).filter((child) => child instanceof EntityOwnerElement);
|
|
1771
1789
|
children.forEach((child) => child._createEntity(app));
|
|
1772
1790
|
children.forEach((child) => child._buildHierarchy(app));
|
|
1773
1791
|
};
|
|
1774
1792
|
/**
|
|
1775
|
-
* The
|
|
1776
|
-
*
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
1779
|
-
*
|
|
1780
|
-
* The pointer events below are dispatched by the containing `<pc-app>` element when the pointer
|
|
1781
|
-
* intersects this entity's geometry. They are only generated while the entity has a listener for
|
|
1782
|
-
* them, registered either with {@link addEventListener} or with the matching inline `onpointer*`
|
|
1783
|
-
* attribute.
|
|
1784
|
-
*
|
|
1785
|
-
* @attribute {string} onpointerenter - Script to run when the pointer moves onto the entity.
|
|
1786
|
-
* @attribute {string} onpointerleave - Script to run when the pointer moves off the entity.
|
|
1787
|
-
* @attribute {string} onpointermove - Script to run when the pointer moves over the entity.
|
|
1788
|
-
* @attribute {string} onpointerdown - Script to run when a pointer button is pressed over the
|
|
1789
|
-
* entity.
|
|
1790
|
-
* @attribute {string} onpointerup - Script to run when a pointer button is released over the
|
|
1791
|
-
* entity.
|
|
1792
|
-
* @fires {PointerEvent} pointerenter - Fired when the pointer moves onto the entity.
|
|
1793
|
-
* @fires {PointerEvent} pointerleave - Fired when the pointer moves off the entity.
|
|
1794
|
-
* @fires {PointerEvent} pointermove - Fired when the pointer moves over the entity.
|
|
1795
|
-
* @fires {PointerEvent} pointerdown - Fired when a pointer button is pressed over the entity.
|
|
1796
|
-
* @fires {PointerEvent} pointerup - Fired when a pointer button is released over the entity.
|
|
1793
|
+
* The base class for elements that create and own their backing entity: `<pc-entity>` and
|
|
1794
|
+
* `<pc-model>`, whose host entity carries the same authored properties. It carries the cached
|
|
1795
|
+
* property state, entity creation and parenting, and the reset that follows the entity's
|
|
1796
|
+
* destruction. `<pc-node>` sits outside this class: it borrows an entity a model instantiated,
|
|
1797
|
+
* and its properties are nullable overrides rather than owned values.
|
|
1797
1798
|
*/
|
|
1798
|
-
class
|
|
1799
|
+
class EntityOwnerElement extends EntityBaseElement {
|
|
1799
1800
|
/**
|
|
1800
1801
|
* Whether the entity is enabled.
|
|
1801
1802
|
*/
|
|
@@ -1821,7 +1822,8 @@
|
|
|
1821
1822
|
*/
|
|
1822
1823
|
_tags = [];
|
|
1823
1824
|
/**
|
|
1824
|
-
* Whether the hierarchy has been built for this entity
|
|
1825
|
+
* Whether the hierarchy has been built for this entity — set once `_buildHierarchy` has
|
|
1826
|
+
* parented it. Read by subclasses that gate work on the entity being in the scene graph.
|
|
1825
1827
|
*/
|
|
1826
1828
|
_built = false;
|
|
1827
1829
|
/**
|
|
@@ -1874,10 +1876,10 @@
|
|
|
1874
1876
|
this._resetReady();
|
|
1875
1877
|
}
|
|
1876
1878
|
/**
|
|
1877
|
-
* Parents the backing entity: under the entity of the nearest ancestor `<pc-entity
|
|
1878
|
-
* `<pc-node>` when there is one, and under the application root otherwise.
|
|
1879
|
-
* containing `<pc-app>` element once a sweep has created every entity, so a
|
|
1880
|
-
* existence never depends on document order.
|
|
1879
|
+
* Parents the backing entity: under the entity of the nearest ancestor `<pc-entity>`,
|
|
1880
|
+
* `<pc-model>` or `<pc-node>` when there is one, and under the application root otherwise.
|
|
1881
|
+
* Called by the containing `<pc-app>` element once a sweep has created every entity, so a
|
|
1882
|
+
* parent's existence never depends on document order.
|
|
1881
1883
|
*
|
|
1882
1884
|
* @param app - The application whose root adopts parentless entities.
|
|
1883
1885
|
* @internal
|
|
@@ -1892,6 +1894,13 @@
|
|
|
1892
1894
|
if (closestEntity && !closestEntity.entity) {
|
|
1893
1895
|
return;
|
|
1894
1896
|
}
|
|
1897
|
+
// An owner that exists but is not yet parented is itself deferred behind an unresolved
|
|
1898
|
+
// node further up. Building beneath it would announce readiness for an entity that is
|
|
1899
|
+
// not in the scene graph; stay unbuilt with it - the node's bind sweeps the whole
|
|
1900
|
+
// subtree, ancestors before descendants.
|
|
1901
|
+
if (closestEntity instanceof EntityOwnerElement && !closestEntity._built) {
|
|
1902
|
+
return;
|
|
1903
|
+
}
|
|
1895
1904
|
this._built = true;
|
|
1896
1905
|
if (closestEntity?.entity) {
|
|
1897
1906
|
closestEntity.entity.addChild(this.entity);
|
|
@@ -1899,35 +1908,16 @@
|
|
|
1899
1908
|
else {
|
|
1900
1909
|
app.root.addChild(this.entity);
|
|
1901
1910
|
}
|
|
1902
|
-
this.
|
|
1911
|
+
this._onBuilt();
|
|
1903
1912
|
}
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
const label = name ? ` '${name}'` : '';
|
|
1913
|
-
console.warn(`pc-entity${label} must be a descendant of pc-app - entity not created`);
|
|
1914
|
-
return;
|
|
1915
|
-
}
|
|
1916
|
-
// If app is already running, create entity immediately
|
|
1917
|
-
if (closestApp._hierarchyReady) {
|
|
1918
|
-
const app = closestApp.app;
|
|
1919
|
-
this._createEntity(app);
|
|
1920
|
-
this._buildHierarchy(app);
|
|
1921
|
-
// Handle any child entities that might exist
|
|
1922
|
-
buildDescendantEntities(this, app);
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
disconnectedCallback() {
|
|
1926
|
-
// Destroying the entity destroys its whole subtree, and the engine fires 'destroy' for
|
|
1927
|
-
// every entity in it - so _onEntityDestroy resets this element AND every descendant
|
|
1928
|
-
// element before the descendants' own disconnectedCallbacks run. Their entities are null
|
|
1929
|
-
// by then, making this call a no-op for them.
|
|
1930
|
-
this._entity?.destroy();
|
|
1913
|
+
/**
|
|
1914
|
+
* Called by `_buildHierarchy` once the backing entity has been parented — exactly once
|
|
1915
|
+
* per build cycle. The default announces readiness, which is what a parented `<pc-entity>`
|
|
1916
|
+
* means; `<pc-model>` overrides it to start loading content instead, because its readiness
|
|
1917
|
+
* tracks the content settling rather than the host entering the scene graph.
|
|
1918
|
+
*/
|
|
1919
|
+
_onBuilt() {
|
|
1920
|
+
this._onReady();
|
|
1931
1921
|
}
|
|
1932
1922
|
/**
|
|
1933
1923
|
* Sets the enabled state of the entity.
|
|
@@ -2032,6 +2022,75 @@
|
|
|
2032
2022
|
get tags() {
|
|
2033
2023
|
return this._tags;
|
|
2034
2024
|
}
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
/**
|
|
2028
|
+
* The EntityElement interface provides properties and methods for manipulating
|
|
2029
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-entity/ | `<pc-entity>`} elements.
|
|
2030
|
+
* The EntityElement interface also inherits the properties and methods of the
|
|
2031
|
+
* {@link HTMLElement} interface.
|
|
2032
|
+
*
|
|
2033
|
+
* The pointer events below are dispatched by the containing `<pc-app>` element when the pointer
|
|
2034
|
+
* intersects this entity's geometry. They are only generated while the entity has a listener for
|
|
2035
|
+
* them, registered either with {@link EventTarget.addEventListener} or with the matching inline `onpointer*`
|
|
2036
|
+
* attribute.
|
|
2037
|
+
*
|
|
2038
|
+
* @elementSummary The `<pc-entity>` element creates an entity: a named, transformable node of the
|
|
2039
|
+
* scene hierarchy, and the host for component elements such as `<pc-camera>`, `<pc-light>` and
|
|
2040
|
+
* `<pc-render>`. Place it in the `<pc-scene>`, or nest it under another `<pc-entity>`, a
|
|
2041
|
+
* `<pc-model>` or a `<pc-node>` to parent it there.
|
|
2042
|
+
*
|
|
2043
|
+
* @attribute {boolean} enabled - The enabled state of the entity.
|
|
2044
|
+
* @attribute {string} name - The name of the entity.
|
|
2045
|
+
* @attribute {string} position - The position of the entity.
|
|
2046
|
+
* @attribute {string} rotation - The rotation of the entity.
|
|
2047
|
+
* @attribute {string} scale - The scale of the entity.
|
|
2048
|
+
* @attribute {string} tags - The tags of the entity.
|
|
2049
|
+
* @attribute {string} onpointerenter - Script to run when the pointer moves onto the entity.
|
|
2050
|
+
* @attribute {string} onpointerleave - Script to run when the pointer moves off the entity.
|
|
2051
|
+
* @attribute {string} onpointermove - Script to run when the pointer moves over the entity.
|
|
2052
|
+
* @attribute {string} onpointerdown - Script to run when a pointer button is pressed over the
|
|
2053
|
+
* entity.
|
|
2054
|
+
* @attribute {string} onpointerup - Script to run when a pointer button is released over the
|
|
2055
|
+
* entity.
|
|
2056
|
+
* @fires {PointerEvent} pointerenter - Fired when the pointer moves onto the entity.
|
|
2057
|
+
* @fires {PointerEvent} pointerleave - Fired when the pointer moves off the entity.
|
|
2058
|
+
* @fires {PointerEvent} pointermove - Fired when the pointer moves over the entity.
|
|
2059
|
+
* @fires {PointerEvent} pointerdown - Fired when a pointer button is pressed over the entity.
|
|
2060
|
+
* @fires {PointerEvent} pointerup - Fired when a pointer button is released over the entity.
|
|
2061
|
+
*/
|
|
2062
|
+
class EntityElement extends EntityOwnerElement {
|
|
2063
|
+
connectedCallback() {
|
|
2064
|
+
// Wait for app to be ready
|
|
2065
|
+
const closestApp = this.closestApp;
|
|
2066
|
+
if (!closestApp) {
|
|
2067
|
+
// An entity outside an application is inert and never becomes ready, so awaiting it
|
|
2068
|
+
// hangs. Warn rather than fail silently, naming the parent it requires, as every other
|
|
2069
|
+
// misplaced element does.
|
|
2070
|
+
const name = this.getAttribute('name');
|
|
2071
|
+
const label = name ? ` '${name}'` : '';
|
|
2072
|
+
console.warn(`pc-entity${label} must be a descendant of pc-app - entity not created`);
|
|
2073
|
+
return;
|
|
2074
|
+
}
|
|
2075
|
+
// If app is already running, create entity immediately
|
|
2076
|
+
if (closestApp._hierarchyReady) {
|
|
2077
|
+
const app = closestApp.app;
|
|
2078
|
+
this._createEntity(app);
|
|
2079
|
+
this._buildHierarchy(app);
|
|
2080
|
+
// Handle any child entities that might exist. A build that deferred (an unresolved
|
|
2081
|
+
// pc-node above) defers the whole subtree with it - the node's bind sweeps it.
|
|
2082
|
+
if (this._built) {
|
|
2083
|
+
buildDescendantEntities(this, app);
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
disconnectedCallback() {
|
|
2088
|
+
// Destroying the entity destroys its whole subtree, and the engine fires 'destroy' for
|
|
2089
|
+
// every entity in it - so _onEntityDestroy resets this element AND every descendant
|
|
2090
|
+
// element before the descendants' own disconnectedCallbacks run. Their entities are null
|
|
2091
|
+
// by then, making this call a no-op for them.
|
|
2092
|
+
this._entity?.destroy();
|
|
2093
|
+
}
|
|
2035
2094
|
static get observedAttributes() {
|
|
2036
2095
|
return ['enabled', 'name', 'position', 'rotation', 'scale', 'tags', ...POINTER_ATTRIBUTES];
|
|
2037
2096
|
}
|
|
@@ -2361,6 +2420,10 @@
|
|
|
2361
2420
|
* Apart from `lazy` and the texture options, these attributes are read once when the asset is
|
|
2362
2421
|
* created, so changing them later has no effect.
|
|
2363
2422
|
*
|
|
2423
|
+
* @elementSummary The `<pc-asset>` element declares an asset for the application to load — a model,
|
|
2424
|
+
* texture, font, sound, script or JSON file — under an `id` that other elements reference. Must be
|
|
2425
|
+
* a direct child of `<pc-app>`.
|
|
2426
|
+
*
|
|
2364
2427
|
* @attribute {string} id - The identifier used to reference the asset from other elements.
|
|
2365
2428
|
* @attribute {string} src - The URL of the asset to load.
|
|
2366
2429
|
* @attribute {string} type - The asset type. Inferred from the `src` file extension when omitted.
|
|
@@ -2969,14 +3032,47 @@
|
|
|
2969
3032
|
* The ModelElement interface also inherits the properties and methods of the
|
|
2970
3033
|
* {@link HTMLElement} interface.
|
|
2971
3034
|
*
|
|
2972
|
-
* The element
|
|
2973
|
-
*
|
|
2974
|
-
*
|
|
2975
|
-
*
|
|
2976
|
-
*
|
|
2977
|
-
*
|
|
2978
|
-
* becomes ready
|
|
3035
|
+
* The element creates and fronts a stable host entity: `entity` is that host, created when the
|
|
3036
|
+
* application builds its hierarchy and kept across `asset` changes, so the element's transform
|
|
3037
|
+
* and tags are instance placement that composes with whatever transform the asset authored on
|
|
3038
|
+
* its root. The instantiated content is parented beneath the host and exposed as
|
|
3039
|
+
* {@link contentEntity}.
|
|
3040
|
+
*
|
|
3041
|
+
* The element becomes ready once its current asset selection has settled: the container asset
|
|
3042
|
+
* has loaded and its content root has been parented beneath the host, the load has failed
|
|
3043
|
+
* (`contentEntity` stays `null` — listen for `error`, or check `contentEntity`, to tell the
|
|
3044
|
+
* outcomes apart), or no asset is assigned at all. Changing `asset` re-arms readiness and
|
|
3045
|
+
* instantiates anew, so a `ready()` obtained after the change resolves against the new content.
|
|
3046
|
+
* A `pc-model` outside a `pc-app`, or referencing an unknown asset id, warns and never becomes
|
|
3047
|
+
* ready.
|
|
3048
|
+
*
|
|
3049
|
+
* The pointer events below are dispatched by the containing `<pc-app>` element when the pointer
|
|
3050
|
+
* intersects the model's geometry, exactly as for `<pc-entity>` — a hit on a content node that no
|
|
3051
|
+
* `pc-node` fronts resolves to this element.
|
|
3052
|
+
*
|
|
3053
|
+
* @elementSummary The `<pc-model>` element instantiates a 3D model from a container asset
|
|
3054
|
+
* (typically a GLB) beneath an entity of its own, so the element's transform and tags place the
|
|
3055
|
+
* instance in the scene. Its `<pc-node>` children override what the asset authored. Place it in the
|
|
3056
|
+
* `<pc-scene>`, or nest it under a `<pc-entity>`, another `<pc-model>` or a `<pc-node>`.
|
|
2979
3057
|
*
|
|
3058
|
+
* @attribute {boolean} enabled - The enabled state of the model.
|
|
3059
|
+
* @attribute {string} name - The name of the model.
|
|
3060
|
+
* @attribute {string} position - The position of the model.
|
|
3061
|
+
* @attribute {string} rotation - The rotation of the model.
|
|
3062
|
+
* @attribute {string} scale - The scale of the model.
|
|
3063
|
+
* @attribute {string} tags - The tags of the model.
|
|
3064
|
+
* @attribute {string} onpointerenter - Script to run when the pointer moves onto the model.
|
|
3065
|
+
* @attribute {string} onpointerleave - Script to run when the pointer moves off the model.
|
|
3066
|
+
* @attribute {string} onpointermove - Script to run when the pointer moves over the model.
|
|
3067
|
+
* @attribute {string} onpointerdown - Script to run when a pointer button is pressed over the
|
|
3068
|
+
* model.
|
|
3069
|
+
* @attribute {string} onpointerup - Script to run when a pointer button is released over the
|
|
3070
|
+
* model.
|
|
3071
|
+
* @fires {PointerEvent} pointerenter - Fired when the pointer moves onto the model.
|
|
3072
|
+
* @fires {PointerEvent} pointerleave - Fired when the pointer moves off the model.
|
|
3073
|
+
* @fires {PointerEvent} pointermove - Fired when the pointer moves over the model.
|
|
3074
|
+
* @fires {PointerEvent} pointerdown - Fired when a pointer button is pressed over the model.
|
|
3075
|
+
* @fires {PointerEvent} pointerup - Fired when a pointer button is released over the model.
|
|
2980
3076
|
* @fires {Event} load - Fired each time a container asset finishes instantiating, including
|
|
2981
3077
|
* re-instantiation after `asset` changes. Does not bubble — listen on this element, or use a
|
|
2982
3078
|
* capture-phase listener on an ancestor.
|
|
@@ -2984,14 +3080,14 @@
|
|
|
2984
3080
|
* error in `message`. Does not bubble. The element still becomes ready — readiness means the load
|
|
2985
3081
|
* settled, not that it succeeded.
|
|
2986
3082
|
*/
|
|
2987
|
-
class ModelElement extends
|
|
3083
|
+
class ModelElement extends EntityOwnerElement {
|
|
2988
3084
|
_asset = '';
|
|
2989
|
-
|
|
3085
|
+
_contentEntity = null;
|
|
2990
3086
|
/**
|
|
2991
|
-
* Incremented on every new load
|
|
2992
|
-
* load that resumes from an await or a load callback abandons
|
|
2993
|
-
* on, so a superseded load can neither instantiate a second
|
|
2994
|
-
*
|
|
3087
|
+
* Incremented on every new load, on disconnect, and when the host entity dies, and captured
|
|
3088
|
+
* by a load when it starts. A load that resumes from an await or a load callback abandons
|
|
3089
|
+
* itself if the value has moved on, so a superseded load can neither instantiate a second
|
|
3090
|
+
* content root nor parent one under a host a newer cycle has already replaced.
|
|
2995
3091
|
*/
|
|
2996
3092
|
_loadGeneration = 0;
|
|
2997
3093
|
/**
|
|
@@ -3002,12 +3098,13 @@
|
|
|
3002
3098
|
_loadHandle = null;
|
|
3003
3099
|
_errorHandle = null;
|
|
3004
3100
|
/**
|
|
3005
|
-
* The root entity of the instantiated model
|
|
3006
|
-
*
|
|
3007
|
-
*
|
|
3101
|
+
* The root entity of the instantiated model content, parented beneath the host entity.
|
|
3102
|
+
* `null` until the container asset has loaded and been instantiated, after a failed load,
|
|
3103
|
+
* and again once the element has been removed from the document.
|
|
3104
|
+
* @returns The content root entity, or `null`.
|
|
3008
3105
|
*/
|
|
3009
|
-
get
|
|
3010
|
-
return this.
|
|
3106
|
+
get contentEntity() {
|
|
3107
|
+
return this._contentEntity;
|
|
3011
3108
|
}
|
|
3012
3109
|
/**
|
|
3013
3110
|
* Returns a snapshot of the instantiated node tree, or `null` while there is none (the
|
|
@@ -3019,12 +3116,13 @@
|
|
|
3019
3116
|
* is the printable form.
|
|
3020
3117
|
*
|
|
3021
3118
|
* The snapshot is plain data, computed afresh each call: it does not follow later changes
|
|
3022
|
-
* to the hierarchy, and mutating it changes nothing.
|
|
3119
|
+
* to the hierarchy, and mutating it changes nothing. It covers the instantiated content
|
|
3120
|
+
* only — the host entity the element fronts is not part of the asset's node tree.
|
|
3023
3121
|
*
|
|
3024
3122
|
* @returns The root of the instantiated node tree, or `null`.
|
|
3025
3123
|
*/
|
|
3026
3124
|
hierarchy() {
|
|
3027
|
-
const root = this.
|
|
3125
|
+
const root = this._contentEntity;
|
|
3028
3126
|
if (!root) {
|
|
3029
3127
|
return null;
|
|
3030
3128
|
}
|
|
@@ -3064,18 +3162,53 @@
|
|
|
3064
3162
|
// A model outside an application is inert and never becomes ready, so awaiting it hangs.
|
|
3065
3163
|
// Warn rather than fail silently, naming the parent it requires, as every other misplaced
|
|
3066
3164
|
// element does.
|
|
3067
|
-
|
|
3165
|
+
const closestApp = this.closestApp;
|
|
3166
|
+
if (!closestApp) {
|
|
3068
3167
|
const label = this._asset ? ` '${this._asset}'` : '';
|
|
3069
3168
|
console.warn(`pc-model${label} must be a descendant of pc-app - model not created`);
|
|
3070
3169
|
return;
|
|
3071
3170
|
}
|
|
3072
|
-
|
|
3171
|
+
// If the app is already running, create the host immediately; during a boot, the app's
|
|
3172
|
+
// own sweep does it. Either way, _onBuilt starts the content load once the host is
|
|
3173
|
+
// parented.
|
|
3174
|
+
if (closestApp._hierarchyReady) {
|
|
3175
|
+
const app = closestApp.app;
|
|
3176
|
+
this._createEntity(app);
|
|
3177
|
+
this._buildHierarchy(app);
|
|
3178
|
+
// A build that deferred (an unresolved pc-node above) defers the whole subtree with
|
|
3179
|
+
// it - the node's bind sweeps it.
|
|
3180
|
+
if (this._built) {
|
|
3181
|
+
buildDescendantEntities(this, app);
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3073
3184
|
}
|
|
3074
3185
|
disconnectedCallback() {
|
|
3186
|
+
// Destroying the host destroys the instantiated content with it, and the destroy hook
|
|
3187
|
+
// resets the element. The generation guard comes first so a load suspended on an await
|
|
3188
|
+
// cannot resume against the torn-down element.
|
|
3075
3189
|
this._loadGeneration++;
|
|
3076
3190
|
this._detachLoadHandlers();
|
|
3077
|
-
this.
|
|
3078
|
-
|
|
3191
|
+
this._entity?.destroy();
|
|
3192
|
+
}
|
|
3193
|
+
/**
|
|
3194
|
+
* Starts (or restarts) the content load once the host has been parented. Readiness is not
|
|
3195
|
+
* announced here — it tracks the content settling, not the host entering the scene graph.
|
|
3196
|
+
*/
|
|
3197
|
+
_onBuilt() {
|
|
3198
|
+
this._loadContent();
|
|
3199
|
+
}
|
|
3200
|
+
/**
|
|
3201
|
+
* Extends the owner reset for the content: the engine's destroy cascade has already taken
|
|
3202
|
+
* the content root down with the host subtree, so only the reference and the in-flight load
|
|
3203
|
+
* are dropped here. The next build re-creates the host and re-instantiates the content.
|
|
3204
|
+
*
|
|
3205
|
+
* @param entity - The host entity that was destroyed.
|
|
3206
|
+
*/
|
|
3207
|
+
_onEntityDestroy(entity) {
|
|
3208
|
+
this._loadGeneration++;
|
|
3209
|
+
this._detachLoadHandlers();
|
|
3210
|
+
this._contentEntity = null;
|
|
3211
|
+
super._onEntityDestroy(entity);
|
|
3079
3212
|
}
|
|
3080
3213
|
_detachLoadHandlers() {
|
|
3081
3214
|
this._loadHandle?.off();
|
|
@@ -3084,51 +3217,34 @@
|
|
|
3084
3217
|
this._errorHandle = null;
|
|
3085
3218
|
}
|
|
3086
3219
|
/**
|
|
3087
|
-
* Resolves readiness and dispatches the `load` event. Called once the instantiated
|
|
3088
|
-
* has been parented —
|
|
3089
|
-
* model's
|
|
3220
|
+
* Resolves readiness and dispatches the `load` event. Called once the instantiated content
|
|
3221
|
+
* has been parented beneath the host — the host itself is already in the scene graph by
|
|
3222
|
+
* then, so a ready model's content always has world transforms.
|
|
3090
3223
|
*/
|
|
3091
3224
|
_announceLoad() {
|
|
3092
3225
|
this._onReady();
|
|
3093
3226
|
this.dispatchEvent(new Event('load'));
|
|
3094
3227
|
}
|
|
3095
3228
|
_instantiate(container) {
|
|
3096
|
-
const
|
|
3097
|
-
|
|
3098
|
-
this._entity
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
});
|
|
3111
|
-
}
|
|
3112
|
-
else {
|
|
3113
|
-
const appElement = this.closestApp;
|
|
3114
|
-
if (appElement) {
|
|
3115
|
-
appElement.ready().then(() => {
|
|
3116
|
-
if (generation !== this._loadGeneration) {
|
|
3117
|
-
return;
|
|
3118
|
-
}
|
|
3119
|
-
appElement.app.root.addChild(entity);
|
|
3120
|
-
this._announceLoad();
|
|
3121
|
-
});
|
|
3122
|
-
}
|
|
3123
|
-
}
|
|
3124
|
-
}
|
|
3125
|
-
async _loadModel() {
|
|
3126
|
-
this._unloadModel();
|
|
3229
|
+
const content = container.instantiateRenderEntity();
|
|
3230
|
+
this._contentEntity = content;
|
|
3231
|
+
this._entity.addChild(content);
|
|
3232
|
+
this._announceLoad();
|
|
3233
|
+
}
|
|
3234
|
+
_destroyContent() {
|
|
3235
|
+
this._contentEntity?.destroy();
|
|
3236
|
+
this._contentEntity = null;
|
|
3237
|
+
}
|
|
3238
|
+
async _loadContent() {
|
|
3239
|
+
// The old content goes down synchronously, so a reader that checks after an asset change
|
|
3240
|
+
// never sees the outgoing hierarchy. The host survives - components and child entities
|
|
3241
|
+
// attached to it carry over to the new content.
|
|
3242
|
+
this._destroyContent();
|
|
3127
3243
|
// Supersede any load already in flight - only the newest load may instantiate
|
|
3128
3244
|
const generation = ++this._loadGeneration;
|
|
3129
3245
|
this._detachLoadHandlers();
|
|
3130
3246
|
// Re-arm readiness so a waiter obtained after an asset change resolves against the new
|
|
3131
|
-
//
|
|
3247
|
+
// content. A no-op on first connection, where readiness is still pending.
|
|
3132
3248
|
this._resetReady();
|
|
3133
3249
|
const appElement = this.closestApp;
|
|
3134
3250
|
if (!appElement) {
|
|
@@ -3140,14 +3256,23 @@
|
|
|
3140
3256
|
if (generation !== this._loadGeneration) {
|
|
3141
3257
|
return;
|
|
3142
3258
|
}
|
|
3259
|
+
// The host may not be parented yet - a model under a pc-node that has not bound, reached
|
|
3260
|
+
// through the asset setter. Nothing settles here: _onBuilt re-runs this load once the
|
|
3261
|
+
// host builds.
|
|
3262
|
+
if (!this._entity || !this._built) {
|
|
3263
|
+
return;
|
|
3264
|
+
}
|
|
3265
|
+
if (this._asset === '') {
|
|
3266
|
+
// No asset assigned is a settled selection: the element is a usable host (components
|
|
3267
|
+
// attach, waiters resolve) with no content. Assigning an asset later re-arms.
|
|
3268
|
+
this._onReady();
|
|
3269
|
+
return;
|
|
3270
|
+
}
|
|
3143
3271
|
const asset = useAsset(this._asset);
|
|
3144
3272
|
if (!asset) {
|
|
3145
|
-
//
|
|
3146
|
-
// non-empty one that resolves to nothing is a dead end - say so rather than staying
|
|
3273
|
+
// A non-empty id that resolves to nothing is a dead end - say so rather than staying
|
|
3147
3274
|
// silently pending.
|
|
3148
|
-
|
|
3149
|
-
console.warn(`pc-model could not find asset '${this._asset}' - model not created`);
|
|
3150
|
-
}
|
|
3275
|
+
console.warn(`pc-model could not find asset '${this._asset}' - model not created`);
|
|
3151
3276
|
return;
|
|
3152
3277
|
}
|
|
3153
3278
|
if (asset.loaded) {
|
|
@@ -3169,7 +3294,7 @@
|
|
|
3169
3294
|
if (generation !== this._loadGeneration) {
|
|
3170
3295
|
return;
|
|
3171
3296
|
}
|
|
3172
|
-
// A failed load settles readiness with a null
|
|
3297
|
+
// A failed load settles readiness with a null contentEntity, mirroring pc-asset:
|
|
3173
3298
|
// readiness means the load settled, not that it succeeded.
|
|
3174
3299
|
this.dispatchEvent(new ErrorEvent('error', {
|
|
3175
3300
|
message: err instanceof Error ? err.message : String(err)
|
|
@@ -3178,10 +3303,6 @@
|
|
|
3178
3303
|
});
|
|
3179
3304
|
}
|
|
3180
3305
|
}
|
|
3181
|
-
_unloadModel() {
|
|
3182
|
-
this._entity?.destroy();
|
|
3183
|
-
this._entity = null;
|
|
3184
|
-
}
|
|
3185
3306
|
/**
|
|
3186
3307
|
* Sets the id of the `pc-asset` to use for the model.
|
|
3187
3308
|
* @param value - The asset ID.
|
|
@@ -3189,7 +3310,7 @@
|
|
|
3189
3310
|
set asset(value) {
|
|
3190
3311
|
this._asset = value;
|
|
3191
3312
|
if (this.isConnected) {
|
|
3192
|
-
this.
|
|
3313
|
+
this._loadContent();
|
|
3193
3314
|
}
|
|
3194
3315
|
}
|
|
3195
3316
|
/**
|
|
@@ -3200,13 +3321,38 @@
|
|
|
3200
3321
|
return this._asset;
|
|
3201
3322
|
}
|
|
3202
3323
|
static get observedAttributes() {
|
|
3203
|
-
return ['asset'];
|
|
3324
|
+
return ['asset', 'enabled', 'name', 'position', 'rotation', 'scale', 'tags', ...POINTER_ATTRIBUTES];
|
|
3204
3325
|
}
|
|
3205
3326
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
3206
3327
|
switch (name) {
|
|
3207
3328
|
case 'asset':
|
|
3208
3329
|
this.asset = newValue ?? '';
|
|
3209
3330
|
break;
|
|
3331
|
+
case 'enabled':
|
|
3332
|
+
this.enabled = parseBool(newValue, true);
|
|
3333
|
+
break;
|
|
3334
|
+
case 'name':
|
|
3335
|
+
this.name = newValue ?? 'Untitled';
|
|
3336
|
+
break;
|
|
3337
|
+
case 'position':
|
|
3338
|
+
this.position = parseVec3(newValue, playcanvas.Vec3.ZERO, name);
|
|
3339
|
+
break;
|
|
3340
|
+
case 'rotation':
|
|
3341
|
+
this.rotation = parseVec3(newValue, playcanvas.Vec3.ZERO, name);
|
|
3342
|
+
break;
|
|
3343
|
+
case 'scale':
|
|
3344
|
+
this.scale = parseVec3(newValue, playcanvas.Vec3.ONE, name);
|
|
3345
|
+
break;
|
|
3346
|
+
case 'tags':
|
|
3347
|
+
this.tags = parseTags(newValue);
|
|
3348
|
+
break;
|
|
3349
|
+
case 'onpointerenter':
|
|
3350
|
+
case 'onpointerleave':
|
|
3351
|
+
case 'onpointerdown':
|
|
3352
|
+
case 'onpointerup':
|
|
3353
|
+
case 'onpointermove':
|
|
3354
|
+
this._updateInlineHandler(name, newValue);
|
|
3355
|
+
break;
|
|
3210
3356
|
}
|
|
3211
3357
|
}
|
|
3212
3358
|
}
|
|
@@ -3297,7 +3443,7 @@
|
|
|
3297
3443
|
// A component can only exist on an entity, so an element placed outside one is inert.
|
|
3298
3444
|
// It still becomes ready (with a null `component`), so warn rather than fail silently
|
|
3299
3445
|
const label = this.id ? ` '${this.id}'` : '';
|
|
3300
|
-
console.warn(`${this.tagName.toLowerCase()}${label} must be a descendant of pc-entity - component not added`);
|
|
3446
|
+
console.warn(`${this.tagName.toLowerCase()}${label} must be a descendant of pc-entity, pc-model or pc-node - component not added`);
|
|
3301
3447
|
return;
|
|
3302
3448
|
}
|
|
3303
3449
|
await entityElement.ready();
|
|
@@ -3385,8 +3531,9 @@
|
|
|
3385
3531
|
}
|
|
3386
3532
|
/**
|
|
3387
3533
|
* The PlayCanvas component instance. `null` until the element is ready, and also for an
|
|
3388
|
-
* element that is not a descendant of
|
|
3389
|
-
* element's `ready()` promise
|
|
3534
|
+
* element that is not a descendant of an entity-fronting element (`<pc-entity>`,
|
|
3535
|
+
* `<pc-model>` or `<pc-node>`) — await {@link whenReady} or the element's `ready()` promise
|
|
3536
|
+
* before accessing it.
|
|
3390
3537
|
* @returns The component instance, or `null`.
|
|
3391
3538
|
*/
|
|
3392
3539
|
get component() {
|
|
@@ -3439,6 +3586,13 @@
|
|
|
3439
3586
|
* the underlying {@link AnimComponent} (via {@link component}) for playback state beyond what
|
|
3440
3587
|
* this element exposes.
|
|
3441
3588
|
*
|
|
3589
|
+
* Engine component: {@link AnimComponent} (`anim`).
|
|
3590
|
+
*
|
|
3591
|
+
* @elementSummary The `<pc-anim>` element plays animation clips over its entity's hierarchy, taken
|
|
3592
|
+
* from `<pc-anim-clip>` children or from the enclosing `<pc-model>`'s own animations. The first
|
|
3593
|
+
* clip plays automatically, and the `clip` attribute switches between them. Must be a child of a
|
|
3594
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
3595
|
+
*
|
|
3442
3596
|
* @category Components
|
|
3443
3597
|
*/
|
|
3444
3598
|
class AnimComponentElement extends ComponentElement {
|
|
@@ -3460,6 +3614,11 @@
|
|
|
3460
3614
|
* The name of the active clip.
|
|
3461
3615
|
*/
|
|
3462
3616
|
_clip = '';
|
|
3617
|
+
/**
|
|
3618
|
+
* The binding root this element last assigned through {@link _applyRootBone}, distinguishing
|
|
3619
|
+
* its own writes from a `rootBone` assigned through the engine API — which is left alone.
|
|
3620
|
+
*/
|
|
3621
|
+
_managedRootBone = null;
|
|
3463
3622
|
/**
|
|
3464
3623
|
* The element the model-readiness listener is attached to, held so disconnection can detach
|
|
3465
3624
|
* it after `closestEntity` no longer resolves.
|
|
@@ -3485,27 +3644,71 @@
|
|
|
3485
3644
|
*/
|
|
3486
3645
|
_warnedClip = null;
|
|
3487
3646
|
/**
|
|
3488
|
-
* Rebinds when a model
|
|
3489
|
-
*
|
|
3647
|
+
* Rebinds when a model that is not this component's host announces readiness — a sibling or
|
|
3648
|
+
* deeper model whose content changed under the assigned clips. The engine resolves each
|
|
3649
|
+
* curve once, at the first tick after assignment, and never retries — and its mesh-instance
|
|
3490
3650
|
* broadcast fires before an instantiated hierarchy is parented, so a model that loads after
|
|
3491
|
-
* the clips were assigned would otherwise stay silently unbound.
|
|
3492
|
-
*
|
|
3493
|
-
*
|
|
3651
|
+
* the clips were assigned would otherwise stay silently unbound. The host model's own cycles
|
|
3652
|
+
* are excluded: those re-enter through {@link initComponent}, which refreshes the whole clip
|
|
3653
|
+
* set against the new container.
|
|
3494
3654
|
*/
|
|
3495
3655
|
_onModelReady = (event) => {
|
|
3496
3656
|
if (!(event.target instanceof ModelElement) || !this.component) {
|
|
3497
3657
|
return;
|
|
3498
3658
|
}
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
}
|
|
3659
|
+
// The host model's own readiness cycle already re-initialized this component through
|
|
3660
|
+
// ComponentElement's host-ready listener, which is attached first and so has run by now.
|
|
3661
|
+
// Acting here too would resolve every track twice and capture the playhead-restore
|
|
3662
|
+
// snapshot mid-rebuild.
|
|
3663
|
+
if (event.target === this._modelListenerTarget) {
|
|
3664
|
+
return;
|
|
3506
3665
|
}
|
|
3666
|
+
// A model cycle can replace the skeleton source's host entity (a rebuild under a
|
|
3667
|
+
// retargeting pc-node), so the binding root is re-asserted before the rebind.
|
|
3668
|
+
this._applyRootBone();
|
|
3507
3669
|
this.component.rebind();
|
|
3508
3670
|
};
|
|
3671
|
+
/**
|
|
3672
|
+
* The model whose host entity scopes this component's curve binding: the parent `pc-model`,
|
|
3673
|
+
* or the sole `pc-model` among the parent's direct children (the arrangement where clips
|
|
3674
|
+
* live in a library asset beside the skeleton). `null` when there is no such model, or more
|
|
3675
|
+
* than one — an ambiguous skeleton is left to the engine's name-based resolution.
|
|
3676
|
+
*/
|
|
3677
|
+
_skeletonSource() {
|
|
3678
|
+
const parent = this.parentElement;
|
|
3679
|
+
if (parent instanceof ModelElement) {
|
|
3680
|
+
return parent;
|
|
3681
|
+
}
|
|
3682
|
+
const models = parent ? parent.querySelectorAll(':scope > pc-model') : null;
|
|
3683
|
+
return models?.length === 1 && models[0] instanceof ModelElement ? models[0] : null;
|
|
3684
|
+
}
|
|
3685
|
+
/**
|
|
3686
|
+
* Keeps the component's binding root pointing at the skeleton source's host entity. The host
|
|
3687
|
+
* wraps the instantiated content, so left at its default — the component's own entity — the
|
|
3688
|
+
* engine binder mis-resolves curves that target the asset's root node: its fallback treats
|
|
3689
|
+
* the graph as the asset root once the root is no longer a direct child.
|
|
3690
|
+
*
|
|
3691
|
+
* Authoritative in both directions for values this element assigned: a source appearing pins
|
|
3692
|
+
* its host, and a source dissolving (the model gone, or a second model making the skeleton
|
|
3693
|
+
* ambiguous) clears the pin rather than leaving it on a stale host. A root assigned through
|
|
3694
|
+
* the engine API is never overwritten — the user's choice outranks the managed default.
|
|
3695
|
+
* Writes are skipped while unchanged, because the engine setter itself triggers a rebind.
|
|
3696
|
+
*/
|
|
3697
|
+
_applyRootBone() {
|
|
3698
|
+
const component = this.component;
|
|
3699
|
+
// A non-null root this element did not assign came through the engine API. A fresh
|
|
3700
|
+
// component starts at null, which is always reclaimable.
|
|
3701
|
+
if (component.rootBone !== null && component.rootBone !== this._managedRootBone) {
|
|
3702
|
+
return;
|
|
3703
|
+
}
|
|
3704
|
+
const host = this._skeletonSource()?.entity ?? null;
|
|
3705
|
+
if (component.rootBone !== host) {
|
|
3706
|
+
// The engine setter accepts null - restoring the component's own entity as the
|
|
3707
|
+
// binding graph - but its declared type does not
|
|
3708
|
+
component.rootBone = host;
|
|
3709
|
+
}
|
|
3710
|
+
this._managedRootBone = host;
|
|
3711
|
+
}
|
|
3509
3712
|
/** @ignore */
|
|
3510
3713
|
constructor() {
|
|
3511
3714
|
super('anim');
|
|
@@ -3530,7 +3733,16 @@
|
|
|
3530
3733
|
host.addEventListener('ready', this._onModelReady);
|
|
3531
3734
|
this._modelListenerTarget = host;
|
|
3532
3735
|
}
|
|
3533
|
-
this.
|
|
3736
|
+
this._applyRootBone();
|
|
3737
|
+
if (this.component.baseLayer) {
|
|
3738
|
+
// The component survived the host's readiness cycle (a pc-model reloading content on
|
|
3739
|
+
// its stable host entity). A loaded graph cannot be reassigned in place, so drop it
|
|
3740
|
+
// and reassign from the current source, restoring the active clip and playhead.
|
|
3741
|
+
this._refreshClips();
|
|
3742
|
+
}
|
|
3743
|
+
else {
|
|
3744
|
+
this._applyClips();
|
|
3745
|
+
}
|
|
3534
3746
|
}
|
|
3535
3747
|
disconnectedCallback() {
|
|
3536
3748
|
this._modelListenerTarget?.removeEventListener('ready', this._onModelReady);
|
|
@@ -3540,6 +3752,7 @@
|
|
|
3540
3752
|
this._sourceGeneration++;
|
|
3541
3753
|
this._assignedClips.clear();
|
|
3542
3754
|
this._autoAssigned = false;
|
|
3755
|
+
this._managedRootBone = null;
|
|
3543
3756
|
super.disconnectedCallback();
|
|
3544
3757
|
}
|
|
3545
3758
|
/**
|
|
@@ -3708,6 +3921,10 @@
|
|
|
3708
3921
|
if (!component) {
|
|
3709
3922
|
return;
|
|
3710
3923
|
}
|
|
3924
|
+
// A clip-set change is also a chance for the skeleton source to have changed shape (a
|
|
3925
|
+
// clip child appearing or leaving can accompany a model coming or going) - re-derive the
|
|
3926
|
+
// binding root before the reassignment binds against it.
|
|
3927
|
+
this._applyRootBone();
|
|
3711
3928
|
const layer = component.baseLayer;
|
|
3712
3929
|
const restore = layer ? {
|
|
3713
3930
|
state: layer.activeState,
|
|
@@ -3994,6 +4211,10 @@
|
|
|
3994
4211
|
* named; in a multi-track source the track named `name` is chosen, falling back to the first
|
|
3995
4212
|
* with a warning. The element becomes ready once its resolved track is assigned.
|
|
3996
4213
|
*
|
|
4214
|
+
* @elementSummary The `<pc-anim-clip>` element declares one named animation clip on its parent
|
|
4215
|
+
* `<pc-anim>`, taken from the `asset` it names or, without one, from the enclosing `<pc-model>`'s
|
|
4216
|
+
* own animations. Must be a direct child of `<pc-anim>`.
|
|
4217
|
+
*
|
|
3997
4218
|
* @category Components
|
|
3998
4219
|
*/
|
|
3999
4220
|
class AnimClipElement extends AsyncElement {
|
|
@@ -4315,14 +4536,20 @@
|
|
|
4315
4536
|
customElements.define('pc-anim-clip', AnimClipElement);
|
|
4316
4537
|
|
|
4317
4538
|
/**
|
|
4318
|
-
* The
|
|
4319
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-listener/ | `<pc-listener>`} elements.
|
|
4320
|
-
* The
|
|
4539
|
+
* The AudioListenerComponentElement interface provides properties and methods for manipulating
|
|
4540
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-audio-listener/ | `<pc-audio-listener>`} elements.
|
|
4541
|
+
* The AudioListenerComponentElement interface also inherits the properties and methods of the
|
|
4321
4542
|
* {@link HTMLElement} interface.
|
|
4322
4543
|
*
|
|
4544
|
+
* Engine component: {@link AudioListenerComponent} (`audiolistener`).
|
|
4545
|
+
*
|
|
4546
|
+
* @elementSummary The `<pc-audio-listener>` element makes its entity the point from which
|
|
4547
|
+
* positional sounds are heard, typically the entity holding the `<pc-camera>`. Must be a child of a
|
|
4548
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
4549
|
+
*
|
|
4323
4550
|
* @category Components
|
|
4324
4551
|
*/
|
|
4325
|
-
class
|
|
4552
|
+
class AudioListenerComponentElement extends ComponentElement {
|
|
4326
4553
|
/** @ignore */
|
|
4327
4554
|
constructor() {
|
|
4328
4555
|
super('audiolistener');
|
|
@@ -4335,7 +4562,7 @@
|
|
|
4335
4562
|
return super.component;
|
|
4336
4563
|
}
|
|
4337
4564
|
}
|
|
4338
|
-
customElements.define('pc-listener',
|
|
4565
|
+
customElements.define('pc-audio-listener', AudioListenerComponentElement);
|
|
4339
4566
|
|
|
4340
4567
|
const transitionModes = new Map([
|
|
4341
4568
|
['tint', playcanvas.BUTTON_TRANSITION_MODE_TINT],
|
|
@@ -4347,6 +4574,13 @@
|
|
|
4347
4574
|
* The ButtonComponentElement interface also inherits the properties and methods of the
|
|
4348
4575
|
* {@link HTMLElement} interface.
|
|
4349
4576
|
*
|
|
4577
|
+
* Engine component: {@link ButtonComponent} (`button`).
|
|
4578
|
+
*
|
|
4579
|
+
* @elementSummary The `<pc-button>` element makes its entity respond to pointer input, tinting or
|
|
4580
|
+
* swapping its image as the pointer hovers, presses and releases it. The entity also needs a
|
|
4581
|
+
* `<pc-element>` with `use-input` set. Must be a child of a `<pc-entity>`, `<pc-model>` or
|
|
4582
|
+
* `<pc-node>`.
|
|
4583
|
+
*
|
|
4350
4584
|
* @category Components
|
|
4351
4585
|
*/
|
|
4352
4586
|
class ButtonComponentElement extends ComponentElement {
|
|
@@ -4427,7 +4661,9 @@
|
|
|
4427
4661
|
}
|
|
4428
4662
|
/**
|
|
4429
4663
|
* Sets the reference (CSS selector, element id or entity name) to the `<pc-entity>` whose image
|
|
4430
|
-
* element is used for visual transitions. Defaults to the button's own entity
|
|
4664
|
+
* element is used for visual transitions. Defaults to the button's own entity — inside a
|
|
4665
|
+
* `<pc-model>`, that is the model's host entity, so supply an explicit reference to target a
|
|
4666
|
+
* UI entity instead.
|
|
4431
4667
|
* @param value - The image entity reference.
|
|
4432
4668
|
*/
|
|
4433
4669
|
set image(value) {
|
|
@@ -4746,13 +4982,20 @@
|
|
|
4746
4982
|
* The CameraComponentElement interface also inherits the properties and methods of the
|
|
4747
4983
|
* {@link HTMLElement} interface.
|
|
4748
4984
|
*
|
|
4985
|
+
* Engine component: {@link CameraComponent} (`camera`).
|
|
4986
|
+
*
|
|
4987
|
+
* @elementSummary The `<pc-camera>` element renders the scene from its entity's transform, with
|
|
4988
|
+
* attributes for the projection, field of view, clip planes, clear color and tonemapping. Must be a
|
|
4989
|
+
* child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
4990
|
+
*
|
|
4749
4991
|
* @category Components
|
|
4750
4992
|
*/
|
|
4751
4993
|
class CameraComponentElement extends ComponentElement {
|
|
4752
4994
|
_clearColor = new playcanvas.Color(0.75, 0.75, 0.75, 1);
|
|
4753
4995
|
_clearColorBuffer = true;
|
|
4996
|
+
_clearDepth = 1;
|
|
4754
4997
|
_clearDepthBuffer = true;
|
|
4755
|
-
_clearStencilBuffer =
|
|
4998
|
+
_clearStencilBuffer = true;
|
|
4756
4999
|
_cullFaces = true;
|
|
4757
5000
|
_farClip = 1000;
|
|
4758
5001
|
_flipFaces = false;
|
|
@@ -4775,6 +5018,7 @@
|
|
|
4775
5018
|
return {
|
|
4776
5019
|
clearColor: this._clearColor,
|
|
4777
5020
|
clearColorBuffer: this._clearColorBuffer,
|
|
5021
|
+
clearDepth: this._clearDepth,
|
|
4778
5022
|
clearDepthBuffer: this._clearDepthBuffer,
|
|
4779
5023
|
clearStencilBuffer: this._clearStencilBuffer,
|
|
4780
5024
|
cullFaces: this._cullFaces,
|
|
@@ -4793,9 +5037,31 @@
|
|
|
4793
5037
|
toneMapping: tonemaps.get(this._tonemap) ?? playcanvas.TONEMAP_NONE
|
|
4794
5038
|
};
|
|
4795
5039
|
}
|
|
4796
|
-
|
|
5040
|
+
/**
|
|
5041
|
+
* Whether immersive AR is available. Independent of {@link vrAvailable}: a device can offer
|
|
5042
|
+
* either mode without the other.
|
|
5043
|
+
* @returns Whether immersive AR is available.
|
|
5044
|
+
*/
|
|
5045
|
+
get arAvailable() {
|
|
5046
|
+
return this._available(playcanvas.XRTYPE_AR);
|
|
5047
|
+
}
|
|
5048
|
+
/**
|
|
5049
|
+
* Whether immersive VR is available. Independent of {@link arAvailable}: a device can offer
|
|
5050
|
+
* either mode without the other.
|
|
5051
|
+
* @returns Whether immersive VR is available.
|
|
5052
|
+
*/
|
|
5053
|
+
get vrAvailable() {
|
|
5054
|
+
return this._available(playcanvas.XRTYPE_VR);
|
|
5055
|
+
}
|
|
5056
|
+
/**
|
|
5057
|
+
* Whether one XR session type is available on this device.
|
|
5058
|
+
*
|
|
5059
|
+
* @param type - The XR session type to test.
|
|
5060
|
+
* @returns Whether that type is available.
|
|
5061
|
+
*/
|
|
5062
|
+
_available(type) {
|
|
4797
5063
|
const xrManager = this.component?.system.app.xr;
|
|
4798
|
-
return xrManager
|
|
5064
|
+
return Boolean(xrManager?.supported && xrManager.isAvailable(type));
|
|
4799
5065
|
}
|
|
4800
5066
|
/**
|
|
4801
5067
|
* Starts the camera in XR mode.
|
|
@@ -4803,11 +5069,13 @@
|
|
|
4803
5069
|
* @param space - The space to start the camera in.
|
|
4804
5070
|
*/
|
|
4805
5071
|
startXr(type, space) {
|
|
4806
|
-
|
|
5072
|
+
// Gated on the mode being started, not on XR in general: a device that offers only
|
|
5073
|
+
// one of the two would otherwise accept a session it cannot serve
|
|
5074
|
+
if (this.component && this._available(type)) {
|
|
4807
5075
|
this.component.startXr(type, space, {
|
|
4808
5076
|
callback: (err) => {
|
|
4809
5077
|
if (err)
|
|
4810
|
-
console.error(`WebXR
|
|
5078
|
+
console.error(`WebXR ${type} failed to start: ${err.message}`);
|
|
4811
5079
|
}
|
|
4812
5080
|
});
|
|
4813
5081
|
}
|
|
@@ -4861,6 +5129,23 @@
|
|
|
4861
5129
|
get clearColorBuffer() {
|
|
4862
5130
|
return this._clearColorBuffer;
|
|
4863
5131
|
}
|
|
5132
|
+
/**
|
|
5133
|
+
* Sets the depth value the depth buffer is cleared to. Defaults to 1.
|
|
5134
|
+
* @param value - The clear depth value.
|
|
5135
|
+
*/
|
|
5136
|
+
set clearDepth(value) {
|
|
5137
|
+
this._clearDepth = value;
|
|
5138
|
+
if (this.component) {
|
|
5139
|
+
this.component.clearDepth = value;
|
|
5140
|
+
}
|
|
5141
|
+
}
|
|
5142
|
+
/**
|
|
5143
|
+
* Gets the depth value the depth buffer is cleared to.
|
|
5144
|
+
* @returns The clear depth value.
|
|
5145
|
+
*/
|
|
5146
|
+
get clearDepth() {
|
|
5147
|
+
return this._clearDepth;
|
|
5148
|
+
}
|
|
4864
5149
|
/**
|
|
4865
5150
|
* Sets the clear depth buffer of the camera.
|
|
4866
5151
|
* @param value - The clear depth buffer.
|
|
@@ -5139,6 +5424,7 @@
|
|
|
5139
5424
|
...super.observedAttributes,
|
|
5140
5425
|
'clear-color',
|
|
5141
5426
|
'clear-color-buffer',
|
|
5427
|
+
'clear-depth',
|
|
5142
5428
|
'clear-depth-buffer',
|
|
5143
5429
|
'clear-stencil-buffer',
|
|
5144
5430
|
'cull-faces',
|
|
@@ -5166,11 +5452,14 @@
|
|
|
5166
5452
|
case 'clear-color-buffer':
|
|
5167
5453
|
this.clearColorBuffer = parseBool(newValue, true);
|
|
5168
5454
|
break;
|
|
5455
|
+
case 'clear-depth':
|
|
5456
|
+
this.clearDepth = parseNumber(newValue, 1, name);
|
|
5457
|
+
break;
|
|
5169
5458
|
case 'clear-depth-buffer':
|
|
5170
5459
|
this.clearDepthBuffer = parseBool(newValue, true);
|
|
5171
5460
|
break;
|
|
5172
5461
|
case 'clear-stencil-buffer':
|
|
5173
|
-
this.clearStencilBuffer = parseBool(newValue,
|
|
5462
|
+
this.clearStencilBuffer = parseBool(newValue, true);
|
|
5174
5463
|
break;
|
|
5175
5464
|
case 'cull-faces':
|
|
5176
5465
|
this.cullFaces = parseBool(newValue, true);
|
|
@@ -5231,6 +5520,12 @@
|
|
|
5231
5520
|
* retargets or rebinds picks up the new node's geometry. An entity with no asset-backed render
|
|
5232
5521
|
* component warns, and the collider has no shape.
|
|
5233
5522
|
*
|
|
5523
|
+
* Engine component: {@link CollisionComponent} (`collision`).
|
|
5524
|
+
*
|
|
5525
|
+
* @elementSummary The `<pc-collision>` element gives its entity a collision shape — a box, sphere,
|
|
5526
|
+
* capsule, cone, cylinder or mesh — for the physics simulation to collide against. Pair it with a
|
|
5527
|
+
* `<pc-rigid-body>`. Must be a child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
5528
|
+
*
|
|
5234
5529
|
* @category Components
|
|
5235
5530
|
*/
|
|
5236
5531
|
class CollisionComponentElement extends ComponentElement {
|
|
@@ -5267,7 +5562,9 @@
|
|
|
5267
5562
|
* no attribute to supply it - so the host's visible geometry, the meaning a mesh collider
|
|
5268
5563
|
* on a glTF node carries, fills the gap. Runs on every application (so a rebound `pc-node`
|
|
5269
5564
|
* recomputes it) and on a runtime switch to `type="mesh"`; an explicitly assigned
|
|
5270
|
-
* `renderAsset` is never overwritten.
|
|
5565
|
+
* `renderAsset` is never overwritten. A `pc-model` host entity never carries a render
|
|
5566
|
+
* component (the instantiated content beneath it does), so a mesh collider that should take
|
|
5567
|
+
* an asset's geometry belongs on a bound `pc-node`.
|
|
5271
5568
|
*/
|
|
5272
5569
|
_applyMeshGeometryDefault() {
|
|
5273
5570
|
const component = this.component;
|
|
@@ -5412,6 +5709,17 @@
|
|
|
5412
5709
|
* The ElementComponentElement interface also inherits the properties and methods of the
|
|
5413
5710
|
* {@link HTMLElement} interface.
|
|
5414
5711
|
*
|
|
5712
|
+
* Despite the name, this is not a base class or a generic wrapper: it is the engine's 2D UI
|
|
5713
|
+
* component, which gives its host entity a rectangle in a `<pc-screen>` hierarchy that draws
|
|
5714
|
+
* either an image, a line of text or nothing (`type="image"`, `"text"` or `"group"`). The tag
|
|
5715
|
+
* spells the engine component it adds, as every component element does.
|
|
5716
|
+
*
|
|
5717
|
+
* Engine component: {@link ElementComponent} (`element`).
|
|
5718
|
+
*
|
|
5719
|
+
* @elementSummary The `<pc-element>` element gives its entity a 2D UI rectangle inside a
|
|
5720
|
+
* `<pc-screen>` hierarchy, drawing an image, a line of text or nothing (`type="image"`, `"text"` or
|
|
5721
|
+
* `"group"`). Must be a child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
5722
|
+
*
|
|
5415
5723
|
* @category Components
|
|
5416
5724
|
*/
|
|
5417
5725
|
class ElementComponentElement extends ComponentElement {
|
|
@@ -6096,10 +6404,17 @@
|
|
|
6096
6404
|
* a rigid body component; leaving `entity-b` empty constrains `entity-a` to a fixed point in world
|
|
6097
6405
|
* space. The underlying engine component is in alpha, so its API may change.
|
|
6098
6406
|
*
|
|
6407
|
+
* @elementSummary The `<pc-joint>` element constrains two rigid bodies to each other — a hinged
|
|
6408
|
+
* door, a swinging chain, a sliding drawer. Its entity's transform is the joint frame, and
|
|
6409
|
+
* `entity-a` and `entity-b` name the bodies. Must be a child of a `<pc-entity>`, `<pc-model>` or
|
|
6410
|
+
* `<pc-node>`.
|
|
6411
|
+
*
|
|
6099
6412
|
* @fires {CustomEvent} break - Fired when the impulse on the joint exceeds `break-impulse` and the
|
|
6100
6413
|
* constraint breaks. A broken joint no longer constrains its bodies; calling `refreshFrames()` on
|
|
6101
6414
|
* the underlying component re-attaches it. Bubbles and is composed.
|
|
6102
6415
|
*
|
|
6416
|
+
* Engine component: {@link JointComponent} (`joint`).
|
|
6417
|
+
*
|
|
6103
6418
|
* @category Components
|
|
6104
6419
|
*/
|
|
6105
6420
|
class JointComponentElement extends ComponentElement {
|
|
@@ -6958,10 +7273,16 @@
|
|
|
6958
7273
|
|
|
6959
7274
|
/**
|
|
6960
7275
|
* The LayoutChildComponentElement interface provides properties and methods for manipulating
|
|
6961
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
7276
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-layout-child/ | `<pc-layout-child>`} elements.
|
|
6962
7277
|
* The LayoutChildComponentElement interface also inherits the properties and methods of the
|
|
6963
7278
|
* {@link HTMLElement} interface.
|
|
6964
7279
|
*
|
|
7280
|
+
* Engine component: {@link LayoutChildComponent} (`layoutchild`).
|
|
7281
|
+
*
|
|
7282
|
+
* @elementSummary The `<pc-layout-child>` element controls how its entity is sized by the
|
|
7283
|
+
* `<pc-layout-group>` above it, through minimum and maximum sizes and fit proportions. Must be a
|
|
7284
|
+
* child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
7285
|
+
*
|
|
6965
7286
|
* @category Components
|
|
6966
7287
|
*/
|
|
6967
7288
|
class LayoutChildComponentElement extends ComponentElement {
|
|
@@ -7154,7 +7475,7 @@
|
|
|
7154
7475
|
}
|
|
7155
7476
|
}
|
|
7156
7477
|
}
|
|
7157
|
-
customElements.define('pc-
|
|
7478
|
+
customElements.define('pc-layout-child', LayoutChildComponentElement);
|
|
7158
7479
|
|
|
7159
7480
|
const orientations$1 = new Map([
|
|
7160
7481
|
['horizontal', playcanvas.ORIENTATION_HORIZONTAL],
|
|
@@ -7168,10 +7489,16 @@
|
|
|
7168
7489
|
]);
|
|
7169
7490
|
/**
|
|
7170
7491
|
* The LayoutGroupComponentElement interface provides properties and methods for manipulating
|
|
7171
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
7492
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-layout-group/ | `<pc-layout-group>`} elements.
|
|
7172
7493
|
* The LayoutGroupComponentElement interface also inherits the properties and methods of the
|
|
7173
7494
|
* {@link HTMLElement} interface.
|
|
7174
7495
|
*
|
|
7496
|
+
* Engine component: {@link LayoutGroupComponent} (`layoutgroup`).
|
|
7497
|
+
*
|
|
7498
|
+
* @elementSummary The `<pc-layout-group>` element arranges its entity's children in a row or
|
|
7499
|
+
* column, with spacing, padding, alignment and fitting. Must be a child of a `<pc-entity>`,
|
|
7500
|
+
* `<pc-model>` or `<pc-node>`.
|
|
7501
|
+
*
|
|
7175
7502
|
* @category Components
|
|
7176
7503
|
*/
|
|
7177
7504
|
class LayoutGroupComponentElement extends ComponentElement {
|
|
@@ -7411,7 +7738,7 @@
|
|
|
7411
7738
|
}
|
|
7412
7739
|
}
|
|
7413
7740
|
}
|
|
7414
|
-
customElements.define('pc-
|
|
7741
|
+
customElements.define('pc-layout-group', LayoutGroupComponentElement);
|
|
7415
7742
|
|
|
7416
7743
|
const shadowTypes = new Map([
|
|
7417
7744
|
['pcf1-16f', playcanvas.SHADOW_PCF1_16F],
|
|
@@ -7430,23 +7757,32 @@
|
|
|
7430
7757
|
* The LightComponentElement interface also inherits the properties and methods of the
|
|
7431
7758
|
* {@link HTMLElement} interface.
|
|
7432
7759
|
*
|
|
7760
|
+
* Engine component: {@link LightComponent} (`light`).
|
|
7761
|
+
*
|
|
7762
|
+
* @elementSummary The `<pc-light>` element lights the scene from its entity — as a directional,
|
|
7763
|
+
* omni or spot light — with attributes for color, intensity, range and shadows. Must be a child of
|
|
7764
|
+
* a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
7765
|
+
*
|
|
7433
7766
|
* @category Components
|
|
7434
7767
|
*/
|
|
7435
7768
|
class LightComponentElement extends ComponentElement {
|
|
7769
|
+
_cascadeBlend = 0;
|
|
7770
|
+
_cascadeDistribution = 0.5;
|
|
7436
7771
|
_castShadows = false;
|
|
7437
7772
|
_color = new playcanvas.Color(1, 1, 1);
|
|
7438
7773
|
_innerConeAngle = 40;
|
|
7439
7774
|
_intensity = 1;
|
|
7440
|
-
_normalOffsetBias = 0
|
|
7775
|
+
_normalOffsetBias = 0;
|
|
7776
|
+
_numCascades = 1;
|
|
7441
7777
|
_outerConeAngle = 45;
|
|
7442
7778
|
_range = 10;
|
|
7443
|
-
_shadowBias = 0.
|
|
7444
|
-
_shadowDistance =
|
|
7779
|
+
_shadowBias = 0.05;
|
|
7780
|
+
_shadowDistance = 40;
|
|
7445
7781
|
_shadowIntensity = 1;
|
|
7446
7782
|
_shadowResolution = 1024;
|
|
7447
7783
|
_shadowType = 'pcf3-32f';
|
|
7448
7784
|
_type = 'directional';
|
|
7449
|
-
_vsmBias = 0.
|
|
7785
|
+
_vsmBias = 0.0025;
|
|
7450
7786
|
_vsmBlurSize = 11;
|
|
7451
7787
|
_penumbraSize = 1;
|
|
7452
7788
|
_penumbraFalloff = 1;
|
|
@@ -7458,11 +7794,14 @@
|
|
|
7458
7794
|
}
|
|
7459
7795
|
getInitialComponentData() {
|
|
7460
7796
|
return {
|
|
7797
|
+
cascadeBlend: this._cascadeBlend,
|
|
7798
|
+
cascadeDistribution: this._cascadeDistribution,
|
|
7461
7799
|
castShadows: this._castShadows,
|
|
7462
7800
|
color: this._color,
|
|
7463
7801
|
innerConeAngle: this._innerConeAngle,
|
|
7464
7802
|
intensity: this._intensity,
|
|
7465
7803
|
normalOffsetBias: this._normalOffsetBias,
|
|
7804
|
+
numCascades: this._numCascades,
|
|
7466
7805
|
outerConeAngle: this._outerConeAngle,
|
|
7467
7806
|
penumbraFalloff: this._penumbraFalloff,
|
|
7468
7807
|
penumbraSize: this._penumbraSize,
|
|
@@ -7473,7 +7812,7 @@
|
|
|
7473
7812
|
shadowIntensity: this._shadowIntensity,
|
|
7474
7813
|
shadowResolution: this._shadowResolution,
|
|
7475
7814
|
shadowSamples: this._shadowSamples,
|
|
7476
|
-
shadowType: shadowTypes.get(this._shadowType),
|
|
7815
|
+
shadowType: shadowTypes.get(this._shadowType) ?? playcanvas.SHADOW_PCF3_32F,
|
|
7477
7816
|
type: this._type,
|
|
7478
7817
|
vsmBias: this._vsmBias,
|
|
7479
7818
|
vsmBlurSize: this._vsmBlurSize
|
|
@@ -7486,6 +7825,47 @@
|
|
|
7486
7825
|
get component() {
|
|
7487
7826
|
return super.component;
|
|
7488
7827
|
}
|
|
7828
|
+
/**
|
|
7829
|
+
* Sets the fraction of each shadow cascade that is blended into the next one, from 0 (no
|
|
7830
|
+
* blending) to 1, which applies only to `directional` lights with `num-cascades` greater than
|
|
7831
|
+
* 1. Defaults to 0.
|
|
7832
|
+
* @param value - The cascade blend factor.
|
|
7833
|
+
*/
|
|
7834
|
+
set cascadeBlend(value) {
|
|
7835
|
+
this._cascadeBlend = value;
|
|
7836
|
+
if (this.component) {
|
|
7837
|
+
this.component.cascadeBlend = value;
|
|
7838
|
+
}
|
|
7839
|
+
}
|
|
7840
|
+
/**
|
|
7841
|
+
* Gets the cascade blend factor of the light, from 0 (no blending) to 1, which applies only to
|
|
7842
|
+
* `directional` lights with `num-cascades` greater than 1.
|
|
7843
|
+
* @returns The cascade blend factor.
|
|
7844
|
+
*/
|
|
7845
|
+
get cascadeBlend() {
|
|
7846
|
+
return this._cascadeBlend;
|
|
7847
|
+
}
|
|
7848
|
+
/**
|
|
7849
|
+
* Sets the distribution of the camera frustum split between shadow cascades, from 0 (linear
|
|
7850
|
+
* split) to 1 (logarithmic split, concentrating shadow resolution near the camera), which
|
|
7851
|
+
* applies only to `directional` lights with `num-cascades` greater than 1. Defaults to 0.5.
|
|
7852
|
+
* @param value - The cascade distribution.
|
|
7853
|
+
*/
|
|
7854
|
+
set cascadeDistribution(value) {
|
|
7855
|
+
this._cascadeDistribution = value;
|
|
7856
|
+
if (this.component) {
|
|
7857
|
+
this.component.cascadeDistribution = value;
|
|
7858
|
+
}
|
|
7859
|
+
}
|
|
7860
|
+
/**
|
|
7861
|
+
* Gets the cascade distribution of the light, from 0 (linear split) to 1 (logarithmic split,
|
|
7862
|
+
* concentrating shadow resolution near the camera), which applies only to `directional` lights
|
|
7863
|
+
* with `num-cascades` greater than 1.
|
|
7864
|
+
* @returns The cascade distribution.
|
|
7865
|
+
*/
|
|
7866
|
+
get cascadeDistribution() {
|
|
7867
|
+
return this._cascadeDistribution;
|
|
7868
|
+
}
|
|
7489
7869
|
/**
|
|
7490
7870
|
* Sets the cast shadows flag of the light.
|
|
7491
7871
|
* @param value - The cast shadows flag.
|
|
@@ -7571,6 +7951,25 @@
|
|
|
7571
7951
|
get normalOffsetBias() {
|
|
7572
7952
|
return this._normalOffsetBias;
|
|
7573
7953
|
}
|
|
7954
|
+
/**
|
|
7955
|
+
* Sets the number of shadow cascades of the light, an integer from 1 (no cascades) to 4, which
|
|
7956
|
+
* applies only to `directional` lights. Defaults to 1.
|
|
7957
|
+
* @param value - The number of shadow cascades.
|
|
7958
|
+
*/
|
|
7959
|
+
set numCascades(value) {
|
|
7960
|
+
this._numCascades = value;
|
|
7961
|
+
if (this.component) {
|
|
7962
|
+
this.component.numCascades = value;
|
|
7963
|
+
}
|
|
7964
|
+
}
|
|
7965
|
+
/**
|
|
7966
|
+
* Gets the number of shadow cascades of the light, an integer from 1 (no cascades) to 4, which
|
|
7967
|
+
* applies only to `directional` lights.
|
|
7968
|
+
* @returns The number of shadow cascades.
|
|
7969
|
+
*/
|
|
7970
|
+
get numCascades() {
|
|
7971
|
+
return this._numCascades;
|
|
7972
|
+
}
|
|
7574
7973
|
/**
|
|
7575
7974
|
* Sets the outer cone angle of the light.
|
|
7576
7975
|
* @param value - The outer cone angle.
|
|
@@ -7823,11 +8222,14 @@
|
|
|
7823
8222
|
static get observedAttributes() {
|
|
7824
8223
|
return [
|
|
7825
8224
|
...super.observedAttributes,
|
|
7826
|
-
'
|
|
8225
|
+
'cascade-blend',
|
|
8226
|
+
'cascade-distribution',
|
|
7827
8227
|
'cast-shadows',
|
|
7828
|
-
'
|
|
8228
|
+
'color',
|
|
7829
8229
|
'inner-cone-angle',
|
|
8230
|
+
'intensity',
|
|
7830
8231
|
'normal-offset-bias',
|
|
8232
|
+
'num-cascades',
|
|
7831
8233
|
'outer-cone-angle',
|
|
7832
8234
|
'penumbra-falloff',
|
|
7833
8235
|
'penumbra-size',
|
|
@@ -7847,12 +8249,18 @@
|
|
|
7847
8249
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
7848
8250
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
7849
8251
|
switch (name) {
|
|
7850
|
-
case '
|
|
7851
|
-
this.
|
|
8252
|
+
case 'cascade-blend':
|
|
8253
|
+
this.cascadeBlend = parseNumber(newValue, 0, name);
|
|
8254
|
+
break;
|
|
8255
|
+
case 'cascade-distribution':
|
|
8256
|
+
this.cascadeDistribution = parseNumber(newValue, 0.5, name);
|
|
7852
8257
|
break;
|
|
7853
8258
|
case 'cast-shadows':
|
|
7854
8259
|
this.castShadows = parseBool(newValue, false);
|
|
7855
8260
|
break;
|
|
8261
|
+
case 'color':
|
|
8262
|
+
this.color = parseColor(newValue, playcanvas.Color.WHITE, name);
|
|
8263
|
+
break;
|
|
7856
8264
|
case 'inner-cone-angle':
|
|
7857
8265
|
this.innerConeAngle = parseNumber(newValue, 40, name);
|
|
7858
8266
|
break;
|
|
@@ -7860,7 +8268,10 @@
|
|
|
7860
8268
|
this.intensity = parseNumber(newValue, 1, name);
|
|
7861
8269
|
break;
|
|
7862
8270
|
case 'normal-offset-bias':
|
|
7863
|
-
this.normalOffsetBias = parseNumber(newValue, 0
|
|
8271
|
+
this.normalOffsetBias = parseNumber(newValue, 0, name);
|
|
8272
|
+
break;
|
|
8273
|
+
case 'num-cascades':
|
|
8274
|
+
this.numCascades = parseNumber(newValue, 1, name);
|
|
7864
8275
|
break;
|
|
7865
8276
|
case 'outer-cone-angle':
|
|
7866
8277
|
this.outerConeAngle = parseNumber(newValue, 45, name);
|
|
@@ -7875,20 +8286,20 @@
|
|
|
7875
8286
|
this.range = parseNumber(newValue, 10, name);
|
|
7876
8287
|
break;
|
|
7877
8288
|
case 'shadow-bias':
|
|
7878
|
-
this.shadowBias = parseNumber(newValue, 0.
|
|
7879
|
-
break;
|
|
7880
|
-
case 'shadow-distance':
|
|
7881
|
-
this.shadowDistance = parseNumber(newValue, 16, name);
|
|
8289
|
+
this.shadowBias = parseNumber(newValue, 0.05, name);
|
|
7882
8290
|
break;
|
|
7883
8291
|
case 'shadow-blocker-samples':
|
|
7884
8292
|
this.shadowBlockerSamples = parseNumber(newValue, 16, name);
|
|
7885
8293
|
break;
|
|
7886
|
-
case 'shadow-
|
|
7887
|
-
this.
|
|
8294
|
+
case 'shadow-distance':
|
|
8295
|
+
this.shadowDistance = parseNumber(newValue, 40, name);
|
|
7888
8296
|
break;
|
|
7889
8297
|
case 'shadow-intensity':
|
|
7890
8298
|
this.shadowIntensity = parseNumber(newValue, 1, name);
|
|
7891
8299
|
break;
|
|
8300
|
+
case 'shadow-resolution':
|
|
8301
|
+
this.shadowResolution = parseNumber(newValue, 1024, name);
|
|
8302
|
+
break;
|
|
7892
8303
|
case 'shadow-samples':
|
|
7893
8304
|
this.shadowSamples = parseNumber(newValue, 16, name);
|
|
7894
8305
|
break;
|
|
@@ -7899,7 +8310,7 @@
|
|
|
7899
8310
|
this.type = parseEnum(newValue, ['directional', 'omni', 'spot'], 'directional', name);
|
|
7900
8311
|
break;
|
|
7901
8312
|
case 'vsm-bias':
|
|
7902
|
-
this.vsmBias = parseNumber(newValue, 0.
|
|
8313
|
+
this.vsmBias = parseNumber(newValue, 0.0025, name);
|
|
7903
8314
|
break;
|
|
7904
8315
|
case 'vsm-blur-size':
|
|
7905
8316
|
this.vsmBlurSize = parseNumber(newValue, 11, name);
|
|
@@ -7911,10 +8322,16 @@
|
|
|
7911
8322
|
|
|
7912
8323
|
/**
|
|
7913
8324
|
* The ParticleSystemComponentElement interface provides properties and methods for manipulating
|
|
7914
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
8325
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-particle-system/ | `<pc-particle-system>`} elements.
|
|
7915
8326
|
* The ParticleSystemComponentElement interface also inherits the properties and methods of the
|
|
7916
8327
|
* {@link HTMLElement} interface.
|
|
7917
8328
|
*
|
|
8329
|
+
* Engine component: {@link ParticleSystemComponent} (`particlesystem`).
|
|
8330
|
+
*
|
|
8331
|
+
* @elementSummary The `<pc-particle-system>` element emits particles from its entity, with
|
|
8332
|
+
* attributes for the emitter's shape, rate, lifetime, textures and blending. Must be a child of a
|
|
8333
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
8334
|
+
*
|
|
7918
8335
|
* @category Components
|
|
7919
8336
|
*/
|
|
7920
8337
|
class ParticleSystemComponentElement extends ComponentElement {
|
|
@@ -8033,7 +8450,7 @@
|
|
|
8033
8450
|
}
|
|
8034
8451
|
}
|
|
8035
8452
|
}
|
|
8036
|
-
customElements.define('pc-
|
|
8453
|
+
customElements.define('pc-particle-system', ParticleSystemComponentElement);
|
|
8037
8454
|
|
|
8038
8455
|
const blendTypes = new Map([
|
|
8039
8456
|
['none', playcanvas.BLEND_NONE],
|
|
@@ -8063,6 +8480,8 @@
|
|
|
8063
8480
|
['ao', playcanvas.SPECOCC_AO],
|
|
8064
8481
|
['gloss-dependent', playcanvas.SPECOCC_GLOSSDEPENDENT]
|
|
8065
8482
|
]);
|
|
8483
|
+
// The DITHER_* constants are strings whose values are exactly these names, so a parsed value is
|
|
8484
|
+
// assigned to the material unchanged rather than mapped through a table.
|
|
8066
8485
|
const opacityDithers = ['none', 'bayer8', 'bluenoise', 'ignnoise'];
|
|
8067
8486
|
const colorChannels = ['r', 'g', 'b', 'a', 'rgb'];
|
|
8068
8487
|
const scalarChannels = ['r', 'g', 'b', 'a'];
|
|
@@ -8099,6 +8518,10 @@
|
|
|
8099
8518
|
* The two aliases are documented here rather than on an accessor, because they resolve to the
|
|
8100
8519
|
* `gloss` properties and would otherwise inherit gloss's description - which reads inverted.
|
|
8101
8520
|
*
|
|
8521
|
+
* @elementSummary The `<pc-material>` element defines a physically based material, which
|
|
8522
|
+
* `<pc-render>` elements apply by naming its `id`. It is metal/rough by default, with `metalness`
|
|
8523
|
+
* starting at 0. Must be a direct child of `<pc-app>`.
|
|
8524
|
+
*
|
|
8102
8525
|
* @attribute {number} roughness - The roughness of the material, from 0 (shiny) to 1 (rough). An
|
|
8103
8526
|
* alias for `gloss` that also inverts it, so do not combine it with the `gloss` attributes.
|
|
8104
8527
|
* @attribute {string} roughness-map - The id of the `pc-asset` to use as the roughness map. An
|
|
@@ -10265,6 +10688,13 @@
|
|
|
10265
10688
|
* to `box`). It does not cover the engine's `asset` render type, since there is no way to supply
|
|
10266
10689
|
* a render asset here — use `pc-model` for glTF content instead.
|
|
10267
10690
|
*
|
|
10691
|
+
* Engine component: {@link RenderComponent} (`render`).
|
|
10692
|
+
*
|
|
10693
|
+
* @elementSummary The `<pc-render>` element renders one of the engine's built-in primitives at its
|
|
10694
|
+
* entity — box, sphere, capsule, cone, cylinder or plane — shaded by the `<pc-material>` its
|
|
10695
|
+
* `material` attribute names. For glTF content, use `<pc-model>` instead. Must be a child of a
|
|
10696
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
10697
|
+
*
|
|
10268
10698
|
* @category Components
|
|
10269
10699
|
*/
|
|
10270
10700
|
class RenderComponentElement extends ComponentElement {
|
|
@@ -10389,10 +10819,17 @@
|
|
|
10389
10819
|
|
|
10390
10820
|
/**
|
|
10391
10821
|
* The RigidBodyComponentElement interface provides properties and methods for manipulating
|
|
10392
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
10822
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-rigid-body/ | `<pc-rigid-body>`} elements.
|
|
10393
10823
|
* The RigidBodyComponentElement interface also inherits the properties and methods of the
|
|
10394
10824
|
* {@link HTMLElement} interface.
|
|
10395
10825
|
*
|
|
10826
|
+
* Engine component: {@link RigidBodyComponent} (`rigidbody`).
|
|
10827
|
+
*
|
|
10828
|
+
* @elementSummary The `<pc-rigid-body>` element hands its entity to the physics simulation, with
|
|
10829
|
+
* attributes for its type, mass, friction and restitution. It needs a sibling `<pc-collision>` for
|
|
10830
|
+
* its shape, and `Ammo` loaded through `<pc-wasm>`. Must be a child of a `<pc-entity>`,
|
|
10831
|
+
* `<pc-model>` or `<pc-node>`.
|
|
10832
|
+
*
|
|
10396
10833
|
* @category Components
|
|
10397
10834
|
*/
|
|
10398
10835
|
class RigidBodyComponentElement extends ComponentElement {
|
|
@@ -10584,7 +11021,7 @@
|
|
|
10584
11021
|
}
|
|
10585
11022
|
}
|
|
10586
11023
|
}
|
|
10587
|
-
customElements.define('pc-
|
|
11024
|
+
customElements.define('pc-rigid-body', RigidBodyComponentElement);
|
|
10588
11025
|
|
|
10589
11026
|
// The engine's SCALEMODE_* constants are the strings 'none' and 'blend', so this map happens to be
|
|
10590
11027
|
// an identity. It is still the right shape: it supplies parseEnum's valid-name list, it is what the
|
|
@@ -10600,6 +11037,12 @@
|
|
|
10600
11037
|
* The ScreenComponentElement interface also inherits the properties and methods of the
|
|
10601
11038
|
* {@link HTMLElement} interface.
|
|
10602
11039
|
*
|
|
11040
|
+
* Engine component: {@link ScreenComponent} (`screen`).
|
|
11041
|
+
*
|
|
11042
|
+
* @elementSummary The `<pc-screen>` element gives its entity a 2D space — in screen space or in the
|
|
11043
|
+
* world — that a hierarchy of `<pc-element>` descendants lays out inside. Must be a child of a
|
|
11044
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
11045
|
+
*
|
|
10603
11046
|
* @category Components
|
|
10604
11047
|
*/
|
|
10605
11048
|
class ScreenComponentElement extends ComponentElement {
|
|
@@ -10752,6 +11195,12 @@
|
|
|
10752
11195
|
* The ScrollbarComponentElement interface also inherits the properties and methods of the
|
|
10753
11196
|
* {@link HTMLElement} interface.
|
|
10754
11197
|
*
|
|
11198
|
+
* Engine component: {@link ScrollbarComponent} (`scrollbar`).
|
|
11199
|
+
*
|
|
11200
|
+
* @elementSummary The `<pc-scrollbar>` element gives its entity a draggable handle reporting a
|
|
11201
|
+
* position from 0 to 1, which a `<pc-scroll-view>` references to scroll its content. Must be a
|
|
11202
|
+
* child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
11203
|
+
*
|
|
10755
11204
|
* @category Components
|
|
10756
11205
|
*/
|
|
10757
11206
|
class ScrollbarComponentElement extends ComponentElement {
|
|
@@ -10887,10 +11336,16 @@
|
|
|
10887
11336
|
]);
|
|
10888
11337
|
/**
|
|
10889
11338
|
* The ScrollViewComponentElement interface provides properties and methods for manipulating
|
|
10890
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
11339
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-scroll-view/ | `<pc-scroll-view>`} elements.
|
|
10891
11340
|
* The ScrollViewComponentElement interface also inherits the properties and methods of the
|
|
10892
11341
|
* {@link HTMLElement} interface.
|
|
10893
11342
|
*
|
|
11343
|
+
* Engine component: {@link ScrollViewComponent} (`scrollview`).
|
|
11344
|
+
*
|
|
11345
|
+
* @elementSummary The `<pc-scroll-view>` element scrolls a larger content entity within a clipped
|
|
11346
|
+
* viewport at its entity, optionally driven by the `<pc-scrollbar>` elements it references. Must be
|
|
11347
|
+
* a child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
11348
|
+
*
|
|
10894
11349
|
* @category Components
|
|
10895
11350
|
*/
|
|
10896
11351
|
class ScrollViewComponentElement extends ComponentElement {
|
|
@@ -11249,11 +11704,11 @@
|
|
|
11249
11704
|
}
|
|
11250
11705
|
}
|
|
11251
11706
|
}
|
|
11252
|
-
customElements.define('pc-
|
|
11707
|
+
customElements.define('pc-scroll-view', ScrollViewComponentElement);
|
|
11253
11708
|
|
|
11254
11709
|
/**
|
|
11255
|
-
* The
|
|
11256
|
-
* `<pc-script>` elements. The
|
|
11710
|
+
* The ScriptInstanceElement interface provides properties and methods for manipulating
|
|
11711
|
+
* `<pc-script-instance>` elements. The ScriptInstanceElement interface also inherits the properties and
|
|
11257
11712
|
* methods of the {@link AsyncElement} interface.
|
|
11258
11713
|
*
|
|
11259
11714
|
* Script attributes can be supplied through two channels:
|
|
@@ -11275,7 +11730,11 @@
|
|
|
11275
11730
|
* new-name one, re-applying both attribute channels to it.
|
|
11276
11731
|
*
|
|
11277
11732
|
* The element becomes ready once its script instance has been created by the parent
|
|
11278
|
-
* `<pc-
|
|
11733
|
+
* `<pc-script>` element.
|
|
11734
|
+
*
|
|
11735
|
+
* @elementSummary The `<pc-script-instance>` element attaches one script class, named by `name`, to
|
|
11736
|
+
* the entity of its parent `<pc-script>`. Its other attributes set script attributes of the same
|
|
11737
|
+
* name, and `attributes` takes a JSON object instead. Must be a direct child of `<pc-script>`.
|
|
11279
11738
|
*
|
|
11280
11739
|
* @fires {CustomEvent} scriptattributeschange - Fired when the script's attributes change. The
|
|
11281
11740
|
* `detail` carries the new `attributes` object. Bubbles.
|
|
@@ -11284,11 +11743,11 @@
|
|
|
11284
11743
|
* @fires {CustomEvent} scriptnamechange - Fired when the script is renamed on a live element. The
|
|
11285
11744
|
* `detail` carries `oldName` and `newName`. Bubbles.
|
|
11286
11745
|
*/
|
|
11287
|
-
class
|
|
11746
|
+
class ScriptInstanceElement extends AsyncElement {
|
|
11288
11747
|
_attributes = {};
|
|
11289
11748
|
_enabled = true;
|
|
11290
11749
|
/**
|
|
11291
|
-
* The Script instance created for this element by its parent `<pc-
|
|
11750
|
+
* The Script instance created for this element by its parent `<pc-script>` element.
|
|
11292
11751
|
* @internal
|
|
11293
11752
|
*/
|
|
11294
11753
|
_script = null;
|
|
@@ -11334,11 +11793,11 @@
|
|
|
11334
11793
|
}
|
|
11335
11794
|
/**
|
|
11336
11795
|
* Sets the name of the script to create. The `name` attribute is the single source of truth
|
|
11337
|
-
* (it is what the parent `<pc-
|
|
11796
|
+
* (it is what the parent `<pc-script>` element reads when creating the instance), so the
|
|
11338
11797
|
* property writes through to it — assigning before insertion works as expected:
|
|
11339
11798
|
*
|
|
11340
11799
|
* ```js
|
|
11341
|
-
* const script = document.createElement('pc-script');
|
|
11800
|
+
* const script = document.createElement('pc-script-instance');
|
|
11342
11801
|
* script.name = 'rotate';
|
|
11343
11802
|
* scriptsElement.appendChild(script);
|
|
11344
11803
|
* await script.ready();
|
|
@@ -11365,10 +11824,10 @@
|
|
|
11365
11824
|
return this._script;
|
|
11366
11825
|
}
|
|
11367
11826
|
connectedCallback() {
|
|
11368
|
-
// Script instances are created by the parent pc-
|
|
11827
|
+
// Script instances are created by the parent pc-script element, so an element placed
|
|
11369
11828
|
// anywhere else is inert and never becomes ready - warn rather than hang silently
|
|
11370
|
-
if (this.parentElement?.tagName !== 'PC-
|
|
11371
|
-
console.warn(`pc-script '${this.getAttribute('name')}' must be a direct child of pc-
|
|
11829
|
+
if (this.parentElement?.tagName !== 'PC-SCRIPT') {
|
|
11830
|
+
console.warn(`pc-script-instance '${this.getAttribute('name')}' must be a direct child of pc-script - script not created`);
|
|
11372
11831
|
}
|
|
11373
11832
|
}
|
|
11374
11833
|
disconnectedCallback() {
|
|
@@ -11379,7 +11838,7 @@
|
|
|
11379
11838
|
this._resetReady();
|
|
11380
11839
|
}
|
|
11381
11840
|
/**
|
|
11382
|
-
* Called by the parent `<pc-
|
|
11841
|
+
* Called by the parent `<pc-script>` element when the script instance has been created.
|
|
11383
11842
|
* Creation can happen more than once per connection (a runtime `name` change recreates the
|
|
11384
11843
|
* instance), but `_onReady` signals readiness at most once per cycle.
|
|
11385
11844
|
* @internal
|
|
@@ -11401,7 +11860,7 @@
|
|
|
11401
11860
|
this.scriptAttributes = JSON.parse(newValue);
|
|
11402
11861
|
}
|
|
11403
11862
|
catch (error) {
|
|
11404
|
-
console.warn(`Invalid 'attributes' JSON on pc-script '${this.getAttribute('name')}': ${error.message}`);
|
|
11863
|
+
console.warn(`Invalid 'attributes' JSON on pc-script-instance '${this.getAttribute('name')}': ${error.message}`);
|
|
11405
11864
|
}
|
|
11406
11865
|
break;
|
|
11407
11866
|
case 'enabled':
|
|
@@ -11421,14 +11880,14 @@
|
|
|
11421
11880
|
}
|
|
11422
11881
|
}
|
|
11423
11882
|
}
|
|
11424
|
-
customElements.define('pc-script',
|
|
11883
|
+
customElements.define('pc-script-instance', ScriptInstanceElement);
|
|
11425
11884
|
|
|
11426
11885
|
/**
|
|
11427
|
-
* Attributes on `pc-script` that never map to script attributes: the element's own API (derived
|
|
11886
|
+
* Attributes on `pc-script-instance` that never map to script attributes: the element's own API (derived
|
|
11428
11887
|
* from its observed attributes) plus reserved and global HTML attribute names.
|
|
11429
11888
|
*/
|
|
11430
11889
|
const RESERVED_ATTRIBUTES = new Set([
|
|
11431
|
-
...
|
|
11890
|
+
...ScriptInstanceElement.observedAttributes,
|
|
11432
11891
|
'accesskey',
|
|
11433
11892
|
'autocapitalize',
|
|
11434
11893
|
'autofocus',
|
|
@@ -11459,7 +11918,7 @@
|
|
|
11459
11918
|
'translate'
|
|
11460
11919
|
]);
|
|
11461
11920
|
/**
|
|
11462
|
-
* Checks whether a `pc-script` attribute name is reserved (and so never maps to a script
|
|
11921
|
+
* Checks whether a `pc-script-instance` attribute name is reserved (and so never maps to a script
|
|
11463
11922
|
* attribute). Reserved names are the element's own API, global HTML attribute names, `data-*`
|
|
11464
11923
|
* and `aria-*` attributes, names starting with `_` (framework-stamped attributes), and real
|
|
11465
11924
|
* inline event handler names (`onclick` etc. — detected via the platform, so script attributes
|
|
@@ -11615,10 +12074,15 @@
|
|
|
11615
12074
|
};
|
|
11616
12075
|
/**
|
|
11617
12076
|
* The ScriptComponentElement interface provides properties and methods for manipulating
|
|
11618
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
12077
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-script/ | `<pc-script>`} elements.
|
|
11619
12078
|
* The ScriptComponentElement interface also inherits the properties and methods of the
|
|
11620
12079
|
* {@link HTMLElement} interface.
|
|
11621
12080
|
*
|
|
12081
|
+
* Engine component: {@link ScriptComponent} (`script`).
|
|
12082
|
+
*
|
|
12083
|
+
* @elementSummary The `<pc-script>` element holds the `<pc-script-instance>` children that attach
|
|
12084
|
+
* scripts to its entity. Must be a child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
12085
|
+
*
|
|
11622
12086
|
* @category Components
|
|
11623
12087
|
*/
|
|
11624
12088
|
class ScriptComponentElement extends ComponentElement {
|
|
@@ -11635,14 +12099,23 @@
|
|
|
11635
12099
|
}
|
|
11636
12100
|
connectedCallback() {
|
|
11637
12101
|
// (Re-)observe on every connection - disconnectedCallback disconnects the observer.
|
|
11638
|
-
// Attribute changes on child pc-script elements are watched here too: per-property
|
|
12102
|
+
// Attribute changes on child pc-script-instance elements are watched here too: per-property
|
|
11639
12103
|
// script attributes are not statically known, so they cannot use observedAttributes.
|
|
11640
12104
|
this.observer.observe(this, { childList: true, subtree: true, attributes: true });
|
|
11641
12105
|
return super.connectedCallback();
|
|
11642
12106
|
}
|
|
11643
12107
|
initComponent() {
|
|
11644
|
-
|
|
11645
|
-
|
|
12108
|
+
this.querySelectorAll(':scope > pc-script-instance').forEach((scriptElement) => {
|
|
12109
|
+
// A host readiness cycle re-runs this against a component that can have survived it
|
|
12110
|
+
// (a pc-model reloading content on its stable host entity). The engine rejects a
|
|
12111
|
+
// duplicate create - returning null, silently in production builds - which would
|
|
12112
|
+
// skip attribute application entirely. A surviving instance is re-asserted instead,
|
|
12113
|
+
// so both cycle outcomes leave the component reflecting the element's declared state.
|
|
12114
|
+
const script = this.scriptFor(scriptElement);
|
|
12115
|
+
if (script) {
|
|
12116
|
+
this.applyDeclaredState(script, scriptElement);
|
|
12117
|
+
return;
|
|
12118
|
+
}
|
|
11646
12119
|
this.createScript(scriptElement);
|
|
11647
12120
|
});
|
|
11648
12121
|
}
|
|
@@ -11776,9 +12249,9 @@
|
|
|
11776
12249
|
this.mergeDeep(script, converted);
|
|
11777
12250
|
}
|
|
11778
12251
|
/**
|
|
11779
|
-
* Returns the camelCase keys of the per-property attributes present on a `pc-script`
|
|
12252
|
+
* Returns the camelCase keys of the per-property attributes present on a `pc-script-instance`
|
|
11780
12253
|
* element.
|
|
11781
|
-
* @param scriptElement - The `pc-script` element.
|
|
12254
|
+
* @param scriptElement - The `pc-script-instance` element.
|
|
11782
12255
|
* @returns The camelCase keys.
|
|
11783
12256
|
*/
|
|
11784
12257
|
inlineKeys(scriptElement) {
|
|
@@ -11791,10 +12264,10 @@
|
|
|
11791
12264
|
return keys;
|
|
11792
12265
|
}
|
|
11793
12266
|
/**
|
|
11794
|
-
* Resolves the script instance owned by a `pc-script` element. Returns `null` when the
|
|
12267
|
+
* Resolves the script instance owned by a `pc-script-instance` element. Returns `null` when the
|
|
11795
12268
|
* element has no created script, or when its name resolves to a script created by a
|
|
11796
12269
|
* different element (e.g. a duplicate-named sibling).
|
|
11797
|
-
* @param scriptElement - The `pc-script` element.
|
|
12270
|
+
* @param scriptElement - The `pc-script-instance` element.
|
|
11798
12271
|
* @returns The owned script, or `null`.
|
|
11799
12272
|
*/
|
|
11800
12273
|
scriptFor(scriptElement) {
|
|
@@ -11823,7 +12296,7 @@
|
|
|
11823
12296
|
}
|
|
11824
12297
|
}
|
|
11825
12298
|
/**
|
|
11826
|
-
* Handles a runtime `name` change on a child `pc-script`, swapping the engine script instance
|
|
12299
|
+
* Handles a runtime `name` change on a child `pc-script-instance`, swapping the engine script instance
|
|
11827
12300
|
* to match. Without this the element would keep pointing at the old-name instance: the old
|
|
11828
12301
|
* script would go on running while every subsequent update (attribute changes, enable
|
|
11829
12302
|
* changes, destruction on removal) resolved the new name and silently no-opped.
|
|
@@ -11834,8 +12307,8 @@
|
|
|
11834
12307
|
*/
|
|
11835
12308
|
handleScriptNameChange(event) {
|
|
11836
12309
|
const scriptElement = event.target;
|
|
11837
|
-
// Only direct children are managed, matching initComponent's ':scope > pc-script'
|
|
11838
|
-
// contract - the event bubbles, so a deeper pc-script must not be created here
|
|
12310
|
+
// Only direct children are managed, matching initComponent's ':scope > pc-script-instance'
|
|
12311
|
+
// contract - the event bubbles, so a deeper pc-script-instance must not be created here
|
|
11839
12312
|
if (scriptElement.parentElement !== this)
|
|
11840
12313
|
return;
|
|
11841
12314
|
// Before the component exists there is nothing to swap: initComponent creates from
|
|
@@ -11852,11 +12325,11 @@
|
|
|
11852
12325
|
this.createScript(scriptElement);
|
|
11853
12326
|
}
|
|
11854
12327
|
/**
|
|
11855
|
-
* Creates the script instance for a `pc-script` element. The instance is created disabled,
|
|
12328
|
+
* Creates the script instance for a `pc-script-instance` element. The instance is created disabled,
|
|
11856
12329
|
* the element's converted attributes are merged over the instance's defaults (which is what
|
|
11857
12330
|
* allows plain numeric arrays to be typed against those defaults), and only then is the
|
|
11858
12331
|
* declared enabled state applied — so `initialize()` runs with every attribute in place.
|
|
11859
|
-
* @param scriptElement - The `pc-script` element to create the script instance for.
|
|
12332
|
+
* @param scriptElement - The `pc-script-instance` element to create the script instance for.
|
|
11860
12333
|
* @returns The created script, or `null`.
|
|
11861
12334
|
*/
|
|
11862
12335
|
createScript(scriptElement) {
|
|
@@ -11867,21 +12340,30 @@
|
|
|
11867
12340
|
if (!script)
|
|
11868
12341
|
return null;
|
|
11869
12342
|
scriptElement._script = script;
|
|
11870
|
-
|
|
11871
|
-
|
|
12343
|
+
this.applyDeclaredState(script, scriptElement);
|
|
12344
|
+
scriptElement._onScriptCreated();
|
|
12345
|
+
return script;
|
|
12346
|
+
}
|
|
12347
|
+
/**
|
|
12348
|
+
* Applies a `pc-script-instance` element's declared state to a script instance: the `attributes` JSON
|
|
12349
|
+
* first with per-property-shadowed keys stripped, then the per-property attributes — each
|
|
12350
|
+
* property is written exactly once and individual attributes win — and finally the declared
|
|
12351
|
+
* enabled state, so `initialize()` runs with every attribute in place.
|
|
12352
|
+
* @param script - The script instance.
|
|
12353
|
+
* @param scriptElement - The `pc-script-instance` element holding the declared state.
|
|
12354
|
+
*/
|
|
12355
|
+
applyDeclaredState(script, scriptElement) {
|
|
11872
12356
|
this.applyAttributes(script, scriptElement.scriptAttributes, this.inlineKeys(scriptElement));
|
|
11873
12357
|
this.applyInlineAttributes(script, scriptElement);
|
|
11874
12358
|
script.enabled = scriptElement.enabled;
|
|
11875
|
-
scriptElement._onScriptCreated();
|
|
11876
|
-
return script;
|
|
11877
12359
|
}
|
|
11878
12360
|
/**
|
|
11879
|
-
* Applies the per-property attributes present on a `pc-script` element — any attribute that
|
|
12361
|
+
* Applies the per-property attributes present on a `pc-script-instance` element — any attribute that
|
|
11880
12362
|
* is not part of the element's own API or a reserved HTML attribute name. These are applied
|
|
11881
12363
|
* after the `attributes` JSON, so an individual attribute always takes precedence over the
|
|
11882
12364
|
* blob.
|
|
11883
12365
|
* @param script - The script to apply the attributes to.
|
|
11884
|
-
* @param scriptElement - The `pc-script` element holding the attributes.
|
|
12366
|
+
* @param scriptElement - The `pc-script-instance` element holding the attributes.
|
|
11885
12367
|
*/
|
|
11886
12368
|
applyInlineAttributes(script, scriptElement) {
|
|
11887
12369
|
const scriptName = scriptElement.getAttribute('name') ?? '';
|
|
@@ -11892,10 +12374,10 @@
|
|
|
11892
12374
|
}
|
|
11893
12375
|
}
|
|
11894
12376
|
/**
|
|
11895
|
-
* Applies a single per-property attribute change to the script of a `pc-script` element.
|
|
12377
|
+
* Applies a single per-property attribute change to the script of a `pc-script-instance` element.
|
|
11896
12378
|
* When the attribute has been removed, the value from the `attributes` JSON (if any) takes
|
|
11897
12379
|
* effect again.
|
|
11898
|
-
* @param scriptElement - The `pc-script` element whose attribute changed.
|
|
12380
|
+
* @param scriptElement - The `pc-script-instance` element whose attribute changed.
|
|
11899
12381
|
* @param attributeName - The name of the changed attribute.
|
|
11900
12382
|
*/
|
|
11901
12383
|
applyScriptProperty(scriptElement, attributeName) {
|
|
@@ -11931,7 +12413,7 @@
|
|
|
11931
12413
|
try {
|
|
11932
12414
|
const current = script[key];
|
|
11933
12415
|
if (typeof current === 'function' || SCRIPT_API_MEMBERS.has(key)) {
|
|
11934
|
-
console.warn(`Ignoring attribute '${attributeName}' on pc-script '${scriptName}' - '${key}' is part of the Script API.`);
|
|
12416
|
+
console.warn(`Ignoring attribute '${attributeName}' on pc-script-instance '${scriptName}' - '${key}' is part of the Script API.`);
|
|
11935
12417
|
return;
|
|
11936
12418
|
}
|
|
11937
12419
|
if (typeof current === 'string') {
|
|
@@ -11987,10 +12469,10 @@
|
|
|
11987
12469
|
}
|
|
11988
12470
|
handleMutations(mutations) {
|
|
11989
12471
|
for (const mutation of mutations) {
|
|
11990
|
-
// Handle per-property attribute changes on child pc-script elements
|
|
12472
|
+
// Handle per-property attribute changes on child pc-script-instance elements
|
|
11991
12473
|
if (mutation.type === 'attributes') {
|
|
11992
12474
|
const target = mutation.target;
|
|
11993
|
-
if (target instanceof
|
|
12475
|
+
if (target instanceof ScriptInstanceElement &&
|
|
11994
12476
|
target.parentElement === this &&
|
|
11995
12477
|
mutation.attributeName &&
|
|
11996
12478
|
!isReservedAttribute(mutation.attributeName)) {
|
|
@@ -12000,16 +12482,16 @@
|
|
|
12000
12482
|
}
|
|
12001
12483
|
// Only direct children are managed - the observer watches the subtree for attribute
|
|
12002
12484
|
// changes, but deeper childList records must not create or destroy scripts
|
|
12003
|
-
// (matching initComponent's ':scope > pc-script' contract)
|
|
12485
|
+
// (matching initComponent's ':scope > pc-script-instance' contract)
|
|
12004
12486
|
if (mutation.target !== this) {
|
|
12005
12487
|
continue;
|
|
12006
12488
|
}
|
|
12007
|
-
// Handle removed nodes first, so that replacing a pc-script with a same-named one
|
|
12489
|
+
// Handle removed nodes first, so that replacing a pc-script-instance with a same-named one
|
|
12008
12490
|
// destroys the old script before the replacement is created. Only destroy a script
|
|
12009
12491
|
// this element actually owns - a duplicate-named element whose own create() failed
|
|
12010
12492
|
// must not take down the live script on removal.
|
|
12011
12493
|
mutation.removedNodes.forEach((node) => {
|
|
12012
|
-
if (node instanceof
|
|
12494
|
+
if (node instanceof ScriptInstanceElement) {
|
|
12013
12495
|
const scriptName = node.getAttribute('name');
|
|
12014
12496
|
if (scriptName &&
|
|
12015
12497
|
node._script &&
|
|
@@ -12022,7 +12504,7 @@
|
|
|
12022
12504
|
});
|
|
12023
12505
|
// Handle added nodes
|
|
12024
12506
|
mutation.addedNodes.forEach((node) => {
|
|
12025
|
-
if (node instanceof
|
|
12507
|
+
if (node instanceof ScriptInstanceElement) {
|
|
12026
12508
|
this.createScript(node);
|
|
12027
12509
|
}
|
|
12028
12510
|
});
|
|
@@ -12040,14 +12522,20 @@
|
|
|
12040
12522
|
return super.component;
|
|
12041
12523
|
}
|
|
12042
12524
|
}
|
|
12043
|
-
customElements.define('pc-
|
|
12525
|
+
customElements.define('pc-script', ScriptComponentElement);
|
|
12044
12526
|
|
|
12045
12527
|
/**
|
|
12046
12528
|
* The SoundComponentElement interface provides properties and methods for manipulating
|
|
12047
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
12529
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-sound/ | `<pc-sound>`} elements.
|
|
12048
12530
|
* The SoundComponentElement interface also inherits the properties and methods of the
|
|
12049
12531
|
* {@link HTMLElement} interface.
|
|
12050
12532
|
*
|
|
12533
|
+
* Engine component: {@link SoundComponent} (`sound`).
|
|
12534
|
+
*
|
|
12535
|
+
* @elementSummary The `<pc-sound>` element holds the `<pc-sound-slot>` children that play sounds at
|
|
12536
|
+
* its entity, along with the positional audio settings they share. Must be a child of a
|
|
12537
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
12538
|
+
*
|
|
12051
12539
|
* @category Components
|
|
12052
12540
|
*/
|
|
12053
12541
|
class SoundComponentElement extends ComponentElement {
|
|
@@ -12238,12 +12726,15 @@
|
|
|
12238
12726
|
}
|
|
12239
12727
|
}
|
|
12240
12728
|
}
|
|
12241
|
-
customElements.define('pc-
|
|
12729
|
+
customElements.define('pc-sound', SoundComponentElement);
|
|
12242
12730
|
|
|
12243
12731
|
/**
|
|
12244
12732
|
* The SoundSlotElement interface provides properties and methods for manipulating
|
|
12245
|
-
* `<pc-sound>` elements. The SoundSlotElement interface also inherits the properties and
|
|
12733
|
+
* `<pc-sound-slot>` elements. The SoundSlotElement interface also inherits the properties and
|
|
12246
12734
|
* methods of the {@link AsyncElement} interface.
|
|
12735
|
+
*
|
|
12736
|
+
* @elementSummary The `<pc-sound-slot>` element declares one named sound on its parent `<pc-sound>`
|
|
12737
|
+
* — its asset, volume, pitch, looping and autoplay. Must be a direct child of `<pc-sound>`.
|
|
12247
12738
|
*/
|
|
12248
12739
|
class SoundSlotElement extends AsyncElement {
|
|
12249
12740
|
_asset = '';
|
|
@@ -12256,7 +12747,7 @@
|
|
|
12256
12747
|
_startTime = 0;
|
|
12257
12748
|
_volume = 1;
|
|
12258
12749
|
/**
|
|
12259
|
-
* The `<pc-
|
|
12750
|
+
* The `<pc-sound>` this slot was added to, captured at connect time.
|
|
12260
12751
|
*
|
|
12261
12752
|
* `disconnectedCallback` cannot rediscover it: by the time the element is disconnected its
|
|
12262
12753
|
* `parentElement` is already `null`, so a lookup would both fail to find the component and
|
|
@@ -12319,7 +12810,7 @@
|
|
|
12319
12810
|
get soundElement() {
|
|
12320
12811
|
const soundElement = this.parentElement;
|
|
12321
12812
|
if (!(soundElement instanceof SoundComponentElement)) {
|
|
12322
|
-
console.warn('pc-sound must be a direct child of a pc-
|
|
12813
|
+
console.warn('pc-sound-slot must be a direct child of a pc-sound element');
|
|
12323
12814
|
return null;
|
|
12324
12815
|
}
|
|
12325
12816
|
return soundElement;
|
|
@@ -12515,7 +13006,7 @@
|
|
|
12515
13006
|
}
|
|
12516
13007
|
}
|
|
12517
13008
|
}
|
|
12518
|
-
customElements.define('pc-sound', SoundSlotElement);
|
|
13009
|
+
customElements.define('pc-sound-slot', SoundSlotElement);
|
|
12519
13010
|
|
|
12520
13011
|
/**
|
|
12521
13012
|
* The GSplatComponentElement interface provides properties and methods for manipulating
|
|
@@ -12523,6 +13014,12 @@
|
|
|
12523
13014
|
* The GSplatComponentElement interface also inherits the properties and methods of the
|
|
12524
13015
|
* {@link HTMLElement} interface.
|
|
12525
13016
|
*
|
|
13017
|
+
* Engine component: {@link GSplatComponent} (`gsplat`).
|
|
13018
|
+
*
|
|
13019
|
+
* @elementSummary The `<pc-gsplat>` element renders the 3D Gaussian splats of a `gsplat` asset at
|
|
13020
|
+
* its entity, with attributes for shadow casting and level of detail. Must be a child of a
|
|
13021
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
13022
|
+
*
|
|
12526
13023
|
* @category Components
|
|
12527
13024
|
*/
|
|
12528
13025
|
class GSplatComponentElement extends ComponentElement {
|
|
@@ -12818,6 +13315,11 @@
|
|
|
12818
13315
|
* The pointer events below are dispatched by the containing `<pc-app>` element when the pointer
|
|
12819
13316
|
* intersects the bound node's geometry, exactly as for `<pc-entity>`.
|
|
12820
13317
|
*
|
|
13318
|
+
* @elementSummary The `<pc-node>` element binds to a node inside the hierarchy a `<pc-model>`
|
|
13319
|
+
* instantiated and declares overrides against it: a transform, an enabled state, tags, components
|
|
13320
|
+
* to add, or content to attach. Its `name` is a lookup, never a rename. Must be a descendant of
|
|
13321
|
+
* `<pc-model>`.
|
|
13322
|
+
*
|
|
12821
13323
|
* @attribute {string} name - The name of the node to bind, resolved within the nearest ancestor
|
|
12822
13324
|
* `pc-model` (or `pc-node`) once it has instantiated.
|
|
12823
13325
|
* @attribute {number} index - Which match to bind when `name` matches more than one node,
|
|
@@ -12944,7 +13446,10 @@
|
|
|
12944
13446
|
* is retained untouched — a redundant edit must not flicker overrides through a revert.
|
|
12945
13447
|
*/
|
|
12946
13448
|
_rebind() {
|
|
12947
|
-
|
|
13449
|
+
// A model fronts a host entity of its own; the names this element resolves are the
|
|
13450
|
+
// asset's, so the search starts at the instantiated content root, not the wrapper.
|
|
13451
|
+
const host = this._host;
|
|
13452
|
+
const hostEntity = (host instanceof ModelElement ? host.contentEntity : host?.entity) ?? null;
|
|
12948
13453
|
if (!hostEntity || !this._name) {
|
|
12949
13454
|
// Host not instantiated (or nothing to look up yet): return to pending. An assigned
|
|
12950
13455
|
// name arriving later, or the host's next cycle, resolves it.
|
|
@@ -13041,8 +13546,9 @@
|
|
|
13041
13546
|
}
|
|
13042
13547
|
this._revertOverrides();
|
|
13043
13548
|
// Attachment points anchor to the bound node, so they cannot outlive the binding. Each
|
|
13044
|
-
// destroyed entity resets its element, which the next _buildChildren re-creates
|
|
13045
|
-
|
|
13549
|
+
// destroyed entity resets its element, which the next _buildChildren re-creates - a
|
|
13550
|
+
// model host among them re-instantiates its content when it rebuilds.
|
|
13551
|
+
this.querySelectorAll('pc-entity, pc-model').forEach((child) => {
|
|
13046
13552
|
if (child.closestEntity === this) {
|
|
13047
13553
|
child.entity?.destroy();
|
|
13048
13554
|
}
|
|
@@ -13554,6 +14060,9 @@
|
|
|
13554
14060
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-scene/ | `<pc-scene>`} elements.
|
|
13555
14061
|
* The SceneElement interface also inherits the properties and methods of the
|
|
13556
14062
|
* {@link HTMLElement} interface.
|
|
14063
|
+
*
|
|
14064
|
+
* @elementSummary The `<pc-scene>` element holds the entity hierarchy the application renders,
|
|
14065
|
+
* along with the scene-wide fog and gravity settings. Must be a direct child of `<pc-app>`.
|
|
13557
14066
|
*/
|
|
13558
14067
|
class SceneElement extends AsyncElement {
|
|
13559
14068
|
/**
|
|
@@ -13777,6 +14286,10 @@
|
|
|
13777
14286
|
* The SkyElement interface provides properties and methods for manipulating
|
|
13778
14287
|
* `<pc-sky>` elements. The SkyElement interface also inherits the properties and
|
|
13779
14288
|
* methods of the {@link HTMLElement} interface.
|
|
14289
|
+
*
|
|
14290
|
+
* @elementSummary The `<pc-sky>` element renders a skybox from a texture asset, projected as an
|
|
14291
|
+
* infinite background, a box or a dome, and optionally lights the scene from it. Must be a direct
|
|
14292
|
+
* child of `<pc-scene>`.
|
|
13780
14293
|
*/
|
|
13781
14294
|
class SkyElement extends AsyncElement {
|
|
13782
14295
|
_asset = '';
|
|
@@ -14073,6 +14586,7 @@
|
|
|
14073
14586
|
exports.AppElement = AppElement;
|
|
14074
14587
|
exports.AssetElement = AssetElement;
|
|
14075
14588
|
exports.AsyncElement = AsyncElement;
|
|
14589
|
+
exports.AudioListenerComponentElement = AudioListenerComponentElement;
|
|
14076
14590
|
exports.ButtonComponentElement = ButtonComponentElement;
|
|
14077
14591
|
exports.CameraComponentElement = CameraComponentElement;
|
|
14078
14592
|
exports.CollisionComponentElement = CollisionComponentElement;
|
|
@@ -14080,15 +14594,14 @@
|
|
|
14080
14594
|
exports.ElementComponentElement = ElementComponentElement;
|
|
14081
14595
|
exports.EntityBaseElement = EntityBaseElement;
|
|
14082
14596
|
exports.EntityElement = EntityElement;
|
|
14597
|
+
exports.EntityOwnerElement = EntityOwnerElement;
|
|
14083
14598
|
exports.GSplatComponentElement = GSplatComponentElement;
|
|
14084
14599
|
exports.JointComponentElement = JointComponentElement;
|
|
14085
14600
|
exports.LayoutChildComponentElement = LayoutChildComponentElement;
|
|
14086
14601
|
exports.LayoutGroupComponentElement = LayoutGroupComponentElement;
|
|
14087
14602
|
exports.LightComponentElement = LightComponentElement;
|
|
14088
|
-
exports.ListenerComponentElement = ListenerComponentElement;
|
|
14089
14603
|
exports.MaterialElement = MaterialElement;
|
|
14090
14604
|
exports.ModelElement = ModelElement;
|
|
14091
|
-
exports.ModuleElement = ModuleElement;
|
|
14092
14605
|
exports.NodeElement = NodeElement;
|
|
14093
14606
|
exports.ParticleSystemComponentElement = ParticleSystemComponentElement;
|
|
14094
14607
|
exports.RenderComponentElement = RenderComponentElement;
|
|
@@ -14096,12 +14609,13 @@
|
|
|
14096
14609
|
exports.SceneElement = SceneElement;
|
|
14097
14610
|
exports.ScreenComponentElement = ScreenComponentElement;
|
|
14098
14611
|
exports.ScriptComponentElement = ScriptComponentElement;
|
|
14099
|
-
exports.
|
|
14612
|
+
exports.ScriptInstanceElement = ScriptInstanceElement;
|
|
14100
14613
|
exports.ScrollViewComponentElement = ScrollViewComponentElement;
|
|
14101
14614
|
exports.ScrollbarComponentElement = ScrollbarComponentElement;
|
|
14102
14615
|
exports.SkyElement = SkyElement;
|
|
14103
14616
|
exports.SoundComponentElement = SoundComponentElement;
|
|
14104
14617
|
exports.SoundSlotElement = SoundSlotElement;
|
|
14618
|
+
exports.WasmElement = WasmElement;
|
|
14105
14619
|
exports.whenReady = whenReady;
|
|
14106
14620
|
|
|
14107
14621
|
}));
|