@playcanvas/web-components 0.10.1 → 0.11.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/README.md +1 -1
- package/dist/app.d.ts +102 -51
- package/dist/asset.d.ts +8 -7
- package/dist/async-element.d.ts +21 -5
- package/dist/components/button-component.d.ts +3 -7
- package/dist/components/camera-component.d.ts +16 -20
- package/dist/components/collision-component.d.ts +3 -7
- package/dist/components/component.d.ts +22 -4
- package/dist/components/element-component.d.ts +4 -8
- package/dist/components/gsplat-component.d.ts +2 -7
- package/dist/components/layoutchild-component.d.ts +2 -7
- package/dist/components/layoutgroup-component.d.ts +3 -7
- package/dist/components/light-component.d.ts +3 -7
- package/dist/components/listener-component.d.ts +1 -6
- package/dist/components/particlesystem-component.d.ts +2 -7
- package/dist/components/render-component.d.ts +2 -7
- package/dist/components/rigidbody-component.d.ts +3 -7
- package/dist/components/screen-component.d.ts +28 -11
- package/dist/components/script-component.d.ts +8 -20
- package/dist/components/script.d.ts +2 -22
- package/dist/components/scrollbar-component.d.ts +2 -7
- package/dist/components/scrollview-component.d.ts +9 -11
- package/dist/components/sound-component.d.ts +2 -7
- package/dist/components/sound-slot.d.ts +8 -6
- package/dist/custom-elements.json +5191 -10695
- package/dist/entity.d.ts +16 -9
- package/dist/index.d.ts +37 -0
- package/dist/material.d.ts +12 -12
- package/dist/model.d.ts +21 -5
- package/dist/module.d.ts +0 -6
- package/dist/parse.d.ts +6 -3
- package/dist/pwc.cjs +799 -287
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +799 -287
- 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 +800 -288
- package/dist/pwc.mjs.map +1 -1
- package/dist/scene.d.ts +4 -7
- package/dist/sky.d.ts +25 -16
- package/dist/vscode.html-custom-data.json +65 -45
- package/dist/web-types.json +585 -557
- package/package.json +8 -7
- package/src/app.ts +326 -144
- package/src/asset.ts +34 -28
- package/src/async-element.ts +34 -8
- package/src/components/button-component.ts +5 -9
- package/src/components/camera-component.ts +55 -36
- package/src/components/collision-component.ts +26 -15
- package/src/components/component.ts +58 -8
- package/src/components/element-component.ts +26 -30
- package/src/components/gsplat-component.ts +4 -9
- package/src/components/layoutchild-component.ts +4 -9
- package/src/components/layoutgroup-component.ts +14 -9
- package/src/components/light-component.ts +42 -12
- package/src/components/listener-component.ts +1 -7
- package/src/components/particlesystem-component.ts +7 -15
- package/src/components/render-component.ts +5 -10
- package/src/components/rigidbody-component.ts +23 -16
- package/src/components/screen-component.ts +46 -20
- package/src/components/script-component.ts +108 -46
- package/src/components/script.ts +38 -33
- package/src/components/scrollbar-component.ts +6 -16
- package/src/components/scrollview-component.ts +22 -15
- package/src/components/sound-component.ts +10 -15
- package/src/components/sound-slot.ts +30 -20
- package/src/entity.ts +75 -34
- package/src/index.ts +45 -1
- package/src/loading-bar.ts +8 -8
- package/src/material.ts +63 -37
- package/src/model.ts +69 -14
- package/src/module.ts +8 -7
- package/src/parse.ts +67 -20
- package/src/scene.ts +12 -9
- package/src/sky.ts +76 -34
package/src/asset.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Asset, SPRITE_RENDERMODE_SIMPLE, SPRITE_RENDERMODE_SLICED, SPRITE_RENDERMODE_TILED } from 'playcanvas';
|
|
2
2
|
|
|
3
|
+
import { MeshoptDecoder } from '../lib/meshopt_decoder.module.js';
|
|
4
|
+
|
|
3
5
|
import { AsyncElement } from './async-element';
|
|
4
6
|
import { parseBool, parseEnum, parseNumber } from './parse';
|
|
5
|
-
import { MeshoptDecoder } from '../lib/meshopt_decoder.module.js';
|
|
6
7
|
|
|
7
8
|
const renderModes = new Map<'simple' | 'sliced' | 'tiled', number>([
|
|
8
9
|
['simple', SPRITE_RENDERMODE_SIMPLE],
|
|
@@ -33,12 +34,11 @@ const extToType = new Map([
|
|
|
33
34
|
['webp', 'texture']
|
|
34
35
|
]);
|
|
35
36
|
|
|
36
|
-
|
|
37
37
|
// provide buffer view callback so we can handle models compressed with MeshOptimizer
|
|
38
38
|
// https://github.com/zeux/meshoptimizer
|
|
39
39
|
const processBufferView = (
|
|
40
40
|
gltfBuffer: any,
|
|
41
|
-
buffers:
|
|
41
|
+
buffers: any[],
|
|
42
42
|
continuation: (err: string | null, result: any) => void
|
|
43
43
|
) => {
|
|
44
44
|
if (gltfBuffer.extensions && gltfBuffer.extensions.EXT_meshopt_compression) {
|
|
@@ -56,14 +56,7 @@ const processBufferView = (
|
|
|
56
56
|
const result = new Uint8Array(count * stride);
|
|
57
57
|
const source = new Uint8Array(buffer.buffer, buffer.byteOffset + byteOffset, byteLength);
|
|
58
58
|
|
|
59
|
-
MeshoptDecoder.decodeGltfBuffer(
|
|
60
|
-
result,
|
|
61
|
-
count,
|
|
62
|
-
stride,
|
|
63
|
-
source,
|
|
64
|
-
extensionDef.mode,
|
|
65
|
-
extensionDef.filter
|
|
66
|
-
);
|
|
59
|
+
MeshoptDecoder.decodeGltfBuffer(result, count, stride, source, extensionDef.mode, extensionDef.filter);
|
|
67
60
|
|
|
68
61
|
continuation(null, result);
|
|
69
62
|
});
|
|
@@ -108,7 +101,7 @@ const processBufferView = (
|
|
|
108
101
|
* not that it succeeded.
|
|
109
102
|
*/
|
|
110
103
|
class AssetElement extends AsyncElement {
|
|
111
|
-
private _lazy
|
|
104
|
+
private _lazy = false;
|
|
112
105
|
|
|
113
106
|
/**
|
|
114
107
|
* The asset that is loaded. Available once the element is ready — await
|
|
@@ -122,7 +115,9 @@ class AssetElement extends AsyncElement {
|
|
|
122
115
|
|
|
123
116
|
// Assets must be direct children of pc-app (matches the boot query ':scope > pc-asset')
|
|
124
117
|
if (this.parentElement !== appElement) {
|
|
125
|
-
console.warn(
|
|
118
|
+
console.warn(
|
|
119
|
+
`pc-asset '${this.getAttribute('id') ?? this.getAttribute('src')}' must be a direct child of pc-app - asset not created`
|
|
120
|
+
);
|
|
126
121
|
return;
|
|
127
122
|
}
|
|
128
123
|
|
|
@@ -137,7 +132,7 @@ class AssetElement extends AsyncElement {
|
|
|
137
132
|
const app = appElement.app;
|
|
138
133
|
if (!app) return; // pc-app is re-connecting; its own boot will create this asset
|
|
139
134
|
|
|
140
|
-
this.
|
|
135
|
+
this._createAsset();
|
|
141
136
|
if (this.asset) {
|
|
142
137
|
app.assets.add(this.asset); // add() auto-loads when preload is true
|
|
143
138
|
if (!this.lazy) {
|
|
@@ -146,14 +141,16 @@ class AssetElement extends AsyncElement {
|
|
|
146
141
|
}
|
|
147
142
|
}
|
|
148
143
|
|
|
149
|
-
// Never ready if
|
|
144
|
+
// Never ready if _createAsset failed (unsupported asset type)
|
|
150
145
|
if (this.asset) {
|
|
151
146
|
this._onReady();
|
|
152
147
|
}
|
|
153
148
|
}
|
|
154
149
|
|
|
155
150
|
disconnectedCallback() {
|
|
156
|
-
this.
|
|
151
|
+
this._destroyAsset();
|
|
152
|
+
// Re-arm readiness so a re-inserted element announces the asset it creates then
|
|
153
|
+
this._resetReady();
|
|
157
154
|
}
|
|
158
155
|
|
|
159
156
|
private _onAssetLoad() {
|
|
@@ -161,12 +158,21 @@ class AssetElement extends AsyncElement {
|
|
|
161
158
|
}
|
|
162
159
|
|
|
163
160
|
private _onAssetError(err: string | Error) {
|
|
164
|
-
this.dispatchEvent(
|
|
165
|
-
|
|
166
|
-
|
|
161
|
+
this.dispatchEvent(
|
|
162
|
+
new ErrorEvent('error', {
|
|
163
|
+
message: err instanceof Error ? err.message : String(err)
|
|
164
|
+
})
|
|
165
|
+
);
|
|
167
166
|
}
|
|
168
167
|
|
|
169
|
-
|
|
168
|
+
/**
|
|
169
|
+
* Creates the asset from the element's attributes. Called by the containing `<pc-app>`
|
|
170
|
+
* element during its boot sweep, and on connection for elements inserted while the
|
|
171
|
+
* application is already running.
|
|
172
|
+
*
|
|
173
|
+
* @internal
|
|
174
|
+
*/
|
|
175
|
+
_createAsset() {
|
|
170
176
|
const id = this.getAttribute('id') || '';
|
|
171
177
|
const src = this.getAttribute('src') || '';
|
|
172
178
|
let type = this.getAttribute('type');
|
|
@@ -268,8 +274,7 @@ class AssetElement extends AsyncElement {
|
|
|
268
274
|
return data;
|
|
269
275
|
}
|
|
270
276
|
|
|
271
|
-
|
|
272
|
-
destroyAsset() {
|
|
277
|
+
private _destroyAsset() {
|
|
273
278
|
if (this.asset) {
|
|
274
279
|
// A caller that keeps the Asset alive must not dispatch on a removed element
|
|
275
280
|
this.asset.off('load', this._onAssetLoad, this);
|
|
@@ -300,6 +305,13 @@ class AssetElement extends AsyncElement {
|
|
|
300
305
|
return this._lazy;
|
|
301
306
|
}
|
|
302
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Returns the {@link Asset} created by the `<pc-asset>` element with the given `id`, or
|
|
310
|
+
* `undefined` if there is no such element or its asset has not been created yet.
|
|
311
|
+
*
|
|
312
|
+
* @param id - The `id` of the `<pc-asset>` element.
|
|
313
|
+
* @returns The asset, or `undefined`.
|
|
314
|
+
*/
|
|
303
315
|
static get(id: string) {
|
|
304
316
|
const assetElement = document.querySelector<AssetElement>(`pc-asset[id="${id}"]`);
|
|
305
317
|
return assetElement?.asset;
|
|
@@ -318,10 +330,4 @@ class AssetElement extends AsyncElement {
|
|
|
318
330
|
|
|
319
331
|
customElements.define('pc-asset', AssetElement);
|
|
320
332
|
|
|
321
|
-
declare global {
|
|
322
|
-
interface HTMLElementTagNameMap {
|
|
323
|
-
'pc-asset': AssetElement;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
333
|
export { AssetElement };
|
package/src/async-element.ts
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import { AppElement } from './app';
|
|
2
|
-
import { EntityElement } from './entity';
|
|
1
|
+
import type { AppElement } from './app';
|
|
2
|
+
import type { EntityElement } from './entity';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Base class for all PlayCanvas Web Components that initialize asynchronously.
|
|
6
6
|
*
|
|
7
|
-
* @fires {CustomEvent} ready - Fired
|
|
8
|
-
*
|
|
7
|
+
* @fires {CustomEvent} ready - Fired when the element is fully initialized — once per readiness
|
|
8
|
+
* cycle, so an element that is torn down and re-initialized (for example by removing and
|
|
9
|
+
* re-inserting it) fires it again. Bubbles and is composed.
|
|
9
10
|
*/
|
|
10
11
|
class AsyncElement extends HTMLElement {
|
|
11
12
|
private _readyPromise: Promise<void>;
|
|
12
13
|
|
|
13
14
|
private _readyResolve!: () => void;
|
|
14
15
|
|
|
16
|
+
private _readyResolved = false;
|
|
17
|
+
|
|
15
18
|
/** @ignore */
|
|
16
19
|
constructor() {
|
|
17
20
|
super();
|
|
@@ -26,7 +29,7 @@ class AsyncElement extends HTMLElement {
|
|
|
26
29
|
* @returns The closest app element, or `null`.
|
|
27
30
|
*/
|
|
28
31
|
get closestApp(): AppElement | null {
|
|
29
|
-
return this.parentElement?.closest('pc-app') as AppElement | null ?? null;
|
|
32
|
+
return (this.parentElement?.closest('pc-app') as AppElement | null) ?? null;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
/**
|
|
@@ -35,22 +38,45 @@ class AsyncElement extends HTMLElement {
|
|
|
35
38
|
* @returns The closest entity element, or `null`.
|
|
36
39
|
*/
|
|
37
40
|
get closestEntity(): EntityElement | null {
|
|
38
|
-
return this.parentElement?.closest('pc-entity') as EntityElement | null ?? null;
|
|
41
|
+
return (this.parentElement?.closest('pc-entity') as EntityElement | null) ?? null;
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
/**
|
|
42
45
|
* Called when the element is fully initialized and ready. Subclasses should call this when
|
|
43
46
|
* they're ready. Resolves the ready promise and dispatches a bubbling, composed `ready`
|
|
44
|
-
* event.
|
|
47
|
+
* event. Signals at most once per readiness cycle: a repeat call before {@link _resetReady}
|
|
48
|
+
* has re-armed the promise does nothing.
|
|
45
49
|
*/
|
|
46
50
|
protected _onReady() {
|
|
51
|
+
if (this._readyResolved) return;
|
|
52
|
+
this._readyResolved = true;
|
|
47
53
|
this._readyResolve();
|
|
48
54
|
this.dispatchEvent(new CustomEvent('ready', { bubbles: true, composed: true }));
|
|
49
55
|
}
|
|
50
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Returns the ready promise to its pending state. Subclasses should call this when the
|
|
59
|
+
* resource their readiness announced is torn down (typically from `disconnectedCallback`),
|
|
60
|
+
* so that a later re-initialization can signal readiness again. Does nothing while the
|
|
61
|
+
* promise is still pending — an in-flight waiter carries over to the next readiness cycle
|
|
62
|
+
* rather than being stranded on a promise nothing will ever resolve.
|
|
63
|
+
*/
|
|
64
|
+
protected _resetReady() {
|
|
65
|
+
if (!this._readyResolved) return;
|
|
66
|
+
this._readyResolved = false;
|
|
67
|
+
this._readyPromise = new Promise<void>((resolve) => {
|
|
68
|
+
this._readyResolve = resolve;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
51
72
|
/**
|
|
52
73
|
* Returns a promise that resolves with this element when it's ready. This is the low-level
|
|
53
74
|
* primitive underlying {@link whenReady}, which is the recommended way to wait for elements.
|
|
75
|
+
*
|
|
76
|
+
* Readiness tracks the element's current lifecycle: once a ready element is torn down (for
|
|
77
|
+
* example by removing it from the document), this returns a fresh promise that resolves when
|
|
78
|
+
* the element is next ready. A promise obtained earlier stays resolved — call this again
|
|
79
|
+
* after re-inserting an element rather than reusing a promise from before its removal.
|
|
54
80
|
* @returns A promise that resolves with this element when it's ready.
|
|
55
81
|
*/
|
|
56
82
|
ready(): Promise<this> {
|
|
@@ -63,7 +89,7 @@ class AsyncElement extends HTMLElement {
|
|
|
63
89
|
* classes extend {@link AsyncElement}).
|
|
64
90
|
*/
|
|
65
91
|
type AsyncElementTagName = {
|
|
66
|
-
[K in keyof HTMLElementTagNameMap]: HTMLElementTagNameMap[K] extends AsyncElement ? K : never
|
|
92
|
+
[K in keyof HTMLElementTagNameMap]: HTMLElementTagNameMap[K] extends AsyncElement ? K : never;
|
|
67
93
|
}[keyof HTMLElementTagNameMap];
|
|
68
94
|
|
|
69
95
|
/**
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ButtonComponent } from 'playcanvas';
|
|
2
|
+
import { BUTTON_TRANSITION_MODE_SPRITE_CHANGE, BUTTON_TRANSITION_MODE_TINT, Color, Vec4 } from 'playcanvas';
|
|
2
3
|
|
|
3
4
|
import { AssetElement } from '../asset';
|
|
4
|
-
import { ComponentElement } from './component';
|
|
5
5
|
import { getEntity, parseBool, parseColor, parseEnum, parseNumber, parseVec4 } from '../parse';
|
|
6
6
|
|
|
7
|
+
import { ComponentElement } from './component';
|
|
8
|
+
|
|
7
9
|
const transitionModes = new Map<'tint' | 'sprite', number>([
|
|
8
10
|
['tint', BUTTON_TRANSITION_MODE_TINT],
|
|
9
11
|
['sprite', BUTTON_TRANSITION_MODE_SPRITE_CHANGE]
|
|
@@ -51,7 +53,7 @@ class ButtonComponentElement extends ComponentElement {
|
|
|
51
53
|
super('button');
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
getInitialComponentData() {
|
|
56
|
+
protected getInitialComponentData() {
|
|
55
57
|
const data: Record<string, any> = {
|
|
56
58
|
active: this._active,
|
|
57
59
|
hitPadding: this._hitPadding,
|
|
@@ -448,10 +450,4 @@ class ButtonComponentElement extends ComponentElement {
|
|
|
448
450
|
|
|
449
451
|
customElements.define('pc-button', ButtonComponentElement);
|
|
450
452
|
|
|
451
|
-
declare global {
|
|
452
|
-
interface HTMLElementTagNameMap {
|
|
453
|
-
'pc-button': ButtonComponentElement;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
453
|
export { ButtonComponentElement };
|
|
@@ -1,8 +1,30 @@
|
|
|
1
|
-
import { CameraComponent
|
|
1
|
+
import type { CameraComponent } from 'playcanvas';
|
|
2
|
+
import {
|
|
3
|
+
Color,
|
|
4
|
+
Vec4,
|
|
5
|
+
GAMMA_NONE,
|
|
6
|
+
GAMMA_SRGB,
|
|
7
|
+
PROJECTION_ORTHOGRAPHIC,
|
|
8
|
+
PROJECTION_PERSPECTIVE,
|
|
9
|
+
TONEMAP_LINEAR,
|
|
10
|
+
TONEMAP_FILMIC,
|
|
11
|
+
TONEMAP_NEUTRAL,
|
|
12
|
+
TONEMAP_ACES2,
|
|
13
|
+
TONEMAP_ACES,
|
|
14
|
+
TONEMAP_HEJL,
|
|
15
|
+
TONEMAP_NONE,
|
|
16
|
+
XRTYPE_VR
|
|
17
|
+
} from 'playcanvas';
|
|
2
18
|
|
|
3
|
-
import { ComponentElement } from './component';
|
|
4
19
|
import { parseBool, parseColor, parseEnum, parseNumber, parseVec4 } from '../parse';
|
|
5
20
|
|
|
21
|
+
import { ComponentElement } from './component';
|
|
22
|
+
|
|
23
|
+
const projections = new Map<'perspective' | 'orthographic', number>([
|
|
24
|
+
['perspective', PROJECTION_PERSPECTIVE],
|
|
25
|
+
['orthographic', PROJECTION_ORTHOGRAPHIC]
|
|
26
|
+
]);
|
|
27
|
+
|
|
6
28
|
const tonemaps = new Map<'none' | 'linear' | 'filmic' | 'hejl' | 'aces' | 'aces2' | 'neutral', number>([
|
|
7
29
|
['none', TONEMAP_NONE],
|
|
8
30
|
['linear', TONEMAP_LINEAR],
|
|
@@ -46,7 +68,7 @@ class CameraComponentElement extends ComponentElement {
|
|
|
46
68
|
|
|
47
69
|
private _nearClip = 0.1;
|
|
48
70
|
|
|
49
|
-
private
|
|
71
|
+
private _projection: 'perspective' | 'orthographic' = 'perspective';
|
|
50
72
|
|
|
51
73
|
private _orthoHeight = 10;
|
|
52
74
|
|
|
@@ -63,7 +85,7 @@ class CameraComponentElement extends ComponentElement {
|
|
|
63
85
|
super('camera');
|
|
64
86
|
}
|
|
65
87
|
|
|
66
|
-
getInitialComponentData() {
|
|
88
|
+
protected getInitialComponentData() {
|
|
67
89
|
return {
|
|
68
90
|
clearColor: this._clearColor,
|
|
69
91
|
clearColorBuffer: this._clearColorBuffer,
|
|
@@ -77,12 +99,12 @@ class CameraComponentElement extends ComponentElement {
|
|
|
77
99
|
gammaCorrection: this._gamma === 'srgb' ? GAMMA_SRGB : GAMMA_NONE,
|
|
78
100
|
horizontalFov: this._horizontalFov,
|
|
79
101
|
nearClip: this._nearClip,
|
|
80
|
-
projection: this.
|
|
102
|
+
projection: projections.get(this._projection) ?? PROJECTION_PERSPECTIVE,
|
|
81
103
|
orthoHeight: this._orthoHeight,
|
|
82
104
|
priority: this._priority,
|
|
83
105
|
rect: this._rect,
|
|
84
106
|
scissorRect: this._scissorRect,
|
|
85
|
-
toneMapping: tonemaps.get(this._tonemap)
|
|
107
|
+
toneMapping: tonemaps.get(this._tonemap) ?? TONEMAP_NONE
|
|
86
108
|
};
|
|
87
109
|
}
|
|
88
110
|
|
|
@@ -96,7 +118,10 @@ class CameraComponentElement extends ComponentElement {
|
|
|
96
118
|
* @param type - The type of XR mode to start.
|
|
97
119
|
* @param space - The space to start the camera in.
|
|
98
120
|
*/
|
|
99
|
-
startXr(
|
|
121
|
+
startXr(
|
|
122
|
+
type: 'immersive-ar' | 'immersive-vr',
|
|
123
|
+
space: 'bounded-floor' | 'local' | 'local-floor' | 'unbounded' | 'viewer'
|
|
124
|
+
) {
|
|
100
125
|
if (this.component && this.xrAvailable) {
|
|
101
126
|
this.component.startXr(type, space, {
|
|
102
127
|
callback: (err: any) => {
|
|
@@ -352,25 +377,6 @@ class CameraComponentElement extends ComponentElement {
|
|
|
352
377
|
return this._nearClip;
|
|
353
378
|
}
|
|
354
379
|
|
|
355
|
-
/**
|
|
356
|
-
* Sets the orthographic projection of the camera.
|
|
357
|
-
* @param value - The orthographic projection.
|
|
358
|
-
*/
|
|
359
|
-
set orthographic(value) {
|
|
360
|
-
this._orthographic = value;
|
|
361
|
-
if (this.component) {
|
|
362
|
-
this.component.projection = value ? PROJECTION_ORTHOGRAPHIC : PROJECTION_PERSPECTIVE;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Gets the orthographic projection of the camera.
|
|
368
|
-
* @returns The orthographic projection.
|
|
369
|
-
*/
|
|
370
|
-
get orthographic(): boolean {
|
|
371
|
-
return this._orthographic;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
380
|
/**
|
|
375
381
|
* Sets the orthographic height of the camera.
|
|
376
382
|
* @param value - The orthographic height.
|
|
@@ -409,6 +415,25 @@ class CameraComponentElement extends ComponentElement {
|
|
|
409
415
|
return this._priority;
|
|
410
416
|
}
|
|
411
417
|
|
|
418
|
+
/**
|
|
419
|
+
* Sets the projection of the camera. Use `orthoHeight` to size an orthographic projection.
|
|
420
|
+
* @param value - The projection ('perspective' or 'orthographic').
|
|
421
|
+
*/
|
|
422
|
+
set projection(value: 'perspective' | 'orthographic') {
|
|
423
|
+
this._projection = value;
|
|
424
|
+
if (this.component) {
|
|
425
|
+
this.component.projection = projections.get(value) ?? PROJECTION_PERSPECTIVE;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Gets the projection of the camera.
|
|
431
|
+
* @returns The projection.
|
|
432
|
+
*/
|
|
433
|
+
get projection() {
|
|
434
|
+
return this._projection;
|
|
435
|
+
}
|
|
436
|
+
|
|
412
437
|
/**
|
|
413
438
|
* Sets the rect of the camera.
|
|
414
439
|
* @param value - The rect.
|
|
@@ -481,9 +506,9 @@ class CameraComponentElement extends ComponentElement {
|
|
|
481
506
|
'gamma',
|
|
482
507
|
'horizontal-fov',
|
|
483
508
|
'near-clip',
|
|
484
|
-
'orthographic',
|
|
485
509
|
'ortho-height',
|
|
486
510
|
'priority',
|
|
511
|
+
'projection',
|
|
487
512
|
'rect',
|
|
488
513
|
'scissor-rect',
|
|
489
514
|
'tonemap'
|
|
@@ -530,15 +555,15 @@ class CameraComponentElement extends ComponentElement {
|
|
|
530
555
|
case 'near-clip':
|
|
531
556
|
this.nearClip = parseNumber(newValue, 0.1, name);
|
|
532
557
|
break;
|
|
533
|
-
case 'orthographic':
|
|
534
|
-
this.orthographic = parseBool(newValue, false);
|
|
535
|
-
break;
|
|
536
558
|
case 'ortho-height':
|
|
537
559
|
this.orthoHeight = parseNumber(newValue, 10, name);
|
|
538
560
|
break;
|
|
539
561
|
case 'priority':
|
|
540
562
|
this.priority = parseNumber(newValue, 0, name);
|
|
541
563
|
break;
|
|
564
|
+
case 'projection':
|
|
565
|
+
this.projection = parseEnum(newValue, projections, 'perspective', name);
|
|
566
|
+
break;
|
|
542
567
|
case 'rect':
|
|
543
568
|
this.rect = parseVec4(newValue, new Vec4(0, 0, 1, 1), name);
|
|
544
569
|
break;
|
|
@@ -554,10 +579,4 @@ class CameraComponentElement extends ComponentElement {
|
|
|
554
579
|
|
|
555
580
|
customElements.define('pc-camera', CameraComponentElement);
|
|
556
581
|
|
|
557
|
-
declare global {
|
|
558
|
-
interface HTMLElementTagNameMap {
|
|
559
|
-
'pc-camera': CameraComponentElement;
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
582
|
export { CameraComponentElement };
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { CollisionComponent
|
|
1
|
+
import type { CollisionComponent } from 'playcanvas';
|
|
2
|
+
import { Quat, Vec3 } from 'playcanvas';
|
|
2
3
|
|
|
3
|
-
import { ComponentElement } from './component';
|
|
4
4
|
import { parseBool, parseEnum, parseNumber, parseQuat, parseVec3 } from '../parse';
|
|
5
5
|
|
|
6
|
+
import { ComponentElement } from './component';
|
|
7
|
+
|
|
6
8
|
/**
|
|
7
9
|
* The CollisionComponentElement interface provides properties and methods for manipulating
|
|
8
10
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-collision/ | `<pc-collision>`} elements.
|
|
@@ -14,17 +16,17 @@ import { parseBool, parseEnum, parseNumber, parseQuat, parseVec3 } from '../pars
|
|
|
14
16
|
class CollisionComponentElement extends ComponentElement {
|
|
15
17
|
private _angularOffset: Quat = new Quat();
|
|
16
18
|
|
|
17
|
-
private _axis
|
|
19
|
+
private _axis = 1;
|
|
18
20
|
|
|
19
|
-
private _convexHull
|
|
21
|
+
private _convexHull = false;
|
|
20
22
|
|
|
21
23
|
private _halfExtents: Vec3 = new Vec3(0.5, 0.5, 0.5);
|
|
22
24
|
|
|
23
|
-
private _height
|
|
25
|
+
private _height = 2;
|
|
24
26
|
|
|
25
27
|
private _linearOffset: Vec3 = new Vec3();
|
|
26
28
|
|
|
27
|
-
private _radius
|
|
29
|
+
private _radius = 0.5;
|
|
28
30
|
|
|
29
31
|
private _type: 'box' | 'capsule' | 'compound' | 'cone' | 'cylinder' | 'mesh' | 'sphere' = 'box';
|
|
30
32
|
|
|
@@ -33,7 +35,7 @@ class CollisionComponentElement extends ComponentElement {
|
|
|
33
35
|
super('collision');
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
getInitialComponentData() {
|
|
38
|
+
protected getInitialComponentData() {
|
|
37
39
|
return {
|
|
38
40
|
axis: this._axis,
|
|
39
41
|
angularOffset: this._angularOffset,
|
|
@@ -143,7 +145,17 @@ class CollisionComponentElement extends ComponentElement {
|
|
|
143
145
|
}
|
|
144
146
|
|
|
145
147
|
static get observedAttributes() {
|
|
146
|
-
return [
|
|
148
|
+
return [
|
|
149
|
+
...super.observedAttributes,
|
|
150
|
+
'angular-offset',
|
|
151
|
+
'axis',
|
|
152
|
+
'convex-hull',
|
|
153
|
+
'half-extents',
|
|
154
|
+
'height',
|
|
155
|
+
'linear-offset',
|
|
156
|
+
'radius',
|
|
157
|
+
'type'
|
|
158
|
+
];
|
|
147
159
|
}
|
|
148
160
|
|
|
149
161
|
attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
|
|
@@ -172,7 +184,12 @@ class CollisionComponentElement extends ComponentElement {
|
|
|
172
184
|
this.radius = parseNumber(newValue, 0.5, name);
|
|
173
185
|
break;
|
|
174
186
|
case 'type':
|
|
175
|
-
this.type = parseEnum(
|
|
187
|
+
this.type = parseEnum(
|
|
188
|
+
newValue,
|
|
189
|
+
['box', 'capsule', 'compound', 'cone', 'cylinder', 'mesh', 'sphere'],
|
|
190
|
+
'box',
|
|
191
|
+
name
|
|
192
|
+
);
|
|
176
193
|
break;
|
|
177
194
|
}
|
|
178
195
|
}
|
|
@@ -180,10 +197,4 @@ class CollisionComponentElement extends ComponentElement {
|
|
|
180
197
|
|
|
181
198
|
customElements.define('pc-collision', CollisionComponentElement);
|
|
182
199
|
|
|
183
|
-
declare global {
|
|
184
|
-
interface HTMLElementTagNameMap {
|
|
185
|
-
'pc-collision': CollisionComponentElement;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
200
|
export { CollisionComponentElement };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Component } from 'playcanvas';
|
|
1
|
+
import type { Component } from 'playcanvas';
|
|
2
2
|
|
|
3
|
-
import { AppElement } from '../app';
|
|
3
|
+
import type { AppElement } from '../app';
|
|
4
4
|
import { AsyncElement } from '../async-element';
|
|
5
5
|
import { parseBool } from '../parse';
|
|
6
6
|
|
|
@@ -18,6 +18,15 @@ class ComponentElement extends AsyncElement {
|
|
|
18
18
|
|
|
19
19
|
private _appElement: AppElement | null = null;
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Incremented on every connect and disconnect. connectedCallback captures the value on entry
|
|
23
|
+
* and abandons itself wherever it resumes from an await if the value has moved on — so a
|
|
24
|
+
* callback whose element was removed cannot act on a torn-down tree, and one whose element
|
|
25
|
+
* was removed and re-inserted (which runs a callback of its own) cannot add the component a
|
|
26
|
+
* second time.
|
|
27
|
+
*/
|
|
28
|
+
private _connectionGeneration = 0;
|
|
29
|
+
|
|
21
30
|
/**
|
|
22
31
|
* Creates a new ComponentElement instance.
|
|
23
32
|
*
|
|
@@ -30,38 +39,78 @@ class ComponentElement extends AsyncElement {
|
|
|
30
39
|
this._componentName = componentName;
|
|
31
40
|
}
|
|
32
41
|
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Returns the data the component is created with. Overridden by subclasses to supply the
|
|
44
|
+
* initial values of their cached properties.
|
|
45
|
+
*
|
|
46
|
+
* @returns The initial component data.
|
|
47
|
+
*/
|
|
48
|
+
protected getInitialComponentData() {
|
|
35
49
|
return {};
|
|
36
50
|
}
|
|
37
51
|
|
|
38
|
-
async
|
|
52
|
+
private async _addComponent() {
|
|
53
|
+
const generation = this._connectionGeneration;
|
|
54
|
+
|
|
39
55
|
const entityElement = this.closestEntity;
|
|
40
56
|
if (!entityElement) {
|
|
41
57
|
// A component can only exist on an entity, so an element placed outside one is inert.
|
|
42
58
|
// It still becomes ready (with a null `component`), so warn rather than fail silently
|
|
43
59
|
const label = this.id ? ` '${this.id}'` : '';
|
|
44
|
-
console.warn(
|
|
60
|
+
console.warn(
|
|
61
|
+
`${this.tagName.toLowerCase()}${label} must be a descendant of pc-entity - component not added`
|
|
62
|
+
);
|
|
45
63
|
return;
|
|
46
64
|
}
|
|
47
65
|
|
|
48
66
|
await entityElement.ready();
|
|
67
|
+
|
|
68
|
+
// The element may have been removed, or removed and re-inserted, while the entity became
|
|
69
|
+
// ready — the component belongs to the connection that owns the current generation.
|
|
70
|
+
if (generation !== this._connectionGeneration) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
49
74
|
// Add the component to the entity
|
|
50
75
|
const data = this.getInitialComponentData();
|
|
51
76
|
this._component = entityElement.entity!.addComponent(this._componentName, data);
|
|
52
77
|
}
|
|
53
78
|
|
|
54
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Configures the newly added component. Overridden by subclasses whose setup goes beyond
|
|
81
|
+
* the initial data — child-element handling, asset resolution and the like.
|
|
82
|
+
*/
|
|
83
|
+
protected initComponent() {
|
|
84
|
+
// optional hook
|
|
85
|
+
}
|
|
55
86
|
|
|
56
87
|
async connectedCallback() {
|
|
88
|
+
const generation = ++this._connectionGeneration;
|
|
89
|
+
|
|
57
90
|
this._appElement = this.closestApp ?? null;
|
|
58
91
|
await this._appElement?.ready();
|
|
59
|
-
|
|
92
|
+
|
|
93
|
+
// The element may have been removed, or removed and re-inserted, while the application
|
|
94
|
+
// became ready. A re-insertion runs a connectedCallback of its own, so a stale resume
|
|
95
|
+
// must not add the component alongside it.
|
|
96
|
+
if (generation !== this._connectionGeneration) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
await this._addComponent();
|
|
101
|
+
|
|
102
|
+
if (generation !== this._connectionGeneration) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
60
106
|
this.initComponent();
|
|
61
107
|
this._onReady();
|
|
62
108
|
}
|
|
63
109
|
|
|
64
110
|
disconnectedCallback() {
|
|
111
|
+
// Invalidate any connectedCallback still suspended on an await
|
|
112
|
+
this._connectionGeneration++;
|
|
113
|
+
|
|
65
114
|
// Remove the component when the element is disconnected. Skip this when the owning
|
|
66
115
|
// application has already been destroyed — removing a <pc-app> disconnects it before
|
|
67
116
|
// its children, taking the component systems with it.
|
|
@@ -70,6 +119,7 @@ class ComponentElement extends AsyncElement {
|
|
|
70
119
|
}
|
|
71
120
|
this._component = null;
|
|
72
121
|
this._appElement = null;
|
|
122
|
+
this._resetReady();
|
|
73
123
|
}
|
|
74
124
|
|
|
75
125
|
/**
|