@playcanvas/web-components 0.17.0 → 0.18.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 (117) hide show
  1. package/README.md +5 -3
  2. package/dist/app.d.cts +4 -0
  3. package/dist/app.d.ts +4 -0
  4. package/dist/asset.d.cts +13 -3
  5. package/dist/asset.d.ts +13 -3
  6. package/dist/components/anim-clip.d.cts +4 -0
  7. package/dist/components/anim-clip.d.ts +4 -0
  8. package/dist/components/anim-component.d.cts +5 -0
  9. package/dist/components/anim-component.d.ts +5 -0
  10. package/dist/components/audio-listener-component.d.cts +4 -0
  11. package/dist/components/audio-listener-component.d.ts +4 -0
  12. package/dist/components/button-component.d.cts +5 -0
  13. package/dist/components/button-component.d.ts +5 -0
  14. package/dist/components/camera-component.d.cts +35 -1
  15. package/dist/components/camera-component.d.ts +35 -1
  16. package/dist/components/collision-component.d.cts +4 -0
  17. package/dist/components/collision-component.d.ts +4 -0
  18. package/dist/components/element-component.d.cts +4 -0
  19. package/dist/components/element-component.d.ts +4 -0
  20. package/dist/components/gsplat-component.d.cts +4 -0
  21. package/dist/components/gsplat-component.d.ts +4 -0
  22. package/dist/components/joint-component.d.cts +12 -2
  23. package/dist/components/joint-component.d.ts +12 -2
  24. package/dist/components/layout-child-component.d.cts +4 -0
  25. package/dist/components/layout-child-component.d.ts +4 -0
  26. package/dist/components/layout-group-component.d.cts +4 -0
  27. package/dist/components/layout-group-component.d.ts +4 -0
  28. package/dist/components/light-component.d.cts +50 -1
  29. package/dist/components/light-component.d.ts +50 -1
  30. package/dist/components/particle-system-component.d.cts +4 -0
  31. package/dist/components/particle-system-component.d.ts +4 -0
  32. package/dist/components/render-component.d.cts +5 -0
  33. package/dist/components/render-component.d.ts +5 -0
  34. package/dist/components/rigid-body-component.d.cts +5 -0
  35. package/dist/components/rigid-body-component.d.ts +5 -0
  36. package/dist/components/screen-component.d.cts +4 -0
  37. package/dist/components/screen-component.d.ts +4 -0
  38. package/dist/components/script-component.d.cts +3 -0
  39. package/dist/components/script-component.d.ts +3 -0
  40. package/dist/components/script-instance.d.cts +4 -0
  41. package/dist/components/script-instance.d.ts +4 -0
  42. package/dist/components/scroll-view-component.d.cts +4 -0
  43. package/dist/components/scroll-view-component.d.ts +4 -0
  44. package/dist/components/scrollbar-component.d.cts +4 -0
  45. package/dist/components/scrollbar-component.d.ts +4 -0
  46. package/dist/components/sound-component.d.cts +4 -0
  47. package/dist/components/sound-component.d.ts +4 -0
  48. package/dist/components/sound-slot.d.cts +3 -0
  49. package/dist/components/sound-slot.d.ts +3 -0
  50. package/dist/custom-elements.json +268 -7
  51. package/dist/entity-base.d.cts +1 -1
  52. package/dist/entity-base.d.ts +1 -1
  53. package/dist/entity-owner.d.cts +2 -2
  54. package/dist/entity-owner.d.ts +2 -2
  55. package/dist/entity.d.cts +6 -1
  56. package/dist/entity.d.ts +6 -1
  57. package/dist/index.d.cts +4 -1
  58. package/dist/index.d.ts +4 -1
  59. package/dist/material.d.cts +18 -7
  60. package/dist/material.d.ts +18 -7
  61. package/dist/model.d.cts +5 -0
  62. package/dist/model.d.ts +5 -0
  63. package/dist/node.d.cts +6 -1
  64. package/dist/node.d.ts +6 -1
  65. package/dist/pwc.cjs +284 -28
  66. package/dist/pwc.cjs.map +1 -1
  67. package/dist/pwc.js +284 -28
  68. package/dist/pwc.js.map +1 -1
  69. package/dist/pwc.min.js +1 -1
  70. package/dist/pwc.min.js.map +1 -1
  71. package/dist/pwc.min.mjs +1 -1
  72. package/dist/pwc.min.mjs.map +1 -1
  73. package/dist/pwc.mjs +285 -29
  74. package/dist/pwc.mjs.map +1 -1
  75. package/dist/scene.d.cts +3 -0
  76. package/dist/scene.d.ts +3 -0
  77. package/dist/sky.d.cts +4 -0
  78. package/dist/sky.d.ts +4 -0
  79. package/dist/vscode.html-custom-data.json +237 -62
  80. package/dist/wasm.d.cts +4 -0
  81. package/dist/wasm.d.ts +4 -0
  82. package/dist/web-types.json +115 -69
  83. package/package.json +1 -1
  84. package/src/app.ts +4 -0
  85. package/src/asset.ts +13 -4
  86. package/src/components/anim-clip.ts +4 -0
  87. package/src/components/anim-component.ts +5 -0
  88. package/src/components/audio-listener-component.ts +4 -0
  89. package/src/components/button-component.ts +5 -0
  90. package/src/components/camera-component.ts +63 -6
  91. package/src/components/collision-component.ts +4 -0
  92. package/src/components/element-component.ts +4 -0
  93. package/src/components/gsplat-component.ts +4 -0
  94. package/src/components/joint-component.ts +12 -2
  95. package/src/components/layout-child-component.ts +4 -0
  96. package/src/components/layout-group-component.ts +4 -0
  97. package/src/components/light-component.ts +108 -17
  98. package/src/components/particle-system-component.ts +4 -0
  99. package/src/components/render-component.ts +5 -0
  100. package/src/components/rigid-body-component.ts +5 -0
  101. package/src/components/screen-component.ts +4 -0
  102. package/src/components/script-component.ts +3 -0
  103. package/src/components/script-instance.ts +4 -0
  104. package/src/components/scroll-view-component.ts +4 -0
  105. package/src/components/scrollbar-component.ts +4 -0
  106. package/src/components/sound-component.ts +4 -0
  107. package/src/components/sound-slot.ts +3 -0
  108. package/src/entity-base.ts +2 -2
  109. package/src/entity-owner.ts +2 -2
  110. package/src/entity.ts +6 -1
  111. package/src/index.ts +12 -1
  112. package/src/material.ts +19 -8
  113. package/src/model.ts +5 -0
  114. package/src/node.ts +6 -1
  115. package/src/scene.ts +3 -0
  116. package/src/sky.ts +4 -0
  117. package/src/wasm.ts +4 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcanvas/web-components",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "author": "PlayCanvas <support@playcanvas.com>",
5
5
  "homepage": "https://playcanvas.com",
6
6
  "description": "Web Components for the PlayCanvas Engine",
package/src/app.ts CHANGED
@@ -112,6 +112,10 @@ const ensureBaseStyles = () => {
112
112
  * tracked live via a ResizeObserver — so the element can be embedded at any size, resized by
113
113
  * its container, or made fullscreen with ordinary CSS such as `width: 100vw; height: 100dvh`.
114
114
  *
115
+ * @elementSummary The `<pc-app>` element creates a PlayCanvas application and the canvas it renders
116
+ * into, and is the root of every scene. It holds the `<pc-asset>`, `<pc-material>`, `<pc-wasm>` and
117
+ * `<pc-scene>` elements, and the page's CSS sizes it, as it would a `<video>`.
118
+ *
115
119
  * @fires {ProgressEvent} progress - Fired while the application preloads its assets. `loaded` and
116
120
  * `total` are asset counts, not bytes, and an asset that fails to load still counts as loaded.
117
121
  * Fired at least once per boot, and the final event always has `loaded` equal to `total`. Does
package/src/asset.ts CHANGED
@@ -26,7 +26,8 @@ const renderModes = new Map<'simple' | 'sliced' | 'tiled', number>([
26
26
  ['tiled', SPRITE_RENDERMODE_TILED]
27
27
  ]);
28
28
 
29
- type AddressMode = 'repeat' | 'clamp' | 'mirror';
29
+ /** The addressing modes for a texture asset. */
30
+ export type AddressMode = 'repeat' | 'clamp' | 'mirror';
30
31
 
31
32
  const addressModes = new Map<AddressMode, number>([
32
33
  ['repeat', ADDRESS_REPEAT],
@@ -34,7 +35,8 @@ const addressModes = new Map<AddressMode, number>([
34
35
  ['mirror', ADDRESS_MIRRORED_REPEAT]
35
36
  ]);
36
37
 
37
- type MinFilterMode =
38
+ /** The minification filter modes for a texture asset. */
39
+ export type MinFilterMode =
38
40
  'nearest' | 'linear' | 'nearest-mip-nearest' | 'linear-mip-nearest' | 'nearest-mip-linear' | 'linear-mip-linear';
39
41
 
40
42
  const minFilterModes = new Map<MinFilterMode, number>([
@@ -46,8 +48,11 @@ const minFilterModes = new Map<MinFilterMode, number>([
46
48
  ['linear-mip-linear', FILTER_LINEAR_MIPMAP_LINEAR]
47
49
  ]);
48
50
 
49
- // Magnification has no mip variants - the engine (and the GPU) only accepts these two.
50
- type MagFilterMode = 'nearest' | 'linear';
51
+ /**
52
+ * The magnification filter modes for a texture asset. Magnification has no mip variants - the
53
+ * engine (and the GPU) only accepts these two.
54
+ */
55
+ export type MagFilterMode = 'nearest' | 'linear';
51
56
 
52
57
  const magFilterModes = new Map<MagFilterMode, number>([
53
58
  ['nearest', FILTER_NEAREST],
@@ -168,6 +173,10 @@ const processBufferView = (
168
173
  * Apart from `lazy` and the texture options, these attributes are read once when the asset is
169
174
  * created, so changing them later has no effect.
170
175
  *
176
+ * @elementSummary The `<pc-asset>` element declares an asset for the application to load — a model,
177
+ * texture, font, sound, script or JSON file — under an `id` that other elements reference. Must be
178
+ * a direct child of `<pc-app>`.
179
+ *
171
180
  * @attribute {string} id - The identifier used to reference the asset from other elements.
172
181
  * @attribute {string} src - The URL of the asset to load.
173
182
  * @attribute {string} type - The asset type. Inferred from the `src` file extension when omitted.
@@ -22,6 +22,10 @@ import { AnimComponentElement } from './anim-component';
22
22
  * named; in a multi-track source the track named `name` is chosen, falling back to the first
23
23
  * with a warning. The element becomes ready once its resolved track is assigned.
24
24
  *
25
+ * @elementSummary The `<pc-anim-clip>` element declares one named animation clip on its parent
26
+ * `<pc-anim>`, taken from the `asset` it names or, without one, from the enclosing `<pc-model>`'s
27
+ * own animations. Must be a direct child of `<pc-anim>`.
28
+ *
25
29
  * @category Components
26
30
  */
27
31
  class AnimClipElement extends AsyncElement {
@@ -48,6 +48,11 @@ type PlaybackState = {
48
48
  *
49
49
  * Engine component: {@link AnimComponent} (`anim`).
50
50
  *
51
+ * @elementSummary The `<pc-anim>` element plays animation clips over its entity's hierarchy, taken
52
+ * from `<pc-anim-clip>` children or from the enclosing `<pc-model>`'s own animations. The first
53
+ * clip plays automatically, and the `clip` attribute switches between them. Must be a child of a
54
+ * `<pc-entity>`, `<pc-model>` or `<pc-node>`.
55
+ *
51
56
  * @category Components
52
57
  */
53
58
  class AnimComponentElement extends ComponentElement {
@@ -10,6 +10,10 @@ import { ComponentElement } from './component';
10
10
  *
11
11
  * Engine component: {@link AudioListenerComponent} (`audiolistener`).
12
12
  *
13
+ * @elementSummary The `<pc-audio-listener>` element makes its entity the point from which
14
+ * positional sounds are heard, typically the entity holding the `<pc-camera>`. Must be a child of a
15
+ * `<pc-entity>`, `<pc-model>` or `<pc-node>`.
16
+ *
13
17
  * @category Components
14
18
  */
15
19
  class AudioListenerComponentElement extends ComponentElement {
@@ -19,6 +19,11 @@ const transitionModes = new Map<'tint' | 'sprite', number>([
19
19
  *
20
20
  * Engine component: {@link ButtonComponent} (`button`).
21
21
  *
22
+ * @elementSummary The `<pc-button>` element makes its entity respond to pointer input, tinting or
23
+ * swapping its image as the pointer hovers, presses and releases it. The entity also needs a
24
+ * `<pc-element>` with `use-input` set. Must be a child of a `<pc-entity>`, `<pc-model>` or
25
+ * `<pc-node>`.
26
+ *
22
27
  * @category Components
23
28
  */
24
29
  class ButtonComponentElement extends ComponentElement {
@@ -13,6 +13,7 @@ import {
13
13
  TONEMAP_ACES,
14
14
  TONEMAP_HEJL,
15
15
  TONEMAP_NONE,
16
+ XRTYPE_AR,
16
17
  XRTYPE_VR
17
18
  } from 'playcanvas';
18
19
 
@@ -43,6 +44,10 @@ const tonemaps = new Map<'none' | 'linear' | 'filmic' | 'hejl' | 'aces' | 'aces2
43
44
  *
44
45
  * Engine component: {@link CameraComponent} (`camera`).
45
46
  *
47
+ * @elementSummary The `<pc-camera>` element renders the scene from its entity's transform, with
48
+ * attributes for the projection, field of view, clip planes, clear color and tonemapping. Must be a
49
+ * child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
50
+ *
46
51
  * @category Components
47
52
  */
48
53
  class CameraComponentElement extends ComponentElement {
@@ -50,9 +55,11 @@ class CameraComponentElement extends ComponentElement {
50
55
 
51
56
  private _clearColorBuffer = true;
52
57
 
58
+ private _clearDepth = 1;
59
+
53
60
  private _clearDepthBuffer = true;
54
61
 
55
- private _clearStencilBuffer = false;
62
+ private _clearStencilBuffer = true;
56
63
 
57
64
  private _cullFaces = true;
58
65
 
@@ -91,6 +98,7 @@ class CameraComponentElement extends ComponentElement {
91
98
  return {
92
99
  clearColor: this._clearColor,
93
100
  clearColorBuffer: this._clearColorBuffer,
101
+ clearDepth: this._clearDepth,
94
102
  clearDepthBuffer: this._clearDepthBuffer,
95
103
  clearStencilBuffer: this._clearStencilBuffer,
96
104
  cullFaces: this._cullFaces,
@@ -110,9 +118,33 @@ class CameraComponentElement extends ComponentElement {
110
118
  };
111
119
  }
112
120
 
113
- get xrAvailable() {
121
+ /**
122
+ * Whether immersive AR is available. Independent of {@link vrAvailable}: a device can offer
123
+ * either mode without the other.
124
+ * @returns Whether immersive AR is available.
125
+ */
126
+ get arAvailable(): boolean {
127
+ return this._available(XRTYPE_AR);
128
+ }
129
+
130
+ /**
131
+ * Whether immersive VR is available. Independent of {@link arAvailable}: a device can offer
132
+ * either mode without the other.
133
+ * @returns Whether immersive VR is available.
134
+ */
135
+ get vrAvailable(): boolean {
136
+ return this._available(XRTYPE_VR);
137
+ }
138
+
139
+ /**
140
+ * Whether one XR session type is available on this device.
141
+ *
142
+ * @param type - The XR session type to test.
143
+ * @returns Whether that type is available.
144
+ */
145
+ private _available(type: string): boolean {
114
146
  const xrManager = this.component?.system.app.xr;
115
- return xrManager && xrManager.supported && xrManager.isAvailable(XRTYPE_VR);
147
+ return Boolean(xrManager?.supported && xrManager.isAvailable(type));
116
148
  }
117
149
 
118
150
  /**
@@ -124,10 +156,12 @@ class CameraComponentElement extends ComponentElement {
124
156
  type: 'immersive-ar' | 'immersive-vr',
125
157
  space: 'bounded-floor' | 'local' | 'local-floor' | 'unbounded' | 'viewer'
126
158
  ) {
127
- if (this.component && this.xrAvailable) {
159
+ // Gated on the mode being started, not on XR in general: a device that offers only
160
+ // one of the two would otherwise accept a session it cannot serve
161
+ if (this.component && this._available(type)) {
128
162
  this.component.startXr(type, space, {
129
163
  callback: (err: any) => {
130
- if (err) console.error(`WebXR Immersive VR failed to start: ${err.message}`);
164
+ if (err) console.error(`WebXR ${type} failed to start: ${err.message}`);
131
165
  }
132
166
  });
133
167
  }
@@ -188,6 +222,25 @@ class CameraComponentElement extends ComponentElement {
188
222
  return this._clearColorBuffer;
189
223
  }
190
224
 
225
+ /**
226
+ * Sets the depth value the depth buffer is cleared to. Defaults to 1.
227
+ * @param value - The clear depth value.
228
+ */
229
+ set clearDepth(value: number) {
230
+ this._clearDepth = value;
231
+ if (this.component) {
232
+ this.component.clearDepth = value;
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Gets the depth value the depth buffer is cleared to.
238
+ * @returns The clear depth value.
239
+ */
240
+ get clearDepth(): number {
241
+ return this._clearDepth;
242
+ }
243
+
191
244
  /**
192
245
  * Sets the clear depth buffer of the camera.
193
246
  * @param value - The clear depth buffer.
@@ -498,6 +551,7 @@ class CameraComponentElement extends ComponentElement {
498
551
  ...super.observedAttributes,
499
552
  'clear-color',
500
553
  'clear-color-buffer',
554
+ 'clear-depth',
501
555
  'clear-depth-buffer',
502
556
  'clear-stencil-buffer',
503
557
  'cull-faces',
@@ -527,11 +581,14 @@ class CameraComponentElement extends ComponentElement {
527
581
  case 'clear-color-buffer':
528
582
  this.clearColorBuffer = parseBool(newValue, true);
529
583
  break;
584
+ case 'clear-depth':
585
+ this.clearDepth = parseNumber(newValue, 1, name);
586
+ break;
530
587
  case 'clear-depth-buffer':
531
588
  this.clearDepthBuffer = parseBool(newValue, true);
532
589
  break;
533
590
  case 'clear-stencil-buffer':
534
- this.clearStencilBuffer = parseBool(newValue, false);
591
+ this.clearStencilBuffer = parseBool(newValue, true);
535
592
  break;
536
593
  case 'cull-faces':
537
594
  this.cullFaces = parseBool(newValue, true);
@@ -19,6 +19,10 @@ import { ComponentElement } from './component';
19
19
  *
20
20
  * Engine component: {@link CollisionComponent} (`collision`).
21
21
  *
22
+ * @elementSummary The `<pc-collision>` element gives its entity a collision shape — a box, sphere,
23
+ * capsule, cone, cylinder or mesh — for the physics simulation to collide against. Pair it with a
24
+ * `<pc-rigid-body>`. Must be a child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
25
+ *
22
26
  * @category Components
23
27
  */
24
28
  class CollisionComponentElement extends ComponentElement {
@@ -19,6 +19,10 @@ import { ComponentElement } from './component';
19
19
  *
20
20
  * Engine component: {@link ElementComponent} (`element`).
21
21
  *
22
+ * @elementSummary The `<pc-element>` element gives its entity a 2D UI rectangle inside a
23
+ * `<pc-screen>` hierarchy, drawing an image, a line of text or nothing (`type="image"`, `"text"` or
24
+ * `"group"`). Must be a child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
25
+ *
22
26
  * @category Components
23
27
  */
24
28
  class ElementComponentElement extends ComponentElement {
@@ -13,6 +13,10 @@ import { ComponentElement } from './component';
13
13
  *
14
14
  * Engine component: {@link GSplatComponent} (`gsplat`).
15
15
  *
16
+ * @elementSummary The `<pc-gsplat>` element renders the 3D Gaussian splats of a `gsplat` asset at
17
+ * its entity, with attributes for shadow casting and level of detail. Must be a child of a
18
+ * `<pc-entity>`, `<pc-model>` or `<pc-node>`.
19
+ *
16
20
  * @category Components
17
21
  */
18
22
  class GSplatComponentElement extends ComponentElement {
@@ -5,9 +5,14 @@ import { getEntity, parseBool, parseEnum, parseNumber, parseVec2, parseVec3 } fr
5
5
 
6
6
  import { ComponentElement } from './component';
7
7
 
8
- type JointType = 'fixed' | 'ball' | 'hinge' | 'slider' | '6dof';
8
+ /** The constraint types supported by the `<pc-joint>` element. */
9
+ export type JointType = 'fixed' | 'ball' | 'hinge' | 'slider' | '6dof';
9
10
 
10
- type MotionMode = 'locked' | 'limited' | 'free';
11
+ /**
12
+ * The motion modes for a single joint axis: fully constrained (`locked`), constrained within
13
+ * limits (`limited`) or unconstrained (`free`).
14
+ */
15
+ export type MotionMode = 'locked' | 'limited' | 'free';
11
16
 
12
17
  /**
13
18
  * The JointComponentElement interface provides properties and methods for manipulating
@@ -22,6 +27,11 @@ type MotionMode = 'locked' | 'limited' | 'free';
22
27
  * a rigid body component; leaving `entity-b` empty constrains `entity-a` to a fixed point in world
23
28
  * space. The underlying engine component is in alpha, so its API may change.
24
29
  *
30
+ * @elementSummary The `<pc-joint>` element constrains two rigid bodies to each other — a hinged
31
+ * door, a swinging chain, a sliding drawer. Its entity's transform is the joint frame, and
32
+ * `entity-a` and `entity-b` name the bodies. Must be a child of a `<pc-entity>`, `<pc-model>` or
33
+ * `<pc-node>`.
34
+ *
25
35
  * @fires {CustomEvent} break - Fired when the impulse on the joint exceeds `break-impulse` and the
26
36
  * constraint breaks. A broken joint no longer constrains its bodies; calling `refreshFrames()` on
27
37
  * the underlying component re-attaches it. Bubbles and is composed.
@@ -12,6 +12,10 @@ import { ComponentElement } from './component';
12
12
  *
13
13
  * Engine component: {@link LayoutChildComponent} (`layoutchild`).
14
14
  *
15
+ * @elementSummary The `<pc-layout-child>` element controls how its entity is sized by the
16
+ * `<pc-layout-group>` above it, through minimum and maximum sizes and fit proportions. Must be a
17
+ * child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
18
+ *
15
19
  * @category Components
16
20
  */
17
21
  class LayoutChildComponentElement extends ComponentElement {
@@ -34,6 +34,10 @@ const fittings = new Map<'none' | 'stretch' | 'shrink' | 'both', number>([
34
34
  *
35
35
  * Engine component: {@link LayoutGroupComponent} (`layoutgroup`).
36
36
  *
37
+ * @elementSummary The `<pc-layout-group>` element arranges its entity's children in a row or
38
+ * column, with spacing, padding, alignment and fitting. Must be a child of a `<pc-entity>`,
39
+ * `<pc-model>` or `<pc-node>`.
40
+ *
37
41
  * @category Components
38
42
  */
39
43
  class LayoutGroupComponentElement extends ComponentElement {
@@ -39,9 +39,17 @@ const shadowTypes = new Map<
39
39
  *
40
40
  * Engine component: {@link LightComponent} (`light`).
41
41
  *
42
+ * @elementSummary The `<pc-light>` element lights the scene from its entity — as a directional,
43
+ * omni or spot light — with attributes for color, intensity, range and shadows. Must be a child of
44
+ * a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
45
+ *
42
46
  * @category Components
43
47
  */
44
48
  class LightComponentElement extends ComponentElement {
49
+ private _cascadeBlend = 0;
50
+
51
+ private _cascadeDistribution = 0.5;
52
+
45
53
  private _castShadows = false;
46
54
 
47
55
  private _color = new Color(1, 1, 1);
@@ -50,15 +58,17 @@ class LightComponentElement extends ComponentElement {
50
58
 
51
59
  private _intensity = 1;
52
60
 
53
- private _normalOffsetBias = 0.05;
61
+ private _normalOffsetBias = 0;
62
+
63
+ private _numCascades = 1;
54
64
 
55
65
  private _outerConeAngle = 45;
56
66
 
57
67
  private _range = 10;
58
68
 
59
- private _shadowBias = 0.2;
69
+ private _shadowBias = 0.05;
60
70
 
61
- private _shadowDistance = 16;
71
+ private _shadowDistance = 40;
62
72
 
63
73
  private _shadowIntensity = 1;
64
74
 
@@ -77,7 +87,7 @@ class LightComponentElement extends ComponentElement {
77
87
 
78
88
  private _type: 'directional' | 'omni' | 'spot' = 'directional';
79
89
 
80
- private _vsmBias = 0.01;
90
+ private _vsmBias = 0.0025;
81
91
 
82
92
  private _vsmBlurSize = 11;
83
93
 
@@ -96,11 +106,14 @@ class LightComponentElement extends ComponentElement {
96
106
 
97
107
  protected getInitialComponentData() {
98
108
  return {
109
+ cascadeBlend: this._cascadeBlend,
110
+ cascadeDistribution: this._cascadeDistribution,
99
111
  castShadows: this._castShadows,
100
112
  color: this._color,
101
113
  innerConeAngle: this._innerConeAngle,
102
114
  intensity: this._intensity,
103
115
  normalOffsetBias: this._normalOffsetBias,
116
+ numCascades: this._numCascades,
104
117
  outerConeAngle: this._outerConeAngle,
105
118
  penumbraFalloff: this._penumbraFalloff,
106
119
  penumbraSize: this._penumbraSize,
@@ -111,7 +124,7 @@ class LightComponentElement extends ComponentElement {
111
124
  shadowIntensity: this._shadowIntensity,
112
125
  shadowResolution: this._shadowResolution,
113
126
  shadowSamples: this._shadowSamples,
114
- shadowType: shadowTypes.get(this._shadowType),
127
+ shadowType: shadowTypes.get(this._shadowType) ?? SHADOW_PCF3_32F,
115
128
  type: this._type,
116
129
  vsmBias: this._vsmBias,
117
130
  vsmBlurSize: this._vsmBlurSize
@@ -126,6 +139,51 @@ class LightComponentElement extends ComponentElement {
126
139
  return super.component as LightComponent;
127
140
  }
128
141
 
142
+ /**
143
+ * Sets the fraction of each shadow cascade that is blended into the next one, from 0 (no
144
+ * blending) to 1, which applies only to `directional` lights with `num-cascades` greater than
145
+ * 1. Defaults to 0.
146
+ * @param value - The cascade blend factor.
147
+ */
148
+ set cascadeBlend(value: number) {
149
+ this._cascadeBlend = value;
150
+ if (this.component) {
151
+ this.component.cascadeBlend = value;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Gets the cascade blend factor of the light, from 0 (no blending) to 1, which applies only to
157
+ * `directional` lights with `num-cascades` greater than 1.
158
+ * @returns The cascade blend factor.
159
+ */
160
+ get cascadeBlend() {
161
+ return this._cascadeBlend;
162
+ }
163
+
164
+ /**
165
+ * Sets the distribution of the camera frustum split between shadow cascades, from 0 (linear
166
+ * split) to 1 (logarithmic split, concentrating shadow resolution near the camera), which
167
+ * applies only to `directional` lights with `num-cascades` greater than 1. Defaults to 0.5.
168
+ * @param value - The cascade distribution.
169
+ */
170
+ set cascadeDistribution(value: number) {
171
+ this._cascadeDistribution = value;
172
+ if (this.component) {
173
+ this.component.cascadeDistribution = value;
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Gets the cascade distribution of the light, from 0 (linear split) to 1 (logarithmic split,
179
+ * concentrating shadow resolution near the camera), which applies only to `directional` lights
180
+ * with `num-cascades` greater than 1.
181
+ * @returns The cascade distribution.
182
+ */
183
+ get cascadeDistribution() {
184
+ return this._cascadeDistribution;
185
+ }
186
+
129
187
  /**
130
188
  * Sets the cast shadows flag of the light.
131
189
  * @param value - The cast shadows flag.
@@ -221,6 +279,27 @@ class LightComponentElement extends ComponentElement {
221
279
  return this._normalOffsetBias;
222
280
  }
223
281
 
282
+ /**
283
+ * Sets the number of shadow cascades of the light, an integer from 1 (no cascades) to 4, which
284
+ * applies only to `directional` lights. Defaults to 1.
285
+ * @param value - The number of shadow cascades.
286
+ */
287
+ set numCascades(value: number) {
288
+ this._numCascades = value;
289
+ if (this.component) {
290
+ this.component.numCascades = value;
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Gets the number of shadow cascades of the light, an integer from 1 (no cascades) to 4, which
296
+ * applies only to `directional` lights.
297
+ * @returns The number of shadow cascades.
298
+ */
299
+ get numCascades() {
300
+ return this._numCascades;
301
+ }
302
+
224
303
  /**
225
304
  * Sets the outer cone angle of the light.
226
305
  * @param value - The outer cone angle.
@@ -512,11 +591,14 @@ class LightComponentElement extends ComponentElement {
512
591
  static get observedAttributes() {
513
592
  return [
514
593
  ...super.observedAttributes,
515
- 'color',
594
+ 'cascade-blend',
595
+ 'cascade-distribution',
516
596
  'cast-shadows',
517
- 'intensity',
597
+ 'color',
518
598
  'inner-cone-angle',
599
+ 'intensity',
519
600
  'normal-offset-bias',
601
+ 'num-cascades',
520
602
  'outer-cone-angle',
521
603
  'penumbra-falloff',
522
604
  'penumbra-size',
@@ -538,12 +620,18 @@ class LightComponentElement extends ComponentElement {
538
620
  super.attributeChangedCallback(name, _oldValue, newValue);
539
621
 
540
622
  switch (name) {
541
- case 'color':
542
- this.color = parseColor(newValue, Color.WHITE, name);
623
+ case 'cascade-blend':
624
+ this.cascadeBlend = parseNumber(newValue, 0, name);
625
+ break;
626
+ case 'cascade-distribution':
627
+ this.cascadeDistribution = parseNumber(newValue, 0.5, name);
543
628
  break;
544
629
  case 'cast-shadows':
545
630
  this.castShadows = parseBool(newValue, false);
546
631
  break;
632
+ case 'color':
633
+ this.color = parseColor(newValue, Color.WHITE, name);
634
+ break;
547
635
  case 'inner-cone-angle':
548
636
  this.innerConeAngle = parseNumber(newValue, 40, name);
549
637
  break;
@@ -551,7 +639,10 @@ class LightComponentElement extends ComponentElement {
551
639
  this.intensity = parseNumber(newValue, 1, name);
552
640
  break;
553
641
  case 'normal-offset-bias':
554
- this.normalOffsetBias = parseNumber(newValue, 0.05, name);
642
+ this.normalOffsetBias = parseNumber(newValue, 0, name);
643
+ break;
644
+ case 'num-cascades':
645
+ this.numCascades = parseNumber(newValue, 1, name);
555
646
  break;
556
647
  case 'outer-cone-angle':
557
648
  this.outerConeAngle = parseNumber(newValue, 45, name);
@@ -566,20 +657,20 @@ class LightComponentElement extends ComponentElement {
566
657
  this.range = parseNumber(newValue, 10, name);
567
658
  break;
568
659
  case 'shadow-bias':
569
- this.shadowBias = parseNumber(newValue, 0.2, name);
570
- break;
571
- case 'shadow-distance':
572
- this.shadowDistance = parseNumber(newValue, 16, name);
660
+ this.shadowBias = parseNumber(newValue, 0.05, name);
573
661
  break;
574
662
  case 'shadow-blocker-samples':
575
663
  this.shadowBlockerSamples = parseNumber(newValue, 16, name);
576
664
  break;
577
- case 'shadow-resolution':
578
- this.shadowResolution = parseNumber(newValue, 1024, name);
665
+ case 'shadow-distance':
666
+ this.shadowDistance = parseNumber(newValue, 40, name);
579
667
  break;
580
668
  case 'shadow-intensity':
581
669
  this.shadowIntensity = parseNumber(newValue, 1, name);
582
670
  break;
671
+ case 'shadow-resolution':
672
+ this.shadowResolution = parseNumber(newValue, 1024, name);
673
+ break;
583
674
  case 'shadow-samples':
584
675
  this.shadowSamples = parseNumber(newValue, 16, name);
585
676
  break;
@@ -590,7 +681,7 @@ class LightComponentElement extends ComponentElement {
590
681
  this.type = parseEnum(newValue, ['directional', 'omni', 'spot'], 'directional', name);
591
682
  break;
592
683
  case 'vsm-bias':
593
- this.vsmBias = parseNumber(newValue, 0.01, name);
684
+ this.vsmBias = parseNumber(newValue, 0.0025, name);
594
685
  break;
595
686
  case 'vsm-blur-size':
596
687
  this.vsmBlurSize = parseNumber(newValue, 11, name);
@@ -12,6 +12,10 @@ import { ComponentElement } from './component';
12
12
  *
13
13
  * Engine component: {@link ParticleSystemComponent} (`particlesystem`).
14
14
  *
15
+ * @elementSummary The `<pc-particle-system>` element emits particles from its entity, with
16
+ * attributes for the emitter's shape, rate, lifetime, textures and blending. Must be a child of a
17
+ * `<pc-entity>`, `<pc-model>` or `<pc-node>`.
18
+ *
15
19
  * @category Components
16
20
  */
17
21
  class ParticleSystemComponentElement extends ComponentElement {
@@ -17,6 +17,11 @@ import { ComponentElement } from './component';
17
17
  *
18
18
  * Engine component: {@link RenderComponent} (`render`).
19
19
  *
20
+ * @elementSummary The `<pc-render>` element renders one of the engine's built-in primitives at its
21
+ * entity — box, sphere, capsule, cone, cylinder or plane — shaded by the `<pc-material>` its
22
+ * `material` attribute names. For glTF content, use `<pc-model>` instead. Must be a child of a
23
+ * `<pc-entity>`, `<pc-model>` or `<pc-node>`.
24
+ *
20
25
  * @category Components
21
26
  */
22
27
  class RenderComponentElement extends ComponentElement {
@@ -13,6 +13,11 @@ import { ComponentElement } from './component';
13
13
  *
14
14
  * Engine component: {@link RigidBodyComponent} (`rigidbody`).
15
15
  *
16
+ * @elementSummary The `<pc-rigid-body>` element hands its entity to the physics simulation, with
17
+ * attributes for its type, mass, friction and restitution. It needs a sibling `<pc-collision>` for
18
+ * its shape, and `Ammo` loaded through `<pc-wasm>`. Must be a child of a `<pc-entity>`,
19
+ * `<pc-model>` or `<pc-node>`.
20
+ *
16
21
  * @category Components
17
22
  */
18
23
  class RigidBodyComponentElement extends ComponentElement {
@@ -22,6 +22,10 @@ const scaleModes = new Map<'none' | 'blend', string>([
22
22
  *
23
23
  * Engine component: {@link ScreenComponent} (`screen`).
24
24
  *
25
+ * @elementSummary The `<pc-screen>` element gives its entity a 2D space — in screen space or in the
26
+ * world — that a hierarchy of `<pc-element>` descendants lays out inside. Must be a child of a
27
+ * `<pc-entity>`, `<pc-model>` or `<pc-node>`.
28
+ *
25
29
  * @category Components
26
30
  */
27
31
  class ScreenComponentElement extends ComponentElement {
@@ -250,6 +250,9 @@ export type ScriptNameChangeEvent = {
250
250
  *
251
251
  * Engine component: {@link ScriptComponent} (`script`).
252
252
  *
253
+ * @elementSummary The `<pc-script>` element holds the `<pc-script-instance>` children that attach
254
+ * scripts to its entity. Must be a child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
255
+ *
253
256
  * @category Components
254
257
  */
255
258
  class ScriptComponentElement extends ComponentElement {
@@ -29,6 +29,10 @@ import { parseBool } from '../parse';
29
29
  * The element becomes ready once its script instance has been created by the parent
30
30
  * `<pc-script>` element.
31
31
  *
32
+ * @elementSummary The `<pc-script-instance>` element attaches one script class, named by `name`, to
33
+ * the entity of its parent `<pc-script>`. Its other attributes set script attributes of the same
34
+ * name, and `attributes` takes a JSON object instead. Must be a direct child of `<pc-script>`.
35
+ *
32
36
  * @fires {CustomEvent} scriptattributeschange - Fired when the script's attributes change. The
33
37
  * `detail` carries the new `attributes` object. Bubbles.
34
38
  * @fires {CustomEvent} scriptenablechange - Fired when the script's enabled state changes. The
@@ -31,6 +31,10 @@ const visibilities = new Map<'always' | 'when-required', number>([
31
31
  *
32
32
  * Engine component: {@link ScrollViewComponent} (`scrollview`).
33
33
  *
34
+ * @elementSummary The `<pc-scroll-view>` element scrolls a larger content entity within a clipped
35
+ * viewport at its entity, optionally driven by the `<pc-scrollbar>` elements it references. Must be
36
+ * a child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
37
+ *
34
38
  * @category Components
35
39
  */
36
40
  class ScrollViewComponentElement extends ComponentElement {