@playcanvas/web-components 0.1.5 → 0.1.7

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/pwc.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { WasmModule, Application, Keyboard, Mouse, FILLMODE_FILL_WINDOW, RESOLUTION_AUTO, Color, Quat, Vec2, Vec3, Vec4, Entity, Asset, XRTYPE_VR, PROJECTION_ORTHOGRAPHIC, PROJECTION_PERSPECTIVE, StandardMaterial, SCALEMODE_BLEND, SCALEMODE_NONE, EnvLighting, LAYERID_SKYBOX } from 'playcanvas';
1
+ import { basisInitialize, WasmModule, Application, Mouse, Keyboard, FILLMODE_FILL_WINDOW, RESOLUTION_AUTO, Vec3, Vec4, Color, Quat, Vec2, Entity, Asset, XRTYPE_VR, PROJECTION_ORTHOGRAPHIC, PROJECTION_PERSPECTIVE, StandardMaterial, SCALEMODE_BLEND, SCALEMODE_NONE, EnvLighting, LAYERID_SKYBOX } from 'playcanvas';
2
2
 
3
3
  /**
4
4
  * Base class for all PlayCanvas web components that initialize asynchronously.
@@ -45,14 +45,23 @@ class ModuleElement extends HTMLElement {
45
45
  const glue = this.getAttribute('glue');
46
46
  const wasm = this.getAttribute('wasm');
47
47
  const fallback = this.getAttribute('fallback');
48
- WasmModule.setConfig(name, {
49
- glueUrl: glue,
50
- wasmUrl: wasm,
51
- fallbackUrl: fallback
52
- });
53
- await new Promise((resolve) => {
54
- WasmModule.getInstance(name, () => resolve());
55
- });
48
+ if (name === 'Basis') {
49
+ basisInitialize({
50
+ glueUrl: glue,
51
+ wasmUrl: wasm,
52
+ fallbackUrl: fallback
53
+ });
54
+ }
55
+ else {
56
+ WasmModule.setConfig(name, {
57
+ glueUrl: glue,
58
+ wasmUrl: wasm,
59
+ fallbackUrl: fallback
60
+ });
61
+ await new Promise((resolve) => {
62
+ WasmModule.getInstance(name, () => resolve());
63
+ });
64
+ }
56
65
  }
57
66
  getLoadPromise() {
58
67
  return this.loadPromise;
@@ -73,6 +82,10 @@ class AppElement extends AsyncElement {
73
82
  * The canvas element.
74
83
  */
75
84
  this._canvas = null;
85
+ this._alpha = true;
86
+ this._antialias = true;
87
+ this._depth = true;
88
+ this._stencil = true;
76
89
  this._highResolution = false;
77
90
  /**
78
91
  * The PlayCanvas application instance.
@@ -92,11 +105,15 @@ class AppElement extends AsyncElement {
92
105
  // Initialize the PlayCanvas application
93
106
  this.app = new Application(this._canvas, {
94
107
  graphicsDeviceOptions: {
95
- devicePixelRatio: this._highResolution ? window.devicePixelRatio : 1
108
+ alpha: this._alpha,
109
+ antialias: this._antialias,
110
+ depth: this._depth,
111
+ stencil: this._stencil
96
112
  },
97
113
  keyboard: new Keyboard(window),
98
114
  mouse: new Mouse(this._canvas)
99
115
  });
116
+ this.app.graphicsDevice.maxPixelRatio = this._highResolution ? window.devicePixelRatio : 1;
100
117
  this.app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
101
118
  this.app.setCanvasResolution(RESOLUTION_AUTO);
102
119
  // Get all pc-asset elements that are direct children of the pc-app element
@@ -141,6 +158,48 @@ class AppElement extends AsyncElement {
141
158
  this.app.resizeCanvas();
142
159
  }
143
160
  }
161
+ /**
162
+ * Sets the alpha flag.
163
+ * @param value - The alpha flag.
164
+ */
165
+ set alpha(value) {
166
+ this._alpha = value;
167
+ }
168
+ /**
169
+ * Gets the alpha flag.
170
+ * @returns The alpha flag.
171
+ */
172
+ get alpha() {
173
+ return this._alpha;
174
+ }
175
+ /**
176
+ * Sets the antialias flag.
177
+ * @param value - The antialias flag.
178
+ */
179
+ set antialias(value) {
180
+ this._antialias = value;
181
+ }
182
+ /**
183
+ * Gets the antialias flag.
184
+ * @returns The antialias flag.
185
+ */
186
+ get antialias() {
187
+ return this._antialias;
188
+ }
189
+ /**
190
+ * Sets the depth flag.
191
+ * @param value - The depth flag.
192
+ */
193
+ set depth(value) {
194
+ this._depth = value;
195
+ }
196
+ /**
197
+ * Gets the depth flag.
198
+ * @returns The depth flag.
199
+ */
200
+ get depth() {
201
+ return this._depth;
202
+ }
144
203
  /**
145
204
  * Sets the high resolution flag. When true, the application will render at the device's
146
205
  * physical resolution. When false, the application will render at CSS resolution.
@@ -159,19 +218,196 @@ class AppElement extends AsyncElement {
159
218
  get highResolution() {
160
219
  return this._highResolution;
161
220
  }
221
+ /**
222
+ * Sets the stencil flag.
223
+ * @param value - The stencil flag.
224
+ */
225
+ set stencil(value) {
226
+ this._stencil = value;
227
+ }
228
+ /**
229
+ * Gets the stencil flag.
230
+ * @returns The stencil flag.
231
+ */
232
+ get stencil() {
233
+ return this._stencil;
234
+ }
162
235
  static get observedAttributes() {
163
- return ['high-resolution'];
236
+ return ['alpha', 'antialias', 'depth', 'stencil', 'high-resolution'];
164
237
  }
165
- attributeChangedCallback(name, _oldValue, _newValue) {
238
+ attributeChangedCallback(name, _oldValue, newValue) {
166
239
  switch (name) {
240
+ case 'alpha':
241
+ this.alpha = newValue !== 'false';
242
+ break;
243
+ case 'antialias':
244
+ this.antialias = newValue !== 'false';
245
+ break;
246
+ case 'depth':
247
+ this.depth = newValue !== 'false';
248
+ break;
167
249
  case 'high-resolution':
168
- this.highResolution = this.hasAttribute(name);
250
+ this.highResolution = newValue !== 'false';
251
+ break;
252
+ case 'stencil':
253
+ this.stencil = newValue !== 'false';
169
254
  break;
170
255
  }
171
256
  }
172
257
  }
173
258
  customElements.define('pc-app', AppElement);
174
259
 
260
+ const CSS_COLORS = {
261
+ aliceblue: '#f0f8ff',
262
+ antiquewhite: '#faebd7',
263
+ aqua: '#00ffff',
264
+ aquamarine: '#7fffd4',
265
+ azure: '#f0ffff',
266
+ beige: '#f5f5dc',
267
+ bisque: '#ffe4c4',
268
+ black: '#000000',
269
+ blanchedalmond: '#ffebcd',
270
+ blue: '#0000ff',
271
+ blueviolet: '#8a2be2',
272
+ brown: '#a52a2a',
273
+ burlywood: '#deb887',
274
+ cadetblue: '#5f9ea0',
275
+ chartreuse: '#7fff00',
276
+ chocolate: '#d2691e',
277
+ coral: '#ff7f50',
278
+ cornflowerblue: '#6495ed',
279
+ cornsilk: '#fff8dc',
280
+ crimson: '#dc143c',
281
+ cyan: '#00ffff',
282
+ darkblue: '#00008b',
283
+ darkcyan: '#008b8b',
284
+ darkgoldenrod: '#b8860b',
285
+ darkgray: '#a9a9a9',
286
+ darkgreen: '#006400',
287
+ darkgrey: '#a9a9a9',
288
+ darkkhaki: '#bdb76b',
289
+ darkmagenta: '#8b008b',
290
+ darkolivegreen: '#556b2f',
291
+ darkorange: '#ff8c00',
292
+ darkorchid: '#9932cc',
293
+ darkred: '#8b0000',
294
+ darksalmon: '#e9967a',
295
+ darkseagreen: '#8fbc8f',
296
+ darkslateblue: '#483d8b',
297
+ darkslategray: '#2f4f4f',
298
+ darkslategrey: '#2f4f4f',
299
+ darkturquoise: '#00ced1',
300
+ darkviolet: '#9400d3',
301
+ deeppink: '#ff1493',
302
+ deepskyblue: '#00bfff',
303
+ dimgray: '#696969',
304
+ dimgrey: '#696969',
305
+ dodgerblue: '#1e90ff',
306
+ firebrick: '#b22222',
307
+ floralwhite: '#fffaf0',
308
+ forestgreen: '#228b22',
309
+ fuchsia: '#ff00ff',
310
+ gainsboro: '#dcdcdc',
311
+ ghostwhite: '#f8f8ff',
312
+ gold: '#ffd700',
313
+ goldenrod: '#daa520',
314
+ gray: '#808080',
315
+ green: '#008000',
316
+ greenyellow: '#adff2f',
317
+ grey: '#808080',
318
+ honeydew: '#f0fff0',
319
+ hotpink: '#ff69b4',
320
+ indianred: '#cd5c5c',
321
+ indigo: '#4b0082',
322
+ ivory: '#fffff0',
323
+ khaki: '#f0e68c',
324
+ lavender: '#e6e6fa',
325
+ lavenderblush: '#fff0f5',
326
+ lawngreen: '#7cfc00',
327
+ lemonchiffon: '#fffacd',
328
+ lightblue: '#add8e6',
329
+ lightcoral: '#f08080',
330
+ lightcyan: '#e0ffff',
331
+ lightgoldenrodyellow: '#fafad2',
332
+ lightgray: '#d3d3d3',
333
+ lightgreen: '#90ee90',
334
+ lightgrey: '#d3d3d3',
335
+ lightpink: '#ffb6c1',
336
+ lightsalmon: '#ffa07a',
337
+ lightseagreen: '#20b2aa',
338
+ lightskyblue: '#87cefa',
339
+ lightslategray: '#778899',
340
+ lightslategrey: '#778899',
341
+ lightsteelblue: '#b0c4de',
342
+ lightyellow: '#ffffe0',
343
+ lime: '#00ff00',
344
+ limegreen: '#32cd32',
345
+ linen: '#faf0e6',
346
+ magenta: '#ff00ff',
347
+ maroon: '#800000',
348
+ mediumaquamarine: '#66cdaa',
349
+ mediumblue: '#0000cd',
350
+ mediumorchid: '#ba55d3',
351
+ mediumpurple: '#9370db',
352
+ mediumseagreen: '#3cb371',
353
+ mediumslateblue: '#7b68ee',
354
+ mediumspringgreen: '#00fa9a',
355
+ mediumturquoise: '#48d1cc',
356
+ mediumvioletred: '#c71585',
357
+ midnightblue: '#191970',
358
+ mintcream: '#f5fffa',
359
+ mistyrose: '#ffe4e1',
360
+ moccasin: '#ffe4b5',
361
+ navajowhite: '#ffdead',
362
+ navy: '#000080',
363
+ oldlace: '#fdf5e6',
364
+ olive: '#808000',
365
+ olivedrab: '#6b8e23',
366
+ orange: '#ffa500',
367
+ orangered: '#ff4500',
368
+ orchid: '#da70d6',
369
+ palegoldenrod: '#eee8aa',
370
+ palegreen: '#98fb98',
371
+ paleturquoise: '#afeeee',
372
+ palevioletred: '#db7093',
373
+ papayawhip: '#ffefd5',
374
+ peachpuff: '#ffdab9',
375
+ peru: '#cd853f',
376
+ pink: '#ffc0cb',
377
+ plum: '#dda0dd',
378
+ powderblue: '#b0e0e6',
379
+ purple: '#800080',
380
+ rebeccapurple: '#663399',
381
+ red: '#ff0000',
382
+ rosybrown: '#bc8f8f',
383
+ royalblue: '#4169e1',
384
+ saddlebrown: '#8b4513',
385
+ salmon: '#fa8072',
386
+ sandybrown: '#f4a460',
387
+ seagreen: '#2e8b57',
388
+ seashell: '#fff5ee',
389
+ sienna: '#a0522d',
390
+ silver: '#c0c0c0',
391
+ skyblue: '#87ceeb',
392
+ slateblue: '#6a5acd',
393
+ slategray: '#708090',
394
+ slategrey: '#708090',
395
+ snow: '#fffafa',
396
+ springgreen: '#00ff7f',
397
+ steelblue: '#4682b4',
398
+ tan: '#d2b48c',
399
+ teal: '#008080',
400
+ thistle: '#d8bfd8',
401
+ tomato: '#ff6347',
402
+ turquoise: '#40e0d0',
403
+ violet: '#ee82ee',
404
+ wheat: '#f5deb3',
405
+ white: '#ffffff',
406
+ whitesmoke: '#f5f5f5',
407
+ yellow: '#ffff00',
408
+ yellowgreen: '#9acd32'
409
+ };
410
+
175
411
  /**
176
412
  * Parse a color string into a Color object. String can be in the format of '#rgb', '#rgba',
177
413
  * '#rrggbb', '#rrggbbaa', or a string of 3 or 4 comma-delimited numbers.
@@ -180,10 +416,15 @@ customElements.define('pc-app', AppElement);
180
416
  * @returns The parsed Color object.
181
417
  */
182
418
  const parseColor = (value) => {
419
+ // Check if it's a CSS color name first
420
+ const hexColor = CSS_COLORS[value.toLowerCase()];
421
+ if (hexColor) {
422
+ return new Color().fromString(hexColor);
423
+ }
183
424
  if (value.startsWith('#')) {
184
425
  return new Color().fromString(value);
185
426
  }
186
- const components = value.split(',').map(Number);
427
+ const components = value.split(' ').map(Number);
187
428
  return new Color(components);
188
429
  };
189
430
  /**
@@ -193,7 +434,7 @@ const parseColor = (value) => {
193
434
  * @returns The parsed Quat object.
194
435
  */
195
436
  const parseQuat = (value) => {
196
- const [x, y, z] = value.split(',').map(Number);
437
+ const [x, y, z] = value.split(' ').map(Number);
197
438
  const q = new Quat();
198
439
  q.setFromEulerAngles(x, y, z);
199
440
  return q;
@@ -205,7 +446,7 @@ const parseQuat = (value) => {
205
446
  * @returns The parsed Vec2 object.
206
447
  */
207
448
  const parseVec2 = (value) => {
208
- const components = value.split(',').map(Number);
449
+ const components = value.split(' ').map(Number);
209
450
  return new Vec2(components);
210
451
  };
211
452
  /**
@@ -215,7 +456,7 @@ const parseVec2 = (value) => {
215
456
  * @returns The parsed Vec3 object.
216
457
  */
217
458
  const parseVec3 = (value) => {
218
- const components = value.split(',').map(Number);
459
+ const components = value.split(' ').map(Number);
219
460
  return new Vec3(components);
220
461
  };
221
462
  /**
@@ -225,7 +466,7 @@ const parseVec3 = (value) => {
225
466
  * @returns The parsed Vec4 object.
226
467
  */
227
468
  const parseVec4 = (value) => {
228
- const components = value.split(',').map(Number);
469
+ const components = value.split(' ').map(Number);
229
470
  return new Vec4(components);
230
471
  };
231
472
 
@@ -2243,6 +2484,9 @@ class ScreenComponentElement extends ComponentElement {
2243
2484
  }
2244
2485
  customElements.define('pc-screen', ScreenComponentElement);
2245
2486
 
2487
+ const tmpV2 = new Vec2();
2488
+ const tmpV3 = new Vec3();
2489
+ const tmpV4 = new Vec4();
2246
2490
  /**
2247
2491
  * Represents a script component in the PlayCanvas engine.
2248
2492
  *
@@ -2272,9 +2516,39 @@ class ScriptComponentElement extends ComponentElement {
2272
2516
  }
2273
2517
  applyAttributes(script, attributes) {
2274
2518
  try {
2275
- // Parse the attributes string into an object and set them on the script
2276
2519
  const attributesObject = attributes ? JSON.parse(attributes) : {};
2277
- Object.assign(script, attributesObject);
2520
+ const applyValue = (target, key, value) => {
2521
+ // Handle vectors
2522
+ if (Array.isArray(value)) {
2523
+ if (target[key] instanceof Vec2) {
2524
+ target[key] = tmpV2.set(value[0], value[1]);
2525
+ return;
2526
+ }
2527
+ if (target[key] instanceof Vec3) {
2528
+ target[key] = tmpV3.set(value[0], value[1], value[2]);
2529
+ return;
2530
+ }
2531
+ if (target[key] instanceof Vec4) {
2532
+ target[key] = tmpV4.set(value[0], value[1], value[2], value[3]);
2533
+ return;
2534
+ }
2535
+ }
2536
+ // Handle nested objects
2537
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
2538
+ if (!target[key] || typeof target[key] !== 'object') {
2539
+ target[key] = {};
2540
+ }
2541
+ for (const nestedKey in value) {
2542
+ applyValue(target[key], nestedKey, value[nestedKey]);
2543
+ }
2544
+ }
2545
+ else {
2546
+ target[key] = value;
2547
+ }
2548
+ };
2549
+ for (const key in attributesObject) {
2550
+ applyValue(script, key, attributesObject[key]);
2551
+ }
2278
2552
  }
2279
2553
  catch (error) {
2280
2554
  console.error(`Error parsing attributes JSON string ${attributes}:`, error);
@@ -2438,14 +2712,22 @@ customElements.define('pc-script', ScriptElement);
2438
2712
  class SoundComponentElement extends ComponentElement {
2439
2713
  constructor() {
2440
2714
  super('sound');
2715
+ this._distanceModel = 'linear';
2716
+ this._maxDistance = 10000;
2441
2717
  this._pitch = 1;
2442
2718
  this._positional = false;
2719
+ this._refDistance = 1;
2720
+ this._rollOffFactor = 1;
2443
2721
  this._volume = 1;
2444
2722
  }
2445
2723
  getInitialComponentData() {
2446
2724
  return {
2725
+ distanceModel: this._distanceModel,
2726
+ maxDistance: this._maxDistance,
2447
2727
  pitch: this._pitch,
2448
2728
  positional: this._positional,
2729
+ refDistance: this._refDistance,
2730
+ rollOffFactor: this._rollOffFactor,
2449
2731
  volume: this._volume
2450
2732
  };
2451
2733
  }
@@ -2456,6 +2738,40 @@ class SoundComponentElement extends ComponentElement {
2456
2738
  get component() {
2457
2739
  return super.component;
2458
2740
  }
2741
+ /**
2742
+ * Sets which algorithm to use to reduce the volume of the sound as it moves away from the listener.
2743
+ * @param value - The distance model.
2744
+ */
2745
+ set distanceModel(value) {
2746
+ this._distanceModel = value;
2747
+ if (this.component) {
2748
+ this.component.distanceModel = value;
2749
+ }
2750
+ }
2751
+ /**
2752
+ * Gets which algorithm to use to reduce the volume of the sound as it moves away from the listener.
2753
+ * @returns The distance model.
2754
+ */
2755
+ get distanceModel() {
2756
+ return this._distanceModel;
2757
+ }
2758
+ /**
2759
+ * Sets the maximum distance from the listener at which audio falloff stops.
2760
+ * @param value - The max distance.
2761
+ */
2762
+ set maxDistance(value) {
2763
+ this._maxDistance = value;
2764
+ if (this.component) {
2765
+ this.component.maxDistance = value;
2766
+ }
2767
+ }
2768
+ /**
2769
+ * Gets the maximum distance from the listener at which audio falloff stops.
2770
+ * @returns The max distance.
2771
+ */
2772
+ get maxDistance() {
2773
+ return this._maxDistance;
2774
+ }
2459
2775
  /**
2460
2776
  * Sets the pitch of the sound.
2461
2777
  * @param value - The pitch.
@@ -2490,6 +2806,40 @@ class SoundComponentElement extends ComponentElement {
2490
2806
  get positional() {
2491
2807
  return this._positional;
2492
2808
  }
2809
+ /**
2810
+ * Sets the reference distance for reducing volume as the sound source moves further from the listener. Defaults to 1.
2811
+ * @param value - The ref distance.
2812
+ */
2813
+ set refDistance(value) {
2814
+ this._refDistance = value;
2815
+ if (this.component) {
2816
+ this.component.refDistance = value;
2817
+ }
2818
+ }
2819
+ /**
2820
+ * Gets the reference distance for reducing volume as the sound source moves further from the listener.
2821
+ * @returns The ref distance.
2822
+ */
2823
+ get refDistance() {
2824
+ return this._refDistance;
2825
+ }
2826
+ /**
2827
+ * Sets the factor used in the falloff equation. Defaults to 1.
2828
+ * @param value - The roll-off factor.
2829
+ */
2830
+ set rollOffFactor(value) {
2831
+ this._rollOffFactor = value;
2832
+ if (this.component) {
2833
+ this.component.rollOffFactor = value;
2834
+ }
2835
+ }
2836
+ /**
2837
+ * Gets the factor used in the falloff equation.
2838
+ * @returns The roll-off factor.
2839
+ */
2840
+ get rollOffFactor() {
2841
+ return this._rollOffFactor;
2842
+ }
2493
2843
  /**
2494
2844
  * Sets the volume of the sound.
2495
2845
  * @param value - The volume.
@@ -2508,17 +2858,38 @@ class SoundComponentElement extends ComponentElement {
2508
2858
  return this._volume;
2509
2859
  }
2510
2860
  static get observedAttributes() {
2511
- return [...super.observedAttributes, 'pitch', 'positional', 'volume'];
2861
+ return [
2862
+ ...super.observedAttributes,
2863
+ 'distance-model',
2864
+ 'max-distance',
2865
+ 'pitch',
2866
+ 'positional',
2867
+ 'ref-distance',
2868
+ 'roll-off-factor',
2869
+ 'volume'
2870
+ ];
2512
2871
  }
2513
2872
  attributeChangedCallback(name, _oldValue, newValue) {
2514
2873
  super.attributeChangedCallback(name, _oldValue, newValue);
2515
2874
  switch (name) {
2875
+ case 'distance-model':
2876
+ this.distanceModel = newValue;
2877
+ break;
2878
+ case 'max-distance':
2879
+ this.maxDistance = parseFloat(newValue);
2880
+ break;
2516
2881
  case 'pitch':
2517
2882
  this.pitch = parseFloat(newValue);
2518
2883
  break;
2519
2884
  case 'positional':
2520
2885
  this.positional = this.hasAttribute('positional');
2521
2886
  break;
2887
+ case 'ref-distance':
2888
+ this.refDistance = parseFloat(newValue);
2889
+ break;
2890
+ case 'roll-off-factor':
2891
+ this.rollOffFactor = parseFloat(newValue);
2892
+ break;
2522
2893
  case 'volume':
2523
2894
  this.volume = parseFloat(newValue);
2524
2895
  break;
@@ -2775,48 +3146,71 @@ class ModelElement extends AsyncElement {
2775
3146
  constructor() {
2776
3147
  super(...arguments);
2777
3148
  this._asset = '';
3149
+ this._entity = null;
2778
3150
  }
2779
- async connectedCallback() {
2780
- var _a;
2781
- await ((_a = this.closestApp) === null || _a === void 0 ? void 0 : _a.ready());
2782
- const asset = this.getAttribute('asset');
2783
- if (asset) {
2784
- this.asset = asset;
2785
- }
3151
+ connectedCallback() {
3152
+ this._loadModel();
2786
3153
  this._onReady();
2787
3154
  }
2788
- _loadModel() {
2789
- const asset = AssetElement.get(this._asset);
2790
- if (!asset) {
2791
- return;
2792
- }
2793
- const entity = asset.resource.instantiateRenderEntity();
2794
- if (asset.resource.animations.length > 0) {
2795
- entity.addComponent('anim');
2796
- entity.anim.assignAnimation('animation', asset.resource.animations[0].resource);
3155
+ disconnectedCallback() {
3156
+ this._unloadModel();
3157
+ }
3158
+ _instantiate(container) {
3159
+ this._entity = container.instantiateRenderEntity();
3160
+ // @ts-ignore
3161
+ if (container.animations.length > 0) {
3162
+ this._entity.addComponent('anim');
3163
+ // @ts-ignore
3164
+ this._entity.anim.assignAnimation('animation', container.animations[0].resource);
2797
3165
  }
2798
3166
  const parentEntityElement = this.closestEntity;
2799
3167
  if (parentEntityElement) {
2800
3168
  parentEntityElement.ready().then(() => {
2801
- parentEntityElement.entity.addChild(entity);
3169
+ parentEntityElement.entity.addChild(this._entity);
2802
3170
  });
2803
3171
  }
2804
3172
  else {
2805
3173
  const appElement = this.closestApp;
2806
3174
  if (appElement) {
2807
3175
  appElement.ready().then(() => {
2808
- appElement.app.root.addChild(entity);
3176
+ appElement.app.root.addChild(this._entity);
2809
3177
  });
2810
3178
  }
2811
3179
  }
2812
3180
  }
3181
+ async _loadModel() {
3182
+ var _a;
3183
+ this._unloadModel();
3184
+ const appElement = await ((_a = this.closestApp) === null || _a === void 0 ? void 0 : _a.ready());
3185
+ const app = appElement === null || appElement === void 0 ? void 0 : appElement.app;
3186
+ const asset = AssetElement.get(this._asset);
3187
+ if (!asset) {
3188
+ return;
3189
+ }
3190
+ if (asset.loaded) {
3191
+ this._instantiate(asset.resource);
3192
+ }
3193
+ else {
3194
+ asset.once('load', () => {
3195
+ this._instantiate(asset.resource);
3196
+ });
3197
+ app.assets.load(asset);
3198
+ }
3199
+ }
3200
+ _unloadModel() {
3201
+ var _a;
3202
+ (_a = this._entity) === null || _a === void 0 ? void 0 : _a.destroy();
3203
+ this._entity = null;
3204
+ }
2813
3205
  /**
2814
3206
  * Sets the asset ID of the model.
2815
3207
  * @param value - The asset ID.
2816
3208
  */
2817
3209
  set asset(value) {
2818
3210
  this._asset = value;
2819
- this._loadModel();
3211
+ if (this.isConnected) {
3212
+ this._loadModel();
3213
+ }
2820
3214
  }
2821
3215
  /**
2822
3216
  * Gets the source URL of the model.
@@ -3008,48 +3402,76 @@ class SkyElement extends AsyncElement {
3008
3402
  this._intensity = 1;
3009
3403
  this._rotation = new Vec3();
3010
3404
  this._level = 0;
3405
+ this._lighting = false;
3011
3406
  this._scale = new Vec3(100, 100, 100);
3012
3407
  this._type = 'infinite';
3408
+ this._scene = null;
3013
3409
  }
3014
- async connectedCallback() {
3015
- var _a;
3016
- await ((_a = this.closestApp) === null || _a === void 0 ? void 0 : _a.ready());
3017
- this.asset = this.getAttribute('asset') || '';
3410
+ connectedCallback() {
3411
+ this._loadSkybox();
3018
3412
  this._onReady();
3019
3413
  }
3020
- getScene() {
3021
- const app = this.closestApp.app;
3022
- if (!app) {
3023
- return;
3024
- }
3025
- return app.scene;
3414
+ disconnectedCallback() {
3415
+ this._unloadSkybox();
3026
3416
  }
3027
- initSkybox(source) {
3417
+ _generateSkybox(asset) {
3418
+ if (!this._scene)
3419
+ return;
3420
+ const source = asset.resource;
3028
3421
  source.anisotropy = 4;
3029
3422
  const skybox = EnvLighting.generateSkyboxCubemap(source);
3030
- const lighting = EnvLighting.generateLightingSource(source);
3031
- const envAtlas = EnvLighting.generateAtlas(lighting);
3032
- const app = this.closestApp.app;
3033
- if (app) {
3034
- app.scene.envAtlas = envAtlas;
3035
- app.scene.skybox = skybox;
3036
- const layer = app.scene.layers.getLayerById(LAYERID_SKYBOX);
3037
- if (layer) {
3038
- layer.enabled = this._type !== 'none';
3039
- }
3040
- app.scene.sky.type = this._type;
3041
- app.scene.sky.node.setLocalScale(this._scale);
3042
- app.scene.sky.center = this._center;
3423
+ this._scene.skybox = skybox;
3424
+ if (this._lighting) {
3425
+ const lighting = EnvLighting.generateLightingSource(source);
3426
+ const envAtlas = EnvLighting.generateAtlas(lighting);
3427
+ this._scene.envAtlas = envAtlas;
3043
3428
  }
3429
+ const layer = this._scene.layers.getLayerById(LAYERID_SKYBOX);
3430
+ if (layer) {
3431
+ layer.enabled = this._type !== 'none';
3432
+ }
3433
+ this._scene.sky.type = this._type;
3434
+ this._scene.sky.node.setLocalScale(this._scale);
3435
+ this._scene.sky.center = this._center;
3436
+ }
3437
+ async _loadSkybox() {
3438
+ var _a;
3439
+ const appElement = await ((_a = this.closestApp) === null || _a === void 0 ? void 0 : _a.ready());
3440
+ const app = appElement === null || appElement === void 0 ? void 0 : appElement.app;
3441
+ if (!app) {
3442
+ return;
3443
+ }
3444
+ const asset = AssetElement.get(this._asset);
3445
+ if (!asset) {
3446
+ return;
3447
+ }
3448
+ this._scene = app.scene;
3449
+ if (asset.loaded) {
3450
+ this._generateSkybox(asset);
3451
+ }
3452
+ else {
3453
+ asset.once('load', () => {
3454
+ this._generateSkybox(asset);
3455
+ });
3456
+ app.assets.load(asset);
3457
+ }
3458
+ }
3459
+ _unloadSkybox() {
3460
+ var _a, _b;
3461
+ if (!this._scene)
3462
+ return;
3463
+ (_a = this._scene.skybox) === null || _a === void 0 ? void 0 : _a.destroy();
3464
+ // @ts-ignore
3465
+ this._scene.skybox = null;
3466
+ (_b = this._scene.envAtlas) === null || _b === void 0 ? void 0 : _b.destroy();
3467
+ // @ts-ignore
3468
+ this._scene.envAtlas = null;
3469
+ this._scene = null;
3044
3470
  }
3045
3471
  set asset(value) {
3046
3472
  this._asset = value;
3047
- const scene = this.getScene();
3048
- if (scene) {
3049
- const asset = AssetElement.get(value);
3050
- if (asset) {
3051
- this.initSkybox(asset.resource);
3052
- }
3473
+ if (this.isConnected) {
3474
+ this._loadSkybox();
3053
3475
  }
3054
3476
  }
3055
3477
  get asset() {
@@ -3057,9 +3479,8 @@ class SkyElement extends AsyncElement {
3057
3479
  }
3058
3480
  set center(value) {
3059
3481
  this._center = value;
3060
- const scene = this.getScene();
3061
- if (scene) {
3062
- scene.sky.center = this._center;
3482
+ if (this._scene) {
3483
+ this._scene.sky.center = this._center;
3063
3484
  }
3064
3485
  }
3065
3486
  get center() {
@@ -3067,19 +3488,32 @@ class SkyElement extends AsyncElement {
3067
3488
  }
3068
3489
  set intensity(value) {
3069
3490
  this._intensity = value;
3070
- const scene = this.getScene();
3071
- if (scene) {
3072
- scene.skyboxIntensity = this._intensity;
3491
+ if (this._scene) {
3492
+ this._scene.skyboxIntensity = this._intensity;
3073
3493
  }
3074
3494
  }
3075
3495
  get intensity() {
3076
3496
  return this._intensity;
3077
3497
  }
3498
+ set level(value) {
3499
+ this._level = value;
3500
+ if (this._scene) {
3501
+ this._scene.skyboxMip = this._level;
3502
+ }
3503
+ }
3504
+ get level() {
3505
+ return this._level;
3506
+ }
3507
+ set lighting(value) {
3508
+ this._lighting = value;
3509
+ }
3510
+ get lighting() {
3511
+ return this._lighting;
3512
+ }
3078
3513
  set rotation(value) {
3079
3514
  this._rotation = value;
3080
- const scene = this.getScene();
3081
- if (scene) {
3082
- scene.skyboxRotation = new Quat().setFromEulerAngles(value);
3515
+ if (this._scene) {
3516
+ this._scene.skyboxRotation = new Quat().setFromEulerAngles(value);
3083
3517
  }
3084
3518
  }
3085
3519
  get rotation() {
@@ -3087,30 +3521,18 @@ class SkyElement extends AsyncElement {
3087
3521
  }
3088
3522
  set scale(value) {
3089
3523
  this._scale = value;
3090
- const scene = this.getScene();
3091
- if (scene) {
3092
- scene.sky.node.setLocalScale(this._scale);
3524
+ if (this._scene) {
3525
+ this._scene.sky.node.setLocalScale(this._scale);
3093
3526
  }
3094
3527
  }
3095
3528
  get scale() {
3096
3529
  return this._scale;
3097
3530
  }
3098
- set level(value) {
3099
- this._level = value;
3100
- const scene = this.getScene();
3101
- if (scene) {
3102
- scene.skyboxMip = this._level;
3103
- }
3104
- }
3105
- get level() {
3106
- return this._level;
3107
- }
3108
3531
  set type(value) {
3109
3532
  this._type = value;
3110
- const scene = this.getScene();
3111
- if (scene) {
3112
- scene.sky.type = this._type;
3113
- const layer = scene.layers.getLayerById(LAYERID_SKYBOX);
3533
+ if (this._scene) {
3534
+ this._scene.sky.type = this._type;
3535
+ const layer = this._scene.layers.getLayerById(LAYERID_SKYBOX);
3114
3536
  if (layer) {
3115
3537
  layer.enabled = this._type !== 'none';
3116
3538
  }
@@ -3120,7 +3542,7 @@ class SkyElement extends AsyncElement {
3120
3542
  return this._type;
3121
3543
  }
3122
3544
  static get observedAttributes() {
3123
- return ['asset', 'center', 'intensity', 'level', 'rotation', 'scale', 'type'];
3545
+ return ['asset', 'center', 'intensity', 'level', 'lighting', 'rotation', 'scale', 'type'];
3124
3546
  }
3125
3547
  attributeChangedCallback(name, _oldValue, newValue) {
3126
3548
  switch (name) {
@@ -3133,12 +3555,15 @@ class SkyElement extends AsyncElement {
3133
3555
  case 'intensity':
3134
3556
  this.intensity = parseFloat(newValue);
3135
3557
  break;
3136
- case 'rotation':
3137
- this.rotation = parseVec3(newValue);
3138
- break;
3139
3558
  case 'level':
3140
3559
  this.level = parseInt(newValue, 10);
3141
3560
  break;
3561
+ case 'lighting':
3562
+ this.lighting = this.hasAttribute(name);
3563
+ break;
3564
+ case 'rotation':
3565
+ this.rotation = parseVec3(newValue);
3566
+ break;
3142
3567
  case 'scale':
3143
3568
  this.scale = parseVec3(newValue);
3144
3569
  break;