@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.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { basisInitialize, WasmModule, Vec3, Color, Vec4, Quat, Vec2, createGraphicsDevice, AppOptions, Keyboard, Mouse, ElementInput, AnimComponentSystem, AnimationComponentSystem, AudioListenerComponentSystem, ButtonComponentSystem, CameraComponentSystem, CollisionComponentSystem, ElementComponentSystem, GSplatComponentSystem, JointComponentSystem, LayoutChildComponentSystem, LayoutGroupComponentSystem, LightComponentSystem, ModelComponentSystem, ParticleSystemComponentSystem, RenderComponentSystem, RigidBodyComponentSystem, ScreenComponentSystem, ScriptComponentSystem, ScrollbarComponentSystem, ScrollViewComponentSystem, SoundComponentSystem, SpriteComponentSystem, ZoneComponentSystem, AnimClipHandler, AnimationHandler, AnimStateGraphHandler, AudioHandler, BinaryHandler, CssHandler, ContainerHandler, CubemapHandler, FolderHandler, FontHandler, GSplatHandler, HierarchyHandler, HtmlHandler, JsonHandler, MaterialHandler, ModelHandler, RenderHandler, ScriptHandler, SceneHandler, ShaderHandler, SpriteHandler, TemplateHandler, TextHandler, TextureAtlasHandler, TextureHandler, SoundManager, Lightmapper, BatchManager, XrManager, AppBase, FILLMODE_NONE, RESOLUTION_AUTO, Picker, MeshInstance, Entity, Asset, SPRITE_RENDERMODE_SIMPLE, FILTER_LINEAR_MIPMAP_LINEAR, FILTER_LINEAR, ADDRESS_REPEAT, SPRITE_RENDERMODE_SLICED, SPRITE_RENDERMODE_TILED, ADDRESS_CLAMP_TO_EDGE, ADDRESS_MIRRORED_REPEAT, FILTER_NEAREST, FILTER_NEAREST_MIPMAP_NEAREST, FILTER_LINEAR_MIPMAP_NEAREST, FILTER_NEAREST_MIPMAP_LINEAR, AnimTrack, ANIM_CONTROL_STATES, BUTTON_TRANSITION_MODE_TINT, BUTTON_TRANSITION_MODE_SPRITE_CHANGE, TONEMAP_NONE, PROJECTION_PERSPECTIVE, GAMMA_SRGB, GAMMA_NONE, XRTYPE_VR, TONEMAP_LINEAR, TONEMAP_FILMIC, TONEMAP_HEJL, TONEMAP_ACES, TONEMAP_ACES2, TONEMAP_NEUTRAL, PROJECTION_ORTHOGRAPHIC, ORIENTATION_HORIZONTAL, FITTING_NONE, FITTING_STRETCH, FITTING_SHRINK, FITTING_BOTH, ORIENTATION_VERTICAL, SHADOW_PCF3_32F, SHADOW_PCF1_16F, SHADOW_PCF1_32F, SHADOW_PCF3_16F, SHADOW_PCF5_16F, SHADOW_PCF5_32F, SHADOW_VSM_16F, SHADOW_VSM_32F, SHADOW_PCSS_32F, StandardMaterial, BLEND_NONE, CULLFACE_BACK, FRESNEL_SCHLICK, SPECOCC_AO, BLEND_NORMAL, BLEND_ADDITIVE, BLEND_ADDITIVEALPHA, BLEND_PREMULTIPLIED, BLEND_MULTIPLICATIVE, BLEND_MULTIPLICATIVE2X, BLEND_SCREEN, BLEND_MIN, BLEND_MAX, BLEND_SUBTRACTIVE, CULLFACE_NONE, CULLFACE_FRONT, CULLFACE_FRONTANDBACK, FRESNEL_NONE, SPECOCC_NONE, SPECOCC_GLOSSDEPENDENT, SCALEMODE_NONE, SCALEMODE_BLEND, SCROLL_MODE_BOUNCE, SCROLLBAR_VISIBILITY_SHOW_WHEN_REQUIRED, SCROLLBAR_VISIBILITY_SHOW_ALWAYS, SCROLL_MODE_CLAMP, SCROLL_MODE_INFINITE, EnvLighting, LAYERID_SKYBOX } from 'playcanvas';
|
|
1
|
+
import { basisInitialize, WasmModule, Vec3, Color, Vec4, Quat, Vec2, createGraphicsDevice, AppOptions, Keyboard, Mouse, ElementInput, AnimComponentSystem, AnimationComponentSystem, AudioListenerComponentSystem, ButtonComponentSystem, CameraComponentSystem, CollisionComponentSystem, ElementComponentSystem, GSplatComponentSystem, JointComponentSystem, LayoutChildComponentSystem, LayoutGroupComponentSystem, LightComponentSystem, ModelComponentSystem, ParticleSystemComponentSystem, RenderComponentSystem, RigidBodyComponentSystem, ScreenComponentSystem, ScriptComponentSystem, ScrollbarComponentSystem, ScrollViewComponentSystem, SoundComponentSystem, SpriteComponentSystem, ZoneComponentSystem, AnimClipHandler, AnimationHandler, AnimStateGraphHandler, AudioHandler, BinaryHandler, CssHandler, ContainerHandler, CubemapHandler, FolderHandler, FontHandler, GSplatHandler, HierarchyHandler, HtmlHandler, JsonHandler, MaterialHandler, ModelHandler, RenderHandler, ScriptHandler, SceneHandler, ShaderHandler, SpriteHandler, TemplateHandler, TextHandler, TextureAtlasHandler, TextureHandler, SoundManager, Lightmapper, BatchManager, XrManager, AppBase, FILLMODE_NONE, RESOLUTION_AUTO, Picker, MeshInstance, Entity, Asset, SPRITE_RENDERMODE_SIMPLE, FILTER_LINEAR_MIPMAP_LINEAR, FILTER_LINEAR, ADDRESS_REPEAT, SPRITE_RENDERMODE_SLICED, SPRITE_RENDERMODE_TILED, ADDRESS_CLAMP_TO_EDGE, ADDRESS_MIRRORED_REPEAT, FILTER_NEAREST, FILTER_NEAREST_MIPMAP_NEAREST, FILTER_LINEAR_MIPMAP_NEAREST, FILTER_NEAREST_MIPMAP_LINEAR, AnimTrack, ANIM_CONTROL_STATES, BUTTON_TRANSITION_MODE_TINT, BUTTON_TRANSITION_MODE_SPRITE_CHANGE, TONEMAP_NONE, PROJECTION_PERSPECTIVE, GAMMA_SRGB, GAMMA_NONE, XRTYPE_AR, XRTYPE_VR, TONEMAP_LINEAR, TONEMAP_FILMIC, TONEMAP_HEJL, TONEMAP_ACES, TONEMAP_ACES2, TONEMAP_NEUTRAL, PROJECTION_ORTHOGRAPHIC, ORIENTATION_HORIZONTAL, FITTING_NONE, FITTING_STRETCH, FITTING_SHRINK, FITTING_BOTH, ORIENTATION_VERTICAL, SHADOW_PCF3_32F, SHADOW_PCF1_16F, SHADOW_PCF1_32F, SHADOW_PCF3_16F, SHADOW_PCF5_16F, SHADOW_PCF5_32F, SHADOW_VSM_16F, SHADOW_VSM_32F, SHADOW_PCSS_32F, StandardMaterial, BLEND_NONE, CULLFACE_BACK, FRESNEL_SCHLICK, SPECOCC_AO, BLEND_NORMAL, BLEND_ADDITIVE, BLEND_ADDITIVEALPHA, BLEND_PREMULTIPLIED, BLEND_MULTIPLICATIVE, BLEND_MULTIPLICATIVE2X, BLEND_SCREEN, BLEND_MIN, BLEND_MAX, BLEND_SUBTRACTIVE, CULLFACE_NONE, CULLFACE_FRONT, CULLFACE_FRONTANDBACK, FRESNEL_NONE, SPECOCC_NONE, SPECOCC_GLOSSDEPENDENT, SCALEMODE_NONE, SCALEMODE_BLEND, SCROLL_MODE_BOUNCE, SCROLLBAR_VISIBILITY_SHOW_WHEN_REQUIRED, SCROLLBAR_VISIBILITY_SHOW_ALWAYS, SCROLL_MODE_CLAMP, SCROLL_MODE_INFINITE, EnvLighting, LAYERID_SKYBOX } from 'playcanvas';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Base class for all PlayCanvas Web Components that initialize asynchronously.
|
|
@@ -27,13 +27,13 @@ class AsyncElement extends HTMLElement {
|
|
|
27
27
|
return this.parentElement?.closest('pc-app') ?? null;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
* The nearest ancestor element that fronts an entity — `<pc-entity
|
|
31
|
-
* `null` if this element has no such ancestor. The search starts at the
|
|
32
|
-
* never resolves to itself.
|
|
30
|
+
* The nearest ancestor element that fronts an entity — `<pc-entity>`, `<pc-model>` or
|
|
31
|
+
* `<pc-node>` — or `null` if this element has no such ancestor. The search starts at the
|
|
32
|
+
* parent, so an element never resolves to itself.
|
|
33
33
|
* @returns The closest entity-fronting element, or `null`.
|
|
34
34
|
*/
|
|
35
35
|
get closestEntity() {
|
|
36
|
-
return this.parentElement?.closest('pc-entity, pc-node') ?? null;
|
|
36
|
+
return this.parentElement?.closest('pc-entity, pc-model, pc-node') ?? null;
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* Called when the element is fully initialized and ready. Subclasses should call this when
|
|
@@ -107,9 +107,9 @@ async function whenReady(target) {
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
/**
|
|
110
|
-
* The
|
|
111
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
112
|
-
* elements. The
|
|
110
|
+
* The WasmElement interface provides properties and methods for manipulating
|
|
111
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-wasm/ | `<pc-wasm>`}
|
|
112
|
+
* elements. The WasmElement interface also inherits the properties and methods of the
|
|
113
113
|
* {@link AsyncElement} interface.
|
|
114
114
|
*
|
|
115
115
|
* The attributes are read once, when the module starts loading - on the element's first
|
|
@@ -118,9 +118,13 @@ async function whenReady(target) {
|
|
|
118
118
|
* modules configure engine-global state that never unloads, so readiness is not re-armed by
|
|
119
119
|
* removing the element, and a re-inserted element does not load again.
|
|
120
120
|
*
|
|
121
|
-
* A `<pc-
|
|
121
|
+
* A `<pc-wasm>` without a `name` warns and never becomes ready; a containing `<pc-app>` still
|
|
122
122
|
* boots.
|
|
123
123
|
*
|
|
124
|
+
* @elementSummary The `<pc-wasm>` element loads a WebAssembly module the engine needs before the
|
|
125
|
+
* application starts — `Ammo` for physics, `Basis` or `DracoDecoderModule` for compressed assets.
|
|
126
|
+
* Must be a direct child of `<pc-app>`.
|
|
127
|
+
*
|
|
124
128
|
* @attribute {string} name - The name of the WebAssembly module to configure, e.g. `Basis` or
|
|
125
129
|
* `Ammo`.
|
|
126
130
|
* @attribute {string} glue - The URL of the module's glue script.
|
|
@@ -128,7 +132,7 @@ async function whenReady(target) {
|
|
|
128
132
|
* @attribute {string} fallback - The URL of the module's asm.js fallback script, used when
|
|
129
133
|
* WebAssembly is unavailable.
|
|
130
134
|
*/
|
|
131
|
-
class
|
|
135
|
+
class WasmElement extends AsyncElement {
|
|
132
136
|
_loadPromise = null;
|
|
133
137
|
connectedCallback() {
|
|
134
138
|
this._getLoadPromise();
|
|
@@ -136,7 +140,7 @@ class ModuleElement extends AsyncElement {
|
|
|
136
140
|
async _loadModule() {
|
|
137
141
|
const name = this.getAttribute('name');
|
|
138
142
|
if (!name) {
|
|
139
|
-
console.warn("pc-
|
|
143
|
+
console.warn("pc-wasm requires a 'name' attribute - no module was configured");
|
|
140
144
|
return;
|
|
141
145
|
}
|
|
142
146
|
const config = {
|
|
@@ -171,7 +175,7 @@ class ModuleElement extends AsyncElement {
|
|
|
171
175
|
return this._loadPromise;
|
|
172
176
|
}
|
|
173
177
|
}
|
|
174
|
-
customElements.define('pc-
|
|
178
|
+
customElements.define('pc-wasm', WasmElement);
|
|
175
179
|
|
|
176
180
|
/** Covers the 0.2s opacity transition; jsdom never fires transitionend, so removal is timed. */
|
|
177
181
|
const REMOVAL_DELAY_MS = 250;
|
|
@@ -728,6 +732,12 @@ const getEntity = (ref) => {
|
|
|
728
732
|
|
|
729
733
|
/** The pointer event types the application synthesizes on `<pc-entity>` elements via picking. */
|
|
730
734
|
const pointerEventTypes = ['pointermove', 'pointerdown', 'pointerup', 'pointerenter', 'pointerleave'];
|
|
735
|
+
/**
|
|
736
|
+
* The event types whose listeners make an element a hover target. Hover resolution walks past
|
|
737
|
+
* elements listening for none of them, so a silent element never swallows an ancestor's
|
|
738
|
+
* enter/leave pair.
|
|
739
|
+
*/
|
|
740
|
+
const hoverEventTypes = ['pointerenter', 'pointerleave', 'pointermove'];
|
|
731
741
|
/**
|
|
732
742
|
* Gives `pc-app` the sizing contract of a replaced element (`<video>`, `<img>`): a block-level
|
|
733
743
|
* box that the page's CSS sizes, defaulting to the canvas's own 300x150 intrinsic size, with the
|
|
@@ -756,6 +766,10 @@ const ensureBaseStyles = () => {
|
|
|
756
766
|
* tracked live via a ResizeObserver — so the element can be embedded at any size, resized by
|
|
757
767
|
* its container, or made fullscreen with ordinary CSS such as `width: 100vw; height: 100dvh`.
|
|
758
768
|
*
|
|
769
|
+
* @elementSummary The `<pc-app>` element creates a PlayCanvas application and the canvas it renders
|
|
770
|
+
* into, and is the root of every scene. It holds the `<pc-asset>`, `<pc-material>`, `<pc-wasm>` and
|
|
771
|
+
* `<pc-scene>` elements, and the page's CSS sizes it, as it would a `<video>`.
|
|
772
|
+
*
|
|
759
773
|
* @fires {ProgressEvent} progress - Fired while the application preloads its assets. `loaded` and
|
|
760
774
|
* `total` are asset counts, not bytes, and an asset that fails to load still counts as loaded.
|
|
761
775
|
* Fired at least once per boot, and the final event always has `loaded` equal to `total`. Does
|
|
@@ -802,9 +816,9 @@ class AppElement extends AsyncElement {
|
|
|
802
816
|
_bootGeneration = 0;
|
|
803
817
|
/**
|
|
804
818
|
* The elements backing this application's entities, keyed by the entity itself. Registered
|
|
805
|
-
* by
|
|
806
|
-
*
|
|
807
|
-
* identity - never by name.
|
|
819
|
+
* by entity-owning elements at creation (pc-entity, and pc-model for its host) and by
|
|
820
|
+
* NodeElement at binding, and removed when an entity is destroyed or unbound, this joins
|
|
821
|
+
* engine scene nodes back to their owning elements by identity - never by name.
|
|
808
822
|
*/
|
|
809
823
|
_entityElements = new Map();
|
|
810
824
|
_picker = null;
|
|
@@ -883,7 +897,7 @@ class AppElement extends AsyncElement {
|
|
|
883
897
|
// there, leaving the element permanently unready: no canvas, no entities, no application.
|
|
884
898
|
//
|
|
885
899
|
// Upgrading is the fix here rather than skipping whatever has not upgraded, because a
|
|
886
|
-
// <pc-
|
|
900
|
+
// <pc-wasm> is the one child that nothing else ever builds on its own behalf - skipping
|
|
887
901
|
// it would drop the wasm module the app asked for, silently and only for cloned apps.
|
|
888
902
|
// Upgrading runs each descendant's connectedCallback synchronously, a few lines earlier
|
|
889
903
|
// than the parser's path runs them but into the same state they see there: no application
|
|
@@ -892,10 +906,10 @@ class AppElement extends AsyncElement {
|
|
|
892
906
|
// as any other disconnect is. An already-upgraded subtree - every other insertion path -
|
|
893
907
|
// is left completely untouched.
|
|
894
908
|
customElements.upgrade(this);
|
|
895
|
-
// Get all pc-
|
|
896
|
-
const
|
|
909
|
+
// Get all pc-wasm elements that are direct children of the pc-app element
|
|
910
|
+
const wasmElements = this.querySelectorAll(':scope > pc-wasm');
|
|
897
911
|
// Wait for all modules to load
|
|
898
|
-
await Promise.all(Array.from(
|
|
912
|
+
await Promise.all(Array.from(wasmElements).map((element) => element._getLoadPromise()));
|
|
899
913
|
// The element may have been removed while the modules loaded. Nothing beyond the loading
|
|
900
914
|
// bar exists yet, and disconnectedCallback has already destroyed that.
|
|
901
915
|
if (generation !== this._bootGeneration) {
|
|
@@ -1065,14 +1079,15 @@ class AppElement extends AsyncElement {
|
|
|
1065
1079
|
Array.from(materialElements).forEach((materialElement) => {
|
|
1066
1080
|
materialElement._createMaterial();
|
|
1067
1081
|
});
|
|
1068
|
-
// Create all entities
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1082
|
+
// Create all entities. pc-model joins the sweep because it owns a host entity of its
|
|
1083
|
+
// own; its instantiated content arrives later, beneath that host.
|
|
1084
|
+
const ownerElements = this.querySelectorAll('pc-entity, pc-model');
|
|
1085
|
+
Array.from(ownerElements).forEach((ownerElement) => {
|
|
1086
|
+
ownerElement._createEntity(app);
|
|
1072
1087
|
});
|
|
1073
1088
|
// Build hierarchy
|
|
1074
|
-
|
|
1075
|
-
|
|
1089
|
+
ownerElements.forEach((ownerElement) => {
|
|
1090
|
+
ownerElement._buildHierarchy(app);
|
|
1076
1091
|
});
|
|
1077
1092
|
// Building the hierarchy dispatched each entity's ready event synchronously, and a
|
|
1078
1093
|
// listener may have removed the element. The sweep itself degrades safely - destroying
|
|
@@ -1183,7 +1198,7 @@ class AppElement extends AsyncElement {
|
|
|
1183
1198
|
// created from onpointer* attributes when their elements were first upgraded, or
|
|
1184
1199
|
// listeners carried over from before a re-boot)
|
|
1185
1200
|
pointerEventTypes.forEach((type) => {
|
|
1186
|
-
const anyListeners = Array.from(this.querySelectorAll('pc-entity, pc-node')).some((entity) => entity._hasListeners(type));
|
|
1201
|
+
const anyListeners = Array.from(this.querySelectorAll('pc-entity, pc-model, pc-node')).some((entity) => entity._hasListeners(type));
|
|
1187
1202
|
if (anyListeners) {
|
|
1188
1203
|
this._onPointerListenerAdded(type);
|
|
1189
1204
|
}
|
|
@@ -1233,10 +1248,10 @@ class AppElement extends AsyncElement {
|
|
|
1233
1248
|
this._entityElements.delete(entity);
|
|
1234
1249
|
}
|
|
1235
1250
|
/**
|
|
1236
|
-
* Returns the `<pc-entity>` or `<pc-node>` element whose backing entity is
|
|
1237
|
-
* `null` if the entity is not fronted by an element of this application - for
|
|
1238
|
-
* unbound node inside a model's instantiated hierarchy, or an entity created
|
|
1239
|
-
* engine API.
|
|
1251
|
+
* Returns the `<pc-entity>`, `<pc-model>` or `<pc-node>` element whose backing entity is
|
|
1252
|
+
* `entity`, or `null` if the entity is not fronted by an element of this application - for
|
|
1253
|
+
* example, an unbound node inside a model's instantiated hierarchy, or an entity created
|
|
1254
|
+
* through the engine API.
|
|
1240
1255
|
*
|
|
1241
1256
|
* @param entity - The entity to look up.
|
|
1242
1257
|
* @returns The element fronting the entity, or `null`.
|
|
@@ -1245,18 +1260,19 @@ class AppElement extends AsyncElement {
|
|
|
1245
1260
|
return this._entityElements.get(entity) ?? null;
|
|
1246
1261
|
}
|
|
1247
1262
|
/**
|
|
1248
|
-
* Resolves the element that owns a picked node: the nearest node up the parent
|
|
1249
|
-
* starting with the node itself -
|
|
1250
|
-
*
|
|
1251
|
-
*
|
|
1263
|
+
* Resolves the element that owns hover for a picked node: the nearest node up the parent
|
|
1264
|
+
* chain - starting with the node itself - whose element listens for any of the hover event
|
|
1265
|
+
* types. Skipping silent elements matches {@link _elementWithListener}, so a registered
|
|
1266
|
+
* element with no hover listeners (a `<pc-model>` host, a plain child entity) is transparent
|
|
1267
|
+
* to hover rather than swallowing a listening ancestor's enter/leave pair.
|
|
1252
1268
|
*
|
|
1253
1269
|
* @param node - The picked node, or `null`.
|
|
1254
|
-
* @returns The owning element, or `null`.
|
|
1270
|
+
* @returns The hover-owning element, or `null`.
|
|
1255
1271
|
*/
|
|
1256
|
-
|
|
1272
|
+
_hoverTarget(node) {
|
|
1257
1273
|
while (node !== null) {
|
|
1258
1274
|
const element = this._entityElements.get(node);
|
|
1259
|
-
if (element) {
|
|
1275
|
+
if (element && hoverEventTypes.some((type) => element._hasListeners(type))) {
|
|
1260
1276
|
return element;
|
|
1261
1277
|
}
|
|
1262
1278
|
node = node.parent;
|
|
@@ -1392,9 +1408,10 @@ class AppElement extends AsyncElement {
|
|
|
1392
1408
|
const node = await this._pickNode(event);
|
|
1393
1409
|
if (token !== this._pickToken || !this._picker)
|
|
1394
1410
|
return;
|
|
1395
|
-
// The hovered element is the nearest one up the node's parent chain
|
|
1396
|
-
//
|
|
1397
|
-
|
|
1411
|
+
// The hovered element is the nearest one up the node's parent chain with a hover
|
|
1412
|
+
// listener - the nearest-listener rule down/up use. Dispatch is still gated per event
|
|
1413
|
+
// type below: having any hover listener selects the target, each event needs its own.
|
|
1414
|
+
const newHoverEntity = this._hoverTarget(node);
|
|
1398
1415
|
// Handle enter/leave events
|
|
1399
1416
|
if (this._hoveredEntity !== newHoverEntity) {
|
|
1400
1417
|
if (this._hoveredEntity && this._hoveredEntity._hasListeners('pointerleave')) {
|
|
@@ -1446,7 +1463,7 @@ class AppElement extends AsyncElement {
|
|
|
1446
1463
|
}
|
|
1447
1464
|
}
|
|
1448
1465
|
_onPointerListenerRemoved(type) {
|
|
1449
|
-
const hasListeners = Array.from(this.querySelectorAll('pc-entity, pc-node')).some((entity) => entity._hasListeners(type));
|
|
1466
|
+
const hasListeners = Array.from(this.querySelectorAll('pc-entity, pc-model, pc-node')).some((entity) => entity._hasListeners(type));
|
|
1450
1467
|
if (!hasListeners && this._canvas) {
|
|
1451
1468
|
this._hasPointerListeners[type] = false;
|
|
1452
1469
|
const handler = type === 'pointerenter' || type === 'pointerleave'
|
|
@@ -1637,11 +1654,12 @@ const POINTER_ATTRIBUTES = [
|
|
|
1637
1654
|
'onpointermove'
|
|
1638
1655
|
];
|
|
1639
1656
|
/**
|
|
1640
|
-
* The base class for elements that front an engine {@link Entity}: `<pc-entity
|
|
1641
|
-
* one, and `<pc-node>`, which binds to one inside a model's
|
|
1642
|
-
* what
|
|
1643
|
-
* picked scene nodes back to elements by identity,
|
|
1644
|
-
* bookkeeping that lets the application lazily attach
|
|
1657
|
+
* The base class for elements that front an engine {@link Entity}: `<pc-entity>` and
|
|
1658
|
+
* `<pc-model>`, which create one, and `<pc-node>`, which binds to one inside a model's
|
|
1659
|
+
* instantiated hierarchy. It carries what all of them need — the `entity` contract, registration
|
|
1660
|
+
* with the owning application (which joins picked scene nodes back to elements by identity,
|
|
1661
|
+
* never by name), and the pointer listener bookkeeping that lets the application lazily attach
|
|
1662
|
+
* its canvas handlers.
|
|
1645
1663
|
*/
|
|
1646
1664
|
class EntityBaseElement extends AsyncElement {
|
|
1647
1665
|
_entity = null;
|
|
@@ -1690,7 +1708,7 @@ class EntityBaseElement extends AsyncElement {
|
|
|
1690
1708
|
* Tracks whether an inline `onpointer*` attribute is present. The browser itself compiles and
|
|
1691
1709
|
* runs these attributes — they are standard `GlobalEventHandlers`, so setting one replaces
|
|
1692
1710
|
* the previous handler and removing it removes the handler, exactly like `onclick` on any
|
|
1693
|
-
* HTML element. But because they bypass {@link addEventListener}, the connect/disconnect
|
|
1711
|
+
* HTML element. But because they bypass {@link EventTarget.addEventListener}, the connect/disconnect
|
|
1694
1712
|
* bookkeeping that lets the application lazily attach its canvas pointer handlers must be
|
|
1695
1713
|
* kept in sync here.
|
|
1696
1714
|
*
|
|
@@ -1731,7 +1749,7 @@ class EntityBaseElement extends AsyncElement {
|
|
|
1731
1749
|
}
|
|
1732
1750
|
/**
|
|
1733
1751
|
* Whether the element has a listener for an event type, registered either with
|
|
1734
|
-
* {@link addEventListener} or with the matching inline `onpointer*` attribute. Read by the
|
|
1752
|
+
* {@link EventTarget.addEventListener} or with the matching inline `onpointer*` attribute. Read by the
|
|
1735
1753
|
* containing `<pc-app>` element to gate pointer event synthesis.
|
|
1736
1754
|
*
|
|
1737
1755
|
* @param type - The event type.
|
|
@@ -1744,17 +1762,17 @@ class EntityBaseElement extends AsyncElement {
|
|
|
1744
1762
|
}
|
|
1745
1763
|
|
|
1746
1764
|
/**
|
|
1747
|
-
* Creates and parents the entities of every descendant
|
|
1748
|
-
* that no parent's existence depends on document order. Called wherever a subtree could
|
|
1749
|
-
* itself: an element inserted into an application that is already running, and a
|
|
1750
|
-
* children waited for it to bind.
|
|
1765
|
+
* Creates and parents the entities of every descendant entity-owning element of `root`, in two
|
|
1766
|
+
* passes so that no parent's existence depends on document order. Called wherever a subtree could
|
|
1767
|
+
* not build itself: an element inserted into an application that is already running, and a
|
|
1768
|
+
* `<pc-node>` whose children waited for it to bind.
|
|
1751
1769
|
*
|
|
1752
1770
|
* Descendants that are not yet custom elements are skipped, because there is nothing useful to do
|
|
1753
1771
|
* for them and reaching for `_createEntity` would throw. A subtree cloned from a `<template>`
|
|
1754
1772
|
* arrives entirely unupgraded — template content lives in an inert document, where custom element
|
|
1755
1773
|
* definitions are never looked up — and appending the clone upgrades its elements in tree order,
|
|
1756
1774
|
* an element before its descendants. So a sweep from an element's own `connectedCallback` sees
|
|
1757
|
-
* plain `HTMLElement`s below it. Each becomes an
|
|
1775
|
+
* plain `HTMLElement`s below it. Each becomes an entity-owning element moments later and its own
|
|
1758
1776
|
* `connectedCallback` creates and parents it, by which time the ancestor it parents under has its
|
|
1759
1777
|
* entity — the same guarantee tree order gives this sweep.
|
|
1760
1778
|
*
|
|
@@ -1763,35 +1781,18 @@ class EntityBaseElement extends AsyncElement {
|
|
|
1763
1781
|
* @internal
|
|
1764
1782
|
*/
|
|
1765
1783
|
const buildDescendantEntities = (root, app) => {
|
|
1766
|
-
const children = Array.from(root.querySelectorAll('pc-entity')).filter((child) => child instanceof
|
|
1784
|
+
const children = Array.from(root.querySelectorAll('pc-entity, pc-model')).filter((child) => child instanceof EntityOwnerElement);
|
|
1767
1785
|
children.forEach((child) => child._createEntity(app));
|
|
1768
1786
|
children.forEach((child) => child._buildHierarchy(app));
|
|
1769
1787
|
};
|
|
1770
1788
|
/**
|
|
1771
|
-
* The
|
|
1772
|
-
*
|
|
1773
|
-
*
|
|
1774
|
-
*
|
|
1775
|
-
*
|
|
1776
|
-
* The pointer events below are dispatched by the containing `<pc-app>` element when the pointer
|
|
1777
|
-
* intersects this entity's geometry. They are only generated while the entity has a listener for
|
|
1778
|
-
* them, registered either with {@link addEventListener} or with the matching inline `onpointer*`
|
|
1779
|
-
* attribute.
|
|
1780
|
-
*
|
|
1781
|
-
* @attribute {string} onpointerenter - Script to run when the pointer moves onto the entity.
|
|
1782
|
-
* @attribute {string} onpointerleave - Script to run when the pointer moves off the entity.
|
|
1783
|
-
* @attribute {string} onpointermove - Script to run when the pointer moves over the entity.
|
|
1784
|
-
* @attribute {string} onpointerdown - Script to run when a pointer button is pressed over the
|
|
1785
|
-
* entity.
|
|
1786
|
-
* @attribute {string} onpointerup - Script to run when a pointer button is released over the
|
|
1787
|
-
* entity.
|
|
1788
|
-
* @fires {PointerEvent} pointerenter - Fired when the pointer moves onto the entity.
|
|
1789
|
-
* @fires {PointerEvent} pointerleave - Fired when the pointer moves off the entity.
|
|
1790
|
-
* @fires {PointerEvent} pointermove - Fired when the pointer moves over the entity.
|
|
1791
|
-
* @fires {PointerEvent} pointerdown - Fired when a pointer button is pressed over the entity.
|
|
1792
|
-
* @fires {PointerEvent} pointerup - Fired when a pointer button is released over the entity.
|
|
1789
|
+
* The base class for elements that create and own their backing entity: `<pc-entity>` and
|
|
1790
|
+
* `<pc-model>`, whose host entity carries the same authored properties. It carries the cached
|
|
1791
|
+
* property state, entity creation and parenting, and the reset that follows the entity's
|
|
1792
|
+
* destruction. `<pc-node>` sits outside this class: it borrows an entity a model instantiated,
|
|
1793
|
+
* and its properties are nullable overrides rather than owned values.
|
|
1793
1794
|
*/
|
|
1794
|
-
class
|
|
1795
|
+
class EntityOwnerElement extends EntityBaseElement {
|
|
1795
1796
|
/**
|
|
1796
1797
|
* Whether the entity is enabled.
|
|
1797
1798
|
*/
|
|
@@ -1817,7 +1818,8 @@ class EntityElement extends EntityBaseElement {
|
|
|
1817
1818
|
*/
|
|
1818
1819
|
_tags = [];
|
|
1819
1820
|
/**
|
|
1820
|
-
* Whether the hierarchy has been built for this entity
|
|
1821
|
+
* Whether the hierarchy has been built for this entity — set once `_buildHierarchy` has
|
|
1822
|
+
* parented it. Read by subclasses that gate work on the entity being in the scene graph.
|
|
1821
1823
|
*/
|
|
1822
1824
|
_built = false;
|
|
1823
1825
|
/**
|
|
@@ -1870,10 +1872,10 @@ class EntityElement extends EntityBaseElement {
|
|
|
1870
1872
|
this._resetReady();
|
|
1871
1873
|
}
|
|
1872
1874
|
/**
|
|
1873
|
-
* Parents the backing entity: under the entity of the nearest ancestor `<pc-entity
|
|
1874
|
-
* `<pc-node>` when there is one, and under the application root otherwise.
|
|
1875
|
-
* containing `<pc-app>` element once a sweep has created every entity, so a
|
|
1876
|
-
* existence never depends on document order.
|
|
1875
|
+
* Parents the backing entity: under the entity of the nearest ancestor `<pc-entity>`,
|
|
1876
|
+
* `<pc-model>` or `<pc-node>` when there is one, and under the application root otherwise.
|
|
1877
|
+
* Called by the containing `<pc-app>` element once a sweep has created every entity, so a
|
|
1878
|
+
* parent's existence never depends on document order.
|
|
1877
1879
|
*
|
|
1878
1880
|
* @param app - The application whose root adopts parentless entities.
|
|
1879
1881
|
* @internal
|
|
@@ -1888,6 +1890,13 @@ class EntityElement extends EntityBaseElement {
|
|
|
1888
1890
|
if (closestEntity && !closestEntity.entity) {
|
|
1889
1891
|
return;
|
|
1890
1892
|
}
|
|
1893
|
+
// An owner that exists but is not yet parented is itself deferred behind an unresolved
|
|
1894
|
+
// node further up. Building beneath it would announce readiness for an entity that is
|
|
1895
|
+
// not in the scene graph; stay unbuilt with it - the node's bind sweeps the whole
|
|
1896
|
+
// subtree, ancestors before descendants.
|
|
1897
|
+
if (closestEntity instanceof EntityOwnerElement && !closestEntity._built) {
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1891
1900
|
this._built = true;
|
|
1892
1901
|
if (closestEntity?.entity) {
|
|
1893
1902
|
closestEntity.entity.addChild(this.entity);
|
|
@@ -1895,35 +1904,16 @@ class EntityElement extends EntityBaseElement {
|
|
|
1895
1904
|
else {
|
|
1896
1905
|
app.root.addChild(this.entity);
|
|
1897
1906
|
}
|
|
1898
|
-
this.
|
|
1907
|
+
this._onBuilt();
|
|
1899
1908
|
}
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
const label = name ? ` '${name}'` : '';
|
|
1909
|
-
console.warn(`pc-entity${label} must be a descendant of pc-app - entity not created`);
|
|
1910
|
-
return;
|
|
1911
|
-
}
|
|
1912
|
-
// If app is already running, create entity immediately
|
|
1913
|
-
if (closestApp._hierarchyReady) {
|
|
1914
|
-
const app = closestApp.app;
|
|
1915
|
-
this._createEntity(app);
|
|
1916
|
-
this._buildHierarchy(app);
|
|
1917
|
-
// Handle any child entities that might exist
|
|
1918
|
-
buildDescendantEntities(this, app);
|
|
1919
|
-
}
|
|
1920
|
-
}
|
|
1921
|
-
disconnectedCallback() {
|
|
1922
|
-
// Destroying the entity destroys its whole subtree, and the engine fires 'destroy' for
|
|
1923
|
-
// every entity in it - so _onEntityDestroy resets this element AND every descendant
|
|
1924
|
-
// element before the descendants' own disconnectedCallbacks run. Their entities are null
|
|
1925
|
-
// by then, making this call a no-op for them.
|
|
1926
|
-
this._entity?.destroy();
|
|
1909
|
+
/**
|
|
1910
|
+
* Called by `_buildHierarchy` once the backing entity has been parented — exactly once
|
|
1911
|
+
* per build cycle. The default announces readiness, which is what a parented `<pc-entity>`
|
|
1912
|
+
* means; `<pc-model>` overrides it to start loading content instead, because its readiness
|
|
1913
|
+
* tracks the content settling rather than the host entering the scene graph.
|
|
1914
|
+
*/
|
|
1915
|
+
_onBuilt() {
|
|
1916
|
+
this._onReady();
|
|
1927
1917
|
}
|
|
1928
1918
|
/**
|
|
1929
1919
|
* Sets the enabled state of the entity.
|
|
@@ -2028,6 +2018,75 @@ class EntityElement extends EntityBaseElement {
|
|
|
2028
2018
|
get tags() {
|
|
2029
2019
|
return this._tags;
|
|
2030
2020
|
}
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
/**
|
|
2024
|
+
* The EntityElement interface provides properties and methods for manipulating
|
|
2025
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-entity/ | `<pc-entity>`} elements.
|
|
2026
|
+
* The EntityElement interface also inherits the properties and methods of the
|
|
2027
|
+
* {@link HTMLElement} interface.
|
|
2028
|
+
*
|
|
2029
|
+
* The pointer events below are dispatched by the containing `<pc-app>` element when the pointer
|
|
2030
|
+
* intersects this entity's geometry. They are only generated while the entity has a listener for
|
|
2031
|
+
* them, registered either with {@link EventTarget.addEventListener} or with the matching inline `onpointer*`
|
|
2032
|
+
* attribute.
|
|
2033
|
+
*
|
|
2034
|
+
* @elementSummary The `<pc-entity>` element creates an entity: a named, transformable node of the
|
|
2035
|
+
* scene hierarchy, and the host for component elements such as `<pc-camera>`, `<pc-light>` and
|
|
2036
|
+
* `<pc-render>`. Place it in the `<pc-scene>`, or nest it under another `<pc-entity>`, a
|
|
2037
|
+
* `<pc-model>` or a `<pc-node>` to parent it there.
|
|
2038
|
+
*
|
|
2039
|
+
* @attribute {boolean} enabled - The enabled state of the entity.
|
|
2040
|
+
* @attribute {string} name - The name of the entity.
|
|
2041
|
+
* @attribute {string} position - The position of the entity.
|
|
2042
|
+
* @attribute {string} rotation - The rotation of the entity.
|
|
2043
|
+
* @attribute {string} scale - The scale of the entity.
|
|
2044
|
+
* @attribute {string} tags - The tags of the entity.
|
|
2045
|
+
* @attribute {string} onpointerenter - Script to run when the pointer moves onto the entity.
|
|
2046
|
+
* @attribute {string} onpointerleave - Script to run when the pointer moves off the entity.
|
|
2047
|
+
* @attribute {string} onpointermove - Script to run when the pointer moves over the entity.
|
|
2048
|
+
* @attribute {string} onpointerdown - Script to run when a pointer button is pressed over the
|
|
2049
|
+
* entity.
|
|
2050
|
+
* @attribute {string} onpointerup - Script to run when a pointer button is released over the
|
|
2051
|
+
* entity.
|
|
2052
|
+
* @fires {PointerEvent} pointerenter - Fired when the pointer moves onto the entity.
|
|
2053
|
+
* @fires {PointerEvent} pointerleave - Fired when the pointer moves off the entity.
|
|
2054
|
+
* @fires {PointerEvent} pointermove - Fired when the pointer moves over the entity.
|
|
2055
|
+
* @fires {PointerEvent} pointerdown - Fired when a pointer button is pressed over the entity.
|
|
2056
|
+
* @fires {PointerEvent} pointerup - Fired when a pointer button is released over the entity.
|
|
2057
|
+
*/
|
|
2058
|
+
class EntityElement extends EntityOwnerElement {
|
|
2059
|
+
connectedCallback() {
|
|
2060
|
+
// Wait for app to be ready
|
|
2061
|
+
const closestApp = this.closestApp;
|
|
2062
|
+
if (!closestApp) {
|
|
2063
|
+
// An entity outside an application is inert and never becomes ready, so awaiting it
|
|
2064
|
+
// hangs. Warn rather than fail silently, naming the parent it requires, as every other
|
|
2065
|
+
// misplaced element does.
|
|
2066
|
+
const name = this.getAttribute('name');
|
|
2067
|
+
const label = name ? ` '${name}'` : '';
|
|
2068
|
+
console.warn(`pc-entity${label} must be a descendant of pc-app - entity not created`);
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
// If app is already running, create entity immediately
|
|
2072
|
+
if (closestApp._hierarchyReady) {
|
|
2073
|
+
const app = closestApp.app;
|
|
2074
|
+
this._createEntity(app);
|
|
2075
|
+
this._buildHierarchy(app);
|
|
2076
|
+
// Handle any child entities that might exist. A build that deferred (an unresolved
|
|
2077
|
+
// pc-node above) defers the whole subtree with it - the node's bind sweeps it.
|
|
2078
|
+
if (this._built) {
|
|
2079
|
+
buildDescendantEntities(this, app);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
disconnectedCallback() {
|
|
2084
|
+
// Destroying the entity destroys its whole subtree, and the engine fires 'destroy' for
|
|
2085
|
+
// every entity in it - so _onEntityDestroy resets this element AND every descendant
|
|
2086
|
+
// element before the descendants' own disconnectedCallbacks run. Their entities are null
|
|
2087
|
+
// by then, making this call a no-op for them.
|
|
2088
|
+
this._entity?.destroy();
|
|
2089
|
+
}
|
|
2031
2090
|
static get observedAttributes() {
|
|
2032
2091
|
return ['enabled', 'name', 'position', 'rotation', 'scale', 'tags', ...POINTER_ATTRIBUTES];
|
|
2033
2092
|
}
|
|
@@ -2357,6 +2416,10 @@ const processBufferView = (gltfBuffer, buffers, continuation) => {
|
|
|
2357
2416
|
* Apart from `lazy` and the texture options, these attributes are read once when the asset is
|
|
2358
2417
|
* created, so changing them later has no effect.
|
|
2359
2418
|
*
|
|
2419
|
+
* @elementSummary The `<pc-asset>` element declares an asset for the application to load — a model,
|
|
2420
|
+
* texture, font, sound, script or JSON file — under an `id` that other elements reference. Must be
|
|
2421
|
+
* a direct child of `<pc-app>`.
|
|
2422
|
+
*
|
|
2360
2423
|
* @attribute {string} id - The identifier used to reference the asset from other elements.
|
|
2361
2424
|
* @attribute {string} src - The URL of the asset to load.
|
|
2362
2425
|
* @attribute {string} type - The asset type. Inferred from the `src` file extension when omitted.
|
|
@@ -2965,14 +3028,47 @@ const formatHierarchy = (root, counts) => {
|
|
|
2965
3028
|
* The ModelElement interface also inherits the properties and methods of the
|
|
2966
3029
|
* {@link HTMLElement} interface.
|
|
2967
3030
|
*
|
|
2968
|
-
* The element
|
|
2969
|
-
*
|
|
2970
|
-
*
|
|
2971
|
-
*
|
|
2972
|
-
*
|
|
2973
|
-
*
|
|
2974
|
-
* becomes ready
|
|
3031
|
+
* The element creates and fronts a stable host entity: `entity` is that host, created when the
|
|
3032
|
+
* application builds its hierarchy and kept across `asset` changes, so the element's transform
|
|
3033
|
+
* and tags are instance placement that composes with whatever transform the asset authored on
|
|
3034
|
+
* its root. The instantiated content is parented beneath the host and exposed as
|
|
3035
|
+
* {@link contentEntity}.
|
|
3036
|
+
*
|
|
3037
|
+
* The element becomes ready once its current asset selection has settled: the container asset
|
|
3038
|
+
* has loaded and its content root has been parented beneath the host, the load has failed
|
|
3039
|
+
* (`contentEntity` stays `null` — listen for `error`, or check `contentEntity`, to tell the
|
|
3040
|
+
* outcomes apart), or no asset is assigned at all. Changing `asset` re-arms readiness and
|
|
3041
|
+
* instantiates anew, so a `ready()` obtained after the change resolves against the new content.
|
|
3042
|
+
* A `pc-model` outside a `pc-app`, or referencing an unknown asset id, warns and never becomes
|
|
3043
|
+
* ready.
|
|
3044
|
+
*
|
|
3045
|
+
* The pointer events below are dispatched by the containing `<pc-app>` element when the pointer
|
|
3046
|
+
* intersects the model's geometry, exactly as for `<pc-entity>` — a hit on a content node that no
|
|
3047
|
+
* `pc-node` fronts resolves to this element.
|
|
3048
|
+
*
|
|
3049
|
+
* @elementSummary The `<pc-model>` element instantiates a 3D model from a container asset
|
|
3050
|
+
* (typically a GLB) beneath an entity of its own, so the element's transform and tags place the
|
|
3051
|
+
* instance in the scene. Its `<pc-node>` children override what the asset authored. Place it in the
|
|
3052
|
+
* `<pc-scene>`, or nest it under a `<pc-entity>`, another `<pc-model>` or a `<pc-node>`.
|
|
2975
3053
|
*
|
|
3054
|
+
* @attribute {boolean} enabled - The enabled state of the model.
|
|
3055
|
+
* @attribute {string} name - The name of the model.
|
|
3056
|
+
* @attribute {string} position - The position of the model.
|
|
3057
|
+
* @attribute {string} rotation - The rotation of the model.
|
|
3058
|
+
* @attribute {string} scale - The scale of the model.
|
|
3059
|
+
* @attribute {string} tags - The tags of the model.
|
|
3060
|
+
* @attribute {string} onpointerenter - Script to run when the pointer moves onto the model.
|
|
3061
|
+
* @attribute {string} onpointerleave - Script to run when the pointer moves off the model.
|
|
3062
|
+
* @attribute {string} onpointermove - Script to run when the pointer moves over the model.
|
|
3063
|
+
* @attribute {string} onpointerdown - Script to run when a pointer button is pressed over the
|
|
3064
|
+
* model.
|
|
3065
|
+
* @attribute {string} onpointerup - Script to run when a pointer button is released over the
|
|
3066
|
+
* model.
|
|
3067
|
+
* @fires {PointerEvent} pointerenter - Fired when the pointer moves onto the model.
|
|
3068
|
+
* @fires {PointerEvent} pointerleave - Fired when the pointer moves off the model.
|
|
3069
|
+
* @fires {PointerEvent} pointermove - Fired when the pointer moves over the model.
|
|
3070
|
+
* @fires {PointerEvent} pointerdown - Fired when a pointer button is pressed over the model.
|
|
3071
|
+
* @fires {PointerEvent} pointerup - Fired when a pointer button is released over the model.
|
|
2976
3072
|
* @fires {Event} load - Fired each time a container asset finishes instantiating, including
|
|
2977
3073
|
* re-instantiation after `asset` changes. Does not bubble — listen on this element, or use a
|
|
2978
3074
|
* capture-phase listener on an ancestor.
|
|
@@ -2980,14 +3076,14 @@ const formatHierarchy = (root, counts) => {
|
|
|
2980
3076
|
* error in `message`. Does not bubble. The element still becomes ready — readiness means the load
|
|
2981
3077
|
* settled, not that it succeeded.
|
|
2982
3078
|
*/
|
|
2983
|
-
class ModelElement extends
|
|
3079
|
+
class ModelElement extends EntityOwnerElement {
|
|
2984
3080
|
_asset = '';
|
|
2985
|
-
|
|
3081
|
+
_contentEntity = null;
|
|
2986
3082
|
/**
|
|
2987
|
-
* Incremented on every new load
|
|
2988
|
-
* load that resumes from an await or a load callback abandons
|
|
2989
|
-
* on, so a superseded load can neither instantiate a second
|
|
2990
|
-
*
|
|
3083
|
+
* Incremented on every new load, on disconnect, and when the host entity dies, and captured
|
|
3084
|
+
* by a load when it starts. A load that resumes from an await or a load callback abandons
|
|
3085
|
+
* itself if the value has moved on, so a superseded load can neither instantiate a second
|
|
3086
|
+
* content root nor parent one under a host a newer cycle has already replaced.
|
|
2991
3087
|
*/
|
|
2992
3088
|
_loadGeneration = 0;
|
|
2993
3089
|
/**
|
|
@@ -2998,12 +3094,13 @@ class ModelElement extends AsyncElement {
|
|
|
2998
3094
|
_loadHandle = null;
|
|
2999
3095
|
_errorHandle = null;
|
|
3000
3096
|
/**
|
|
3001
|
-
* The root entity of the instantiated model
|
|
3002
|
-
*
|
|
3003
|
-
*
|
|
3097
|
+
* The root entity of the instantiated model content, parented beneath the host entity.
|
|
3098
|
+
* `null` until the container asset has loaded and been instantiated, after a failed load,
|
|
3099
|
+
* and again once the element has been removed from the document.
|
|
3100
|
+
* @returns The content root entity, or `null`.
|
|
3004
3101
|
*/
|
|
3005
|
-
get
|
|
3006
|
-
return this.
|
|
3102
|
+
get contentEntity() {
|
|
3103
|
+
return this._contentEntity;
|
|
3007
3104
|
}
|
|
3008
3105
|
/**
|
|
3009
3106
|
* Returns a snapshot of the instantiated node tree, or `null` while there is none (the
|
|
@@ -3015,12 +3112,13 @@ class ModelElement extends AsyncElement {
|
|
|
3015
3112
|
* is the printable form.
|
|
3016
3113
|
*
|
|
3017
3114
|
* The snapshot is plain data, computed afresh each call: it does not follow later changes
|
|
3018
|
-
* to the hierarchy, and mutating it changes nothing.
|
|
3115
|
+
* to the hierarchy, and mutating it changes nothing. It covers the instantiated content
|
|
3116
|
+
* only — the host entity the element fronts is not part of the asset's node tree.
|
|
3019
3117
|
*
|
|
3020
3118
|
* @returns The root of the instantiated node tree, or `null`.
|
|
3021
3119
|
*/
|
|
3022
3120
|
hierarchy() {
|
|
3023
|
-
const root = this.
|
|
3121
|
+
const root = this._contentEntity;
|
|
3024
3122
|
if (!root) {
|
|
3025
3123
|
return null;
|
|
3026
3124
|
}
|
|
@@ -3060,18 +3158,53 @@ class ModelElement extends AsyncElement {
|
|
|
3060
3158
|
// A model outside an application is inert and never becomes ready, so awaiting it hangs.
|
|
3061
3159
|
// Warn rather than fail silently, naming the parent it requires, as every other misplaced
|
|
3062
3160
|
// element does.
|
|
3063
|
-
|
|
3161
|
+
const closestApp = this.closestApp;
|
|
3162
|
+
if (!closestApp) {
|
|
3064
3163
|
const label = this._asset ? ` '${this._asset}'` : '';
|
|
3065
3164
|
console.warn(`pc-model${label} must be a descendant of pc-app - model not created`);
|
|
3066
3165
|
return;
|
|
3067
3166
|
}
|
|
3068
|
-
|
|
3167
|
+
// If the app is already running, create the host immediately; during a boot, the app's
|
|
3168
|
+
// own sweep does it. Either way, _onBuilt starts the content load once the host is
|
|
3169
|
+
// parented.
|
|
3170
|
+
if (closestApp._hierarchyReady) {
|
|
3171
|
+
const app = closestApp.app;
|
|
3172
|
+
this._createEntity(app);
|
|
3173
|
+
this._buildHierarchy(app);
|
|
3174
|
+
// A build that deferred (an unresolved pc-node above) defers the whole subtree with
|
|
3175
|
+
// it - the node's bind sweeps it.
|
|
3176
|
+
if (this._built) {
|
|
3177
|
+
buildDescendantEntities(this, app);
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3069
3180
|
}
|
|
3070
3181
|
disconnectedCallback() {
|
|
3182
|
+
// Destroying the host destroys the instantiated content with it, and the destroy hook
|
|
3183
|
+
// resets the element. The generation guard comes first so a load suspended on an await
|
|
3184
|
+
// cannot resume against the torn-down element.
|
|
3071
3185
|
this._loadGeneration++;
|
|
3072
3186
|
this._detachLoadHandlers();
|
|
3073
|
-
this.
|
|
3074
|
-
|
|
3187
|
+
this._entity?.destroy();
|
|
3188
|
+
}
|
|
3189
|
+
/**
|
|
3190
|
+
* Starts (or restarts) the content load once the host has been parented. Readiness is not
|
|
3191
|
+
* announced here — it tracks the content settling, not the host entering the scene graph.
|
|
3192
|
+
*/
|
|
3193
|
+
_onBuilt() {
|
|
3194
|
+
this._loadContent();
|
|
3195
|
+
}
|
|
3196
|
+
/**
|
|
3197
|
+
* Extends the owner reset for the content: the engine's destroy cascade has already taken
|
|
3198
|
+
* the content root down with the host subtree, so only the reference and the in-flight load
|
|
3199
|
+
* are dropped here. The next build re-creates the host and re-instantiates the content.
|
|
3200
|
+
*
|
|
3201
|
+
* @param entity - The host entity that was destroyed.
|
|
3202
|
+
*/
|
|
3203
|
+
_onEntityDestroy(entity) {
|
|
3204
|
+
this._loadGeneration++;
|
|
3205
|
+
this._detachLoadHandlers();
|
|
3206
|
+
this._contentEntity = null;
|
|
3207
|
+
super._onEntityDestroy(entity);
|
|
3075
3208
|
}
|
|
3076
3209
|
_detachLoadHandlers() {
|
|
3077
3210
|
this._loadHandle?.off();
|
|
@@ -3080,51 +3213,34 @@ class ModelElement extends AsyncElement {
|
|
|
3080
3213
|
this._errorHandle = null;
|
|
3081
3214
|
}
|
|
3082
3215
|
/**
|
|
3083
|
-
* Resolves readiness and dispatches the `load` event. Called once the instantiated
|
|
3084
|
-
* has been parented —
|
|
3085
|
-
* model's
|
|
3216
|
+
* Resolves readiness and dispatches the `load` event. Called once the instantiated content
|
|
3217
|
+
* has been parented beneath the host — the host itself is already in the scene graph by
|
|
3218
|
+
* then, so a ready model's content always has world transforms.
|
|
3086
3219
|
*/
|
|
3087
3220
|
_announceLoad() {
|
|
3088
3221
|
this._onReady();
|
|
3089
3222
|
this.dispatchEvent(new Event('load'));
|
|
3090
3223
|
}
|
|
3091
3224
|
_instantiate(container) {
|
|
3092
|
-
const
|
|
3093
|
-
|
|
3094
|
-
this._entity
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
});
|
|
3107
|
-
}
|
|
3108
|
-
else {
|
|
3109
|
-
const appElement = this.closestApp;
|
|
3110
|
-
if (appElement) {
|
|
3111
|
-
appElement.ready().then(() => {
|
|
3112
|
-
if (generation !== this._loadGeneration) {
|
|
3113
|
-
return;
|
|
3114
|
-
}
|
|
3115
|
-
appElement.app.root.addChild(entity);
|
|
3116
|
-
this._announceLoad();
|
|
3117
|
-
});
|
|
3118
|
-
}
|
|
3119
|
-
}
|
|
3120
|
-
}
|
|
3121
|
-
async _loadModel() {
|
|
3122
|
-
this._unloadModel();
|
|
3225
|
+
const content = container.instantiateRenderEntity();
|
|
3226
|
+
this._contentEntity = content;
|
|
3227
|
+
this._entity.addChild(content);
|
|
3228
|
+
this._announceLoad();
|
|
3229
|
+
}
|
|
3230
|
+
_destroyContent() {
|
|
3231
|
+
this._contentEntity?.destroy();
|
|
3232
|
+
this._contentEntity = null;
|
|
3233
|
+
}
|
|
3234
|
+
async _loadContent() {
|
|
3235
|
+
// The old content goes down synchronously, so a reader that checks after an asset change
|
|
3236
|
+
// never sees the outgoing hierarchy. The host survives - components and child entities
|
|
3237
|
+
// attached to it carry over to the new content.
|
|
3238
|
+
this._destroyContent();
|
|
3123
3239
|
// Supersede any load already in flight - only the newest load may instantiate
|
|
3124
3240
|
const generation = ++this._loadGeneration;
|
|
3125
3241
|
this._detachLoadHandlers();
|
|
3126
3242
|
// Re-arm readiness so a waiter obtained after an asset change resolves against the new
|
|
3127
|
-
//
|
|
3243
|
+
// content. A no-op on first connection, where readiness is still pending.
|
|
3128
3244
|
this._resetReady();
|
|
3129
3245
|
const appElement = this.closestApp;
|
|
3130
3246
|
if (!appElement) {
|
|
@@ -3136,14 +3252,23 @@ class ModelElement extends AsyncElement {
|
|
|
3136
3252
|
if (generation !== this._loadGeneration) {
|
|
3137
3253
|
return;
|
|
3138
3254
|
}
|
|
3255
|
+
// The host may not be parented yet - a model under a pc-node that has not bound, reached
|
|
3256
|
+
// through the asset setter. Nothing settles here: _onBuilt re-runs this load once the
|
|
3257
|
+
// host builds.
|
|
3258
|
+
if (!this._entity || !this._built) {
|
|
3259
|
+
return;
|
|
3260
|
+
}
|
|
3261
|
+
if (this._asset === '') {
|
|
3262
|
+
// No asset assigned is a settled selection: the element is a usable host (components
|
|
3263
|
+
// attach, waiters resolve) with no content. Assigning an asset later re-arms.
|
|
3264
|
+
this._onReady();
|
|
3265
|
+
return;
|
|
3266
|
+
}
|
|
3139
3267
|
const asset = useAsset(this._asset);
|
|
3140
3268
|
if (!asset) {
|
|
3141
|
-
//
|
|
3142
|
-
// non-empty one that resolves to nothing is a dead end - say so rather than staying
|
|
3269
|
+
// A non-empty id that resolves to nothing is a dead end - say so rather than staying
|
|
3143
3270
|
// silently pending.
|
|
3144
|
-
|
|
3145
|
-
console.warn(`pc-model could not find asset '${this._asset}' - model not created`);
|
|
3146
|
-
}
|
|
3271
|
+
console.warn(`pc-model could not find asset '${this._asset}' - model not created`);
|
|
3147
3272
|
return;
|
|
3148
3273
|
}
|
|
3149
3274
|
if (asset.loaded) {
|
|
@@ -3165,7 +3290,7 @@ class ModelElement extends AsyncElement {
|
|
|
3165
3290
|
if (generation !== this._loadGeneration) {
|
|
3166
3291
|
return;
|
|
3167
3292
|
}
|
|
3168
|
-
// A failed load settles readiness with a null
|
|
3293
|
+
// A failed load settles readiness with a null contentEntity, mirroring pc-asset:
|
|
3169
3294
|
// readiness means the load settled, not that it succeeded.
|
|
3170
3295
|
this.dispatchEvent(new ErrorEvent('error', {
|
|
3171
3296
|
message: err instanceof Error ? err.message : String(err)
|
|
@@ -3174,10 +3299,6 @@ class ModelElement extends AsyncElement {
|
|
|
3174
3299
|
});
|
|
3175
3300
|
}
|
|
3176
3301
|
}
|
|
3177
|
-
_unloadModel() {
|
|
3178
|
-
this._entity?.destroy();
|
|
3179
|
-
this._entity = null;
|
|
3180
|
-
}
|
|
3181
3302
|
/**
|
|
3182
3303
|
* Sets the id of the `pc-asset` to use for the model.
|
|
3183
3304
|
* @param value - The asset ID.
|
|
@@ -3185,7 +3306,7 @@ class ModelElement extends AsyncElement {
|
|
|
3185
3306
|
set asset(value) {
|
|
3186
3307
|
this._asset = value;
|
|
3187
3308
|
if (this.isConnected) {
|
|
3188
|
-
this.
|
|
3309
|
+
this._loadContent();
|
|
3189
3310
|
}
|
|
3190
3311
|
}
|
|
3191
3312
|
/**
|
|
@@ -3196,13 +3317,38 @@ class ModelElement extends AsyncElement {
|
|
|
3196
3317
|
return this._asset;
|
|
3197
3318
|
}
|
|
3198
3319
|
static get observedAttributes() {
|
|
3199
|
-
return ['asset'];
|
|
3320
|
+
return ['asset', 'enabled', 'name', 'position', 'rotation', 'scale', 'tags', ...POINTER_ATTRIBUTES];
|
|
3200
3321
|
}
|
|
3201
3322
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
3202
3323
|
switch (name) {
|
|
3203
3324
|
case 'asset':
|
|
3204
3325
|
this.asset = newValue ?? '';
|
|
3205
3326
|
break;
|
|
3327
|
+
case 'enabled':
|
|
3328
|
+
this.enabled = parseBool(newValue, true);
|
|
3329
|
+
break;
|
|
3330
|
+
case 'name':
|
|
3331
|
+
this.name = newValue ?? 'Untitled';
|
|
3332
|
+
break;
|
|
3333
|
+
case 'position':
|
|
3334
|
+
this.position = parseVec3(newValue, Vec3.ZERO, name);
|
|
3335
|
+
break;
|
|
3336
|
+
case 'rotation':
|
|
3337
|
+
this.rotation = parseVec3(newValue, Vec3.ZERO, name);
|
|
3338
|
+
break;
|
|
3339
|
+
case 'scale':
|
|
3340
|
+
this.scale = parseVec3(newValue, Vec3.ONE, name);
|
|
3341
|
+
break;
|
|
3342
|
+
case 'tags':
|
|
3343
|
+
this.tags = parseTags(newValue);
|
|
3344
|
+
break;
|
|
3345
|
+
case 'onpointerenter':
|
|
3346
|
+
case 'onpointerleave':
|
|
3347
|
+
case 'onpointerdown':
|
|
3348
|
+
case 'onpointerup':
|
|
3349
|
+
case 'onpointermove':
|
|
3350
|
+
this._updateInlineHandler(name, newValue);
|
|
3351
|
+
break;
|
|
3206
3352
|
}
|
|
3207
3353
|
}
|
|
3208
3354
|
}
|
|
@@ -3293,7 +3439,7 @@ class ComponentElement extends AsyncElement {
|
|
|
3293
3439
|
// A component can only exist on an entity, so an element placed outside one is inert.
|
|
3294
3440
|
// It still becomes ready (with a null `component`), so warn rather than fail silently
|
|
3295
3441
|
const label = this.id ? ` '${this.id}'` : '';
|
|
3296
|
-
console.warn(`${this.tagName.toLowerCase()}${label} must be a descendant of pc-entity - component not added`);
|
|
3442
|
+
console.warn(`${this.tagName.toLowerCase()}${label} must be a descendant of pc-entity, pc-model or pc-node - component not added`);
|
|
3297
3443
|
return;
|
|
3298
3444
|
}
|
|
3299
3445
|
await entityElement.ready();
|
|
@@ -3381,8 +3527,9 @@ class ComponentElement extends AsyncElement {
|
|
|
3381
3527
|
}
|
|
3382
3528
|
/**
|
|
3383
3529
|
* The PlayCanvas component instance. `null` until the element is ready, and also for an
|
|
3384
|
-
* element that is not a descendant of
|
|
3385
|
-
* element's `ready()` promise
|
|
3530
|
+
* element that is not a descendant of an entity-fronting element (`<pc-entity>`,
|
|
3531
|
+
* `<pc-model>` or `<pc-node>`) — await {@link whenReady} or the element's `ready()` promise
|
|
3532
|
+
* before accessing it.
|
|
3386
3533
|
* @returns The component instance, or `null`.
|
|
3387
3534
|
*/
|
|
3388
3535
|
get component() {
|
|
@@ -3435,6 +3582,13 @@ class ComponentElement extends AsyncElement {
|
|
|
3435
3582
|
* the underlying {@link AnimComponent} (via {@link component}) for playback state beyond what
|
|
3436
3583
|
* this element exposes.
|
|
3437
3584
|
*
|
|
3585
|
+
* Engine component: {@link AnimComponent} (`anim`).
|
|
3586
|
+
*
|
|
3587
|
+
* @elementSummary The `<pc-anim>` element plays animation clips over its entity's hierarchy, taken
|
|
3588
|
+
* from `<pc-anim-clip>` children or from the enclosing `<pc-model>`'s own animations. The first
|
|
3589
|
+
* clip plays automatically, and the `clip` attribute switches between them. Must be a child of a
|
|
3590
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
3591
|
+
*
|
|
3438
3592
|
* @category Components
|
|
3439
3593
|
*/
|
|
3440
3594
|
class AnimComponentElement extends ComponentElement {
|
|
@@ -3456,6 +3610,11 @@ class AnimComponentElement extends ComponentElement {
|
|
|
3456
3610
|
* The name of the active clip.
|
|
3457
3611
|
*/
|
|
3458
3612
|
_clip = '';
|
|
3613
|
+
/**
|
|
3614
|
+
* The binding root this element last assigned through {@link _applyRootBone}, distinguishing
|
|
3615
|
+
* its own writes from a `rootBone` assigned through the engine API — which is left alone.
|
|
3616
|
+
*/
|
|
3617
|
+
_managedRootBone = null;
|
|
3459
3618
|
/**
|
|
3460
3619
|
* The element the model-readiness listener is attached to, held so disconnection can detach
|
|
3461
3620
|
* it after `closestEntity` no longer resolves.
|
|
@@ -3481,27 +3640,71 @@ class AnimComponentElement extends ComponentElement {
|
|
|
3481
3640
|
*/
|
|
3482
3641
|
_warnedClip = null;
|
|
3483
3642
|
/**
|
|
3484
|
-
* Rebinds when a model
|
|
3485
|
-
*
|
|
3643
|
+
* Rebinds when a model that is not this component's host announces readiness — a sibling or
|
|
3644
|
+
* deeper model whose content changed under the assigned clips. The engine resolves each
|
|
3645
|
+
* curve once, at the first tick after assignment, and never retries — and its mesh-instance
|
|
3486
3646
|
* broadcast fires before an instantiated hierarchy is parented, so a model that loads after
|
|
3487
|
-
* the clips were assigned would otherwise stay silently unbound.
|
|
3488
|
-
*
|
|
3489
|
-
*
|
|
3647
|
+
* the clips were assigned would otherwise stay silently unbound. The host model's own cycles
|
|
3648
|
+
* are excluded: those re-enter through {@link initComponent}, which refreshes the whole clip
|
|
3649
|
+
* set against the new container.
|
|
3490
3650
|
*/
|
|
3491
3651
|
_onModelReady = (event) => {
|
|
3492
3652
|
if (!(event.target instanceof ModelElement) || !this.component) {
|
|
3493
3653
|
return;
|
|
3494
3654
|
}
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
}
|
|
3655
|
+
// The host model's own readiness cycle already re-initialized this component through
|
|
3656
|
+
// ComponentElement's host-ready listener, which is attached first and so has run by now.
|
|
3657
|
+
// Acting here too would resolve every track twice and capture the playhead-restore
|
|
3658
|
+
// snapshot mid-rebuild.
|
|
3659
|
+
if (event.target === this._modelListenerTarget) {
|
|
3660
|
+
return;
|
|
3502
3661
|
}
|
|
3662
|
+
// A model cycle can replace the skeleton source's host entity (a rebuild under a
|
|
3663
|
+
// retargeting pc-node), so the binding root is re-asserted before the rebind.
|
|
3664
|
+
this._applyRootBone();
|
|
3503
3665
|
this.component.rebind();
|
|
3504
3666
|
};
|
|
3667
|
+
/**
|
|
3668
|
+
* The model whose host entity scopes this component's curve binding: the parent `pc-model`,
|
|
3669
|
+
* or the sole `pc-model` among the parent's direct children (the arrangement where clips
|
|
3670
|
+
* live in a library asset beside the skeleton). `null` when there is no such model, or more
|
|
3671
|
+
* than one — an ambiguous skeleton is left to the engine's name-based resolution.
|
|
3672
|
+
*/
|
|
3673
|
+
_skeletonSource() {
|
|
3674
|
+
const parent = this.parentElement;
|
|
3675
|
+
if (parent instanceof ModelElement) {
|
|
3676
|
+
return parent;
|
|
3677
|
+
}
|
|
3678
|
+
const models = parent ? parent.querySelectorAll(':scope > pc-model') : null;
|
|
3679
|
+
return models?.length === 1 && models[0] instanceof ModelElement ? models[0] : null;
|
|
3680
|
+
}
|
|
3681
|
+
/**
|
|
3682
|
+
* Keeps the component's binding root pointing at the skeleton source's host entity. The host
|
|
3683
|
+
* wraps the instantiated content, so left at its default — the component's own entity — the
|
|
3684
|
+
* engine binder mis-resolves curves that target the asset's root node: its fallback treats
|
|
3685
|
+
* the graph as the asset root once the root is no longer a direct child.
|
|
3686
|
+
*
|
|
3687
|
+
* Authoritative in both directions for values this element assigned: a source appearing pins
|
|
3688
|
+
* its host, and a source dissolving (the model gone, or a second model making the skeleton
|
|
3689
|
+
* ambiguous) clears the pin rather than leaving it on a stale host. A root assigned through
|
|
3690
|
+
* the engine API is never overwritten — the user's choice outranks the managed default.
|
|
3691
|
+
* Writes are skipped while unchanged, because the engine setter itself triggers a rebind.
|
|
3692
|
+
*/
|
|
3693
|
+
_applyRootBone() {
|
|
3694
|
+
const component = this.component;
|
|
3695
|
+
// A non-null root this element did not assign came through the engine API. A fresh
|
|
3696
|
+
// component starts at null, which is always reclaimable.
|
|
3697
|
+
if (component.rootBone !== null && component.rootBone !== this._managedRootBone) {
|
|
3698
|
+
return;
|
|
3699
|
+
}
|
|
3700
|
+
const host = this._skeletonSource()?.entity ?? null;
|
|
3701
|
+
if (component.rootBone !== host) {
|
|
3702
|
+
// The engine setter accepts null - restoring the component's own entity as the
|
|
3703
|
+
// binding graph - but its declared type does not
|
|
3704
|
+
component.rootBone = host;
|
|
3705
|
+
}
|
|
3706
|
+
this._managedRootBone = host;
|
|
3707
|
+
}
|
|
3505
3708
|
/** @ignore */
|
|
3506
3709
|
constructor() {
|
|
3507
3710
|
super('anim');
|
|
@@ -3526,7 +3729,16 @@ class AnimComponentElement extends ComponentElement {
|
|
|
3526
3729
|
host.addEventListener('ready', this._onModelReady);
|
|
3527
3730
|
this._modelListenerTarget = host;
|
|
3528
3731
|
}
|
|
3529
|
-
this.
|
|
3732
|
+
this._applyRootBone();
|
|
3733
|
+
if (this.component.baseLayer) {
|
|
3734
|
+
// The component survived the host's readiness cycle (a pc-model reloading content on
|
|
3735
|
+
// its stable host entity). A loaded graph cannot be reassigned in place, so drop it
|
|
3736
|
+
// and reassign from the current source, restoring the active clip and playhead.
|
|
3737
|
+
this._refreshClips();
|
|
3738
|
+
}
|
|
3739
|
+
else {
|
|
3740
|
+
this._applyClips();
|
|
3741
|
+
}
|
|
3530
3742
|
}
|
|
3531
3743
|
disconnectedCallback() {
|
|
3532
3744
|
this._modelListenerTarget?.removeEventListener('ready', this._onModelReady);
|
|
@@ -3536,6 +3748,7 @@ class AnimComponentElement extends ComponentElement {
|
|
|
3536
3748
|
this._sourceGeneration++;
|
|
3537
3749
|
this._assignedClips.clear();
|
|
3538
3750
|
this._autoAssigned = false;
|
|
3751
|
+
this._managedRootBone = null;
|
|
3539
3752
|
super.disconnectedCallback();
|
|
3540
3753
|
}
|
|
3541
3754
|
/**
|
|
@@ -3704,6 +3917,10 @@ class AnimComponentElement extends ComponentElement {
|
|
|
3704
3917
|
if (!component) {
|
|
3705
3918
|
return;
|
|
3706
3919
|
}
|
|
3920
|
+
// A clip-set change is also a chance for the skeleton source to have changed shape (a
|
|
3921
|
+
// clip child appearing or leaving can accompany a model coming or going) - re-derive the
|
|
3922
|
+
// binding root before the reassignment binds against it.
|
|
3923
|
+
this._applyRootBone();
|
|
3707
3924
|
const layer = component.baseLayer;
|
|
3708
3925
|
const restore = layer ? {
|
|
3709
3926
|
state: layer.activeState,
|
|
@@ -3990,6 +4207,10 @@ customElements.define('pc-anim', AnimComponentElement);
|
|
|
3990
4207
|
* named; in a multi-track source the track named `name` is chosen, falling back to the first
|
|
3991
4208
|
* with a warning. The element becomes ready once its resolved track is assigned.
|
|
3992
4209
|
*
|
|
4210
|
+
* @elementSummary The `<pc-anim-clip>` element declares one named animation clip on its parent
|
|
4211
|
+
* `<pc-anim>`, taken from the `asset` it names or, without one, from the enclosing `<pc-model>`'s
|
|
4212
|
+
* own animations. Must be a direct child of `<pc-anim>`.
|
|
4213
|
+
*
|
|
3993
4214
|
* @category Components
|
|
3994
4215
|
*/
|
|
3995
4216
|
class AnimClipElement extends AsyncElement {
|
|
@@ -4311,14 +4532,20 @@ class AnimClipElement extends AsyncElement {
|
|
|
4311
4532
|
customElements.define('pc-anim-clip', AnimClipElement);
|
|
4312
4533
|
|
|
4313
4534
|
/**
|
|
4314
|
-
* The
|
|
4315
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-listener/ | `<pc-listener>`} elements.
|
|
4316
|
-
* The
|
|
4535
|
+
* The AudioListenerComponentElement interface provides properties and methods for manipulating
|
|
4536
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-audio-listener/ | `<pc-audio-listener>`} elements.
|
|
4537
|
+
* The AudioListenerComponentElement interface also inherits the properties and methods of the
|
|
4317
4538
|
* {@link HTMLElement} interface.
|
|
4318
4539
|
*
|
|
4540
|
+
* Engine component: {@link AudioListenerComponent} (`audiolistener`).
|
|
4541
|
+
*
|
|
4542
|
+
* @elementSummary The `<pc-audio-listener>` element makes its entity the point from which
|
|
4543
|
+
* positional sounds are heard, typically the entity holding the `<pc-camera>`. Must be a child of a
|
|
4544
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
4545
|
+
*
|
|
4319
4546
|
* @category Components
|
|
4320
4547
|
*/
|
|
4321
|
-
class
|
|
4548
|
+
class AudioListenerComponentElement extends ComponentElement {
|
|
4322
4549
|
/** @ignore */
|
|
4323
4550
|
constructor() {
|
|
4324
4551
|
super('audiolistener');
|
|
@@ -4331,7 +4558,7 @@ class ListenerComponentElement extends ComponentElement {
|
|
|
4331
4558
|
return super.component;
|
|
4332
4559
|
}
|
|
4333
4560
|
}
|
|
4334
|
-
customElements.define('pc-listener',
|
|
4561
|
+
customElements.define('pc-audio-listener', AudioListenerComponentElement);
|
|
4335
4562
|
|
|
4336
4563
|
const transitionModes = new Map([
|
|
4337
4564
|
['tint', BUTTON_TRANSITION_MODE_TINT],
|
|
@@ -4343,6 +4570,13 @@ const transitionModes = new Map([
|
|
|
4343
4570
|
* The ButtonComponentElement interface also inherits the properties and methods of the
|
|
4344
4571
|
* {@link HTMLElement} interface.
|
|
4345
4572
|
*
|
|
4573
|
+
* Engine component: {@link ButtonComponent} (`button`).
|
|
4574
|
+
*
|
|
4575
|
+
* @elementSummary The `<pc-button>` element makes its entity respond to pointer input, tinting or
|
|
4576
|
+
* swapping its image as the pointer hovers, presses and releases it. The entity also needs a
|
|
4577
|
+
* `<pc-element>` with `use-input` set. Must be a child of a `<pc-entity>`, `<pc-model>` or
|
|
4578
|
+
* `<pc-node>`.
|
|
4579
|
+
*
|
|
4346
4580
|
* @category Components
|
|
4347
4581
|
*/
|
|
4348
4582
|
class ButtonComponentElement extends ComponentElement {
|
|
@@ -4423,7 +4657,9 @@ class ButtonComponentElement extends ComponentElement {
|
|
|
4423
4657
|
}
|
|
4424
4658
|
/**
|
|
4425
4659
|
* Sets the reference (CSS selector, element id or entity name) to the `<pc-entity>` whose image
|
|
4426
|
-
* element is used for visual transitions. Defaults to the button's own entity
|
|
4660
|
+
* element is used for visual transitions. Defaults to the button's own entity — inside a
|
|
4661
|
+
* `<pc-model>`, that is the model's host entity, so supply an explicit reference to target a
|
|
4662
|
+
* UI entity instead.
|
|
4427
4663
|
* @param value - The image entity reference.
|
|
4428
4664
|
*/
|
|
4429
4665
|
set image(value) {
|
|
@@ -4742,13 +4978,20 @@ const tonemaps = new Map([
|
|
|
4742
4978
|
* The CameraComponentElement interface also inherits the properties and methods of the
|
|
4743
4979
|
* {@link HTMLElement} interface.
|
|
4744
4980
|
*
|
|
4981
|
+
* Engine component: {@link CameraComponent} (`camera`).
|
|
4982
|
+
*
|
|
4983
|
+
* @elementSummary The `<pc-camera>` element renders the scene from its entity's transform, with
|
|
4984
|
+
* attributes for the projection, field of view, clip planes, clear color and tonemapping. Must be a
|
|
4985
|
+
* child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
4986
|
+
*
|
|
4745
4987
|
* @category Components
|
|
4746
4988
|
*/
|
|
4747
4989
|
class CameraComponentElement extends ComponentElement {
|
|
4748
4990
|
_clearColor = new Color(0.75, 0.75, 0.75, 1);
|
|
4749
4991
|
_clearColorBuffer = true;
|
|
4992
|
+
_clearDepth = 1;
|
|
4750
4993
|
_clearDepthBuffer = true;
|
|
4751
|
-
_clearStencilBuffer =
|
|
4994
|
+
_clearStencilBuffer = true;
|
|
4752
4995
|
_cullFaces = true;
|
|
4753
4996
|
_farClip = 1000;
|
|
4754
4997
|
_flipFaces = false;
|
|
@@ -4771,6 +5014,7 @@ class CameraComponentElement extends ComponentElement {
|
|
|
4771
5014
|
return {
|
|
4772
5015
|
clearColor: this._clearColor,
|
|
4773
5016
|
clearColorBuffer: this._clearColorBuffer,
|
|
5017
|
+
clearDepth: this._clearDepth,
|
|
4774
5018
|
clearDepthBuffer: this._clearDepthBuffer,
|
|
4775
5019
|
clearStencilBuffer: this._clearStencilBuffer,
|
|
4776
5020
|
cullFaces: this._cullFaces,
|
|
@@ -4789,9 +5033,31 @@ class CameraComponentElement extends ComponentElement {
|
|
|
4789
5033
|
toneMapping: tonemaps.get(this._tonemap) ?? TONEMAP_NONE
|
|
4790
5034
|
};
|
|
4791
5035
|
}
|
|
4792
|
-
|
|
5036
|
+
/**
|
|
5037
|
+
* Whether immersive AR is available. Independent of {@link vrAvailable}: a device can offer
|
|
5038
|
+
* either mode without the other.
|
|
5039
|
+
* @returns Whether immersive AR is available.
|
|
5040
|
+
*/
|
|
5041
|
+
get arAvailable() {
|
|
5042
|
+
return this._available(XRTYPE_AR);
|
|
5043
|
+
}
|
|
5044
|
+
/**
|
|
5045
|
+
* Whether immersive VR is available. Independent of {@link arAvailable}: a device can offer
|
|
5046
|
+
* either mode without the other.
|
|
5047
|
+
* @returns Whether immersive VR is available.
|
|
5048
|
+
*/
|
|
5049
|
+
get vrAvailable() {
|
|
5050
|
+
return this._available(XRTYPE_VR);
|
|
5051
|
+
}
|
|
5052
|
+
/**
|
|
5053
|
+
* Whether one XR session type is available on this device.
|
|
5054
|
+
*
|
|
5055
|
+
* @param type - The XR session type to test.
|
|
5056
|
+
* @returns Whether that type is available.
|
|
5057
|
+
*/
|
|
5058
|
+
_available(type) {
|
|
4793
5059
|
const xrManager = this.component?.system.app.xr;
|
|
4794
|
-
return xrManager
|
|
5060
|
+
return Boolean(xrManager?.supported && xrManager.isAvailable(type));
|
|
4795
5061
|
}
|
|
4796
5062
|
/**
|
|
4797
5063
|
* Starts the camera in XR mode.
|
|
@@ -4799,11 +5065,13 @@ class CameraComponentElement extends ComponentElement {
|
|
|
4799
5065
|
* @param space - The space to start the camera in.
|
|
4800
5066
|
*/
|
|
4801
5067
|
startXr(type, space) {
|
|
4802
|
-
|
|
5068
|
+
// Gated on the mode being started, not on XR in general: a device that offers only
|
|
5069
|
+
// one of the two would otherwise accept a session it cannot serve
|
|
5070
|
+
if (this.component && this._available(type)) {
|
|
4803
5071
|
this.component.startXr(type, space, {
|
|
4804
5072
|
callback: (err) => {
|
|
4805
5073
|
if (err)
|
|
4806
|
-
console.error(`WebXR
|
|
5074
|
+
console.error(`WebXR ${type} failed to start: ${err.message}`);
|
|
4807
5075
|
}
|
|
4808
5076
|
});
|
|
4809
5077
|
}
|
|
@@ -4857,6 +5125,23 @@ class CameraComponentElement extends ComponentElement {
|
|
|
4857
5125
|
get clearColorBuffer() {
|
|
4858
5126
|
return this._clearColorBuffer;
|
|
4859
5127
|
}
|
|
5128
|
+
/**
|
|
5129
|
+
* Sets the depth value the depth buffer is cleared to. Defaults to 1.
|
|
5130
|
+
* @param value - The clear depth value.
|
|
5131
|
+
*/
|
|
5132
|
+
set clearDepth(value) {
|
|
5133
|
+
this._clearDepth = value;
|
|
5134
|
+
if (this.component) {
|
|
5135
|
+
this.component.clearDepth = value;
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5138
|
+
/**
|
|
5139
|
+
* Gets the depth value the depth buffer is cleared to.
|
|
5140
|
+
* @returns The clear depth value.
|
|
5141
|
+
*/
|
|
5142
|
+
get clearDepth() {
|
|
5143
|
+
return this._clearDepth;
|
|
5144
|
+
}
|
|
4860
5145
|
/**
|
|
4861
5146
|
* Sets the clear depth buffer of the camera.
|
|
4862
5147
|
* @param value - The clear depth buffer.
|
|
@@ -5135,6 +5420,7 @@ class CameraComponentElement extends ComponentElement {
|
|
|
5135
5420
|
...super.observedAttributes,
|
|
5136
5421
|
'clear-color',
|
|
5137
5422
|
'clear-color-buffer',
|
|
5423
|
+
'clear-depth',
|
|
5138
5424
|
'clear-depth-buffer',
|
|
5139
5425
|
'clear-stencil-buffer',
|
|
5140
5426
|
'cull-faces',
|
|
@@ -5162,11 +5448,14 @@ class CameraComponentElement extends ComponentElement {
|
|
|
5162
5448
|
case 'clear-color-buffer':
|
|
5163
5449
|
this.clearColorBuffer = parseBool(newValue, true);
|
|
5164
5450
|
break;
|
|
5451
|
+
case 'clear-depth':
|
|
5452
|
+
this.clearDepth = parseNumber(newValue, 1, name);
|
|
5453
|
+
break;
|
|
5165
5454
|
case 'clear-depth-buffer':
|
|
5166
5455
|
this.clearDepthBuffer = parseBool(newValue, true);
|
|
5167
5456
|
break;
|
|
5168
5457
|
case 'clear-stencil-buffer':
|
|
5169
|
-
this.clearStencilBuffer = parseBool(newValue,
|
|
5458
|
+
this.clearStencilBuffer = parseBool(newValue, true);
|
|
5170
5459
|
break;
|
|
5171
5460
|
case 'cull-faces':
|
|
5172
5461
|
this.cullFaces = parseBool(newValue, true);
|
|
@@ -5227,6 +5516,12 @@ customElements.define('pc-camera', CameraComponentElement);
|
|
|
5227
5516
|
* retargets or rebinds picks up the new node's geometry. An entity with no asset-backed render
|
|
5228
5517
|
* component warns, and the collider has no shape.
|
|
5229
5518
|
*
|
|
5519
|
+
* Engine component: {@link CollisionComponent} (`collision`).
|
|
5520
|
+
*
|
|
5521
|
+
* @elementSummary The `<pc-collision>` element gives its entity a collision shape — a box, sphere,
|
|
5522
|
+
* capsule, cone, cylinder or mesh — for the physics simulation to collide against. Pair it with a
|
|
5523
|
+
* `<pc-rigid-body>`. Must be a child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
5524
|
+
*
|
|
5230
5525
|
* @category Components
|
|
5231
5526
|
*/
|
|
5232
5527
|
class CollisionComponentElement extends ComponentElement {
|
|
@@ -5263,7 +5558,9 @@ class CollisionComponentElement extends ComponentElement {
|
|
|
5263
5558
|
* no attribute to supply it - so the host's visible geometry, the meaning a mesh collider
|
|
5264
5559
|
* on a glTF node carries, fills the gap. Runs on every application (so a rebound `pc-node`
|
|
5265
5560
|
* recomputes it) and on a runtime switch to `type="mesh"`; an explicitly assigned
|
|
5266
|
-
* `renderAsset` is never overwritten.
|
|
5561
|
+
* `renderAsset` is never overwritten. A `pc-model` host entity never carries a render
|
|
5562
|
+
* component (the instantiated content beneath it does), so a mesh collider that should take
|
|
5563
|
+
* an asset's geometry belongs on a bound `pc-node`.
|
|
5267
5564
|
*/
|
|
5268
5565
|
_applyMeshGeometryDefault() {
|
|
5269
5566
|
const component = this.component;
|
|
@@ -5408,6 +5705,17 @@ customElements.define('pc-collision', CollisionComponentElement);
|
|
|
5408
5705
|
* The ElementComponentElement interface also inherits the properties and methods of the
|
|
5409
5706
|
* {@link HTMLElement} interface.
|
|
5410
5707
|
*
|
|
5708
|
+
* Despite the name, this is not a base class or a generic wrapper: it is the engine's 2D UI
|
|
5709
|
+
* component, which gives its host entity a rectangle in a `<pc-screen>` hierarchy that draws
|
|
5710
|
+
* either an image, a line of text or nothing (`type="image"`, `"text"` or `"group"`). The tag
|
|
5711
|
+
* spells the engine component it adds, as every component element does.
|
|
5712
|
+
*
|
|
5713
|
+
* Engine component: {@link ElementComponent} (`element`).
|
|
5714
|
+
*
|
|
5715
|
+
* @elementSummary The `<pc-element>` element gives its entity a 2D UI rectangle inside a
|
|
5716
|
+
* `<pc-screen>` hierarchy, drawing an image, a line of text or nothing (`type="image"`, `"text"` or
|
|
5717
|
+
* `"group"`). Must be a child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
5718
|
+
*
|
|
5411
5719
|
* @category Components
|
|
5412
5720
|
*/
|
|
5413
5721
|
class ElementComponentElement extends ComponentElement {
|
|
@@ -6092,10 +6400,17 @@ customElements.define('pc-element', ElementComponentElement);
|
|
|
6092
6400
|
* a rigid body component; leaving `entity-b` empty constrains `entity-a` to a fixed point in world
|
|
6093
6401
|
* space. The underlying engine component is in alpha, so its API may change.
|
|
6094
6402
|
*
|
|
6403
|
+
* @elementSummary The `<pc-joint>` element constrains two rigid bodies to each other — a hinged
|
|
6404
|
+
* door, a swinging chain, a sliding drawer. Its entity's transform is the joint frame, and
|
|
6405
|
+
* `entity-a` and `entity-b` name the bodies. Must be a child of a `<pc-entity>`, `<pc-model>` or
|
|
6406
|
+
* `<pc-node>`.
|
|
6407
|
+
*
|
|
6095
6408
|
* @fires {CustomEvent} break - Fired when the impulse on the joint exceeds `break-impulse` and the
|
|
6096
6409
|
* constraint breaks. A broken joint no longer constrains its bodies; calling `refreshFrames()` on
|
|
6097
6410
|
* the underlying component re-attaches it. Bubbles and is composed.
|
|
6098
6411
|
*
|
|
6412
|
+
* Engine component: {@link JointComponent} (`joint`).
|
|
6413
|
+
*
|
|
6099
6414
|
* @category Components
|
|
6100
6415
|
*/
|
|
6101
6416
|
class JointComponentElement extends ComponentElement {
|
|
@@ -6954,10 +7269,16 @@ customElements.define('pc-joint', JointComponentElement);
|
|
|
6954
7269
|
|
|
6955
7270
|
/**
|
|
6956
7271
|
* The LayoutChildComponentElement interface provides properties and methods for manipulating
|
|
6957
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
7272
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-layout-child/ | `<pc-layout-child>`} elements.
|
|
6958
7273
|
* The LayoutChildComponentElement interface also inherits the properties and methods of the
|
|
6959
7274
|
* {@link HTMLElement} interface.
|
|
6960
7275
|
*
|
|
7276
|
+
* Engine component: {@link LayoutChildComponent} (`layoutchild`).
|
|
7277
|
+
*
|
|
7278
|
+
* @elementSummary The `<pc-layout-child>` element controls how its entity is sized by the
|
|
7279
|
+
* `<pc-layout-group>` above it, through minimum and maximum sizes and fit proportions. Must be a
|
|
7280
|
+
* child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
7281
|
+
*
|
|
6961
7282
|
* @category Components
|
|
6962
7283
|
*/
|
|
6963
7284
|
class LayoutChildComponentElement extends ComponentElement {
|
|
@@ -7150,7 +7471,7 @@ class LayoutChildComponentElement extends ComponentElement {
|
|
|
7150
7471
|
}
|
|
7151
7472
|
}
|
|
7152
7473
|
}
|
|
7153
|
-
customElements.define('pc-
|
|
7474
|
+
customElements.define('pc-layout-child', LayoutChildComponentElement);
|
|
7154
7475
|
|
|
7155
7476
|
const orientations$1 = new Map([
|
|
7156
7477
|
['horizontal', ORIENTATION_HORIZONTAL],
|
|
@@ -7164,10 +7485,16 @@ const fittings = new Map([
|
|
|
7164
7485
|
]);
|
|
7165
7486
|
/**
|
|
7166
7487
|
* The LayoutGroupComponentElement interface provides properties and methods for manipulating
|
|
7167
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
7488
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-layout-group/ | `<pc-layout-group>`} elements.
|
|
7168
7489
|
* The LayoutGroupComponentElement interface also inherits the properties and methods of the
|
|
7169
7490
|
* {@link HTMLElement} interface.
|
|
7170
7491
|
*
|
|
7492
|
+
* Engine component: {@link LayoutGroupComponent} (`layoutgroup`).
|
|
7493
|
+
*
|
|
7494
|
+
* @elementSummary The `<pc-layout-group>` element arranges its entity's children in a row or
|
|
7495
|
+
* column, with spacing, padding, alignment and fitting. Must be a child of a `<pc-entity>`,
|
|
7496
|
+
* `<pc-model>` or `<pc-node>`.
|
|
7497
|
+
*
|
|
7171
7498
|
* @category Components
|
|
7172
7499
|
*/
|
|
7173
7500
|
class LayoutGroupComponentElement extends ComponentElement {
|
|
@@ -7407,7 +7734,7 @@ class LayoutGroupComponentElement extends ComponentElement {
|
|
|
7407
7734
|
}
|
|
7408
7735
|
}
|
|
7409
7736
|
}
|
|
7410
|
-
customElements.define('pc-
|
|
7737
|
+
customElements.define('pc-layout-group', LayoutGroupComponentElement);
|
|
7411
7738
|
|
|
7412
7739
|
const shadowTypes = new Map([
|
|
7413
7740
|
['pcf1-16f', SHADOW_PCF1_16F],
|
|
@@ -7426,23 +7753,32 @@ const shadowTypes = new Map([
|
|
|
7426
7753
|
* The LightComponentElement interface also inherits the properties and methods of the
|
|
7427
7754
|
* {@link HTMLElement} interface.
|
|
7428
7755
|
*
|
|
7756
|
+
* Engine component: {@link LightComponent} (`light`).
|
|
7757
|
+
*
|
|
7758
|
+
* @elementSummary The `<pc-light>` element lights the scene from its entity — as a directional,
|
|
7759
|
+
* omni or spot light — with attributes for color, intensity, range and shadows. Must be a child of
|
|
7760
|
+
* a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
7761
|
+
*
|
|
7429
7762
|
* @category Components
|
|
7430
7763
|
*/
|
|
7431
7764
|
class LightComponentElement extends ComponentElement {
|
|
7765
|
+
_cascadeBlend = 0;
|
|
7766
|
+
_cascadeDistribution = 0.5;
|
|
7432
7767
|
_castShadows = false;
|
|
7433
7768
|
_color = new Color(1, 1, 1);
|
|
7434
7769
|
_innerConeAngle = 40;
|
|
7435
7770
|
_intensity = 1;
|
|
7436
|
-
_normalOffsetBias = 0
|
|
7771
|
+
_normalOffsetBias = 0;
|
|
7772
|
+
_numCascades = 1;
|
|
7437
7773
|
_outerConeAngle = 45;
|
|
7438
7774
|
_range = 10;
|
|
7439
|
-
_shadowBias = 0.
|
|
7440
|
-
_shadowDistance =
|
|
7775
|
+
_shadowBias = 0.05;
|
|
7776
|
+
_shadowDistance = 40;
|
|
7441
7777
|
_shadowIntensity = 1;
|
|
7442
7778
|
_shadowResolution = 1024;
|
|
7443
7779
|
_shadowType = 'pcf3-32f';
|
|
7444
7780
|
_type = 'directional';
|
|
7445
|
-
_vsmBias = 0.
|
|
7781
|
+
_vsmBias = 0.0025;
|
|
7446
7782
|
_vsmBlurSize = 11;
|
|
7447
7783
|
_penumbraSize = 1;
|
|
7448
7784
|
_penumbraFalloff = 1;
|
|
@@ -7454,11 +7790,14 @@ class LightComponentElement extends ComponentElement {
|
|
|
7454
7790
|
}
|
|
7455
7791
|
getInitialComponentData() {
|
|
7456
7792
|
return {
|
|
7793
|
+
cascadeBlend: this._cascadeBlend,
|
|
7794
|
+
cascadeDistribution: this._cascadeDistribution,
|
|
7457
7795
|
castShadows: this._castShadows,
|
|
7458
7796
|
color: this._color,
|
|
7459
7797
|
innerConeAngle: this._innerConeAngle,
|
|
7460
7798
|
intensity: this._intensity,
|
|
7461
7799
|
normalOffsetBias: this._normalOffsetBias,
|
|
7800
|
+
numCascades: this._numCascades,
|
|
7462
7801
|
outerConeAngle: this._outerConeAngle,
|
|
7463
7802
|
penumbraFalloff: this._penumbraFalloff,
|
|
7464
7803
|
penumbraSize: this._penumbraSize,
|
|
@@ -7469,7 +7808,7 @@ class LightComponentElement extends ComponentElement {
|
|
|
7469
7808
|
shadowIntensity: this._shadowIntensity,
|
|
7470
7809
|
shadowResolution: this._shadowResolution,
|
|
7471
7810
|
shadowSamples: this._shadowSamples,
|
|
7472
|
-
shadowType: shadowTypes.get(this._shadowType),
|
|
7811
|
+
shadowType: shadowTypes.get(this._shadowType) ?? SHADOW_PCF3_32F,
|
|
7473
7812
|
type: this._type,
|
|
7474
7813
|
vsmBias: this._vsmBias,
|
|
7475
7814
|
vsmBlurSize: this._vsmBlurSize
|
|
@@ -7482,6 +7821,47 @@ class LightComponentElement extends ComponentElement {
|
|
|
7482
7821
|
get component() {
|
|
7483
7822
|
return super.component;
|
|
7484
7823
|
}
|
|
7824
|
+
/**
|
|
7825
|
+
* Sets the fraction of each shadow cascade that is blended into the next one, from 0 (no
|
|
7826
|
+
* blending) to 1, which applies only to `directional` lights with `num-cascades` greater than
|
|
7827
|
+
* 1. Defaults to 0.
|
|
7828
|
+
* @param value - The cascade blend factor.
|
|
7829
|
+
*/
|
|
7830
|
+
set cascadeBlend(value) {
|
|
7831
|
+
this._cascadeBlend = value;
|
|
7832
|
+
if (this.component) {
|
|
7833
|
+
this.component.cascadeBlend = value;
|
|
7834
|
+
}
|
|
7835
|
+
}
|
|
7836
|
+
/**
|
|
7837
|
+
* Gets the cascade blend factor of the light, from 0 (no blending) to 1, which applies only to
|
|
7838
|
+
* `directional` lights with `num-cascades` greater than 1.
|
|
7839
|
+
* @returns The cascade blend factor.
|
|
7840
|
+
*/
|
|
7841
|
+
get cascadeBlend() {
|
|
7842
|
+
return this._cascadeBlend;
|
|
7843
|
+
}
|
|
7844
|
+
/**
|
|
7845
|
+
* Sets the distribution of the camera frustum split between shadow cascades, from 0 (linear
|
|
7846
|
+
* split) to 1 (logarithmic split, concentrating shadow resolution near the camera), which
|
|
7847
|
+
* applies only to `directional` lights with `num-cascades` greater than 1. Defaults to 0.5.
|
|
7848
|
+
* @param value - The cascade distribution.
|
|
7849
|
+
*/
|
|
7850
|
+
set cascadeDistribution(value) {
|
|
7851
|
+
this._cascadeDistribution = value;
|
|
7852
|
+
if (this.component) {
|
|
7853
|
+
this.component.cascadeDistribution = value;
|
|
7854
|
+
}
|
|
7855
|
+
}
|
|
7856
|
+
/**
|
|
7857
|
+
* Gets the cascade distribution of the light, from 0 (linear split) to 1 (logarithmic split,
|
|
7858
|
+
* concentrating shadow resolution near the camera), which applies only to `directional` lights
|
|
7859
|
+
* with `num-cascades` greater than 1.
|
|
7860
|
+
* @returns The cascade distribution.
|
|
7861
|
+
*/
|
|
7862
|
+
get cascadeDistribution() {
|
|
7863
|
+
return this._cascadeDistribution;
|
|
7864
|
+
}
|
|
7485
7865
|
/**
|
|
7486
7866
|
* Sets the cast shadows flag of the light.
|
|
7487
7867
|
* @param value - The cast shadows flag.
|
|
@@ -7567,6 +7947,25 @@ class LightComponentElement extends ComponentElement {
|
|
|
7567
7947
|
get normalOffsetBias() {
|
|
7568
7948
|
return this._normalOffsetBias;
|
|
7569
7949
|
}
|
|
7950
|
+
/**
|
|
7951
|
+
* Sets the number of shadow cascades of the light, an integer from 1 (no cascades) to 4, which
|
|
7952
|
+
* applies only to `directional` lights. Defaults to 1.
|
|
7953
|
+
* @param value - The number of shadow cascades.
|
|
7954
|
+
*/
|
|
7955
|
+
set numCascades(value) {
|
|
7956
|
+
this._numCascades = value;
|
|
7957
|
+
if (this.component) {
|
|
7958
|
+
this.component.numCascades = value;
|
|
7959
|
+
}
|
|
7960
|
+
}
|
|
7961
|
+
/**
|
|
7962
|
+
* Gets the number of shadow cascades of the light, an integer from 1 (no cascades) to 4, which
|
|
7963
|
+
* applies only to `directional` lights.
|
|
7964
|
+
* @returns The number of shadow cascades.
|
|
7965
|
+
*/
|
|
7966
|
+
get numCascades() {
|
|
7967
|
+
return this._numCascades;
|
|
7968
|
+
}
|
|
7570
7969
|
/**
|
|
7571
7970
|
* Sets the outer cone angle of the light.
|
|
7572
7971
|
* @param value - The outer cone angle.
|
|
@@ -7819,11 +8218,14 @@ class LightComponentElement extends ComponentElement {
|
|
|
7819
8218
|
static get observedAttributes() {
|
|
7820
8219
|
return [
|
|
7821
8220
|
...super.observedAttributes,
|
|
7822
|
-
'
|
|
8221
|
+
'cascade-blend',
|
|
8222
|
+
'cascade-distribution',
|
|
7823
8223
|
'cast-shadows',
|
|
7824
|
-
'
|
|
8224
|
+
'color',
|
|
7825
8225
|
'inner-cone-angle',
|
|
8226
|
+
'intensity',
|
|
7826
8227
|
'normal-offset-bias',
|
|
8228
|
+
'num-cascades',
|
|
7827
8229
|
'outer-cone-angle',
|
|
7828
8230
|
'penumbra-falloff',
|
|
7829
8231
|
'penumbra-size',
|
|
@@ -7843,12 +8245,18 @@ class LightComponentElement extends ComponentElement {
|
|
|
7843
8245
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
7844
8246
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
7845
8247
|
switch (name) {
|
|
7846
|
-
case '
|
|
7847
|
-
this.
|
|
8248
|
+
case 'cascade-blend':
|
|
8249
|
+
this.cascadeBlend = parseNumber(newValue, 0, name);
|
|
8250
|
+
break;
|
|
8251
|
+
case 'cascade-distribution':
|
|
8252
|
+
this.cascadeDistribution = parseNumber(newValue, 0.5, name);
|
|
7848
8253
|
break;
|
|
7849
8254
|
case 'cast-shadows':
|
|
7850
8255
|
this.castShadows = parseBool(newValue, false);
|
|
7851
8256
|
break;
|
|
8257
|
+
case 'color':
|
|
8258
|
+
this.color = parseColor(newValue, Color.WHITE, name);
|
|
8259
|
+
break;
|
|
7852
8260
|
case 'inner-cone-angle':
|
|
7853
8261
|
this.innerConeAngle = parseNumber(newValue, 40, name);
|
|
7854
8262
|
break;
|
|
@@ -7856,7 +8264,10 @@ class LightComponentElement extends ComponentElement {
|
|
|
7856
8264
|
this.intensity = parseNumber(newValue, 1, name);
|
|
7857
8265
|
break;
|
|
7858
8266
|
case 'normal-offset-bias':
|
|
7859
|
-
this.normalOffsetBias = parseNumber(newValue, 0
|
|
8267
|
+
this.normalOffsetBias = parseNumber(newValue, 0, name);
|
|
8268
|
+
break;
|
|
8269
|
+
case 'num-cascades':
|
|
8270
|
+
this.numCascades = parseNumber(newValue, 1, name);
|
|
7860
8271
|
break;
|
|
7861
8272
|
case 'outer-cone-angle':
|
|
7862
8273
|
this.outerConeAngle = parseNumber(newValue, 45, name);
|
|
@@ -7871,20 +8282,20 @@ class LightComponentElement extends ComponentElement {
|
|
|
7871
8282
|
this.range = parseNumber(newValue, 10, name);
|
|
7872
8283
|
break;
|
|
7873
8284
|
case 'shadow-bias':
|
|
7874
|
-
this.shadowBias = parseNumber(newValue, 0.
|
|
7875
|
-
break;
|
|
7876
|
-
case 'shadow-distance':
|
|
7877
|
-
this.shadowDistance = parseNumber(newValue, 16, name);
|
|
8285
|
+
this.shadowBias = parseNumber(newValue, 0.05, name);
|
|
7878
8286
|
break;
|
|
7879
8287
|
case 'shadow-blocker-samples':
|
|
7880
8288
|
this.shadowBlockerSamples = parseNumber(newValue, 16, name);
|
|
7881
8289
|
break;
|
|
7882
|
-
case 'shadow-
|
|
7883
|
-
this.
|
|
8290
|
+
case 'shadow-distance':
|
|
8291
|
+
this.shadowDistance = parseNumber(newValue, 40, name);
|
|
7884
8292
|
break;
|
|
7885
8293
|
case 'shadow-intensity':
|
|
7886
8294
|
this.shadowIntensity = parseNumber(newValue, 1, name);
|
|
7887
8295
|
break;
|
|
8296
|
+
case 'shadow-resolution':
|
|
8297
|
+
this.shadowResolution = parseNumber(newValue, 1024, name);
|
|
8298
|
+
break;
|
|
7888
8299
|
case 'shadow-samples':
|
|
7889
8300
|
this.shadowSamples = parseNumber(newValue, 16, name);
|
|
7890
8301
|
break;
|
|
@@ -7895,7 +8306,7 @@ class LightComponentElement extends ComponentElement {
|
|
|
7895
8306
|
this.type = parseEnum(newValue, ['directional', 'omni', 'spot'], 'directional', name);
|
|
7896
8307
|
break;
|
|
7897
8308
|
case 'vsm-bias':
|
|
7898
|
-
this.vsmBias = parseNumber(newValue, 0.
|
|
8309
|
+
this.vsmBias = parseNumber(newValue, 0.0025, name);
|
|
7899
8310
|
break;
|
|
7900
8311
|
case 'vsm-blur-size':
|
|
7901
8312
|
this.vsmBlurSize = parseNumber(newValue, 11, name);
|
|
@@ -7907,10 +8318,16 @@ customElements.define('pc-light', LightComponentElement);
|
|
|
7907
8318
|
|
|
7908
8319
|
/**
|
|
7909
8320
|
* The ParticleSystemComponentElement interface provides properties and methods for manipulating
|
|
7910
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
8321
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-particle-system/ | `<pc-particle-system>`} elements.
|
|
7911
8322
|
* The ParticleSystemComponentElement interface also inherits the properties and methods of the
|
|
7912
8323
|
* {@link HTMLElement} interface.
|
|
7913
8324
|
*
|
|
8325
|
+
* Engine component: {@link ParticleSystemComponent} (`particlesystem`).
|
|
8326
|
+
*
|
|
8327
|
+
* @elementSummary The `<pc-particle-system>` element emits particles from its entity, with
|
|
8328
|
+
* attributes for the emitter's shape, rate, lifetime, textures and blending. Must be a child of a
|
|
8329
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
8330
|
+
*
|
|
7914
8331
|
* @category Components
|
|
7915
8332
|
*/
|
|
7916
8333
|
class ParticleSystemComponentElement extends ComponentElement {
|
|
@@ -8029,7 +8446,7 @@ class ParticleSystemComponentElement extends ComponentElement {
|
|
|
8029
8446
|
}
|
|
8030
8447
|
}
|
|
8031
8448
|
}
|
|
8032
|
-
customElements.define('pc-
|
|
8449
|
+
customElements.define('pc-particle-system', ParticleSystemComponentElement);
|
|
8033
8450
|
|
|
8034
8451
|
const blendTypes = new Map([
|
|
8035
8452
|
['none', BLEND_NONE],
|
|
@@ -8059,6 +8476,8 @@ const occludeSpeculars = new Map([
|
|
|
8059
8476
|
['ao', SPECOCC_AO],
|
|
8060
8477
|
['gloss-dependent', SPECOCC_GLOSSDEPENDENT]
|
|
8061
8478
|
]);
|
|
8479
|
+
// The DITHER_* constants are strings whose values are exactly these names, so a parsed value is
|
|
8480
|
+
// assigned to the material unchanged rather than mapped through a table.
|
|
8062
8481
|
const opacityDithers = ['none', 'bayer8', 'bluenoise', 'ignnoise'];
|
|
8063
8482
|
const colorChannels = ['r', 'g', 'b', 'a', 'rgb'];
|
|
8064
8483
|
const scalarChannels = ['r', 'g', 'b', 'a'];
|
|
@@ -8095,6 +8514,10 @@ const roughnessAliases = ['roughness', 'roughness-map'];
|
|
|
8095
8514
|
* The two aliases are documented here rather than on an accessor, because they resolve to the
|
|
8096
8515
|
* `gloss` properties and would otherwise inherit gloss's description - which reads inverted.
|
|
8097
8516
|
*
|
|
8517
|
+
* @elementSummary The `<pc-material>` element defines a physically based material, which
|
|
8518
|
+
* `<pc-render>` elements apply by naming its `id`. It is metal/rough by default, with `metalness`
|
|
8519
|
+
* starting at 0. Must be a direct child of `<pc-app>`.
|
|
8520
|
+
*
|
|
8098
8521
|
* @attribute {number} roughness - The roughness of the material, from 0 (shiny) to 1 (rough). An
|
|
8099
8522
|
* alias for `gloss` that also inverts it, so do not combine it with the `gloss` attributes.
|
|
8100
8523
|
* @attribute {string} roughness-map - The id of the `pc-asset` to use as the roughness map. An
|
|
@@ -10261,6 +10684,13 @@ customElements.define('pc-material', MaterialElement);
|
|
|
10261
10684
|
* to `box`). It does not cover the engine's `asset` render type, since there is no way to supply
|
|
10262
10685
|
* a render asset here — use `pc-model` for glTF content instead.
|
|
10263
10686
|
*
|
|
10687
|
+
* Engine component: {@link RenderComponent} (`render`).
|
|
10688
|
+
*
|
|
10689
|
+
* @elementSummary The `<pc-render>` element renders one of the engine's built-in primitives at its
|
|
10690
|
+
* entity — box, sphere, capsule, cone, cylinder or plane — shaded by the `<pc-material>` its
|
|
10691
|
+
* `material` attribute names. For glTF content, use `<pc-model>` instead. Must be a child of a
|
|
10692
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
10693
|
+
*
|
|
10264
10694
|
* @category Components
|
|
10265
10695
|
*/
|
|
10266
10696
|
class RenderComponentElement extends ComponentElement {
|
|
@@ -10385,10 +10815,17 @@ customElements.define('pc-render', RenderComponentElement);
|
|
|
10385
10815
|
|
|
10386
10816
|
/**
|
|
10387
10817
|
* The RigidBodyComponentElement interface provides properties and methods for manipulating
|
|
10388
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
10818
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-rigid-body/ | `<pc-rigid-body>`} elements.
|
|
10389
10819
|
* The RigidBodyComponentElement interface also inherits the properties and methods of the
|
|
10390
10820
|
* {@link HTMLElement} interface.
|
|
10391
10821
|
*
|
|
10822
|
+
* Engine component: {@link RigidBodyComponent} (`rigidbody`).
|
|
10823
|
+
*
|
|
10824
|
+
* @elementSummary The `<pc-rigid-body>` element hands its entity to the physics simulation, with
|
|
10825
|
+
* attributes for its type, mass, friction and restitution. It needs a sibling `<pc-collision>` for
|
|
10826
|
+
* its shape, and `Ammo` loaded through `<pc-wasm>`. Must be a child of a `<pc-entity>`,
|
|
10827
|
+
* `<pc-model>` or `<pc-node>`.
|
|
10828
|
+
*
|
|
10392
10829
|
* @category Components
|
|
10393
10830
|
*/
|
|
10394
10831
|
class RigidBodyComponentElement extends ComponentElement {
|
|
@@ -10580,7 +11017,7 @@ class RigidBodyComponentElement extends ComponentElement {
|
|
|
10580
11017
|
}
|
|
10581
11018
|
}
|
|
10582
11019
|
}
|
|
10583
|
-
customElements.define('pc-
|
|
11020
|
+
customElements.define('pc-rigid-body', RigidBodyComponentElement);
|
|
10584
11021
|
|
|
10585
11022
|
// The engine's SCALEMODE_* constants are the strings 'none' and 'blend', so this map happens to be
|
|
10586
11023
|
// an identity. It is still the right shape: it supplies parseEnum's valid-name list, it is what the
|
|
@@ -10596,6 +11033,12 @@ const scaleModes = new Map([
|
|
|
10596
11033
|
* The ScreenComponentElement interface also inherits the properties and methods of the
|
|
10597
11034
|
* {@link HTMLElement} interface.
|
|
10598
11035
|
*
|
|
11036
|
+
* Engine component: {@link ScreenComponent} (`screen`).
|
|
11037
|
+
*
|
|
11038
|
+
* @elementSummary The `<pc-screen>` element gives its entity a 2D space — in screen space or in the
|
|
11039
|
+
* world — that a hierarchy of `<pc-element>` descendants lays out inside. Must be a child of a
|
|
11040
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
11041
|
+
*
|
|
10599
11042
|
* @category Components
|
|
10600
11043
|
*/
|
|
10601
11044
|
class ScreenComponentElement extends ComponentElement {
|
|
@@ -10748,6 +11191,12 @@ const orientations = new Map([
|
|
|
10748
11191
|
* The ScrollbarComponentElement interface also inherits the properties and methods of the
|
|
10749
11192
|
* {@link HTMLElement} interface.
|
|
10750
11193
|
*
|
|
11194
|
+
* Engine component: {@link ScrollbarComponent} (`scrollbar`).
|
|
11195
|
+
*
|
|
11196
|
+
* @elementSummary The `<pc-scrollbar>` element gives its entity a draggable handle reporting a
|
|
11197
|
+
* position from 0 to 1, which a `<pc-scroll-view>` references to scroll its content. Must be a
|
|
11198
|
+
* child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
11199
|
+
*
|
|
10751
11200
|
* @category Components
|
|
10752
11201
|
*/
|
|
10753
11202
|
class ScrollbarComponentElement extends ComponentElement {
|
|
@@ -10883,10 +11332,16 @@ const visibilities = new Map([
|
|
|
10883
11332
|
]);
|
|
10884
11333
|
/**
|
|
10885
11334
|
* The ScrollViewComponentElement interface provides properties and methods for manipulating
|
|
10886
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
11335
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-scroll-view/ | `<pc-scroll-view>`} elements.
|
|
10887
11336
|
* The ScrollViewComponentElement interface also inherits the properties and methods of the
|
|
10888
11337
|
* {@link HTMLElement} interface.
|
|
10889
11338
|
*
|
|
11339
|
+
* Engine component: {@link ScrollViewComponent} (`scrollview`).
|
|
11340
|
+
*
|
|
11341
|
+
* @elementSummary The `<pc-scroll-view>` element scrolls a larger content entity within a clipped
|
|
11342
|
+
* viewport at its entity, optionally driven by the `<pc-scrollbar>` elements it references. Must be
|
|
11343
|
+
* a child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
11344
|
+
*
|
|
10890
11345
|
* @category Components
|
|
10891
11346
|
*/
|
|
10892
11347
|
class ScrollViewComponentElement extends ComponentElement {
|
|
@@ -11245,11 +11700,11 @@ class ScrollViewComponentElement extends ComponentElement {
|
|
|
11245
11700
|
}
|
|
11246
11701
|
}
|
|
11247
11702
|
}
|
|
11248
|
-
customElements.define('pc-
|
|
11703
|
+
customElements.define('pc-scroll-view', ScrollViewComponentElement);
|
|
11249
11704
|
|
|
11250
11705
|
/**
|
|
11251
|
-
* The
|
|
11252
|
-
* `<pc-script>` elements. The
|
|
11706
|
+
* The ScriptInstanceElement interface provides properties and methods for manipulating
|
|
11707
|
+
* `<pc-script-instance>` elements. The ScriptInstanceElement interface also inherits the properties and
|
|
11253
11708
|
* methods of the {@link AsyncElement} interface.
|
|
11254
11709
|
*
|
|
11255
11710
|
* Script attributes can be supplied through two channels:
|
|
@@ -11271,7 +11726,11 @@ customElements.define('pc-scrollview', ScrollViewComponentElement);
|
|
|
11271
11726
|
* new-name one, re-applying both attribute channels to it.
|
|
11272
11727
|
*
|
|
11273
11728
|
* The element becomes ready once its script instance has been created by the parent
|
|
11274
|
-
* `<pc-
|
|
11729
|
+
* `<pc-script>` element.
|
|
11730
|
+
*
|
|
11731
|
+
* @elementSummary The `<pc-script-instance>` element attaches one script class, named by `name`, to
|
|
11732
|
+
* the entity of its parent `<pc-script>`. Its other attributes set script attributes of the same
|
|
11733
|
+
* name, and `attributes` takes a JSON object instead. Must be a direct child of `<pc-script>`.
|
|
11275
11734
|
*
|
|
11276
11735
|
* @fires {CustomEvent} scriptattributeschange - Fired when the script's attributes change. The
|
|
11277
11736
|
* `detail` carries the new `attributes` object. Bubbles.
|
|
@@ -11280,11 +11739,11 @@ customElements.define('pc-scrollview', ScrollViewComponentElement);
|
|
|
11280
11739
|
* @fires {CustomEvent} scriptnamechange - Fired when the script is renamed on a live element. The
|
|
11281
11740
|
* `detail` carries `oldName` and `newName`. Bubbles.
|
|
11282
11741
|
*/
|
|
11283
|
-
class
|
|
11742
|
+
class ScriptInstanceElement extends AsyncElement {
|
|
11284
11743
|
_attributes = {};
|
|
11285
11744
|
_enabled = true;
|
|
11286
11745
|
/**
|
|
11287
|
-
* The Script instance created for this element by its parent `<pc-
|
|
11746
|
+
* The Script instance created for this element by its parent `<pc-script>` element.
|
|
11288
11747
|
* @internal
|
|
11289
11748
|
*/
|
|
11290
11749
|
_script = null;
|
|
@@ -11330,11 +11789,11 @@ class ScriptElement extends AsyncElement {
|
|
|
11330
11789
|
}
|
|
11331
11790
|
/**
|
|
11332
11791
|
* Sets the name of the script to create. The `name` attribute is the single source of truth
|
|
11333
|
-
* (it is what the parent `<pc-
|
|
11792
|
+
* (it is what the parent `<pc-script>` element reads when creating the instance), so the
|
|
11334
11793
|
* property writes through to it — assigning before insertion works as expected:
|
|
11335
11794
|
*
|
|
11336
11795
|
* ```js
|
|
11337
|
-
* const script = document.createElement('pc-script');
|
|
11796
|
+
* const script = document.createElement('pc-script-instance');
|
|
11338
11797
|
* script.name = 'rotate';
|
|
11339
11798
|
* scriptsElement.appendChild(script);
|
|
11340
11799
|
* await script.ready();
|
|
@@ -11361,10 +11820,10 @@ class ScriptElement extends AsyncElement {
|
|
|
11361
11820
|
return this._script;
|
|
11362
11821
|
}
|
|
11363
11822
|
connectedCallback() {
|
|
11364
|
-
// Script instances are created by the parent pc-
|
|
11823
|
+
// Script instances are created by the parent pc-script element, so an element placed
|
|
11365
11824
|
// anywhere else is inert and never becomes ready - warn rather than hang silently
|
|
11366
|
-
if (this.parentElement?.tagName !== 'PC-
|
|
11367
|
-
console.warn(`pc-script '${this.getAttribute('name')}' must be a direct child of pc-
|
|
11825
|
+
if (this.parentElement?.tagName !== 'PC-SCRIPT') {
|
|
11826
|
+
console.warn(`pc-script-instance '${this.getAttribute('name')}' must be a direct child of pc-script - script not created`);
|
|
11368
11827
|
}
|
|
11369
11828
|
}
|
|
11370
11829
|
disconnectedCallback() {
|
|
@@ -11375,7 +11834,7 @@ class ScriptElement extends AsyncElement {
|
|
|
11375
11834
|
this._resetReady();
|
|
11376
11835
|
}
|
|
11377
11836
|
/**
|
|
11378
|
-
* Called by the parent `<pc-
|
|
11837
|
+
* Called by the parent `<pc-script>` element when the script instance has been created.
|
|
11379
11838
|
* Creation can happen more than once per connection (a runtime `name` change recreates the
|
|
11380
11839
|
* instance), but `_onReady` signals readiness at most once per cycle.
|
|
11381
11840
|
* @internal
|
|
@@ -11397,7 +11856,7 @@ class ScriptElement extends AsyncElement {
|
|
|
11397
11856
|
this.scriptAttributes = JSON.parse(newValue);
|
|
11398
11857
|
}
|
|
11399
11858
|
catch (error) {
|
|
11400
|
-
console.warn(`Invalid 'attributes' JSON on pc-script '${this.getAttribute('name')}': ${error.message}`);
|
|
11859
|
+
console.warn(`Invalid 'attributes' JSON on pc-script-instance '${this.getAttribute('name')}': ${error.message}`);
|
|
11401
11860
|
}
|
|
11402
11861
|
break;
|
|
11403
11862
|
case 'enabled':
|
|
@@ -11417,14 +11876,14 @@ class ScriptElement extends AsyncElement {
|
|
|
11417
11876
|
}
|
|
11418
11877
|
}
|
|
11419
11878
|
}
|
|
11420
|
-
customElements.define('pc-script',
|
|
11879
|
+
customElements.define('pc-script-instance', ScriptInstanceElement);
|
|
11421
11880
|
|
|
11422
11881
|
/**
|
|
11423
|
-
* Attributes on `pc-script` that never map to script attributes: the element's own API (derived
|
|
11882
|
+
* Attributes on `pc-script-instance` that never map to script attributes: the element's own API (derived
|
|
11424
11883
|
* from its observed attributes) plus reserved and global HTML attribute names.
|
|
11425
11884
|
*/
|
|
11426
11885
|
const RESERVED_ATTRIBUTES = new Set([
|
|
11427
|
-
...
|
|
11886
|
+
...ScriptInstanceElement.observedAttributes,
|
|
11428
11887
|
'accesskey',
|
|
11429
11888
|
'autocapitalize',
|
|
11430
11889
|
'autofocus',
|
|
@@ -11455,7 +11914,7 @@ const RESERVED_ATTRIBUTES = new Set([
|
|
|
11455
11914
|
'translate'
|
|
11456
11915
|
]);
|
|
11457
11916
|
/**
|
|
11458
|
-
* Checks whether a `pc-script` attribute name is reserved (and so never maps to a script
|
|
11917
|
+
* Checks whether a `pc-script-instance` attribute name is reserved (and so never maps to a script
|
|
11459
11918
|
* attribute). Reserved names are the element's own API, global HTML attribute names, `data-*`
|
|
11460
11919
|
* and `aria-*` attributes, names starting with `_` (framework-stamped attributes), and real
|
|
11461
11920
|
* inline event handler names (`onclick` etc. — detected via the platform, so script attributes
|
|
@@ -11611,10 +12070,15 @@ const findCaseMatch = (script, key) => {
|
|
|
11611
12070
|
};
|
|
11612
12071
|
/**
|
|
11613
12072
|
* The ScriptComponentElement interface provides properties and methods for manipulating
|
|
11614
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
12073
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-script/ | `<pc-script>`} elements.
|
|
11615
12074
|
* The ScriptComponentElement interface also inherits the properties and methods of the
|
|
11616
12075
|
* {@link HTMLElement} interface.
|
|
11617
12076
|
*
|
|
12077
|
+
* Engine component: {@link ScriptComponent} (`script`).
|
|
12078
|
+
*
|
|
12079
|
+
* @elementSummary The `<pc-script>` element holds the `<pc-script-instance>` children that attach
|
|
12080
|
+
* scripts to its entity. Must be a child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
12081
|
+
*
|
|
11618
12082
|
* @category Components
|
|
11619
12083
|
*/
|
|
11620
12084
|
class ScriptComponentElement extends ComponentElement {
|
|
@@ -11631,14 +12095,23 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
11631
12095
|
}
|
|
11632
12096
|
connectedCallback() {
|
|
11633
12097
|
// (Re-)observe on every connection - disconnectedCallback disconnects the observer.
|
|
11634
|
-
// Attribute changes on child pc-script elements are watched here too: per-property
|
|
12098
|
+
// Attribute changes on child pc-script-instance elements are watched here too: per-property
|
|
11635
12099
|
// script attributes are not statically known, so they cannot use observedAttributes.
|
|
11636
12100
|
this.observer.observe(this, { childList: true, subtree: true, attributes: true });
|
|
11637
12101
|
return super.connectedCallback();
|
|
11638
12102
|
}
|
|
11639
12103
|
initComponent() {
|
|
11640
|
-
|
|
11641
|
-
|
|
12104
|
+
this.querySelectorAll(':scope > pc-script-instance').forEach((scriptElement) => {
|
|
12105
|
+
// A host readiness cycle re-runs this against a component that can have survived it
|
|
12106
|
+
// (a pc-model reloading content on its stable host entity). The engine rejects a
|
|
12107
|
+
// duplicate create - returning null, silently in production builds - which would
|
|
12108
|
+
// skip attribute application entirely. A surviving instance is re-asserted instead,
|
|
12109
|
+
// so both cycle outcomes leave the component reflecting the element's declared state.
|
|
12110
|
+
const script = this.scriptFor(scriptElement);
|
|
12111
|
+
if (script) {
|
|
12112
|
+
this.applyDeclaredState(script, scriptElement);
|
|
12113
|
+
return;
|
|
12114
|
+
}
|
|
11642
12115
|
this.createScript(scriptElement);
|
|
11643
12116
|
});
|
|
11644
12117
|
}
|
|
@@ -11772,9 +12245,9 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
11772
12245
|
this.mergeDeep(script, converted);
|
|
11773
12246
|
}
|
|
11774
12247
|
/**
|
|
11775
|
-
* Returns the camelCase keys of the per-property attributes present on a `pc-script`
|
|
12248
|
+
* Returns the camelCase keys of the per-property attributes present on a `pc-script-instance`
|
|
11776
12249
|
* element.
|
|
11777
|
-
* @param scriptElement - The `pc-script` element.
|
|
12250
|
+
* @param scriptElement - The `pc-script-instance` element.
|
|
11778
12251
|
* @returns The camelCase keys.
|
|
11779
12252
|
*/
|
|
11780
12253
|
inlineKeys(scriptElement) {
|
|
@@ -11787,10 +12260,10 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
11787
12260
|
return keys;
|
|
11788
12261
|
}
|
|
11789
12262
|
/**
|
|
11790
|
-
* Resolves the script instance owned by a `pc-script` element. Returns `null` when the
|
|
12263
|
+
* Resolves the script instance owned by a `pc-script-instance` element. Returns `null` when the
|
|
11791
12264
|
* element has no created script, or when its name resolves to a script created by a
|
|
11792
12265
|
* different element (e.g. a duplicate-named sibling).
|
|
11793
|
-
* @param scriptElement - The `pc-script` element.
|
|
12266
|
+
* @param scriptElement - The `pc-script-instance` element.
|
|
11794
12267
|
* @returns The owned script, or `null`.
|
|
11795
12268
|
*/
|
|
11796
12269
|
scriptFor(scriptElement) {
|
|
@@ -11819,7 +12292,7 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
11819
12292
|
}
|
|
11820
12293
|
}
|
|
11821
12294
|
/**
|
|
11822
|
-
* Handles a runtime `name` change on a child `pc-script`, swapping the engine script instance
|
|
12295
|
+
* Handles a runtime `name` change on a child `pc-script-instance`, swapping the engine script instance
|
|
11823
12296
|
* to match. Without this the element would keep pointing at the old-name instance: the old
|
|
11824
12297
|
* script would go on running while every subsequent update (attribute changes, enable
|
|
11825
12298
|
* changes, destruction on removal) resolved the new name and silently no-opped.
|
|
@@ -11830,8 +12303,8 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
11830
12303
|
*/
|
|
11831
12304
|
handleScriptNameChange(event) {
|
|
11832
12305
|
const scriptElement = event.target;
|
|
11833
|
-
// Only direct children are managed, matching initComponent's ':scope > pc-script'
|
|
11834
|
-
// contract - the event bubbles, so a deeper pc-script must not be created here
|
|
12306
|
+
// Only direct children are managed, matching initComponent's ':scope > pc-script-instance'
|
|
12307
|
+
// contract - the event bubbles, so a deeper pc-script-instance must not be created here
|
|
11835
12308
|
if (scriptElement.parentElement !== this)
|
|
11836
12309
|
return;
|
|
11837
12310
|
// Before the component exists there is nothing to swap: initComponent creates from
|
|
@@ -11848,11 +12321,11 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
11848
12321
|
this.createScript(scriptElement);
|
|
11849
12322
|
}
|
|
11850
12323
|
/**
|
|
11851
|
-
* Creates the script instance for a `pc-script` element. The instance is created disabled,
|
|
12324
|
+
* Creates the script instance for a `pc-script-instance` element. The instance is created disabled,
|
|
11852
12325
|
* the element's converted attributes are merged over the instance's defaults (which is what
|
|
11853
12326
|
* allows plain numeric arrays to be typed against those defaults), and only then is the
|
|
11854
12327
|
* declared enabled state applied — so `initialize()` runs with every attribute in place.
|
|
11855
|
-
* @param scriptElement - The `pc-script` element to create the script instance for.
|
|
12328
|
+
* @param scriptElement - The `pc-script-instance` element to create the script instance for.
|
|
11856
12329
|
* @returns The created script, or `null`.
|
|
11857
12330
|
*/
|
|
11858
12331
|
createScript(scriptElement) {
|
|
@@ -11863,21 +12336,30 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
11863
12336
|
if (!script)
|
|
11864
12337
|
return null;
|
|
11865
12338
|
scriptElement._script = script;
|
|
11866
|
-
|
|
11867
|
-
|
|
12339
|
+
this.applyDeclaredState(script, scriptElement);
|
|
12340
|
+
scriptElement._onScriptCreated();
|
|
12341
|
+
return script;
|
|
12342
|
+
}
|
|
12343
|
+
/**
|
|
12344
|
+
* Applies a `pc-script-instance` element's declared state to a script instance: the `attributes` JSON
|
|
12345
|
+
* first with per-property-shadowed keys stripped, then the per-property attributes — each
|
|
12346
|
+
* property is written exactly once and individual attributes win — and finally the declared
|
|
12347
|
+
* enabled state, so `initialize()` runs with every attribute in place.
|
|
12348
|
+
* @param script - The script instance.
|
|
12349
|
+
* @param scriptElement - The `pc-script-instance` element holding the declared state.
|
|
12350
|
+
*/
|
|
12351
|
+
applyDeclaredState(script, scriptElement) {
|
|
11868
12352
|
this.applyAttributes(script, scriptElement.scriptAttributes, this.inlineKeys(scriptElement));
|
|
11869
12353
|
this.applyInlineAttributes(script, scriptElement);
|
|
11870
12354
|
script.enabled = scriptElement.enabled;
|
|
11871
|
-
scriptElement._onScriptCreated();
|
|
11872
|
-
return script;
|
|
11873
12355
|
}
|
|
11874
12356
|
/**
|
|
11875
|
-
* Applies the per-property attributes present on a `pc-script` element — any attribute that
|
|
12357
|
+
* Applies the per-property attributes present on a `pc-script-instance` element — any attribute that
|
|
11876
12358
|
* is not part of the element's own API or a reserved HTML attribute name. These are applied
|
|
11877
12359
|
* after the `attributes` JSON, so an individual attribute always takes precedence over the
|
|
11878
12360
|
* blob.
|
|
11879
12361
|
* @param script - The script to apply the attributes to.
|
|
11880
|
-
* @param scriptElement - The `pc-script` element holding the attributes.
|
|
12362
|
+
* @param scriptElement - The `pc-script-instance` element holding the attributes.
|
|
11881
12363
|
*/
|
|
11882
12364
|
applyInlineAttributes(script, scriptElement) {
|
|
11883
12365
|
const scriptName = scriptElement.getAttribute('name') ?? '';
|
|
@@ -11888,10 +12370,10 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
11888
12370
|
}
|
|
11889
12371
|
}
|
|
11890
12372
|
/**
|
|
11891
|
-
* Applies a single per-property attribute change to the script of a `pc-script` element.
|
|
12373
|
+
* Applies a single per-property attribute change to the script of a `pc-script-instance` element.
|
|
11892
12374
|
* When the attribute has been removed, the value from the `attributes` JSON (if any) takes
|
|
11893
12375
|
* effect again.
|
|
11894
|
-
* @param scriptElement - The `pc-script` element whose attribute changed.
|
|
12376
|
+
* @param scriptElement - The `pc-script-instance` element whose attribute changed.
|
|
11895
12377
|
* @param attributeName - The name of the changed attribute.
|
|
11896
12378
|
*/
|
|
11897
12379
|
applyScriptProperty(scriptElement, attributeName) {
|
|
@@ -11927,7 +12409,7 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
11927
12409
|
try {
|
|
11928
12410
|
const current = script[key];
|
|
11929
12411
|
if (typeof current === 'function' || SCRIPT_API_MEMBERS.has(key)) {
|
|
11930
|
-
console.warn(`Ignoring attribute '${attributeName}' on pc-script '${scriptName}' - '${key}' is part of the Script API.`);
|
|
12412
|
+
console.warn(`Ignoring attribute '${attributeName}' on pc-script-instance '${scriptName}' - '${key}' is part of the Script API.`);
|
|
11931
12413
|
return;
|
|
11932
12414
|
}
|
|
11933
12415
|
if (typeof current === 'string') {
|
|
@@ -11983,10 +12465,10 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
11983
12465
|
}
|
|
11984
12466
|
handleMutations(mutations) {
|
|
11985
12467
|
for (const mutation of mutations) {
|
|
11986
|
-
// Handle per-property attribute changes on child pc-script elements
|
|
12468
|
+
// Handle per-property attribute changes on child pc-script-instance elements
|
|
11987
12469
|
if (mutation.type === 'attributes') {
|
|
11988
12470
|
const target = mutation.target;
|
|
11989
|
-
if (target instanceof
|
|
12471
|
+
if (target instanceof ScriptInstanceElement &&
|
|
11990
12472
|
target.parentElement === this &&
|
|
11991
12473
|
mutation.attributeName &&
|
|
11992
12474
|
!isReservedAttribute(mutation.attributeName)) {
|
|
@@ -11996,16 +12478,16 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
11996
12478
|
}
|
|
11997
12479
|
// Only direct children are managed - the observer watches the subtree for attribute
|
|
11998
12480
|
// changes, but deeper childList records must not create or destroy scripts
|
|
11999
|
-
// (matching initComponent's ':scope > pc-script' contract)
|
|
12481
|
+
// (matching initComponent's ':scope > pc-script-instance' contract)
|
|
12000
12482
|
if (mutation.target !== this) {
|
|
12001
12483
|
continue;
|
|
12002
12484
|
}
|
|
12003
|
-
// Handle removed nodes first, so that replacing a pc-script with a same-named one
|
|
12485
|
+
// Handle removed nodes first, so that replacing a pc-script-instance with a same-named one
|
|
12004
12486
|
// destroys the old script before the replacement is created. Only destroy a script
|
|
12005
12487
|
// this element actually owns - a duplicate-named element whose own create() failed
|
|
12006
12488
|
// must not take down the live script on removal.
|
|
12007
12489
|
mutation.removedNodes.forEach((node) => {
|
|
12008
|
-
if (node instanceof
|
|
12490
|
+
if (node instanceof ScriptInstanceElement) {
|
|
12009
12491
|
const scriptName = node.getAttribute('name');
|
|
12010
12492
|
if (scriptName &&
|
|
12011
12493
|
node._script &&
|
|
@@ -12018,7 +12500,7 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
12018
12500
|
});
|
|
12019
12501
|
// Handle added nodes
|
|
12020
12502
|
mutation.addedNodes.forEach((node) => {
|
|
12021
|
-
if (node instanceof
|
|
12503
|
+
if (node instanceof ScriptInstanceElement) {
|
|
12022
12504
|
this.createScript(node);
|
|
12023
12505
|
}
|
|
12024
12506
|
});
|
|
@@ -12036,14 +12518,20 @@ class ScriptComponentElement extends ComponentElement {
|
|
|
12036
12518
|
return super.component;
|
|
12037
12519
|
}
|
|
12038
12520
|
}
|
|
12039
|
-
customElements.define('pc-
|
|
12521
|
+
customElements.define('pc-script', ScriptComponentElement);
|
|
12040
12522
|
|
|
12041
12523
|
/**
|
|
12042
12524
|
* The SoundComponentElement interface provides properties and methods for manipulating
|
|
12043
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
12525
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-sound/ | `<pc-sound>`} elements.
|
|
12044
12526
|
* The SoundComponentElement interface also inherits the properties and methods of the
|
|
12045
12527
|
* {@link HTMLElement} interface.
|
|
12046
12528
|
*
|
|
12529
|
+
* Engine component: {@link SoundComponent} (`sound`).
|
|
12530
|
+
*
|
|
12531
|
+
* @elementSummary The `<pc-sound>` element holds the `<pc-sound-slot>` children that play sounds at
|
|
12532
|
+
* its entity, along with the positional audio settings they share. Must be a child of a
|
|
12533
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
12534
|
+
*
|
|
12047
12535
|
* @category Components
|
|
12048
12536
|
*/
|
|
12049
12537
|
class SoundComponentElement extends ComponentElement {
|
|
@@ -12234,12 +12722,15 @@ class SoundComponentElement extends ComponentElement {
|
|
|
12234
12722
|
}
|
|
12235
12723
|
}
|
|
12236
12724
|
}
|
|
12237
|
-
customElements.define('pc-
|
|
12725
|
+
customElements.define('pc-sound', SoundComponentElement);
|
|
12238
12726
|
|
|
12239
12727
|
/**
|
|
12240
12728
|
* The SoundSlotElement interface provides properties and methods for manipulating
|
|
12241
|
-
* `<pc-sound>` elements. The SoundSlotElement interface also inherits the properties and
|
|
12729
|
+
* `<pc-sound-slot>` elements. The SoundSlotElement interface also inherits the properties and
|
|
12242
12730
|
* methods of the {@link AsyncElement} interface.
|
|
12731
|
+
*
|
|
12732
|
+
* @elementSummary The `<pc-sound-slot>` element declares one named sound on its parent `<pc-sound>`
|
|
12733
|
+
* — its asset, volume, pitch, looping and autoplay. Must be a direct child of `<pc-sound>`.
|
|
12243
12734
|
*/
|
|
12244
12735
|
class SoundSlotElement extends AsyncElement {
|
|
12245
12736
|
_asset = '';
|
|
@@ -12252,7 +12743,7 @@ class SoundSlotElement extends AsyncElement {
|
|
|
12252
12743
|
_startTime = 0;
|
|
12253
12744
|
_volume = 1;
|
|
12254
12745
|
/**
|
|
12255
|
-
* The `<pc-
|
|
12746
|
+
* The `<pc-sound>` this slot was added to, captured at connect time.
|
|
12256
12747
|
*
|
|
12257
12748
|
* `disconnectedCallback` cannot rediscover it: by the time the element is disconnected its
|
|
12258
12749
|
* `parentElement` is already `null`, so a lookup would both fail to find the component and
|
|
@@ -12315,7 +12806,7 @@ class SoundSlotElement extends AsyncElement {
|
|
|
12315
12806
|
get soundElement() {
|
|
12316
12807
|
const soundElement = this.parentElement;
|
|
12317
12808
|
if (!(soundElement instanceof SoundComponentElement)) {
|
|
12318
|
-
console.warn('pc-sound must be a direct child of a pc-
|
|
12809
|
+
console.warn('pc-sound-slot must be a direct child of a pc-sound element');
|
|
12319
12810
|
return null;
|
|
12320
12811
|
}
|
|
12321
12812
|
return soundElement;
|
|
@@ -12511,7 +13002,7 @@ class SoundSlotElement extends AsyncElement {
|
|
|
12511
13002
|
}
|
|
12512
13003
|
}
|
|
12513
13004
|
}
|
|
12514
|
-
customElements.define('pc-sound', SoundSlotElement);
|
|
13005
|
+
customElements.define('pc-sound-slot', SoundSlotElement);
|
|
12515
13006
|
|
|
12516
13007
|
/**
|
|
12517
13008
|
* The GSplatComponentElement interface provides properties and methods for manipulating
|
|
@@ -12519,6 +13010,12 @@ customElements.define('pc-sound', SoundSlotElement);
|
|
|
12519
13010
|
* The GSplatComponentElement interface also inherits the properties and methods of the
|
|
12520
13011
|
* {@link HTMLElement} interface.
|
|
12521
13012
|
*
|
|
13013
|
+
* Engine component: {@link GSplatComponent} (`gsplat`).
|
|
13014
|
+
*
|
|
13015
|
+
* @elementSummary The `<pc-gsplat>` element renders the 3D Gaussian splats of a `gsplat` asset at
|
|
13016
|
+
* its entity, with attributes for shadow casting and level of detail. Must be a child of a
|
|
13017
|
+
* `<pc-entity>`, `<pc-model>` or `<pc-node>`.
|
|
13018
|
+
*
|
|
12522
13019
|
* @category Components
|
|
12523
13020
|
*/
|
|
12524
13021
|
class GSplatComponentElement extends ComponentElement {
|
|
@@ -12814,6 +13311,11 @@ const levenshtein = (a, b) => {
|
|
|
12814
13311
|
* The pointer events below are dispatched by the containing `<pc-app>` element when the pointer
|
|
12815
13312
|
* intersects the bound node's geometry, exactly as for `<pc-entity>`.
|
|
12816
13313
|
*
|
|
13314
|
+
* @elementSummary The `<pc-node>` element binds to a node inside the hierarchy a `<pc-model>`
|
|
13315
|
+
* instantiated and declares overrides against it: a transform, an enabled state, tags, components
|
|
13316
|
+
* to add, or content to attach. Its `name` is a lookup, never a rename. Must be a descendant of
|
|
13317
|
+
* `<pc-model>`.
|
|
13318
|
+
*
|
|
12817
13319
|
* @attribute {string} name - The name of the node to bind, resolved within the nearest ancestor
|
|
12818
13320
|
* `pc-model` (or `pc-node`) once it has instantiated.
|
|
12819
13321
|
* @attribute {number} index - Which match to bind when `name` matches more than one node,
|
|
@@ -12940,7 +13442,10 @@ class NodeElement extends EntityBaseElement {
|
|
|
12940
13442
|
* is retained untouched — a redundant edit must not flicker overrides through a revert.
|
|
12941
13443
|
*/
|
|
12942
13444
|
_rebind() {
|
|
12943
|
-
|
|
13445
|
+
// A model fronts a host entity of its own; the names this element resolves are the
|
|
13446
|
+
// asset's, so the search starts at the instantiated content root, not the wrapper.
|
|
13447
|
+
const host = this._host;
|
|
13448
|
+
const hostEntity = (host instanceof ModelElement ? host.contentEntity : host?.entity) ?? null;
|
|
12944
13449
|
if (!hostEntity || !this._name) {
|
|
12945
13450
|
// Host not instantiated (or nothing to look up yet): return to pending. An assigned
|
|
12946
13451
|
// name arriving later, or the host's next cycle, resolves it.
|
|
@@ -13037,8 +13542,9 @@ class NodeElement extends EntityBaseElement {
|
|
|
13037
13542
|
}
|
|
13038
13543
|
this._revertOverrides();
|
|
13039
13544
|
// Attachment points anchor to the bound node, so they cannot outlive the binding. Each
|
|
13040
|
-
// destroyed entity resets its element, which the next _buildChildren re-creates
|
|
13041
|
-
|
|
13545
|
+
// destroyed entity resets its element, which the next _buildChildren re-creates - a
|
|
13546
|
+
// model host among them re-instantiates its content when it rebuilds.
|
|
13547
|
+
this.querySelectorAll('pc-entity, pc-model').forEach((child) => {
|
|
13042
13548
|
if (child.closestEntity === this) {
|
|
13043
13549
|
child.entity?.destroy();
|
|
13044
13550
|
}
|
|
@@ -13550,6 +14056,9 @@ customElements.define('pc-node', NodeElement);
|
|
|
13550
14056
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-scene/ | `<pc-scene>`} elements.
|
|
13551
14057
|
* The SceneElement interface also inherits the properties and methods of the
|
|
13552
14058
|
* {@link HTMLElement} interface.
|
|
14059
|
+
*
|
|
14060
|
+
* @elementSummary The `<pc-scene>` element holds the entity hierarchy the application renders,
|
|
14061
|
+
* along with the scene-wide fog and gravity settings. Must be a direct child of `<pc-app>`.
|
|
13553
14062
|
*/
|
|
13554
14063
|
class SceneElement extends AsyncElement {
|
|
13555
14064
|
/**
|
|
@@ -13773,6 +14282,10 @@ customElements.define('pc-scene', SceneElement);
|
|
|
13773
14282
|
* The SkyElement interface provides properties and methods for manipulating
|
|
13774
14283
|
* `<pc-sky>` elements. The SkyElement interface also inherits the properties and
|
|
13775
14284
|
* methods of the {@link HTMLElement} interface.
|
|
14285
|
+
*
|
|
14286
|
+
* @elementSummary The `<pc-sky>` element renders a skybox from a texture asset, projected as an
|
|
14287
|
+
* infinite background, a box or a dome, and optionally lights the scene from it. Must be a direct
|
|
14288
|
+
* child of `<pc-scene>`.
|
|
13776
14289
|
*/
|
|
13777
14290
|
class SkyElement extends AsyncElement {
|
|
13778
14291
|
_asset = '';
|
|
@@ -14064,5 +14577,5 @@ class SkyElement extends AsyncElement {
|
|
|
14064
14577
|
}
|
|
14065
14578
|
customElements.define('pc-sky', SkyElement);
|
|
14066
14579
|
|
|
14067
|
-
export { AnimClipElement, AnimComponentElement, AppElement, AssetElement, AsyncElement, ButtonComponentElement, CameraComponentElement, CollisionComponentElement, ComponentElement, ElementComponentElement, EntityBaseElement, EntityElement, GSplatComponentElement, JointComponentElement, LayoutChildComponentElement, LayoutGroupComponentElement, LightComponentElement,
|
|
14580
|
+
export { AnimClipElement, AnimComponentElement, AppElement, AssetElement, AsyncElement, AudioListenerComponentElement, ButtonComponentElement, CameraComponentElement, CollisionComponentElement, ComponentElement, ElementComponentElement, EntityBaseElement, EntityElement, EntityOwnerElement, GSplatComponentElement, JointComponentElement, LayoutChildComponentElement, LayoutGroupComponentElement, LightComponentElement, MaterialElement, ModelElement, NodeElement, ParticleSystemComponentElement, RenderComponentElement, RigidBodyComponentElement, SceneElement, ScreenComponentElement, ScriptComponentElement, ScriptInstanceElement, ScrollViewComponentElement, ScrollbarComponentElement, SkyElement, SoundComponentElement, SoundSlotElement, WasmElement, whenReady };
|
|
14068
14581
|
//# sourceMappingURL=pwc.mjs.map
|