@playcanvas/web-components 0.11.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +1 -1
  2. package/dist/app.d.cts +246 -0
  3. package/dist/app.d.ts +38 -13
  4. package/dist/asset.d.cts +218 -0
  5. package/dist/asset.d.ts +145 -6
  6. package/dist/async-element.d.cts +103 -0
  7. package/dist/async-element.d.ts +11 -8
  8. package/dist/colors.d.cts +1 -0
  9. package/dist/components/button-component.d.cts +186 -0
  10. package/dist/components/button-component.d.ts +1 -1
  11. package/dist/components/camera-component.d.cts +253 -0
  12. package/dist/components/camera-component.d.ts +1 -1
  13. package/dist/components/collision-component.d.cts +73 -0
  14. package/dist/components/collision-component.d.ts +17 -1
  15. package/dist/components/component.d.cts +82 -0
  16. package/dist/components/component.d.ts +20 -1
  17. package/dist/components/element-component.d.cts +316 -0
  18. package/dist/components/element-component.d.ts +1 -1
  19. package/dist/components/gsplat-component.d.cts +108 -0
  20. package/dist/components/gsplat-component.d.ts +1 -1
  21. package/dist/components/layoutchild-component.d.cts +110 -0
  22. package/dist/components/layoutchild-component.d.ts +1 -1
  23. package/dist/components/layoutgroup-component.d.cts +136 -0
  24. package/dist/components/layoutgroup-component.d.ts +1 -1
  25. package/dist/components/light-component.d.cts +264 -0
  26. package/dist/components/light-component.d.ts +1 -1
  27. package/dist/components/listener-component.d.cts +20 -0
  28. package/dist/components/listener-component.d.ts +1 -1
  29. package/dist/components/particlesystem-component.d.cts +52 -0
  30. package/dist/components/particlesystem-component.d.ts +1 -1
  31. package/dist/components/render-component.d.cts +76 -0
  32. package/dist/components/render-component.d.ts +1 -1
  33. package/dist/components/rigidbody-component.d.cts +88 -0
  34. package/dist/components/rigidbody-component.d.ts +1 -1
  35. package/dist/components/screen-component.d.cts +70 -0
  36. package/dist/components/screen-component.d.ts +1 -1
  37. package/dist/components/script-component.d.cts +163 -0
  38. package/dist/components/script-component.d.ts +1 -1
  39. package/dist/components/script.d.cts +94 -0
  40. package/dist/components/script.d.ts +1 -1
  41. package/dist/components/scrollbar-component.d.cts +69 -0
  42. package/dist/components/scrollbar-component.d.ts +1 -1
  43. package/dist/components/scrollview-component.d.cts +178 -0
  44. package/dist/components/scrollview-component.d.ts +1 -1
  45. package/dist/components/sound-component.d.cts +108 -0
  46. package/dist/components/sound-component.d.ts +1 -1
  47. package/dist/components/sound-slot.d.cts +134 -0
  48. package/dist/components/sound-slot.d.ts +2 -2
  49. package/dist/custom-elements.json +1127 -179
  50. package/dist/entity-base.d.cts +67 -0
  51. package/dist/entity-base.d.ts +67 -0
  52. package/dist/entity.d.cts +131 -0
  53. package/dist/entity.d.ts +3 -38
  54. package/dist/index.d.cts +79 -0
  55. package/dist/index.d.ts +35 -32
  56. package/dist/loading-bar.d.cts +35 -0
  57. package/dist/material.d.cts +1011 -0
  58. package/dist/material.d.ts +2 -1
  59. package/dist/model.d.cts +72 -0
  60. package/dist/model.d.ts +27 -5
  61. package/dist/module.d.cts +29 -0
  62. package/dist/module.d.ts +16 -10
  63. package/dist/node.d.cts +253 -0
  64. package/dist/node.d.ts +253 -0
  65. package/dist/parse.d.cts +147 -0
  66. package/dist/pwc.cjs +1496 -200
  67. package/dist/pwc.cjs.map +1 -1
  68. package/dist/pwc.js +1497 -201
  69. package/dist/pwc.js.map +1 -1
  70. package/dist/pwc.min.js +1 -1
  71. package/dist/pwc.min.js.map +1 -1
  72. package/dist/pwc.min.mjs +1 -1
  73. package/dist/pwc.min.mjs.map +1 -1
  74. package/dist/pwc.mjs +1496 -202
  75. package/dist/pwc.mjs.map +1 -1
  76. package/dist/scene.d.cts +117 -0
  77. package/dist/scene.d.ts +1 -1
  78. package/dist/sky.d.cts +121 -0
  79. package/dist/sky.d.ts +1 -1
  80. package/dist/vscode.html-custom-data.json +127 -5
  81. package/dist/web-types.json +399 -59
  82. package/package.json +16 -7
  83. package/src/app.ts +137 -45
  84. package/src/asset.ts +439 -9
  85. package/src/async-element.ts +11 -8
  86. package/src/components/collision-component.ts +35 -0
  87. package/src/components/component.ts +93 -3
  88. package/src/entity-base.ts +136 -0
  89. package/src/entity.ts +23 -117
  90. package/src/index.ts +5 -0
  91. package/src/loading-bar.ts +2 -2
  92. package/src/material.ts +2 -2
  93. package/src/model.ts +79 -11
  94. package/src/module.ts +39 -20
  95. package/src/node.ts +715 -0
  96. package/src/sky.ts +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcanvas/web-components",
3
- "version": "0.11.1",
3
+ "version": "0.13.0",
4
4
  "author": "PlayCanvas <support@playcanvas.com>",
5
5
  "homepage": "https://playcanvas.com",
6
6
  "description": "Web Components for the PlayCanvas Engine",
@@ -32,14 +32,23 @@
32
32
  "web-types": "dist/web-types.json",
33
33
  "exports": {
34
34
  ".": {
35
- "types": "./dist/index.d.ts",
36
- "import": "./dist/pwc.mjs",
37
- "require": "./dist/pwc.cjs"
35
+ "import": {
36
+ "types": "./dist/index.d.ts",
37
+ "default": "./dist/pwc.mjs"
38
+ },
39
+ "require": {
40
+ "types": "./dist/index.d.cts",
41
+ "default": "./dist/pwc.cjs"
42
+ }
38
43
  },
39
44
  "./dist/*": "./dist/*",
40
45
  "./package.json": "./package.json"
41
46
  },
42
47
  "type": "module",
48
+ "sideEffects": true,
49
+ "engines": {
50
+ "node": ">=18.3.0"
51
+ },
43
52
  "files": [
44
53
  "dist",
45
54
  "src"
@@ -47,7 +56,7 @@
47
56
  "scripts": {
48
57
  "prebuild": "node -e \"fs.rmSync('dist', { recursive: true, force: true })\"",
49
58
  "build": "rollup -c",
50
- "postbuild": "npm run cem",
59
+ "postbuild": "node utils/fix-declarations.mjs && npm run cem",
51
60
  "cem": "cem analyze && node utils/cem/validate.mjs",
52
61
  "dev": "concurrently \"npm run watch\" \"npm run serve\"",
53
62
  "docs": "typedoc",
@@ -89,9 +98,9 @@
89
98
  "eslint": "9.39.5",
90
99
  "globals": "17.9.0",
91
100
  "jsdom": "30.0.1",
92
- "mediabunny": "1.52.3",
101
+ "mediabunny": "1.53.0",
93
102
  "opentype.js": "2.0.0",
94
- "playcanvas": "2.21.3",
103
+ "playcanvas": "2.22.0-beta.12",
95
104
  "prettier": "3.9.6",
96
105
  "publint": "0.3.23",
97
106
  "rollup": "4.62.4",
package/src/app.ts CHANGED
@@ -1,10 +1,10 @@
1
- import type { CameraComponent, GraphNode, GSplatComponent, Entity } from 'playcanvas';
1
+ import type { CameraComponent, GraphicsDevice, GraphNode, GSplatComponent, Entity } from 'playcanvas';
2
2
  import {
3
3
  AppBase,
4
4
  AppOptions,
5
5
  createGraphicsDevice,
6
6
  ElementInput,
7
- FILLMODE_FILL_WINDOW,
7
+ FILLMODE_NONE,
8
8
  Keyboard,
9
9
  Mouse,
10
10
  Picker,
@@ -67,6 +67,7 @@ import {
67
67
  import type { AssetElement } from './asset';
68
68
  import { AsyncElement } from './async-element';
69
69
  import type { EntityElement } from './entity';
70
+ import type { EntityBaseElement } from './entity-base';
70
71
  import { LoadingBar } from './loading-bar';
71
72
  import type { MaterialElement } from './material';
72
73
  import type { ModuleElement } from './module';
@@ -75,16 +76,45 @@ import { parseBool, parseEnum, parseNumber } from './parse';
75
76
  /** The pointer event types the application synthesizes on `<pc-entity>` elements via picking. */
76
77
  const pointerEventTypes = ['pointermove', 'pointerdown', 'pointerup', 'pointerenter', 'pointerleave'] as const;
77
78
 
79
+ /**
80
+ * Gives `pc-app` the sizing contract of a replaced element (`<video>`, `<img>`): a block-level
81
+ * box that the page's CSS sizes, defaulting to the canvas's own 300x150 intrinsic size, with the
82
+ * canvas and loading bar anchored to it. `:where()` keeps every declaration at zero specificity,
83
+ * so any page rule - however plain - overrides these defaults.
84
+ */
85
+ const ensureBaseStyles = () => {
86
+ const id = 'pc-app-styles';
87
+ if (document.getElementById(id)) {
88
+ return;
89
+ }
90
+ const style = document.createElement('style');
91
+ style.id = id;
92
+ style.textContent = ':where(pc-app) { display: block; position: relative; width: 300px; height: 150px; }';
93
+ document.head.appendChild(style);
94
+ };
95
+
78
96
  /**
79
97
  * The AppElement interface provides properties and methods for manipulating
80
98
  * {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-app/ | `<pc-app>`} elements.
81
99
  * The AppElement interface also inherits the properties and methods of the
82
100
  * {@link HTMLElement} interface.
83
101
  *
102
+ * The element is sized like a replaced element such as `<video>`: a block-level box that the
103
+ * page's CSS controls, 300x150 by default. The application's canvas always fills the element,
104
+ * and the drawing buffer resolution follows the element's size (capped by `max-pixel-ratio`),
105
+ * tracked live via a ResizeObserver — so the element can be embedded at any size, resized by
106
+ * its container, or made fullscreen with ordinary CSS such as `width: 100vw; height: 100dvh`.
107
+ *
84
108
  * @fires {ProgressEvent} progress - Fired while the application preloads its assets. `loaded` and
85
109
  * `total` are asset counts, not bytes, and an asset that fails to load still counts as loaded.
86
110
  * Fired at least once per boot, and the final event always has `loaded` equal to `total`. Does
87
111
  * not bubble.
112
+ *
113
+ * @fires {ErrorEvent} error - Fired when the application cannot boot because no graphics device
114
+ * could be created (for example, a browser with WebGL disabled). `message` names the requested
115
+ * backends and `error` holds the underlying failure. The element never becomes ready
116
+ * and `app` stays `null` — listen for this event to show a fallback UI. Removing the element and
117
+ * re-inserting it retries the boot with its current attributes. Does not bubble.
88
118
  */
89
119
  class AppElement extends AsyncElement {
90
120
  /**
@@ -133,10 +163,11 @@ class AppElement extends AsyncElement {
133
163
 
134
164
  /**
135
165
  * The elements backing this application's entities, keyed by the entity itself. Registered
136
- * by EntityElement at creation and removed when an entity is destroyed, this joins engine
137
- * scene nodes back to their owning elements by identity - never by name.
166
+ * by EntityElement at creation (and NodeElement at binding) and removed when an entity is
167
+ * destroyed or unbound, this joins engine scene nodes back to their owning elements by
168
+ * identity - never by name.
138
169
  */
139
- private _entityElements = new Map<GraphNode, EntityElement>();
170
+ private _entityElements = new Map<GraphNode, EntityBaseElement>();
140
171
 
141
172
  private _picker: Picker | null = null;
142
173
 
@@ -148,7 +179,7 @@ class AppElement extends AsyncElement {
148
179
  pointermove: false
149
180
  };
150
181
 
151
- private _hoveredEntity: EntityElement | null = null;
182
+ private _hoveredEntity: EntityBaseElement | null = null;
152
183
 
153
184
  // Identifies the newest in-flight hover pick, so out-of-order results can be discarded
154
185
  private _pickToken = 0;
@@ -163,6 +194,13 @@ class AppElement extends AsyncElement {
163
194
 
164
195
  private _loadProgress = 0;
165
196
 
197
+ /**
198
+ * Tracks the element's box so the drawing buffer and picker follow it. Created per boot once
199
+ * the application exists, and disconnected on teardown. `null` where ResizeObserver is
200
+ * unavailable (jsdom), where the boot-time resolution set is the only sizing that happens.
201
+ */
202
+ private _resizeObserver: ResizeObserver | null = null;
203
+
166
204
  /**
167
205
  * The PlayCanvas application instance. `null` until the element is ready, and again once it
168
206
  * has been removed from the document — await {@link whenReady} or the element's `ready()`
@@ -192,9 +230,6 @@ class AppElement extends AsyncElement {
192
230
  constructor() {
193
231
  super();
194
232
 
195
- // Bind methods to maintain 'this' context
196
- this._onWindowResize = this._onWindowResize.bind(this);
197
-
198
233
  // Track pointer listeners being added to and removed from descendant entities.
199
234
  // Registered once here rather than on every boot - the handlers no-op while there is no
200
235
  // canvas, and a re-booted element must not stack a second set.
@@ -207,6 +242,10 @@ class AppElement extends AsyncElement {
207
242
  async connectedCallback() {
208
243
  const generation = ++this._bootGeneration;
209
244
 
245
+ // Installed before the loading bar is created: the bar anchors to this element, which
246
+ // these styles make a positioned block box
247
+ ensureBaseStyles();
248
+
210
249
  // Created before the first await, so the bar is visible while modules and the graphics
211
250
  // device are created, and exists before any disconnect could need to clean it up
212
251
  if (this._loadingBar && !this._bar) {
@@ -225,8 +264,11 @@ class AppElement extends AsyncElement {
225
264
  return;
226
265
  }
227
266
 
228
- // Create and append the canvas to the element
267
+ // Create and append the canvas, filling the element's content box - the page sizes the
268
+ // element, and everything else follows. touch-action: none keeps touch drags driving the
269
+ // engine's input handlers instead of scrolling the page.
229
270
  this._canvas = document.createElement('canvas');
271
+ this._canvas.style.cssText = 'display: block; width: 100%; height: 100%; touch-action: none;';
230
272
  this.appendChild(this._canvas);
231
273
 
232
274
  // Configure device types based on backend selection
@@ -239,14 +281,46 @@ class AppElement extends AsyncElement {
239
281
 
240
282
  this._optionsLocked = true;
241
283
 
242
- const device = await createGraphicsDevice(this._canvas, {
243
- // @ts-ignore - alpha needs to be documented
244
- alpha: this._alpha,
245
- antialias: this._antialias,
246
- depth: this._depthBuffer,
247
- deviceTypes: deviceTypes,
248
- stencil: this._stencilBuffer
249
- });
284
+ // createGraphicsDevice appends its final null-device fallback to the array in place, so
285
+ // the requested list is captured now for the failure message.
286
+ const requested = deviceTypes.join(', ');
287
+
288
+ let device: GraphicsDevice;
289
+ try {
290
+ device = await createGraphicsDevice(this._canvas, {
291
+ // @ts-ignore - alpha needs to be documented
292
+ alpha: this._alpha,
293
+ antialias: this._antialias,
294
+ depth: this._depthBuffer,
295
+ deviceTypes: deviceTypes,
296
+ stencil: this._stencilBuffer
297
+ });
298
+ } catch (error) {
299
+ // The element may have been removed while device creation was failing. The teardown
300
+ // has already cleaned up, and the failure belongs to a boot that no longer owns the
301
+ // element.
302
+ if (generation !== this._bootGeneration) {
303
+ return;
304
+ }
305
+
306
+ // Return the element to its pre-boot state - no dead canvas, no loading bar stuck at
307
+ // zero - before announcing the failure. Readiness deliberately stays pending: nothing
308
+ // it would announce (the app, the entity hierarchy) exists, so a device-less element
309
+ // joins the documented never-ready cases and the failure surfaces through the error
310
+ // event instead.
311
+ if (this._canvas && this.contains(this._canvas)) {
312
+ this.removeChild(this._canvas);
313
+ }
314
+ this._canvas = null;
315
+ this._bar?.destroy();
316
+ this._bar = null;
317
+
318
+ const reason = error instanceof Error ? error.message : String(error);
319
+ const message = `pc-app failed to create a graphics device (${requested}) - ${reason}`;
320
+ console.error(message, error);
321
+ this.dispatchEvent(new ErrorEvent('error', { message, error }));
322
+ return;
323
+ }
250
324
 
251
325
  // The element may have been removed while the device was created. disconnectedCallback
252
326
  // has already cleaned up the canvas; the device was created inside the await, so it is
@@ -330,11 +404,22 @@ class AppElement extends AsyncElement {
330
404
  this._app = app;
331
405
  app.init(createOptions);
332
406
 
333
- app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
407
+ // FILLMODE_NONE leaves the canvas's CSS sizing alone (the engine's other fill modes
408
+ // stamp window-derived pixel sizes onto it); RESOLUTION_AUTO sizes the drawing buffer
409
+ // from the canvas's client size
410
+ app.setCanvasFillMode(FILLMODE_NONE);
334
411
  app.setCanvasResolution(RESOLUTION_AUTO);
335
412
 
336
413
  this._pickerCreate();
337
414
 
415
+ // Track the element's box rather than the window: containers resize without any window
416
+ // event (splitter drags, flex reflow, animations). Guarded because jsdom has no
417
+ // ResizeObserver - there, the resolution set above is the only sizing that happens.
418
+ if (typeof ResizeObserver !== 'undefined') {
419
+ this._resizeObserver = new ResizeObserver(() => this._syncCanvasSize());
420
+ this._resizeObserver.observe(this);
421
+ }
422
+
338
423
  // Get all pc-asset elements that are direct children of the pc-app element
339
424
  const assetElements = this.querySelectorAll<AssetElement>(':scope > pc-asset');
340
425
  for (const assetElement of Array.from(assetElements)) {
@@ -424,9 +509,6 @@ class AppElement extends AsyncElement {
424
509
  // first rAF tick
425
510
  app.once('frameend', () => this._bar?.complete());
426
511
 
427
- // Handle window resize to keep the canvas responsive
428
- window.addEventListener('resize', this._onWindowResize);
429
-
430
512
  this._onReady();
431
513
  });
432
514
  }
@@ -456,8 +538,9 @@ class AppElement extends AsyncElement {
456
538
  this._hierarchyReady = false;
457
539
  this._resetReady();
458
540
 
459
- // Remove event listeners
460
- window.removeEventListener('resize', this._onWindowResize);
541
+ // Stop tracking the element's size
542
+ this._resizeObserver?.disconnect();
543
+ this._resizeObserver = null;
461
544
 
462
545
  // Remove the canvas
463
546
  if (this._canvas && this.contains(this._canvas)) {
@@ -466,10 +549,18 @@ class AppElement extends AsyncElement {
466
549
  }
467
550
  }
468
551
 
469
- private _onWindowResize() {
470
- if (this.app) {
471
- this.app.resizeCanvas();
552
+ /**
553
+ * Syncs the drawing buffer and the picker to the canvas's current CSS size. The picker must
554
+ * track the buffer, or picks would land at stale coordinates after a resize. Skipped while
555
+ * an XR session presents - the session owns the buffer size.
556
+ */
557
+ private _syncCanvasSize() {
558
+ if (!this.app || this.app.xr?.active) {
559
+ return;
472
560
  }
561
+ this.app.updateCanvasSize();
562
+ const { width, height } = this.app.graphicsDevice;
563
+ this._picker?.resize(width, height);
473
564
  }
474
565
 
475
566
  private _pickerCreate() {
@@ -493,8 +584,8 @@ class AppElement extends AsyncElement {
493
584
  // created from onpointer* attributes when their elements were first upgraded, or
494
585
  // listeners carried over from before a re-boot)
495
586
  pointerEventTypes.forEach((type) => {
496
- const anyListeners = Array.from(this.querySelectorAll<EntityElement>('pc-entity')).some((entity) =>
497
- entity._hasListeners(type)
587
+ const anyListeners = Array.from(this.querySelectorAll<EntityBaseElement>('pc-entity, pc-node')).some(
588
+ (entity) => entity._hasListeners(type)
498
589
  );
499
590
  if (anyListeners) {
500
591
  this._onPointerListenerAdded(type);
@@ -528,14 +619,14 @@ class AppElement extends AsyncElement {
528
619
  }
529
620
 
530
621
  /**
531
- * Registers the element that created an entity. Called by EntityElement when it creates its
532
- * entity.
622
+ * Registers the element that fronts an entity. Called by EntityElement when it creates its
623
+ * entity, and by NodeElement when it binds one.
533
624
  *
534
625
  * @param entity - The entity.
535
- * @param element - The element that created it.
626
+ * @param element - The element that fronts it.
536
627
  * @internal
537
628
  */
538
- _registerEntityElement(entity: Entity, element: EntityElement) {
629
+ _registerEntityElement(entity: Entity, element: EntityBaseElement) {
539
630
  this._entityElements.set(entity, element);
540
631
  }
541
632
 
@@ -550,27 +641,28 @@ class AppElement extends AsyncElement {
550
641
  }
551
642
 
552
643
  /**
553
- * Returns the `<pc-entity>` element whose backing entity is `entity`, or `null` if the
554
- * entity was not created by an element of this application - for example, a node inside a
555
- * model's instantiated hierarchy, or an entity created through the engine API.
644
+ * Returns the `<pc-entity>` or `<pc-node>` element whose backing entity is `entity`, or
645
+ * `null` if the entity is not fronted by an element of this application - for example, an
646
+ * unbound node inside a model's instantiated hierarchy, or an entity created through the
647
+ * engine API.
556
648
  *
557
649
  * @param entity - The entity to look up.
558
- * @returns The element backing the entity, or `null`.
650
+ * @returns The element fronting the entity, or `null`.
559
651
  */
560
- elementFromEntity(entity: Entity): EntityElement | null {
652
+ elementFromEntity(entity: Entity): EntityBaseElement | null {
561
653
  return this._entityElements.get(entity) ?? null;
562
654
  }
563
655
 
564
656
  /**
565
657
  * Resolves the element that owns a picked node: the nearest node up the parent chain -
566
- * starting with the node itself - that was created by a `<pc-entity>` of this application.
567
- * A hit inside a model's instantiated hierarchy therefore resolves to the element hosting
568
- * the model.
658
+ * starting with the node itself - that is fronted by a `<pc-entity>` or `<pc-node>` of this
659
+ * application. A hit inside a model's instantiated hierarchy therefore resolves to the
660
+ * nearest bound `<pc-node>`, or failing that the element hosting the model.
569
661
  *
570
662
  * @param node - The picked node, or `null`.
571
663
  * @returns The owning element, or `null`.
572
664
  */
573
- private _elementFromNode(node: GraphNode | null): EntityElement | null {
665
+ private _elementFromNode(node: GraphNode | null): EntityBaseElement | null {
574
666
  while (node !== null) {
575
667
  const element = this._entityElements.get(node);
576
668
  if (element) {
@@ -589,7 +681,7 @@ class AppElement extends AsyncElement {
589
681
  * @param type - The pointer event type a listener is required for.
590
682
  * @returns The nearest listening element, or `null`.
591
683
  */
592
- private _elementWithListener(node: GraphNode | null, type: string): EntityElement | null {
684
+ private _elementWithListener(node: GraphNode | null, type: string): EntityBaseElement | null {
593
685
  while (node !== null) {
594
686
  const element = this._entityElements.get(node);
595
687
  if (element?._hasListeners(type)) {
@@ -715,7 +807,7 @@ class AppElement extends AsyncElement {
715
807
  }
716
808
 
717
809
  private _onPointerListenerRemoved(type: string) {
718
- const hasListeners = Array.from(this.querySelectorAll<EntityElement>('pc-entity')).some((entity) =>
810
+ const hasListeners = Array.from(this.querySelectorAll<EntityBaseElement>('pc-entity, pc-node')).some((entity) =>
719
811
  entity._hasListeners(type)
720
812
  );
721
813
 
@@ -859,7 +951,7 @@ class AppElement extends AsyncElement {
859
951
  this._maxPixelRatio = value;
860
952
  if (this.app) {
861
953
  this.app.graphicsDevice.maxPixelRatio = value;
862
- this.app.resizeCanvas();
954
+ this._syncCanvasSize();
863
955
  }
864
956
  }
865
957