@playcanvas/web-components 0.1.9 → 0.1.10

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.js CHANGED
@@ -101,6 +101,20 @@
101
101
  this._stencil = true;
102
102
  this._highResolution = false;
103
103
  this._hierarchyReady = false;
104
+ this._picker = null;
105
+ this._hasPointerListeners = {
106
+ pointerenter: false,
107
+ pointerleave: false,
108
+ pointerdown: false,
109
+ pointerup: false,
110
+ pointermove: false
111
+ };
112
+ this._hoveredEntity = null;
113
+ this._pointerHandlers = {
114
+ pointermove: null,
115
+ pointerdown: null,
116
+ pointerup: null
117
+ };
104
118
  /**
105
119
  * The PlayCanvas application instance.
106
120
  */
@@ -130,6 +144,7 @@
130
144
  this.app.graphicsDevice.maxPixelRatio = this._highResolution ? window.devicePixelRatio : 1;
131
145
  this.app.setCanvasFillMode(playcanvas.FILLMODE_FILL_WINDOW);
132
146
  this.app.setCanvasResolution(playcanvas.RESOLUTION_AUTO);
147
+ this._pickerCreate();
133
148
  // Get all pc-asset elements that are direct children of the pc-app element
134
149
  const assetElements = this.querySelectorAll(':scope > pc-asset');
135
150
  Array.from(assetElements).forEach((assetElement) => {
@@ -164,6 +179,7 @@
164
179
  });
165
180
  }
166
181
  disconnectedCallback() {
182
+ this._pickerDestroy();
167
183
  // Clean up the application
168
184
  if (this.app) {
169
185
  this.app.destroy();
@@ -182,6 +198,139 @@
182
198
  this.app.resizeCanvas();
183
199
  }
184
200
  }
201
+ _pickerCreate() {
202
+ const { width, height } = this.app.graphicsDevice;
203
+ this._picker = new playcanvas.Picker(this.app, width, height);
204
+ // Create bound handlers but don't attach them yet
205
+ this._pointerHandlers.pointermove = this._onPointerMove.bind(this);
206
+ this._pointerHandlers.pointerdown = this._onPointerDown.bind(this);
207
+ this._pointerHandlers.pointerup = this._onPointerUp.bind(this);
208
+ // Listen for pointer listeners being added/removed
209
+ ['pointermove', 'pointerdown', 'pointerup', 'pointerenter', 'pointerleave'].forEach((type) => {
210
+ this.addEventListener(`${type}:connect`, () => this._onPointerListenerAdded(type));
211
+ this.addEventListener(`${type}:disconnect`, () => this._onPointerListenerRemoved(type));
212
+ });
213
+ }
214
+ _pickerDestroy() {
215
+ if (this._canvas) {
216
+ Object.entries(this._pointerHandlers).forEach(([type, handler]) => {
217
+ if (handler) {
218
+ this._canvas.removeEventListener(type, handler);
219
+ }
220
+ });
221
+ }
222
+ this._picker = null;
223
+ this._pointerHandlers = {
224
+ pointermove: null,
225
+ pointerdown: null,
226
+ pointerup: null
227
+ };
228
+ }
229
+ _onPointerMove(event) {
230
+ if (!this._picker || !this.app)
231
+ return;
232
+ const camera = this.app.root.findComponent('camera');
233
+ if (!camera)
234
+ return;
235
+ const canvasRect = this._canvas.getBoundingClientRect();
236
+ const x = event.clientX - canvasRect.left;
237
+ const y = event.clientY - canvasRect.top;
238
+ this._picker.prepare(camera, this.app.scene);
239
+ const selection = this._picker.getSelection(x, y);
240
+ // Get the currently hovered entity by walking up the hierarchy
241
+ let newHoverEntity = null;
242
+ if (selection.length > 0) {
243
+ let node = selection[0].node;
244
+ while (node && !newHoverEntity) {
245
+ const entityElement = this.querySelector(`pc-entity[name="${node.name}"]`);
246
+ if (entityElement) {
247
+ newHoverEntity = entityElement;
248
+ }
249
+ node = node.parent;
250
+ }
251
+ }
252
+ // Handle enter/leave events
253
+ if (this._hoveredEntity !== newHoverEntity) {
254
+ if (this._hoveredEntity && this._hoveredEntity.hasListeners('pointerleave')) {
255
+ this._hoveredEntity.dispatchEvent(new PointerEvent('pointerleave', event));
256
+ }
257
+ if (newHoverEntity && newHoverEntity.hasListeners('pointerenter')) {
258
+ newHoverEntity.dispatchEvent(new PointerEvent('pointerenter', event));
259
+ }
260
+ }
261
+ // Update hover state
262
+ this._hoveredEntity = newHoverEntity;
263
+ // Handle pointermove event
264
+ if (newHoverEntity && newHoverEntity.hasListeners('pointermove')) {
265
+ newHoverEntity.dispatchEvent(new PointerEvent('pointermove', event));
266
+ }
267
+ }
268
+ _onPointerDown(event) {
269
+ if (!this._picker || !this.app)
270
+ return;
271
+ const camera = this.app.root.findComponent('camera');
272
+ if (!camera)
273
+ return;
274
+ const canvasRect = this._canvas.getBoundingClientRect();
275
+ const x = event.clientX - canvasRect.left;
276
+ const y = event.clientY - canvasRect.top;
277
+ this._picker.prepare(camera, this.app.scene);
278
+ const selection = this._picker.getSelection(x, y);
279
+ if (selection.length > 0) {
280
+ let node = selection[0].node;
281
+ while (node) {
282
+ const entityElement = this.querySelector(`pc-entity[name="${node.name}"]`);
283
+ if (entityElement && entityElement.hasListeners('pointerdown')) {
284
+ entityElement.dispatchEvent(new PointerEvent('pointerdown', event));
285
+ break;
286
+ }
287
+ node = node.parent;
288
+ }
289
+ }
290
+ }
291
+ _onPointerUp(event) {
292
+ if (!this._picker || !this.app)
293
+ return;
294
+ const camera = this.app.root.findComponent('camera');
295
+ if (!camera)
296
+ return;
297
+ const canvasRect = this._canvas.getBoundingClientRect();
298
+ const x = event.clientX - canvasRect.left;
299
+ const y = event.clientY - canvasRect.top;
300
+ this._picker.prepare(camera, this.app.scene);
301
+ const selection = this._picker.getSelection(x, y);
302
+ if (selection.length > 0) {
303
+ const entityElement = this.querySelector(`pc-entity[name="${selection[0].node.name}"]`);
304
+ if (entityElement && entityElement.hasListeners('pointerup')) {
305
+ entityElement.dispatchEvent(new PointerEvent('pointerup', event));
306
+ }
307
+ }
308
+ }
309
+ _onPointerListenerAdded(type) {
310
+ if (!this._hasPointerListeners[type] && this._canvas) {
311
+ this._hasPointerListeners[type] = true;
312
+ // For enter/leave events, we need the move handler
313
+ const handler = (type === 'pointerenter' || type === 'pointerleave') ?
314
+ this._pointerHandlers.pointermove :
315
+ this._pointerHandlers[type];
316
+ if (handler) {
317
+ this._canvas.addEventListener(type === 'pointerenter' || type === 'pointerleave' ? 'pointermove' : type, handler);
318
+ }
319
+ }
320
+ }
321
+ _onPointerListenerRemoved(type) {
322
+ const hasListeners = Array.from(this.querySelectorAll('pc-entity'))
323
+ .some(entity => entity.hasListeners(type));
324
+ if (!hasListeners && this._canvas) {
325
+ this._hasPointerListeners[type] = false;
326
+ const handler = (type === 'pointerenter' || type === 'pointerleave') ?
327
+ this._pointerHandlers.pointermove :
328
+ this._pointerHandlers[type];
329
+ if (handler) {
330
+ this._canvas.removeEventListener(type === 'pointerenter' || type === 'pointerleave' ? 'pointermove' : type, handler);
331
+ }
332
+ }
333
+ }
185
334
  /**
186
335
  * Sets the alpha flag.
187
336
  * @param value - The alpha flag.
@@ -534,6 +683,10 @@
534
683
  * The tags of the entity.
535
684
  */
536
685
  this._tags = [];
686
+ /**
687
+ * The pointer event listeners for the entity.
688
+ */
689
+ this._listeners = {};
537
690
  /**
538
691
  * The PlayCanvas entity instance.
539
692
  */
@@ -562,6 +715,30 @@
562
715
  if (tags) {
563
716
  this.entity.tags.add(tags.split(',').map(tag => tag.trim()));
564
717
  }
718
+ // Handle pointer events
719
+ const pointerEvents = [
720
+ 'onpointerenter',
721
+ 'onpointerleave',
722
+ 'onpointerdown',
723
+ 'onpointerup',
724
+ 'onpointermove'
725
+ ];
726
+ pointerEvents.forEach((eventName) => {
727
+ const handler = this.getAttribute(eventName);
728
+ if (handler) {
729
+ const eventType = eventName.substring(2); // remove 'on' prefix
730
+ const eventHandler = (event) => {
731
+ try {
732
+ /* eslint-disable-next-line no-new-func */
733
+ new Function('event', handler).call(this, event);
734
+ }
735
+ catch (e) {
736
+ console.error('Error in event handler:', e);
737
+ }
738
+ };
739
+ this.addEventListener(eventType, eventHandler);
740
+ }
741
+ });
565
742
  }
566
743
  buildHierarchy(app) {
567
744
  if (!this.entity)
@@ -711,7 +888,19 @@
711
888
  return this._tags;
712
889
  }
713
890
  static get observedAttributes() {
714
- return ['enabled', 'name', 'position', 'rotation', 'scale', 'tags'];
891
+ return [
892
+ 'enabled',
893
+ 'name',
894
+ 'position',
895
+ 'rotation',
896
+ 'scale',
897
+ 'tags',
898
+ 'onpointerenter',
899
+ 'onpointerleave',
900
+ 'onpointerdown',
901
+ 'onpointerup',
902
+ 'onpointermove'
903
+ ];
715
904
  }
716
905
  attributeChangedCallback(name, _oldValue, newValue) {
717
906
  switch (name) {
@@ -733,7 +922,51 @@
733
922
  case 'tags':
734
923
  this.tags = newValue.split(',').map(tag => tag.trim());
735
924
  break;
925
+ case 'onpointerenter':
926
+ case 'onpointerleave':
927
+ case 'onpointerdown':
928
+ case 'onpointerup':
929
+ case 'onpointermove':
930
+ if (newValue) {
931
+ const eventName = name.substring(2);
932
+ // Use Function.prototype.bind to avoid new Function
933
+ const handler = (event) => {
934
+ try {
935
+ const handlerStr = this.getAttribute(eventName) || '';
936
+ /* eslint-disable-next-line no-new-func */
937
+ new Function('event', handlerStr).call(this, event);
938
+ }
939
+ catch (e) {
940
+ console.error('Error in event handler:', e);
941
+ }
942
+ };
943
+ this.addEventListener(eventName, handler);
944
+ }
945
+ break;
946
+ }
947
+ }
948
+ addEventListener(type, listener, options) {
949
+ if (!this._listeners[type]) {
950
+ this._listeners[type] = [];
736
951
  }
952
+ this._listeners[type].push(listener);
953
+ super.addEventListener(type, listener, options);
954
+ if (type.startsWith('pointer')) {
955
+ this.dispatchEvent(new CustomEvent(`${type}:connect`, { bubbles: true }));
956
+ }
957
+ }
958
+ removeEventListener(type, listener, options) {
959
+ if (this._listeners[type]) {
960
+ this._listeners[type] = this._listeners[type].filter(l => l !== listener);
961
+ }
962
+ super.removeEventListener(type, listener, options);
963
+ if (type.startsWith('pointer')) {
964
+ this.dispatchEvent(new CustomEvent(`${type}:disconnect`, { bubbles: true }));
965
+ }
966
+ }
967
+ hasListeners(type) {
968
+ var _a;
969
+ return Boolean((_a = this._listeners[type]) === null || _a === void 0 ? void 0 : _a.length);
737
970
  }
738
971
  }
739
972
  customElements.define('pc-entity', EntityElement);
@@ -929,6 +1162,15 @@
929
1162
  }
930
1163
  customElements.define('pc-listener', ListenerComponentElement);
931
1164
 
1165
+ const tonemaps = new Map([
1166
+ ['none', playcanvas.TONEMAP_NONE],
1167
+ ['linear', playcanvas.TONEMAP_LINEAR],
1168
+ ['filmic', playcanvas.TONEMAP_FILMIC],
1169
+ ['hejl', playcanvas.TONEMAP_HEJL],
1170
+ ['aces', playcanvas.TONEMAP_ACES],
1171
+ ['aces2', playcanvas.TONEMAP_ACES2],
1172
+ ['neutral', playcanvas.TONEMAP_NEUTRAL]
1173
+ ]);
932
1174
  /**
933
1175
  * The CameraComponentElement interface provides properties and methods for manipulating
934
1176
  * `<pc-camera>` elements. The CameraComponentElement interface also inherits the properties and
@@ -949,12 +1191,14 @@
949
1191
  this._flipFaces = false;
950
1192
  this._fov = 45;
951
1193
  this._frustumCulling = true;
1194
+ this._gamma = 'srgb';
952
1195
  this._nearClip = 0.1;
953
1196
  this._orthographic = false;
954
1197
  this._orthoHeight = 10;
955
1198
  this._priority = 0;
956
1199
  this._rect = new playcanvas.Vec4(0, 0, 1, 1);
957
1200
  this._scissorRect = new playcanvas.Vec4(0, 0, 1, 1);
1201
+ this._tonemap = 'none';
958
1202
  }
959
1203
  getInitialComponentData() {
960
1204
  return {
@@ -967,12 +1211,14 @@
967
1211
  flipFaces: this._flipFaces,
968
1212
  fov: this._fov,
969
1213
  frustumCulling: this._frustumCulling,
1214
+ gammaCorrection: this._gamma === 'srgb' ? playcanvas.GAMMA_SRGB : playcanvas.GAMMA_NONE,
970
1215
  nearClip: this._nearClip,
971
1216
  orthographic: this._orthographic,
972
1217
  orthoHeight: this._orthoHeight,
973
1218
  priority: this._priority,
974
1219
  rect: this._rect,
975
- scissorRect: this._scissorRect
1220
+ scissorRect: this._scissorRect,
1221
+ toneMapping: tonemaps.get(this._tonemap)
976
1222
  };
977
1223
  }
978
1224
  get xrAvailable() {
@@ -1155,6 +1401,23 @@
1155
1401
  get frustumCulling() {
1156
1402
  return this._frustumCulling;
1157
1403
  }
1404
+ /**
1405
+ * Sets the gamma correction of the camera.
1406
+ * @param value - The gamma correction.
1407
+ */
1408
+ set gamma(value) {
1409
+ this._gamma = value;
1410
+ if (this.component) {
1411
+ this.component.gammaCorrection = value === 'srgb' ? playcanvas.GAMMA_SRGB : playcanvas.GAMMA_NONE;
1412
+ }
1413
+ }
1414
+ /**
1415
+ * Gets the gamma correction of the camera.
1416
+ * @returns The gamma correction.
1417
+ */
1418
+ get gamma() {
1419
+ return this._gamma;
1420
+ }
1158
1421
  /**
1159
1422
  * Sets the near clip distance of the camera.
1160
1423
  * @param value - The near clip distance.
@@ -1257,6 +1520,24 @@
1257
1520
  get scissorRect() {
1258
1521
  return this._scissorRect;
1259
1522
  }
1523
+ /**
1524
+ * Sets the tone mapping of the camera.
1525
+ * @param value - The tone mapping.
1526
+ */
1527
+ set tonemap(value) {
1528
+ var _a;
1529
+ this._tonemap = value;
1530
+ if (this.component) {
1531
+ this.component.toneMapping = (_a = tonemaps.get(value)) !== null && _a !== void 0 ? _a : playcanvas.TONEMAP_NONE;
1532
+ }
1533
+ }
1534
+ /**
1535
+ * Gets the tone mapping of the camera.
1536
+ * @returns The tone mapping.
1537
+ */
1538
+ get tonemap() {
1539
+ return this._tonemap;
1540
+ }
1260
1541
  static get observedAttributes() {
1261
1542
  return [
1262
1543
  ...super.observedAttributes,
@@ -1269,12 +1550,14 @@
1269
1550
  'flip-faces',
1270
1551
  'fov',
1271
1552
  'frustum-culling',
1553
+ 'gamma',
1272
1554
  'near-clip',
1273
1555
  'orthographic',
1274
1556
  'ortho-height',
1275
1557
  'priority',
1276
1558
  'rect',
1277
- 'scissor-rect'
1559
+ 'scissor-rect',
1560
+ 'tonemap'
1278
1561
  ];
1279
1562
  }
1280
1563
  attributeChangedCallback(name, _oldValue, newValue) {
@@ -1307,6 +1590,9 @@
1307
1590
  case 'frustum-culling':
1308
1591
  this.frustumCulling = newValue !== 'false';
1309
1592
  break;
1593
+ case 'gamma':
1594
+ this.gamma = newValue;
1595
+ break;
1310
1596
  case 'near-clip':
1311
1597
  this.nearClip = parseFloat(newValue);
1312
1598
  break;
@@ -1325,6 +1611,9 @@
1325
1611
  case 'scissor-rect':
1326
1612
  this.scissorRect = parseVec4(newValue);
1327
1613
  break;
1614
+ case 'tonemap':
1615
+ this.tonemap = newValue;
1616
+ break;
1328
1617
  }
1329
1618
  }
1330
1619
  }
@@ -1738,6 +2027,17 @@
1738
2027
  }
1739
2028
  customElements.define('pc-splat', GSplatComponentElement);
1740
2029
 
2030
+ const shadowTypes = new Map([
2031
+ ['pcf1-16f', playcanvas.SHADOW_PCF1_16F],
2032
+ ['pcf1-32f', playcanvas.SHADOW_PCF1_32F],
2033
+ ['pcf3-16f', playcanvas.SHADOW_PCF3_16F],
2034
+ ['pcf3-32f', playcanvas.SHADOW_PCF3_32F],
2035
+ ['pcf5-16f', playcanvas.SHADOW_PCF5_16F],
2036
+ ['pcf5-32f', playcanvas.SHADOW_PCF5_32F],
2037
+ ['vsm-16f', playcanvas.SHADOW_VSM_16F],
2038
+ ['vsm-32f', playcanvas.SHADOW_VSM_32F],
2039
+ ['pcss-32f', playcanvas.SHADOW_PCSS_32F]
2040
+ ]);
1741
2041
  /**
1742
2042
  * The LightComponentElement interface provides properties and methods for manipulating
1743
2043
  * `<pc-light>` elements. The LightComponentElement interface also inherits the properties and
@@ -1758,8 +2058,11 @@
1758
2058
  this._range = 10;
1759
2059
  this._shadowBias = 0.2;
1760
2060
  this._shadowDistance = 16;
2061
+ this._shadowIntensity = 1;
1761
2062
  this._shadowResolution = 1024;
2063
+ this._shadowType = 'pcf3-32f';
1762
2064
  this._type = 'directional';
2065
+ this._vsmBias = 0.01;
1763
2066
  }
1764
2067
  getInitialComponentData() {
1765
2068
  return {
@@ -1772,8 +2075,11 @@
1772
2075
  range: this._range,
1773
2076
  shadowBias: this._shadowBias,
1774
2077
  shadowDistance: this._shadowDistance,
2078
+ shadowIntensity: this._shadowIntensity,
1775
2079
  shadowResolution: this._shadowResolution,
1776
- type: this._type
2080
+ shadowType: shadowTypes.get(this._shadowType),
2081
+ type: this._type,
2082
+ vsmBias: this._vsmBias
1777
2083
  };
1778
2084
  }
1779
2085
  /**
@@ -1936,6 +2242,23 @@
1936
2242
  get shadowDistance() {
1937
2243
  return this._shadowDistance;
1938
2244
  }
2245
+ /**
2246
+ * Sets the shadow intensity of the light.
2247
+ * @param value - The shadow intensity.
2248
+ */
2249
+ set shadowIntensity(value) {
2250
+ this._shadowIntensity = value;
2251
+ if (this.component) {
2252
+ this.component.shadowIntensity = value;
2253
+ }
2254
+ }
2255
+ /**
2256
+ * Gets the shadow intensity of the light.
2257
+ * @returns The shadow intensity.
2258
+ */
2259
+ get shadowIntensity() {
2260
+ return this._shadowIntensity;
2261
+ }
1939
2262
  /**
1940
2263
  * Sets the shadow resolution of the light.
1941
2264
  * @param value - The shadow resolution.
@@ -1953,6 +2276,34 @@
1953
2276
  get shadowResolution() {
1954
2277
  return this._shadowResolution;
1955
2278
  }
2279
+ /**
2280
+ * Sets the shadow type of the light.
2281
+ * @param value - The shadow type. Can be:
2282
+ *
2283
+ * - `pcf1-16f` - 1-tap percentage-closer filtered shadow map with 16-bit depth.
2284
+ * - `pcf1-32f` - 1-tap percentage-closer filtered shadow map with 32-bit depth.
2285
+ * - `pcf3-16f` - 3-tap percentage-closer filtered shadow map with 16-bit depth.
2286
+ * - `pcf3-32f` - 3-tap percentage-closer filtered shadow map with 32-bit depth.
2287
+ * - `pcf5-16f` - 5-tap percentage-closer filtered shadow map with 16-bit depth.
2288
+ * - `pcf5-32f` - 5-tap percentage-closer filtered shadow map with 32-bit depth.
2289
+ * - `vsm-16f` - Variance shadow map with 16-bit depth.
2290
+ * - `vsm-32f` - Variance shadow map with 32-bit depth.
2291
+ * - `pcss-32f` - Percentage-closer soft shadow with 32-bit depth.
2292
+ */
2293
+ set shadowType(value) {
2294
+ var _a;
2295
+ this._shadowType = value;
2296
+ if (this.component) {
2297
+ this.component.shadowType = (_a = shadowTypes.get(value)) !== null && _a !== void 0 ? _a : playcanvas.SHADOW_PCF3_32F;
2298
+ }
2299
+ }
2300
+ /**
2301
+ * Gets the shadow type of the light.
2302
+ * @returns The shadow type.
2303
+ */
2304
+ get shadowType() {
2305
+ return this._shadowType;
2306
+ }
1956
2307
  /**
1957
2308
  * Sets the type of the light.
1958
2309
  * @param value - The type.
@@ -1974,6 +2325,23 @@
1974
2325
  get type() {
1975
2326
  return this._type;
1976
2327
  }
2328
+ /**
2329
+ * Sets the VSM bias of the light.
2330
+ * @param value - The VSM bias.
2331
+ */
2332
+ set vsmBias(value) {
2333
+ this._vsmBias = value;
2334
+ if (this.component) {
2335
+ this.component.vsmBias = value;
2336
+ }
2337
+ }
2338
+ /**
2339
+ * Gets the VSM bias of the light.
2340
+ * @returns The VSM bias.
2341
+ */
2342
+ get vsmBias() {
2343
+ return this._vsmBias;
2344
+ }
1977
2345
  static get observedAttributes() {
1978
2346
  return [
1979
2347
  ...super.observedAttributes,
@@ -1986,8 +2354,11 @@
1986
2354
  'range',
1987
2355
  'shadow-bias',
1988
2356
  'shadow-distance',
2357
+ 'shadow-intensity',
1989
2358
  'shadow-resolution',
1990
- 'type'
2359
+ 'shadow-type',
2360
+ 'type',
2361
+ 'vsm-bias'
1991
2362
  ];
1992
2363
  }
1993
2364
  attributeChangedCallback(name, _oldValue, newValue) {
@@ -2023,9 +2394,18 @@
2023
2394
  case 'shadow-resolution':
2024
2395
  this.shadowResolution = Number(newValue);
2025
2396
  break;
2397
+ case 'shadow-intensity':
2398
+ this.shadowIntensity = Number(newValue);
2399
+ break;
2400
+ case 'shadow-type':
2401
+ this.shadowType = newValue;
2402
+ break;
2026
2403
  case 'type':
2027
2404
  this.type = newValue;
2028
2405
  break;
2406
+ case 'vsm-bias':
2407
+ this.vsmBias = Number(newValue);
2408
+ break;
2029
2409
  }
2030
2410
  }
2031
2411
  }
@@ -2048,8 +2428,8 @@
2048
2428
  }
2049
2429
  createMaterial() {
2050
2430
  this.material = new playcanvas.StandardMaterial();
2051
- this.material.glossInvert = true;
2052
- this.material.useMetalness = true;
2431
+ this.material.glossInvert = false;
2432
+ this.material.useMetalness = false;
2053
2433
  this.material.diffuse = this._diffuse;
2054
2434
  this.diffuseMap = this._diffuseMap;
2055
2435
  this.metalnessMap = this._metalnessMap;
@@ -2582,9 +2962,6 @@
2582
2962
  }
2583
2963
  customElements.define('pc-screen', ScreenComponentElement);
2584
2964
 
2585
- const tmpV2 = new playcanvas.Vec2();
2586
- const tmpV3 = new playcanvas.Vec3();
2587
- const tmpV4 = new playcanvas.Vec4();
2588
2965
  /**
2589
2966
  * The ScriptComponentElement interface provides properties and methods for manipulating
2590
2967
  * `<pc-scripts>` elements. The ScriptComponentElement interface also inherits the properties and
@@ -2628,22 +3005,34 @@
2628
3005
  return;
2629
3006
  }
2630
3007
  }
2631
- // Handle vectors
2632
- if (Array.isArray(value)) {
2633
- if (target[key] instanceof playcanvas.Vec2) {
2634
- target[key] = tmpV2.set(value[0], value[1]);
3008
+ // Handle arrays
3009
+ if (value && typeof value === 'object' && Array.isArray(value)) {
3010
+ // If it's an array of objects, recursively apply to each object
3011
+ if (value.length > 0 && typeof value[0] === 'object') {
3012
+ target[key] = value.map((item) => {
3013
+ const obj = {};
3014
+ for (const itemKey in item) {
3015
+ applyValue(obj, itemKey, item[itemKey]);
3016
+ }
3017
+ return obj;
3018
+ });
3019
+ return;
3020
+ }
3021
+ // Handle vectors
3022
+ if (value.length === 2 && typeof value[0] === 'number') {
3023
+ target[key] = new playcanvas.Vec2(value[0], value[1]);
2635
3024
  return;
2636
3025
  }
2637
- if (target[key] instanceof playcanvas.Vec3) {
2638
- target[key] = tmpV3.set(value[0], value[1], value[2]);
3026
+ if (value.length === 3 && typeof value[0] === 'number') {
3027
+ target[key] = new playcanvas.Vec3(value[0], value[1], value[2]);
2639
3028
  return;
2640
3029
  }
2641
- if (target[key] instanceof playcanvas.Vec4) {
2642
- target[key] = tmpV4.set(value[0], value[1], value[2], value[3]);
3030
+ if (value.length === 4 && typeof value[0] === 'number') {
3031
+ target[key] = new playcanvas.Vec4(value[0], value[1], value[2], value[3]);
2643
3032
  return;
2644
3033
  }
2645
3034
  }
2646
- // Handle nested objects
3035
+ // Handle nested objects (non-array)
2647
3036
  if (value && typeof value === 'object' && !Array.isArray(value)) {
2648
3037
  if (!target[key] || typeof target[key] !== 'object') {
2649
3038
  target[key] = {};