@playcanvas/web-components 0.10.0 → 0.10.1
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/dist/app.d.ts +52 -7
- package/dist/asset.d.ts +9 -0
- package/dist/async-element.d.ts +12 -2
- package/dist/components/component.d.ts +5 -4
- package/dist/custom-elements.json +583 -110
- package/dist/entity.d.ts +5 -4
- package/dist/loading-bar.d.ts +35 -0
- package/dist/material.d.ts +8 -2
- package/dist/pwc.cjs +385 -105
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +385 -105
- 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 +385 -105
- package/dist/pwc.mjs.map +1 -1
- package/dist/scene.d.ts +11 -3
- package/dist/vscode.html-custom-data.json +8 -3
- package/dist/web-types.json +322 -78
- package/package.json +1 -1
- package/src/app.ts +172 -73
- package/src/asset.ts +25 -0
- package/src/async-element.ts +14 -4
- package/src/components/component.ts +6 -5
- package/src/entity.ts +34 -18
- package/src/loading-bar.ts +122 -0
- package/src/material.ts +10 -4
- package/src/scene.ts +49 -19
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/** Covers the 0.2s opacity transition; jsdom never fires transitionend, so removal is timed. */
|
|
2
|
+
const REMOVAL_DELAY_MS = 250;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The slim progress bar `<pc-app>` shows while it boots and preloads. An implementation detail of
|
|
6
|
+
* AppElement rather than a custom element, so its shape can change without a breaking change.
|
|
7
|
+
*
|
|
8
|
+
* All styling is inline, so the library injects no stylesheet. The colors and height resolve CSS
|
|
9
|
+
* custom properties — `--pc-loading-bar-color`, `--pc-loading-bar-background` and
|
|
10
|
+
* `--pc-loading-bar-height` — so a page can theme the bar from `pc-app` or `:root`.
|
|
11
|
+
*/
|
|
12
|
+
class LoadingBar {
|
|
13
|
+
private _track: HTMLDivElement;
|
|
14
|
+
|
|
15
|
+
private _fill: HTMLDivElement;
|
|
16
|
+
|
|
17
|
+
private _sweep: Animation | null = null;
|
|
18
|
+
|
|
19
|
+
private _removal: ReturnType<typeof setTimeout> | null = null;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates the bar and appends it to `parent`, starting in the indeterminate state.
|
|
23
|
+
* @param parent - The element to append the bar to.
|
|
24
|
+
*/
|
|
25
|
+
constructor(parent: HTMLElement) {
|
|
26
|
+
this._track = document.createElement('div');
|
|
27
|
+
this._track.setAttribute('role', 'progressbar');
|
|
28
|
+
this._track.setAttribute('aria-label', 'Loading');
|
|
29
|
+
this._track.setAttribute('aria-valuemin', '0');
|
|
30
|
+
this._track.setAttribute('aria-valuemax', '100');
|
|
31
|
+
// Fixed positioning matches the canvas, which always fills the window (FILLMODE_FILL_WINDOW)
|
|
32
|
+
this._track.style.cssText = [
|
|
33
|
+
'position: fixed',
|
|
34
|
+
'top: 0',
|
|
35
|
+
'left: 0',
|
|
36
|
+
'width: 100%',
|
|
37
|
+
'height: var(--pc-loading-bar-height, 3px)',
|
|
38
|
+
'background: var(--pc-loading-bar-background, rgba(0, 0, 0, 0.1))',
|
|
39
|
+
'z-index: 10000',
|
|
40
|
+
'pointer-events: none',
|
|
41
|
+
'opacity: 1',
|
|
42
|
+
'transition: opacity 0.2s ease'
|
|
43
|
+
].join('; ');
|
|
44
|
+
|
|
45
|
+
this._fill = document.createElement('div');
|
|
46
|
+
this._fill.style.cssText = [
|
|
47
|
+
'width: 100%',
|
|
48
|
+
'height: 100%',
|
|
49
|
+
'transform-origin: left center',
|
|
50
|
+
'transform: scaleX(0)',
|
|
51
|
+
'background: var(--pc-loading-bar-color, #f60)',
|
|
52
|
+
'transition: transform 0.2s ease'
|
|
53
|
+
].join('; ');
|
|
54
|
+
|
|
55
|
+
this._track.appendChild(this._fill);
|
|
56
|
+
parent.appendChild(this._track);
|
|
57
|
+
|
|
58
|
+
// Indeterminate sweep until the first progress() call reports a real total. No
|
|
59
|
+
// aria-valuenow is set, which is what marks a progressbar indeterminate. jsdom has no Web
|
|
60
|
+
// Animations API, so the guard degrades to a static bar there rather than crashing boot.
|
|
61
|
+
if (typeof this._fill.animate === 'function') {
|
|
62
|
+
this._sweep = this._fill.animate([
|
|
63
|
+
{ transform: 'scaleX(0.25) translateX(-100%)' },
|
|
64
|
+
{ transform: 'scaleX(0.25) translateX(500%)' }
|
|
65
|
+
], {
|
|
66
|
+
duration: 1000,
|
|
67
|
+
iterations: Infinity,
|
|
68
|
+
easing: 'ease-in-out'
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Reflects preload progress, switching the bar from indeterminate to determinate on the first
|
|
75
|
+
* call.
|
|
76
|
+
* @param loaded - The number of assets that have finished loading.
|
|
77
|
+
* @param total - The number of assets being preloaded.
|
|
78
|
+
*/
|
|
79
|
+
progress(loaded: number, total: number) {
|
|
80
|
+
if (this._sweep) {
|
|
81
|
+
this._sweep.cancel();
|
|
82
|
+
this._sweep = null;
|
|
83
|
+
}
|
|
84
|
+
const fraction = total === 0 ? 1 : loaded / total;
|
|
85
|
+
this._track.setAttribute('aria-valuenow', String(Math.round(fraction * 100)));
|
|
86
|
+
this._fill.style.transform = `scaleX(${fraction})`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Fills the bar, fades it out and removes it. Idempotent.
|
|
91
|
+
*/
|
|
92
|
+
complete() {
|
|
93
|
+
if (this._removal !== null) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (this._sweep) {
|
|
97
|
+
this._sweep.cancel();
|
|
98
|
+
this._sweep = null;
|
|
99
|
+
}
|
|
100
|
+
this._track.setAttribute('aria-valuenow', '100');
|
|
101
|
+
this._fill.style.transform = 'scaleX(1)';
|
|
102
|
+
this._track.style.opacity = '0';
|
|
103
|
+
this._removal = setTimeout(() => this._track.remove(), REMOVAL_DELAY_MS);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Removes the bar immediately, cancelling any pending fade. Idempotent.
|
|
108
|
+
*/
|
|
109
|
+
destroy() {
|
|
110
|
+
if (this._sweep) {
|
|
111
|
+
this._sweep.cancel();
|
|
112
|
+
this._sweep = null;
|
|
113
|
+
}
|
|
114
|
+
if (this._removal !== null) {
|
|
115
|
+
clearTimeout(this._removal);
|
|
116
|
+
this._removal = null;
|
|
117
|
+
}
|
|
118
|
+
this._track.remove();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { LoadingBar };
|
package/src/material.ts
CHANGED
|
@@ -114,8 +114,14 @@ type TextureSlot = 'aoMap' | 'diffuseMap' | 'emissiveMap' | 'glossMap' | 'height
|
|
|
114
114
|
* created on insertion.
|
|
115
115
|
*
|
|
116
116
|
* The element is metal/rough by default: unlike a bare `StandardMaterial` it enables the metalness
|
|
117
|
-
* workflow, which is what the `metalness-*` attributes assume and what glTF means by PBR.
|
|
118
|
-
* `
|
|
117
|
+
* workflow, which is what the `metalness-*` attributes assume and what glTF means by PBR. It also
|
|
118
|
+
* defaults `metalness` to 0 rather than the engine's 1, because those two defaults have to be
|
|
119
|
+
* chosen together - the engine's 1 is unreachable under its own `useMetalness` of false, and with
|
|
120
|
+
* the workflow on it would make every material fully metallic, so `<pc-material diffuse="crimson">`
|
|
121
|
+
* would render as dark tinted reflections of an environment that may not exist rather than as a
|
|
122
|
+
* crimson surface. `metalness="1"` remains one attribute away.
|
|
123
|
+
*
|
|
124
|
+
* The `roughness` and `roughness-map` attributes are aliases for `gloss` and `gloss-map` that
|
|
119
125
|
* additionally invert the gloss channel; do not mix the two families on one element.
|
|
120
126
|
*
|
|
121
127
|
* The two aliases are documented here rather than on an accessor, because they resolve to the
|
|
@@ -222,7 +228,7 @@ class MaterialElement extends HTMLElement {
|
|
|
222
228
|
|
|
223
229
|
private _heightMapUv = 0;
|
|
224
230
|
|
|
225
|
-
private _metalness =
|
|
231
|
+
private _metalness = 0;
|
|
226
232
|
|
|
227
233
|
private _metalnessMap = '';
|
|
228
234
|
|
|
@@ -2386,7 +2392,7 @@ class MaterialElement extends HTMLElement {
|
|
|
2386
2392
|
this.heightMapUv = parseNumber(newValue, 0, name);
|
|
2387
2393
|
break;
|
|
2388
2394
|
case 'metalness':
|
|
2389
|
-
this.metalness = parseNumber(newValue,
|
|
2395
|
+
this.metalness = parseNumber(newValue, 0, name);
|
|
2390
2396
|
break;
|
|
2391
2397
|
case 'metalness-map':
|
|
2392
2398
|
this.metalnessMap = newValue ?? '';
|
package/src/scene.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Color, Scene, Vec3 } from 'playcanvas';
|
|
2
2
|
|
|
3
|
-
import { AppElement } from './app';
|
|
4
3
|
import { AsyncElement } from './async-element';
|
|
5
4
|
import { parseColor, parseEnum, parseNumber, parseVec3 } from './parse';
|
|
6
5
|
|
|
@@ -44,36 +43,68 @@ class SceneElement extends AsyncElement {
|
|
|
44
43
|
private _scene: Scene | null = null;
|
|
45
44
|
|
|
46
45
|
/**
|
|
47
|
-
* The PlayCanvas scene instance.
|
|
46
|
+
* The PlayCanvas scene instance. `null` until the element is ready — await
|
|
48
47
|
* {@link whenReady} or the element's `ready()` promise before accessing it.
|
|
49
|
-
* @returns The scene instance
|
|
48
|
+
* @returns The scene instance, or `null`.
|
|
50
49
|
*/
|
|
51
|
-
get scene(): Scene {
|
|
52
|
-
return this._scene
|
|
50
|
+
get scene(): Scene | null {
|
|
51
|
+
return this._scene;
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
async connectedCallback() {
|
|
56
|
-
|
|
55
|
+
const appElement = this.closestApp;
|
|
56
|
+
if (!appElement) {
|
|
57
|
+
console.warn('pc-scene must be a descendant of pc-app - scene settings not applied');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
await appElement.ready();
|
|
62
|
+
|
|
63
|
+
// The element may have been removed or re-parented while waiting for the app. Matches the
|
|
64
|
+
// guard in AssetElement and MaterialElement, but compares closestApp rather than
|
|
65
|
+
// parentElement because pc-scene resolves its app by ancestor rather than direct child.
|
|
66
|
+
// Without this, a scene re-parented mid-await would take its Scene from the app it started
|
|
67
|
+
// under while _applyGravity resolved the app it ended up under, splitting the two.
|
|
68
|
+
if (!this.isConnected || this.closestApp !== appElement) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
57
71
|
|
|
58
|
-
|
|
72
|
+
// The application is gone if the tree was torn down while we awaited readiness. There is
|
|
73
|
+
// nothing to configure and nothing the author can act on, so this stays silent.
|
|
74
|
+
const app = appElement.app;
|
|
75
|
+
if (!app) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this._scene = app.scene;
|
|
59
80
|
this.updateSceneSettings();
|
|
60
81
|
|
|
61
82
|
this._onReady();
|
|
62
83
|
}
|
|
63
84
|
|
|
64
85
|
updateSceneSettings() {
|
|
65
|
-
if (this.
|
|
66
|
-
this.
|
|
67
|
-
this.
|
|
68
|
-
this.
|
|
69
|
-
this.
|
|
70
|
-
this.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
appElement.app!.systems.rigidbody!.gravity.copy(this._gravity);
|
|
86
|
+
if (this._scene) {
|
|
87
|
+
this._scene.fog.type = this._fog;
|
|
88
|
+
this._scene.fog.color = this._fogColor;
|
|
89
|
+
this._scene.fog.density = this._fogDensity;
|
|
90
|
+
this._scene.fog.start = this._fogStart;
|
|
91
|
+
this._scene.fog.end = this._fogEnd;
|
|
92
|
+
|
|
93
|
+
this._applyGravity(this._gravity);
|
|
74
94
|
}
|
|
75
95
|
}
|
|
76
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Applies gravity to the rigid body system. Resolved through `closestApp` rather than
|
|
99
|
+
* `parentElement` so that a `<pc-scene>` nested inside a wrapper element behaves the same as
|
|
100
|
+
* a direct child, matching how `connectedCallback` resolves the application.
|
|
101
|
+
*
|
|
102
|
+
* @param value - The gravity to apply.
|
|
103
|
+
*/
|
|
104
|
+
private _applyGravity(value: Vec3) {
|
|
105
|
+
this.closestApp?.app?.systems.rigidbody?.gravity.copy(value);
|
|
106
|
+
}
|
|
107
|
+
|
|
77
108
|
/**
|
|
78
109
|
* Sets the fog type of the scene. Can be `none`, `linear`, `exp` or `exp2`. Defaults to
|
|
79
110
|
* `none`.
|
|
@@ -176,9 +207,8 @@ class SceneElement extends AsyncElement {
|
|
|
176
207
|
*/
|
|
177
208
|
set gravity(value: Vec3) {
|
|
178
209
|
this._gravity = value;
|
|
179
|
-
if (this.
|
|
180
|
-
|
|
181
|
-
appElement.app!.systems.rigidbody!.gravity.copy(value);
|
|
210
|
+
if (this._scene) {
|
|
211
|
+
this._applyGravity(value);
|
|
182
212
|
}
|
|
183
213
|
}
|
|
184
214
|
|