@playcanvas/web-components 0.17.0 → 0.19.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 +28 -3
  3. package/dist/app.d.ts +28 -3
  4. package/dist/asset.d.cts +13 -3
  5. package/dist/asset.d.ts +13 -3
  6. package/dist/components/anim-clip.d.cts +3 -1
  7. package/dist/components/anim-clip.d.ts +3 -1
  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 +338 -7
  51. package/dist/entity-base.d.cts +5 -4
  52. package/dist/entity-base.d.ts +5 -4
  53. package/dist/entity-owner.d.cts +2 -2
  54. package/dist/entity-owner.d.ts +2 -2
  55. package/dist/entity.d.cts +13 -2
  56. package/dist/entity.d.ts +13 -2
  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 +11 -0
  62. package/dist/model.d.ts +11 -0
  63. package/dist/node.d.cts +12 -1
  64. package/dist/node.d.ts +12 -1
  65. package/dist/pwc.cjs +601 -206
  66. package/dist/pwc.cjs.map +1 -1
  67. package/dist/pwc.js +601 -206
  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 +602 -207
  74. package/dist/pwc.mjs.map +1 -1
  75. package/dist/scene.d.cts +19 -0
  76. package/dist/scene.d.ts +19 -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 +257 -62
  80. package/dist/wasm.d.cts +4 -0
  81. package/dist/wasm.d.ts +4 -0
  82. package/dist/web-types.json +169 -69
  83. package/package.json +3 -3
  84. package/src/app.ts +150 -71
  85. package/src/asset.ts +13 -4
  86. package/src/components/anim-clip.ts +3 -1
  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 +28 -16
  109. package/src/entity-owner.ts +2 -2
  110. package/src/entity.ts +16 -4
  111. package/src/index.ts +12 -1
  112. package/src/material.ts +19 -8
  113. package/src/model.ts +14 -2
  114. package/src/node.ts +15 -3
  115. package/src/scene.ts +35 -1
  116. package/src/sky.ts +4 -0
  117. package/src/wasm.ts +4 -0
@@ -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 {
@@ -18,6 +18,10 @@ const orientations = new Map<'horizontal' | 'vertical', number>([
18
18
  *
19
19
  * Engine component: {@link ScrollbarComponent} (`scrollbar`).
20
20
  *
21
+ * @elementSummary The `<pc-scrollbar>` element gives its entity a draggable handle reporting a
22
+ * position from 0 to 1, which a `<pc-scroll-view>` references to scroll its content. Must be a
23
+ * child of a `<pc-entity>`, `<pc-model>` or `<pc-node>`.
24
+ *
21
25
  * @category Components
22
26
  */
23
27
  class ScrollbarComponentElement extends ComponentElement {
@@ -12,6 +12,10 @@ import { ComponentElement } from './component';
12
12
  *
13
13
  * Engine component: {@link SoundComponent} (`sound`).
14
14
  *
15
+ * @elementSummary The `<pc-sound>` element holds the `<pc-sound-slot>` children that play sounds at
16
+ * its entity, along with the positional audio settings they share. Must be a child of a
17
+ * `<pc-entity>`, `<pc-model>` or `<pc-node>`.
18
+ *
15
19
  * @category Components
16
20
  */
17
21
  class SoundComponentElement extends ComponentElement {
@@ -10,6 +10,9 @@ import { SoundComponentElement } from './sound-component';
10
10
  * The SoundSlotElement interface provides properties and methods for manipulating
11
11
  * `<pc-sound-slot>` elements. The SoundSlotElement interface also inherits the properties and
12
12
  * methods of the {@link AsyncElement} interface.
13
+ *
14
+ * @elementSummary The `<pc-sound-slot>` element declares one named sound on its parent `<pc-sound>`
15
+ * — its asset, volume, pitch, looping and autoplay. Must be a direct child of `<pc-sound>`.
13
16
  */
14
17
  class SoundSlotElement extends AsyncElement {
15
18
  private _asset = '';
@@ -4,18 +4,29 @@ import type { AppElement } from './app';
4
4
  import { AsyncElement } from './async-element';
5
5
 
6
6
  /**
7
- * The attribute names of the inline `onpointer*` event handlers, shared by every element that
8
- * fronts an engine entity. Spread into `observedAttributes` by subclasses.
7
+ * The event types the containing `<pc-app>` synthesizes on entity-fronting elements via picking:
8
+ * the `pointer*` events, plus `click` which concludes a primary-button press and release, and
9
+ * is delivered as a `PointerEvent` exactly as modern browsers deliver native clicks.
9
10
  * @internal
10
11
  */
11
- export const POINTER_ATTRIBUTES = [
12
- 'onpointerenter',
13
- 'onpointerleave',
14
- 'onpointerdown',
15
- 'onpointerup',
16
- 'onpointermove'
12
+ export const SYNTHESIZED_EVENTS = [
13
+ 'pointerenter',
14
+ 'pointerleave',
15
+ 'pointerdown',
16
+ 'pointerup',
17
+ 'pointermove',
18
+ 'click'
17
19
  ] as const;
18
20
 
21
+ const SYNTHESIZED_EVENT_SET: ReadonlySet<string> = new Set(SYNTHESIZED_EVENTS);
22
+
23
+ /**
24
+ * The attribute names of the inline event handlers (`onpointerdown`, `onclick`, ...), shared by
25
+ * every element that fronts an engine entity. Spread into `observedAttributes` by subclasses.
26
+ * @internal
27
+ */
28
+ export const EVENT_ATTRIBUTES = SYNTHESIZED_EVENTS.map((type) => `on${type}`);
29
+
19
30
  /**
20
31
  * The base class for elements that front an engine {@link Entity}: `<pc-entity>` and
21
32
  * `<pc-model>`, which create one, and `<pc-node>`, which binds to one inside a model's
@@ -34,12 +45,13 @@ class EntityBaseElement extends AsyncElement {
34
45
  protected _appElement: AppElement | null = null;
35
46
 
36
47
  /**
37
- * The pointer event listeners for the entity.
48
+ * The event listeners registered on the element, by type.
38
49
  */
39
50
  private _listeners: Record<string, EventListener[]> = {};
40
51
 
41
52
  /**
42
- * The event types for which an inline `onpointer*` attribute is currently present.
53
+ * The event types for which an inline handler attribute (`onpointerdown`, `onclick`, ...)
54
+ * is currently present.
43
55
  */
44
56
  private _inlineHandlerTypes = new Set<string>();
45
57
 
@@ -75,10 +87,10 @@ class EntityBaseElement extends AsyncElement {
75
87
  }
76
88
 
77
89
  /**
78
- * Tracks whether an inline `onpointer*` attribute is present. The browser itself compiles and
90
+ * Tracks whether an inline handler attribute is present. The browser itself compiles and
79
91
  * runs these attributes — they are standard `GlobalEventHandlers`, so setting one replaces
80
92
  * the previous handler and removing it removes the handler, exactly like `onclick` on any
81
- * HTML element. But because they bypass {@link addEventListener}, the connect/disconnect
93
+ * HTML element. But because they bypass {@link EventTarget.addEventListener}, the connect/disconnect
82
94
  * bookkeeping that lets the application lazily attach its canvas pointer handlers must be
83
95
  * kept in sync here.
84
96
  *
@@ -105,7 +117,7 @@ class EntityBaseElement extends AsyncElement {
105
117
  }
106
118
  this._listeners[type].push(listener);
107
119
  super.addEventListener(type, listener, options);
108
- if (type.startsWith('pointer')) {
120
+ if (SYNTHESIZED_EVENT_SET.has(type)) {
109
121
  this.dispatchEvent(new CustomEvent(`${type}:connect`, { bubbles: true }));
110
122
  }
111
123
  }
@@ -115,15 +127,15 @@ class EntityBaseElement extends AsyncElement {
115
127
  this._listeners[type] = this._listeners[type].filter((l) => l !== listener);
116
128
  }
117
129
  super.removeEventListener(type, listener, options);
118
- if (type.startsWith('pointer')) {
130
+ if (SYNTHESIZED_EVENT_SET.has(type)) {
119
131
  this.dispatchEvent(new CustomEvent(`${type}:disconnect`, { bubbles: true }));
120
132
  }
121
133
  }
122
134
 
123
135
  /**
124
136
  * Whether the element has a listener for an event type, registered either with
125
- * {@link addEventListener} or with the matching inline `onpointer*` attribute. Read by the
126
- * containing `<pc-app>` element to gate pointer event synthesis.
137
+ * {@link EventTarget.addEventListener} or with the matching inline handler attribute. Read by the
138
+ * containing `<pc-app>` element to gate event synthesis.
127
139
  *
128
140
  * @param type - The event type.
129
141
  * @returns Whether a listener is registered.
@@ -69,7 +69,7 @@ class EntityOwnerElement extends EntityBaseElement {
69
69
  private _tags: string[] = [];
70
70
 
71
71
  /**
72
- * Whether the hierarchy has been built for this entity — set once {@link _buildHierarchy} has
72
+ * Whether the hierarchy has been built for this entity — set once `_buildHierarchy` has
73
73
  * parented it. Read by subclasses that gate work on the entity being in the scene graph.
74
74
  */
75
75
  protected _built = false;
@@ -170,7 +170,7 @@ class EntityOwnerElement extends EntityBaseElement {
170
170
  }
171
171
 
172
172
  /**
173
- * Called by {@link _buildHierarchy} once the backing entity has been parented — exactly once
173
+ * Called by `_buildHierarchy` once the backing entity has been parented — exactly once
174
174
  * per build cycle. The default announces readiness, which is what a parented `<pc-entity>`
175
175
  * means; `<pc-model>` overrides it to start loading content instead, because its readiness
176
176
  * tracks the content settling rather than the host entering the scene graph.
package/src/entity.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Vec3 } from 'playcanvas';
2
2
 
3
- import { POINTER_ATTRIBUTES } from './entity-base';
3
+ import { EVENT_ATTRIBUTES } from './entity-base';
4
4
  import { buildDescendantEntities, EntityOwnerElement } from './entity-owner';
5
5
  import { parseBool, parseTags, parseVec3 } from './parse';
6
6
 
@@ -12,8 +12,13 @@ import { parseBool, parseTags, parseVec3 } from './parse';
12
12
  *
13
13
  * The pointer events below are dispatched by the containing `<pc-app>` element when the pointer
14
14
  * intersects this entity's geometry. They are only generated while the entity has a listener for
15
- * them, registered either with {@link addEventListener} or with the matching inline `onpointer*`
16
- * attribute.
15
+ * them, registered either with {@link EventTarget.addEventListener} or with the matching inline
16
+ * attribute (`onpointerdown`, `onclick`, ...).
17
+ *
18
+ * @elementSummary The `<pc-entity>` element creates an entity: a named, transformable node of the
19
+ * scene hierarchy, and the host for component elements such as `<pc-camera>`, `<pc-light>` and
20
+ * `<pc-render>`. Place it in the `<pc-scene>`, or nest it under another `<pc-entity>`, a
21
+ * `<pc-model>` or a `<pc-node>` to parent it there.
17
22
  *
18
23
  * @attribute {boolean} enabled - The enabled state of the entity.
19
24
  * @attribute {string} name - The name of the entity.
@@ -28,11 +33,17 @@ import { parseBool, parseTags, parseVec3 } from './parse';
28
33
  * entity.
29
34
  * @attribute {string} onpointerup - Script to run when a pointer button is released over the
30
35
  * entity.
36
+ * @attribute {string} onclick - Script to run when the entity is clicked: a primary pointer
37
+ * button pressed and then released over it.
31
38
  * @fires {PointerEvent} pointerenter - Fired when the pointer moves onto the entity.
32
39
  * @fires {PointerEvent} pointerleave - Fired when the pointer moves off the entity.
33
40
  * @fires {PointerEvent} pointermove - Fired when the pointer moves over the entity.
34
41
  * @fires {PointerEvent} pointerdown - Fired when a pointer button is pressed over the entity.
35
42
  * @fires {PointerEvent} pointerup - Fired when a pointer button is released over the entity.
43
+ * @fires {PointerEvent} click - Fired when a primary pointer button is pressed and then released
44
+ * over the entity. A press and release that picked different entities fires on their nearest
45
+ * common ancestor instead, as in the DOM. `detail` carries the click count, so a double click
46
+ * arrives as a click whose `detail` is 2.
36
47
  */
37
48
  class EntityElement extends EntityOwnerElement {
38
49
  connectedCallback() {
@@ -72,7 +83,7 @@ class EntityElement extends EntityOwnerElement {
72
83
  }
73
84
 
74
85
  static get observedAttributes() {
75
- return ['enabled', 'name', 'position', 'rotation', 'scale', 'tags', ...POINTER_ATTRIBUTES];
86
+ return ['enabled', 'name', 'position', 'rotation', 'scale', 'tags', ...EVENT_ATTRIBUTES];
76
87
  }
77
88
 
78
89
  attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
@@ -100,6 +111,7 @@ class EntityElement extends EntityOwnerElement {
100
111
  case 'onpointerdown':
101
112
  case 'onpointerup':
102
113
  case 'onpointermove':
114
+ case 'onclick':
103
115
  this._updateInlineHandler(name, newValue);
104
116
  break;
105
117
  }
package/src/index.ts CHANGED
@@ -134,6 +134,17 @@ export {
134
134
  whenReady
135
135
  };
136
136
 
137
+ export type { AddressMode, MagFilterMode, MinFilterMode } from './asset';
137
138
  export type { AsyncElementTagName } from './async-element';
139
+ export type { JointType, MotionMode } from './components/joint-component';
140
+ export type {
141
+ BlendType,
142
+ ColorChannel,
143
+ CullMode,
144
+ FresnelModel,
145
+ OccludeSpecular,
146
+ OpacityDither,
147
+ ScalarChannel
148
+ } from './material';
138
149
  export type { HierarchyMaterial, HierarchyNode } from './model';
139
- export type { MaterialOverrides } from './node';
150
+ export type { MaterialOverrides, NodeBindingState } from './node';
package/src/material.ts CHANGED
@@ -29,7 +29,8 @@ import type { AppElement } from './app';
29
29
  import { useAsset } from './asset';
30
30
  import { parseBool, parseColor, parseEnum, parseNumber, parseVec2 } from './parse';
31
31
 
32
- type BlendType =
32
+ /** The blend modes for a material. */
33
+ export type BlendType =
33
34
  | 'none'
34
35
  | 'normal'
35
36
  | 'additive'
@@ -56,7 +57,8 @@ const blendTypes = new Map<BlendType, number>([
56
57
  ['subtractive', BLEND_SUBTRACTIVE]
57
58
  ]);
58
59
 
59
- type CullMode = 'none' | 'back' | 'front' | 'front-and-back';
60
+ /** The face culling modes for a material. */
61
+ export type CullMode = 'none' | 'back' | 'front' | 'front-and-back';
60
62
 
61
63
  const cullModes = new Map<CullMode, number>([
62
64
  ['none', CULLFACE_NONE],
@@ -65,14 +67,16 @@ const cullModes = new Map<CullMode, number>([
65
67
  ['front-and-back', CULLFACE_FRONTANDBACK]
66
68
  ]);
67
69
 
68
- type FresnelModel = 'none' | 'schlick';
70
+ /** The Fresnel models for a material. */
71
+ export type FresnelModel = 'none' | 'schlick';
69
72
 
70
73
  const fresnelModels = new Map<FresnelModel, number>([
71
74
  ['none', FRESNEL_NONE],
72
75
  ['schlick', FRESNEL_SCHLICK]
73
76
  ]);
74
77
 
75
- type OccludeSpecular = 'none' | 'ao' | 'gloss-dependent';
78
+ /** The specular occlusion modes for a material. */
79
+ export type OccludeSpecular = 'none' | 'ao' | 'gloss-dependent';
76
80
 
77
81
  const occludeSpeculars = new Map<OccludeSpecular, number>([
78
82
  ['none', SPECOCC_NONE],
@@ -80,17 +84,20 @@ const occludeSpeculars = new Map<OccludeSpecular, number>([
80
84
  ['gloss-dependent', SPECOCC_GLOSSDEPENDENT]
81
85
  ]);
82
86
 
87
+ /** The opacity dithering modes for a material. */
88
+ export type OpacityDither = 'none' | 'bayer8' | 'bluenoise' | 'ignnoise';
89
+
83
90
  // The DITHER_* constants are strings whose values are exactly these names, so a parsed value is
84
91
  // assigned to the material unchanged rather than mapped through a table.
85
- type OpacityDither = 'none' | 'bayer8' | 'bluenoise' | 'ignnoise';
86
-
87
92
  const opacityDithers: OpacityDither[] = ['none', 'bayer8', 'bluenoise', 'ignnoise'];
88
93
 
89
- type ColorChannel = 'r' | 'g' | 'b' | 'a' | 'rgb';
94
+ /** The texture channels a color map can sample. */
95
+ export type ColorChannel = 'r' | 'g' | 'b' | 'a' | 'rgb';
90
96
 
91
97
  const colorChannels: ColorChannel[] = ['r', 'g', 'b', 'a', 'rgb'];
92
98
 
93
- type ScalarChannel = 'r' | 'g' | 'b' | 'a';
99
+ /** The texture channels a scalar map can sample. */
100
+ export type ScalarChannel = 'r' | 'g' | 'b' | 'a';
94
101
 
95
102
  const scalarChannels: ScalarChannel[] = ['r', 'g', 'b', 'a'];
96
103
 
@@ -136,6 +143,10 @@ type TextureSlot =
136
143
  * The two aliases are documented here rather than on an accessor, because they resolve to the
137
144
  * `gloss` properties and would otherwise inherit gloss's description - which reads inverted.
138
145
  *
146
+ * @elementSummary The `<pc-material>` element defines a physically based material, which
147
+ * `<pc-render>` elements apply by naming its `id`. It is metal/rough by default, with `metalness`
148
+ * starting at 0. Must be a direct child of `<pc-app>`.
149
+ *
139
150
  * @attribute {number} roughness - The roughness of the material, from 0 (shiny) to 1 (rough). An
140
151
  * alias for `gloss` that also inverts it, so do not combine it with the `gloss` attributes.
141
152
  * @attribute {string} roughness-map - The id of the `pc-asset` to use as the roughness map. An