@playcanvas/web-components 0.3.0 → 0.5.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.
- package/LICENSE +21 -21
- package/README.md +84 -84
- package/dist/components/light-component.d.ts +48 -0
- package/dist/components/splat-component.d.ts +0 -13
- package/dist/pwc.cjs +275 -207
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +275 -207
- package/dist/pwc.js.map +1 -1
- package/dist/pwc.min.js +1 -1
- package/dist/pwc.min.js.map +1 -1
- package/dist/pwc.mjs +276 -208
- package/dist/pwc.mjs.map +1 -1
- package/package.json +76 -66
- package/src/app.ts +612 -606
- package/src/asset.ts +159 -159
- package/src/async-element.ts +46 -46
- package/src/colors.ts +150 -150
- package/src/components/camera-component.ts +557 -557
- package/src/components/collision-component.ts +183 -183
- package/src/components/component.ts +97 -97
- package/src/components/element-component.ts +367 -367
- package/src/components/light-component.ts +570 -466
- package/src/components/listener-component.ts +30 -30
- package/src/components/particlesystem-component.ts +155 -155
- package/src/components/render-component.ts +147 -147
- package/src/components/rigidbody-component.ts +227 -227
- package/src/components/screen-component.ts +157 -157
- package/src/components/script-component.ts +270 -270
- package/src/components/script.ts +90 -90
- package/src/components/sound-component.ts +230 -230
- package/src/components/sound-slot.ts +288 -288
- package/src/components/splat-component.ts +102 -133
- package/src/entity.ts +360 -360
- package/src/index.ts +63 -63
- package/src/material.ts +141 -141
- package/src/model.ts +111 -111
- package/src/module.ts +43 -43
- package/src/scene.ts +217 -217
- package/src/sky.ts +293 -293
- package/src/utils.ts +71 -71
package/src/app.ts
CHANGED
|
@@ -1,606 +1,612 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AppBase,
|
|
3
|
-
AppOptions,
|
|
4
|
-
CameraComponent,
|
|
5
|
-
createGraphicsDevice,
|
|
6
|
-
FILLMODE_FILL_WINDOW,
|
|
7
|
-
GraphNode,
|
|
8
|
-
Keyboard,
|
|
9
|
-
Mouse,
|
|
10
|
-
Picker,
|
|
11
|
-
RESOLUTION_AUTO,
|
|
12
|
-
AnimComponentSystem,
|
|
13
|
-
AnimationComponentSystem,
|
|
14
|
-
AudioListenerComponentSystem,
|
|
15
|
-
ButtonComponentSystem,
|
|
16
|
-
CameraComponentSystem,
|
|
17
|
-
CollisionComponentSystem,
|
|
18
|
-
ElementComponentSystem,
|
|
19
|
-
GSplatComponentSystem,
|
|
20
|
-
JointComponentSystem,
|
|
21
|
-
LayoutChildComponentSystem,
|
|
22
|
-
LayoutGroupComponentSystem,
|
|
23
|
-
LightComponentSystem,
|
|
24
|
-
ModelComponentSystem,
|
|
25
|
-
ParticleSystemComponentSystem,
|
|
26
|
-
RenderComponentSystem,
|
|
27
|
-
RigidBodyComponentSystem,
|
|
28
|
-
ScriptComponentSystem,
|
|
29
|
-
ScreenComponentSystem,
|
|
30
|
-
ScrollbarComponentSystem,
|
|
31
|
-
ScrollViewComponentSystem,
|
|
32
|
-
SoundComponentSystem,
|
|
33
|
-
SpriteComponentSystem,
|
|
34
|
-
ZoneComponentSystem,
|
|
35
|
-
RenderHandler,
|
|
36
|
-
AnimationHandler,
|
|
37
|
-
AnimClipHandler,
|
|
38
|
-
AnimStateGraphHandler,
|
|
39
|
-
AudioHandler,
|
|
40
|
-
BinaryHandler,
|
|
41
|
-
ContainerHandler,
|
|
42
|
-
CssHandler,
|
|
43
|
-
CubemapHandler,
|
|
44
|
-
FolderHandler,
|
|
45
|
-
FontHandler,
|
|
46
|
-
GSplatHandler,
|
|
47
|
-
HierarchyHandler,
|
|
48
|
-
HtmlHandler,
|
|
49
|
-
JsonHandler,
|
|
50
|
-
MaterialHandler,
|
|
51
|
-
ModelHandler,
|
|
52
|
-
SceneHandler,
|
|
53
|
-
ScriptHandler,
|
|
54
|
-
ShaderHandler,
|
|
55
|
-
SpriteHandler,
|
|
56
|
-
TemplateHandler,
|
|
57
|
-
TextHandler,
|
|
58
|
-
TextureHandler,
|
|
59
|
-
TextureAtlasHandler,
|
|
60
|
-
BatchManager,
|
|
61
|
-
SoundManager,
|
|
62
|
-
Lightmapper,
|
|
63
|
-
XrManager
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
import {
|
|
69
|
-
import {
|
|
70
|
-
import {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
* The AppElement interface
|
|
76
|
-
* {@link
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
private
|
|
85
|
-
|
|
86
|
-
private
|
|
87
|
-
|
|
88
|
-
private
|
|
89
|
-
|
|
90
|
-
private
|
|
91
|
-
|
|
92
|
-
private
|
|
93
|
-
|
|
94
|
-
private
|
|
95
|
-
|
|
96
|
-
private
|
|
97
|
-
|
|
98
|
-
private
|
|
99
|
-
|
|
100
|
-
private
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
private
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
*
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
createOptions
|
|
165
|
-
createOptions.
|
|
166
|
-
createOptions.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
createOptions.
|
|
221
|
-
createOptions.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
this.app.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
this.
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
this.
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
this._pointerHandlers.
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
//
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if (
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
//
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
if (!
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
case '
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
break;
|
|
597
|
-
case '
|
|
598
|
-
this.
|
|
599
|
-
break;
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
1
|
+
import {
|
|
2
|
+
AppBase,
|
|
3
|
+
AppOptions,
|
|
4
|
+
CameraComponent,
|
|
5
|
+
createGraphicsDevice,
|
|
6
|
+
FILLMODE_FILL_WINDOW,
|
|
7
|
+
GraphNode,
|
|
8
|
+
Keyboard,
|
|
9
|
+
Mouse,
|
|
10
|
+
Picker,
|
|
11
|
+
RESOLUTION_AUTO,
|
|
12
|
+
AnimComponentSystem,
|
|
13
|
+
AnimationComponentSystem,
|
|
14
|
+
AudioListenerComponentSystem,
|
|
15
|
+
ButtonComponentSystem,
|
|
16
|
+
CameraComponentSystem,
|
|
17
|
+
CollisionComponentSystem,
|
|
18
|
+
ElementComponentSystem,
|
|
19
|
+
GSplatComponentSystem,
|
|
20
|
+
JointComponentSystem,
|
|
21
|
+
LayoutChildComponentSystem,
|
|
22
|
+
LayoutGroupComponentSystem,
|
|
23
|
+
LightComponentSystem,
|
|
24
|
+
ModelComponentSystem,
|
|
25
|
+
ParticleSystemComponentSystem,
|
|
26
|
+
RenderComponentSystem,
|
|
27
|
+
RigidBodyComponentSystem,
|
|
28
|
+
ScriptComponentSystem,
|
|
29
|
+
ScreenComponentSystem,
|
|
30
|
+
ScrollbarComponentSystem,
|
|
31
|
+
ScrollViewComponentSystem,
|
|
32
|
+
SoundComponentSystem,
|
|
33
|
+
SpriteComponentSystem,
|
|
34
|
+
ZoneComponentSystem,
|
|
35
|
+
RenderHandler,
|
|
36
|
+
AnimationHandler,
|
|
37
|
+
AnimClipHandler,
|
|
38
|
+
AnimStateGraphHandler,
|
|
39
|
+
AudioHandler,
|
|
40
|
+
BinaryHandler,
|
|
41
|
+
ContainerHandler,
|
|
42
|
+
CssHandler,
|
|
43
|
+
CubemapHandler,
|
|
44
|
+
FolderHandler,
|
|
45
|
+
FontHandler,
|
|
46
|
+
GSplatHandler,
|
|
47
|
+
HierarchyHandler,
|
|
48
|
+
HtmlHandler,
|
|
49
|
+
JsonHandler,
|
|
50
|
+
MaterialHandler,
|
|
51
|
+
ModelHandler,
|
|
52
|
+
SceneHandler,
|
|
53
|
+
ScriptHandler,
|
|
54
|
+
ShaderHandler,
|
|
55
|
+
SpriteHandler,
|
|
56
|
+
TemplateHandler,
|
|
57
|
+
TextHandler,
|
|
58
|
+
TextureHandler,
|
|
59
|
+
TextureAtlasHandler,
|
|
60
|
+
BatchManager,
|
|
61
|
+
SoundManager,
|
|
62
|
+
Lightmapper,
|
|
63
|
+
XrManager,
|
|
64
|
+
MeshInstance,
|
|
65
|
+
GSplatComponent
|
|
66
|
+
} from 'playcanvas';
|
|
67
|
+
|
|
68
|
+
import { AssetElement } from './asset';
|
|
69
|
+
import { AsyncElement } from './async-element';
|
|
70
|
+
import { EntityElement } from './entity';
|
|
71
|
+
import { MaterialElement } from './material';
|
|
72
|
+
import { ModuleElement } from './module';
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The AppElement interface provides properties and methods for manipulating
|
|
76
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-app/ | `<pc-app>`} elements.
|
|
77
|
+
* The AppElement interface also inherits the properties and methods of the
|
|
78
|
+
* {@link HTMLElement} interface.
|
|
79
|
+
*/
|
|
80
|
+
class AppElement extends AsyncElement {
|
|
81
|
+
/**
|
|
82
|
+
* The canvas element.
|
|
83
|
+
*/
|
|
84
|
+
private _canvas: HTMLCanvasElement | null = null;
|
|
85
|
+
|
|
86
|
+
private _alpha = true;
|
|
87
|
+
|
|
88
|
+
private _backend: 'webgpu' | 'webgl2' | 'null' = 'webgl2';
|
|
89
|
+
|
|
90
|
+
private _antialias = true;
|
|
91
|
+
|
|
92
|
+
private _depth = true;
|
|
93
|
+
|
|
94
|
+
private _stencil = true;
|
|
95
|
+
|
|
96
|
+
private _highResolution = true;
|
|
97
|
+
|
|
98
|
+
private _hierarchyReady = false;
|
|
99
|
+
|
|
100
|
+
private _picker: Picker | null = null;
|
|
101
|
+
|
|
102
|
+
private _hasPointerListeners: { [key: string]: boolean } = {
|
|
103
|
+
pointerenter: false,
|
|
104
|
+
pointerleave: false,
|
|
105
|
+
pointerdown: false,
|
|
106
|
+
pointerup: false,
|
|
107
|
+
pointermove: false
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
private _hoveredEntity: EntityElement | null = null;
|
|
111
|
+
|
|
112
|
+
private _pointerHandlers: { [key: string]: EventListener | null } = {
|
|
113
|
+
pointermove: null,
|
|
114
|
+
pointerdown: null,
|
|
115
|
+
pointerup: null
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The PlayCanvas application instance.
|
|
120
|
+
*/
|
|
121
|
+
app: AppBase | null = null;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Creates a new AppElement instance.
|
|
125
|
+
*
|
|
126
|
+
* @ignore
|
|
127
|
+
*/
|
|
128
|
+
constructor() {
|
|
129
|
+
super();
|
|
130
|
+
|
|
131
|
+
// Bind methods to maintain 'this' context
|
|
132
|
+
this._onWindowResize = this._onWindowResize.bind(this);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async connectedCallback() {
|
|
136
|
+
// Get all pc-module elements that are direct children of the pc-app element
|
|
137
|
+
const moduleElements = this.querySelectorAll<ModuleElement>(':scope > pc-module');
|
|
138
|
+
|
|
139
|
+
// Wait for all modules to load
|
|
140
|
+
await Promise.all(Array.from(moduleElements).map(module => module.getLoadPromise()));
|
|
141
|
+
|
|
142
|
+
// Create and append the canvas to the element
|
|
143
|
+
this._canvas = document.createElement('canvas');
|
|
144
|
+
this.appendChild(this._canvas);
|
|
145
|
+
|
|
146
|
+
// Configure device types based on backend selection
|
|
147
|
+
const backendToDeviceTypes: { [key: string]: string[] } = {
|
|
148
|
+
webgpu: ['webgpu', 'webgl2'], // fallback to webgl2 if webgpu not available
|
|
149
|
+
webgl2: ['webgl2'],
|
|
150
|
+
null: ['null']
|
|
151
|
+
};
|
|
152
|
+
const deviceTypes = backendToDeviceTypes[this._backend] || [];
|
|
153
|
+
|
|
154
|
+
const device = await createGraphicsDevice(this._canvas, {
|
|
155
|
+
// @ts-ignore - alpha needs to be documented
|
|
156
|
+
alpha: this._alpha,
|
|
157
|
+
antialias: this._antialias,
|
|
158
|
+
depth: this._depth,
|
|
159
|
+
deviceTypes: deviceTypes,
|
|
160
|
+
stencil: this._stencil
|
|
161
|
+
});
|
|
162
|
+
device.maxPixelRatio = this._highResolution ? window.devicePixelRatio : 1;
|
|
163
|
+
|
|
164
|
+
const createOptions = new AppOptions();
|
|
165
|
+
createOptions.graphicsDevice = device;
|
|
166
|
+
createOptions.keyboard = new Keyboard(window);
|
|
167
|
+
createOptions.mouse = new Mouse(this._canvas);
|
|
168
|
+
createOptions.componentSystems = [
|
|
169
|
+
AnimComponentSystem,
|
|
170
|
+
AnimationComponentSystem,
|
|
171
|
+
AudioListenerComponentSystem,
|
|
172
|
+
ButtonComponentSystem,
|
|
173
|
+
CameraComponentSystem,
|
|
174
|
+
CollisionComponentSystem,
|
|
175
|
+
ElementComponentSystem,
|
|
176
|
+
GSplatComponentSystem,
|
|
177
|
+
JointComponentSystem,
|
|
178
|
+
LayoutChildComponentSystem,
|
|
179
|
+
LayoutGroupComponentSystem,
|
|
180
|
+
LightComponentSystem,
|
|
181
|
+
ModelComponentSystem,
|
|
182
|
+
ParticleSystemComponentSystem,
|
|
183
|
+
RenderComponentSystem,
|
|
184
|
+
RigidBodyComponentSystem,
|
|
185
|
+
ScreenComponentSystem,
|
|
186
|
+
ScriptComponentSystem,
|
|
187
|
+
ScrollbarComponentSystem,
|
|
188
|
+
ScrollViewComponentSystem,
|
|
189
|
+
SoundComponentSystem,
|
|
190
|
+
SpriteComponentSystem,
|
|
191
|
+
ZoneComponentSystem
|
|
192
|
+
];
|
|
193
|
+
createOptions.resourceHandlers = [
|
|
194
|
+
AnimClipHandler,
|
|
195
|
+
AnimationHandler,
|
|
196
|
+
AnimStateGraphHandler,
|
|
197
|
+
AudioHandler,
|
|
198
|
+
BinaryHandler,
|
|
199
|
+
CssHandler,
|
|
200
|
+
ContainerHandler,
|
|
201
|
+
CubemapHandler,
|
|
202
|
+
FolderHandler,
|
|
203
|
+
FontHandler,
|
|
204
|
+
GSplatHandler,
|
|
205
|
+
HierarchyHandler,
|
|
206
|
+
HtmlHandler,
|
|
207
|
+
JsonHandler,
|
|
208
|
+
MaterialHandler,
|
|
209
|
+
ModelHandler,
|
|
210
|
+
RenderHandler,
|
|
211
|
+
ScriptHandler,
|
|
212
|
+
SceneHandler,
|
|
213
|
+
ShaderHandler,
|
|
214
|
+
SpriteHandler,
|
|
215
|
+
TemplateHandler,
|
|
216
|
+
TextHandler,
|
|
217
|
+
TextureAtlasHandler,
|
|
218
|
+
TextureHandler
|
|
219
|
+
];
|
|
220
|
+
createOptions.soundManager = new SoundManager();
|
|
221
|
+
createOptions.lightmapper = Lightmapper;
|
|
222
|
+
createOptions.batchManager = BatchManager;
|
|
223
|
+
createOptions.xr = XrManager;
|
|
224
|
+
|
|
225
|
+
this.app = new AppBase(this._canvas);
|
|
226
|
+
this.app.init(createOptions);
|
|
227
|
+
|
|
228
|
+
this.app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
|
|
229
|
+
this.app.setCanvasResolution(RESOLUTION_AUTO);
|
|
230
|
+
|
|
231
|
+
this._pickerCreate();
|
|
232
|
+
|
|
233
|
+
// Get all pc-asset elements that are direct children of the pc-app element
|
|
234
|
+
const assetElements = this.querySelectorAll<AssetElement>(':scope > pc-asset');
|
|
235
|
+
Array.from(assetElements).forEach((assetElement) => {
|
|
236
|
+
assetElement.createAsset();
|
|
237
|
+
const asset = assetElement.asset;
|
|
238
|
+
if (asset) {
|
|
239
|
+
this.app!.assets.add(asset);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Get all pc-material elements that are direct children of the pc-app element
|
|
244
|
+
const materialElements = this.querySelectorAll<MaterialElement>(':scope > pc-material');
|
|
245
|
+
Array.from(materialElements).forEach((materialElement) => {
|
|
246
|
+
materialElement.createMaterial();
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Create all entities
|
|
250
|
+
const entityElements = this.querySelectorAll<EntityElement>('pc-entity');
|
|
251
|
+
Array.from(entityElements).forEach((entityElement) => {
|
|
252
|
+
entityElement.createEntity(this.app!);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Build hierarchy
|
|
256
|
+
entityElements.forEach((entityElement) => {
|
|
257
|
+
entityElement.buildHierarchy(this.app!);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
this._hierarchyReady = true;
|
|
261
|
+
|
|
262
|
+
// Load assets before starting the application
|
|
263
|
+
this.app.preload(() => {
|
|
264
|
+
// Start the application
|
|
265
|
+
this.app!.start();
|
|
266
|
+
|
|
267
|
+
// Handle window resize to keep the canvas responsive
|
|
268
|
+
window.addEventListener('resize', this._onWindowResize);
|
|
269
|
+
|
|
270
|
+
this._onReady();
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
disconnectedCallback() {
|
|
275
|
+
this._pickerDestroy();
|
|
276
|
+
|
|
277
|
+
// Clean up the application
|
|
278
|
+
if (this.app) {
|
|
279
|
+
this.app.destroy();
|
|
280
|
+
this.app = null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Remove event listeners
|
|
284
|
+
window.removeEventListener('resize', this._onWindowResize);
|
|
285
|
+
|
|
286
|
+
// Remove the canvas
|
|
287
|
+
if (this._canvas && this.contains(this._canvas)) {
|
|
288
|
+
this.removeChild(this._canvas);
|
|
289
|
+
this._canvas = null;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
_onWindowResize() {
|
|
294
|
+
if (this.app) {
|
|
295
|
+
this.app.resizeCanvas();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
_pickerCreate() {
|
|
300
|
+
const { width, height } = this.app!.graphicsDevice;
|
|
301
|
+
this._picker = new Picker(this.app!, width, height);
|
|
302
|
+
|
|
303
|
+
// Create bound handlers but don't attach them yet
|
|
304
|
+
this._pointerHandlers.pointermove = this._onPointerMove.bind(this) as EventListener;
|
|
305
|
+
this._pointerHandlers.pointerdown = this._onPointerDown.bind(this) as EventListener;
|
|
306
|
+
this._pointerHandlers.pointerup = this._onPointerUp.bind(this) as EventListener;
|
|
307
|
+
|
|
308
|
+
// Listen for pointer listeners being added/removed
|
|
309
|
+
['pointermove', 'pointerdown', 'pointerup', 'pointerenter', 'pointerleave'].forEach((type) => {
|
|
310
|
+
this.addEventListener(`${type}:connect`, () => this._onPointerListenerAdded(type));
|
|
311
|
+
this.addEventListener(`${type}:disconnect`, () => this._onPointerListenerRemoved(type));
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
_pickerDestroy() {
|
|
316
|
+
if (this._canvas) {
|
|
317
|
+
Object.entries(this._pointerHandlers).forEach(([type, handler]) => {
|
|
318
|
+
if (handler) {
|
|
319
|
+
this._canvas!.removeEventListener(type, handler);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
this._picker = null;
|
|
325
|
+
this._pointerHandlers = {
|
|
326
|
+
pointermove: null,
|
|
327
|
+
pointerdown: null,
|
|
328
|
+
pointerup: null
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// New helper to convert CSS coordinates to canvas (picker) coordinates
|
|
333
|
+
private _getPickerCoordinates(event: PointerEvent): { x: number, y: number } {
|
|
334
|
+
// Get the canvas' bounding rectangle in CSS pixels.
|
|
335
|
+
const canvasRect = this._canvas!.getBoundingClientRect();
|
|
336
|
+
// Compute scale factors based on canvas actual resolution vs. its CSS display size.
|
|
337
|
+
const scaleX = this._canvas!.width / canvasRect.width;
|
|
338
|
+
const scaleY = this._canvas!.height / canvasRect.height;
|
|
339
|
+
// Convert the client coordinates accordingly.
|
|
340
|
+
const x = (event.clientX - canvasRect.left) * scaleX;
|
|
341
|
+
const y = (event.clientY - canvasRect.top) * scaleY;
|
|
342
|
+
return { x, y };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
_onPointerMove(event: PointerEvent) {
|
|
346
|
+
if (!this._picker || !this.app) return;
|
|
347
|
+
|
|
348
|
+
const camera = this.app!.root.findComponent('camera') as CameraComponent;
|
|
349
|
+
if (!camera) return;
|
|
350
|
+
|
|
351
|
+
// Use the helper to convert event coordinates into canvas/picker coordinates.
|
|
352
|
+
const { x, y } = this._getPickerCoordinates(event);
|
|
353
|
+
|
|
354
|
+
this._picker.prepare(camera, this.app!.scene);
|
|
355
|
+
const selection = this._picker.getSelection(x, y);
|
|
356
|
+
|
|
357
|
+
// Get the currently hovered entity by walking up the hierarchy
|
|
358
|
+
let newHoverEntity: EntityElement | null = null;
|
|
359
|
+
if (selection.length > 0) {
|
|
360
|
+
const item = selection[0];
|
|
361
|
+
let currentNode: GraphNode | null = item instanceof MeshInstance ? item.node : (item as GSplatComponent).entity;
|
|
362
|
+
while (currentNode !== null) {
|
|
363
|
+
const entityElement = this.querySelector(`pc-entity[name="${currentNode.name}"]`) as EntityElement;
|
|
364
|
+
if (entityElement) {
|
|
365
|
+
newHoverEntity = entityElement;
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
currentNode = currentNode.parent;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Handle enter/leave events
|
|
373
|
+
if (this._hoveredEntity !== newHoverEntity) {
|
|
374
|
+
if (this._hoveredEntity && this._hoveredEntity.hasListeners('pointerleave')) {
|
|
375
|
+
this._hoveredEntity.dispatchEvent(new PointerEvent('pointerleave', event));
|
|
376
|
+
}
|
|
377
|
+
if (newHoverEntity && newHoverEntity.hasListeners('pointerenter')) {
|
|
378
|
+
newHoverEntity.dispatchEvent(new PointerEvent('pointerenter', event));
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Update hover state
|
|
383
|
+
this._hoveredEntity = newHoverEntity;
|
|
384
|
+
|
|
385
|
+
// Handle pointermove event
|
|
386
|
+
if (newHoverEntity && newHoverEntity.hasListeners('pointermove')) {
|
|
387
|
+
newHoverEntity.dispatchEvent(new PointerEvent('pointermove', event));
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
_onPointerDown(event: PointerEvent) {
|
|
392
|
+
if (!this._picker || !this.app) return;
|
|
393
|
+
|
|
394
|
+
const camera = this.app!.root.findComponent('camera') as CameraComponent;
|
|
395
|
+
if (!camera) return;
|
|
396
|
+
|
|
397
|
+
// Convert the event's pointer coordinates
|
|
398
|
+
const { x, y } = this._getPickerCoordinates(event);
|
|
399
|
+
|
|
400
|
+
this._picker.prepare(camera, this.app!.scene);
|
|
401
|
+
const selection = this._picker.getSelection(x, y);
|
|
402
|
+
|
|
403
|
+
if (selection.length > 0) {
|
|
404
|
+
const item = selection[0];
|
|
405
|
+
let currentNode: GraphNode | null = item instanceof MeshInstance ? item.node : (item as GSplatComponent).entity;
|
|
406
|
+
while (currentNode !== null) {
|
|
407
|
+
const entityElement = this.querySelector(`pc-entity[name="${currentNode.name}"]`) as EntityElement;
|
|
408
|
+
if (entityElement && entityElement.hasListeners('pointerdown')) {
|
|
409
|
+
entityElement.dispatchEvent(new PointerEvent('pointerdown', event));
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
currentNode = currentNode.parent;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
_onPointerUp(event: PointerEvent) {
|
|
418
|
+
if (!this._picker || !this.app) return;
|
|
419
|
+
|
|
420
|
+
const camera = this.app!.root.findComponent('camera') as CameraComponent;
|
|
421
|
+
if (!camera) return;
|
|
422
|
+
|
|
423
|
+
// Convert CSS coordinates to picker coordinates
|
|
424
|
+
const { x, y } = this._getPickerCoordinates(event);
|
|
425
|
+
|
|
426
|
+
this._picker.prepare(camera, this.app!.scene);
|
|
427
|
+
const selection = this._picker.getSelection(x, y);
|
|
428
|
+
|
|
429
|
+
if (selection.length > 0) {
|
|
430
|
+
const item = selection[0];
|
|
431
|
+
const node = item instanceof MeshInstance ? item.node : (item as GSplatComponent).entity;
|
|
432
|
+
const entityElement = this.querySelector(`pc-entity[name="${node.name}"]`) as EntityElement;
|
|
433
|
+
if (entityElement && entityElement.hasListeners('pointerup')) {
|
|
434
|
+
entityElement.dispatchEvent(new PointerEvent('pointerup', event));
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
_onPointerListenerAdded(type: string) {
|
|
440
|
+
if (!this._hasPointerListeners[type] && this._canvas) {
|
|
441
|
+
this._hasPointerListeners[type] = true;
|
|
442
|
+
|
|
443
|
+
// For enter/leave events, we need the move handler
|
|
444
|
+
const handler = (type === 'pointerenter' || type === 'pointerleave') ?
|
|
445
|
+
this._pointerHandlers.pointermove :
|
|
446
|
+
this._pointerHandlers[type];
|
|
447
|
+
|
|
448
|
+
if (handler) {
|
|
449
|
+
this._canvas.addEventListener(type === 'pointerenter' || type === 'pointerleave' ? 'pointermove' : type, handler);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
_onPointerListenerRemoved(type: string) {
|
|
455
|
+
const hasListeners = Array.from(this.querySelectorAll<EntityElement>('pc-entity'))
|
|
456
|
+
.some(entity => entity.hasListeners(type));
|
|
457
|
+
|
|
458
|
+
if (!hasListeners && this._canvas) {
|
|
459
|
+
this._hasPointerListeners[type] = false;
|
|
460
|
+
|
|
461
|
+
const handler = (type === 'pointerenter' || type === 'pointerleave') ?
|
|
462
|
+
this._pointerHandlers.pointermove :
|
|
463
|
+
this._pointerHandlers[type];
|
|
464
|
+
|
|
465
|
+
if (handler) {
|
|
466
|
+
this._canvas.removeEventListener(type === 'pointerenter' || type === 'pointerleave' ? 'pointermove' : type, handler);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Sets the alpha flag.
|
|
473
|
+
* @param value - The alpha flag.
|
|
474
|
+
*/
|
|
475
|
+
set alpha(value: boolean) {
|
|
476
|
+
this._alpha = value;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Gets the alpha flag.
|
|
481
|
+
* @returns The alpha flag.
|
|
482
|
+
*/
|
|
483
|
+
get alpha() {
|
|
484
|
+
return this._alpha;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Sets the antialias flag.
|
|
489
|
+
* @param value - The antialias flag.
|
|
490
|
+
*/
|
|
491
|
+
set antialias(value: boolean) {
|
|
492
|
+
this._antialias = value;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Gets the antialias flag.
|
|
497
|
+
* @returns The antialias flag.
|
|
498
|
+
*/
|
|
499
|
+
get antialias() {
|
|
500
|
+
return this._antialias;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Sets the graphics backend.
|
|
505
|
+
* @param value - The graphics backend ('webgpu', 'webgl2', or 'null').
|
|
506
|
+
*/
|
|
507
|
+
set backend(value: 'webgpu' | 'webgl2' | 'null') {
|
|
508
|
+
this._backend = value;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Gets the graphics backend.
|
|
513
|
+
* @returns The graphics backend.
|
|
514
|
+
*/
|
|
515
|
+
get backend() {
|
|
516
|
+
return this._backend;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Sets the depth flag.
|
|
521
|
+
* @param value - The depth flag.
|
|
522
|
+
*/
|
|
523
|
+
set depth(value: boolean) {
|
|
524
|
+
this._depth = value;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Gets the depth flag.
|
|
529
|
+
* @returns The depth flag.
|
|
530
|
+
*/
|
|
531
|
+
get depth() {
|
|
532
|
+
return this._depth;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Gets the hierarchy ready flag.
|
|
537
|
+
* @returns The hierarchy ready flag.
|
|
538
|
+
* @ignore
|
|
539
|
+
*/
|
|
540
|
+
get hierarchyReady() {
|
|
541
|
+
return this._hierarchyReady;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Sets the high resolution flag. When true, the application will render at the device's
|
|
546
|
+
* physical resolution. When false, the application will render at CSS resolution.
|
|
547
|
+
* @param value - The high resolution flag.
|
|
548
|
+
*/
|
|
549
|
+
set highResolution(value: boolean) {
|
|
550
|
+
this._highResolution = value;
|
|
551
|
+
if (this.app) {
|
|
552
|
+
this.app.graphicsDevice.maxPixelRatio = value ? window.devicePixelRatio : 1;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Gets the high resolution flag.
|
|
558
|
+
* @returns The high resolution flag.
|
|
559
|
+
*/
|
|
560
|
+
get highResolution() {
|
|
561
|
+
return this._highResolution;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Sets the stencil flag.
|
|
566
|
+
* @param value - The stencil flag.
|
|
567
|
+
*/
|
|
568
|
+
set stencil(value: boolean) {
|
|
569
|
+
this._stencil = value;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Gets the stencil flag.
|
|
574
|
+
* @returns The stencil flag.
|
|
575
|
+
*/
|
|
576
|
+
get stencil() {
|
|
577
|
+
return this._stencil;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
static get observedAttributes() {
|
|
581
|
+
return ['alpha', 'antialias', 'backend', 'depth', 'stencil', 'high-resolution'];
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
|
|
585
|
+
switch (name) {
|
|
586
|
+
case 'alpha':
|
|
587
|
+
this.alpha = newValue !== 'false';
|
|
588
|
+
break;
|
|
589
|
+
case 'antialias':
|
|
590
|
+
this.antialias = newValue !== 'false';
|
|
591
|
+
break;
|
|
592
|
+
case 'backend':
|
|
593
|
+
if (newValue === 'webgpu' || newValue === 'webgl2' || newValue === 'null') {
|
|
594
|
+
this.backend = newValue;
|
|
595
|
+
}
|
|
596
|
+
break;
|
|
597
|
+
case 'depth':
|
|
598
|
+
this.depth = newValue !== 'false';
|
|
599
|
+
break;
|
|
600
|
+
case 'high-resolution':
|
|
601
|
+
this.highResolution = newValue !== 'false';
|
|
602
|
+
break;
|
|
603
|
+
case 'stencil':
|
|
604
|
+
this.stencil = newValue !== 'false';
|
|
605
|
+
break;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
customElements.define('pc-app', AppElement);
|
|
611
|
+
|
|
612
|
+
export { AppElement };
|