@playcanvas/web-components 0.1.5 → 0.1.7

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/src/colors.ts ADDED
@@ -0,0 +1,150 @@
1
+ export const CSS_COLORS: Record<string, string> = {
2
+ aliceblue: '#f0f8ff',
3
+ antiquewhite: '#faebd7',
4
+ aqua: '#00ffff',
5
+ aquamarine: '#7fffd4',
6
+ azure: '#f0ffff',
7
+ beige: '#f5f5dc',
8
+ bisque: '#ffe4c4',
9
+ black: '#000000',
10
+ blanchedalmond: '#ffebcd',
11
+ blue: '#0000ff',
12
+ blueviolet: '#8a2be2',
13
+ brown: '#a52a2a',
14
+ burlywood: '#deb887',
15
+ cadetblue: '#5f9ea0',
16
+ chartreuse: '#7fff00',
17
+ chocolate: '#d2691e',
18
+ coral: '#ff7f50',
19
+ cornflowerblue: '#6495ed',
20
+ cornsilk: '#fff8dc',
21
+ crimson: '#dc143c',
22
+ cyan: '#00ffff',
23
+ darkblue: '#00008b',
24
+ darkcyan: '#008b8b',
25
+ darkgoldenrod: '#b8860b',
26
+ darkgray: '#a9a9a9',
27
+ darkgreen: '#006400',
28
+ darkgrey: '#a9a9a9',
29
+ darkkhaki: '#bdb76b',
30
+ darkmagenta: '#8b008b',
31
+ darkolivegreen: '#556b2f',
32
+ darkorange: '#ff8c00',
33
+ darkorchid: '#9932cc',
34
+ darkred: '#8b0000',
35
+ darksalmon: '#e9967a',
36
+ darkseagreen: '#8fbc8f',
37
+ darkslateblue: '#483d8b',
38
+ darkslategray: '#2f4f4f',
39
+ darkslategrey: '#2f4f4f',
40
+ darkturquoise: '#00ced1',
41
+ darkviolet: '#9400d3',
42
+ deeppink: '#ff1493',
43
+ deepskyblue: '#00bfff',
44
+ dimgray: '#696969',
45
+ dimgrey: '#696969',
46
+ dodgerblue: '#1e90ff',
47
+ firebrick: '#b22222',
48
+ floralwhite: '#fffaf0',
49
+ forestgreen: '#228b22',
50
+ fuchsia: '#ff00ff',
51
+ gainsboro: '#dcdcdc',
52
+ ghostwhite: '#f8f8ff',
53
+ gold: '#ffd700',
54
+ goldenrod: '#daa520',
55
+ gray: '#808080',
56
+ green: '#008000',
57
+ greenyellow: '#adff2f',
58
+ grey: '#808080',
59
+ honeydew: '#f0fff0',
60
+ hotpink: '#ff69b4',
61
+ indianred: '#cd5c5c',
62
+ indigo: '#4b0082',
63
+ ivory: '#fffff0',
64
+ khaki: '#f0e68c',
65
+ lavender: '#e6e6fa',
66
+ lavenderblush: '#fff0f5',
67
+ lawngreen: '#7cfc00',
68
+ lemonchiffon: '#fffacd',
69
+ lightblue: '#add8e6',
70
+ lightcoral: '#f08080',
71
+ lightcyan: '#e0ffff',
72
+ lightgoldenrodyellow: '#fafad2',
73
+ lightgray: '#d3d3d3',
74
+ lightgreen: '#90ee90',
75
+ lightgrey: '#d3d3d3',
76
+ lightpink: '#ffb6c1',
77
+ lightsalmon: '#ffa07a',
78
+ lightseagreen: '#20b2aa',
79
+ lightskyblue: '#87cefa',
80
+ lightslategray: '#778899',
81
+ lightslategrey: '#778899',
82
+ lightsteelblue: '#b0c4de',
83
+ lightyellow: '#ffffe0',
84
+ lime: '#00ff00',
85
+ limegreen: '#32cd32',
86
+ linen: '#faf0e6',
87
+ magenta: '#ff00ff',
88
+ maroon: '#800000',
89
+ mediumaquamarine: '#66cdaa',
90
+ mediumblue: '#0000cd',
91
+ mediumorchid: '#ba55d3',
92
+ mediumpurple: '#9370db',
93
+ mediumseagreen: '#3cb371',
94
+ mediumslateblue: '#7b68ee',
95
+ mediumspringgreen: '#00fa9a',
96
+ mediumturquoise: '#48d1cc',
97
+ mediumvioletred: '#c71585',
98
+ midnightblue: '#191970',
99
+ mintcream: '#f5fffa',
100
+ mistyrose: '#ffe4e1',
101
+ moccasin: '#ffe4b5',
102
+ navajowhite: '#ffdead',
103
+ navy: '#000080',
104
+ oldlace: '#fdf5e6',
105
+ olive: '#808000',
106
+ olivedrab: '#6b8e23',
107
+ orange: '#ffa500',
108
+ orangered: '#ff4500',
109
+ orchid: '#da70d6',
110
+ palegoldenrod: '#eee8aa',
111
+ palegreen: '#98fb98',
112
+ paleturquoise: '#afeeee',
113
+ palevioletred: '#db7093',
114
+ papayawhip: '#ffefd5',
115
+ peachpuff: '#ffdab9',
116
+ peru: '#cd853f',
117
+ pink: '#ffc0cb',
118
+ plum: '#dda0dd',
119
+ powderblue: '#b0e0e6',
120
+ purple: '#800080',
121
+ rebeccapurple: '#663399',
122
+ red: '#ff0000',
123
+ rosybrown: '#bc8f8f',
124
+ royalblue: '#4169e1',
125
+ saddlebrown: '#8b4513',
126
+ salmon: '#fa8072',
127
+ sandybrown: '#f4a460',
128
+ seagreen: '#2e8b57',
129
+ seashell: '#fff5ee',
130
+ sienna: '#a0522d',
131
+ silver: '#c0c0c0',
132
+ skyblue: '#87ceeb',
133
+ slateblue: '#6a5acd',
134
+ slategray: '#708090',
135
+ slategrey: '#708090',
136
+ snow: '#fffafa',
137
+ springgreen: '#00ff7f',
138
+ steelblue: '#4682b4',
139
+ tan: '#d2b48c',
140
+ teal: '#008080',
141
+ thistle: '#d8bfd8',
142
+ tomato: '#ff6347',
143
+ turquoise: '#40e0d0',
144
+ violet: '#ee82ee',
145
+ wheat: '#f5deb3',
146
+ white: '#ffffff',
147
+ whitesmoke: '#f5f5f5',
148
+ yellow: '#ffff00',
149
+ yellowgreen: '#9acd32'
150
+ };
@@ -1,8 +1,12 @@
1
- import { ScriptComponent, ScriptType } from 'playcanvas';
1
+ import { ScriptComponent, Script, Vec2, Vec3, Vec4 } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
4
  import { ScriptElement } from './script';
5
5
 
6
+ const tmpV2 = new Vec2();
7
+ const tmpV3 = new Vec3();
8
+ const tmpV4 = new Vec4();
9
+
6
10
  // Add these interfaces at the top of the file, after the imports
7
11
  interface ScriptAttributesChangeEvent extends CustomEvent {
8
12
  detail: { attributes: any };
@@ -53,11 +57,43 @@ class ScriptComponentElement extends ComponentElement {
53
57
  });
54
58
  }
55
59
 
56
- private applyAttributes(script: ScriptType, attributes: string | null) {
60
+ private applyAttributes(script: any, attributes: string | null) {
57
61
  try {
58
- // Parse the attributes string into an object and set them on the script
59
62
  const attributesObject = attributes ? JSON.parse(attributes) : {};
60
- Object.assign(script, attributesObject);
63
+
64
+ const applyValue = (target: any, key: string, value: any) => {
65
+ // Handle vectors
66
+ if (Array.isArray(value)) {
67
+ if (target[key] instanceof Vec2) {
68
+ target[key] = tmpV2.set(value[0], value[1]);
69
+ return;
70
+ }
71
+ if (target[key] instanceof Vec3) {
72
+ target[key] = tmpV3.set(value[0], value[1], value[2]);
73
+ return;
74
+ }
75
+ if (target[key] instanceof Vec4) {
76
+ target[key] = tmpV4.set(value[0], value[1], value[2], value[3]);
77
+ return;
78
+ }
79
+ }
80
+
81
+ // Handle nested objects
82
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
83
+ if (!target[key] || typeof target[key] !== 'object') {
84
+ target[key] = {};
85
+ }
86
+ for (const nestedKey in value) {
87
+ applyValue(target[key], nestedKey, value[nestedKey]);
88
+ }
89
+ } else {
90
+ target[key] = value;
91
+ }
92
+ };
93
+
94
+ for (const key in attributesObject) {
95
+ applyValue(script, key, attributesObject[key]);
96
+ }
61
97
  } catch (error) {
62
98
  console.error(`Error parsing attributes JSON string ${attributes}:`, error);
63
99
  }
@@ -85,7 +121,7 @@ class ScriptComponentElement extends ComponentElement {
85
121
  }
86
122
  }
87
123
 
88
- private createScript(name: string, attributes: string | null): ScriptType | null {
124
+ private createScript(name: string, attributes: string | null): Script | null {
89
125
  if (!this.component) return null;
90
126
 
91
127
  this.component.on(`create:${name}`, (script) => {
@@ -8,10 +8,18 @@ import { ComponentElement } from './component';
8
8
  * @category Components
9
9
  */
10
10
  class SoundComponentElement extends ComponentElement {
11
+ private _distanceModel: 'exponential' | 'inverse' | 'linear' = 'linear';
12
+
13
+ private _maxDistance: number = 10000;
14
+
11
15
  private _pitch: number = 1;
12
16
 
13
17
  private _positional: boolean = false;
14
18
 
19
+ private _refDistance: number = 1;
20
+
21
+ private _rollOffFactor: number = 1;
22
+
15
23
  private _volume: number = 1;
16
24
 
17
25
  constructor() {
@@ -20,8 +28,12 @@ class SoundComponentElement extends ComponentElement {
20
28
 
21
29
  getInitialComponentData() {
22
30
  return {
31
+ distanceModel: this._distanceModel,
32
+ maxDistance: this._maxDistance,
23
33
  pitch: this._pitch,
24
34
  positional: this._positional,
35
+ refDistance: this._refDistance,
36
+ rollOffFactor: this._rollOffFactor,
25
37
  volume: this._volume
26
38
  };
27
39
  }
@@ -34,6 +46,44 @@ class SoundComponentElement extends ComponentElement {
34
46
  return super.component as SoundComponent | null;
35
47
  }
36
48
 
49
+ /**
50
+ * Sets which algorithm to use to reduce the volume of the sound as it moves away from the listener.
51
+ * @param value - The distance model.
52
+ */
53
+ set distanceModel(value: 'exponential' | 'inverse' | 'linear') {
54
+ this._distanceModel = value;
55
+ if (this.component) {
56
+ this.component.distanceModel = value;
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Gets which algorithm to use to reduce the volume of the sound as it moves away from the listener.
62
+ * @returns The distance model.
63
+ */
64
+ get distanceModel(): 'exponential' | 'inverse' | 'linear' {
65
+ return this._distanceModel;
66
+ }
67
+
68
+ /**
69
+ * Sets the maximum distance from the listener at which audio falloff stops.
70
+ * @param value - The max distance.
71
+ */
72
+ set maxDistance(value: number) {
73
+ this._maxDistance = value;
74
+ if (this.component) {
75
+ this.component.maxDistance = value;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Gets the maximum distance from the listener at which audio falloff stops.
81
+ * @returns The max distance.
82
+ */
83
+ get maxDistance() {
84
+ return this._maxDistance;
85
+ }
86
+
37
87
  /**
38
88
  * Sets the pitch of the sound.
39
89
  * @param value - The pitch.
@@ -72,6 +122,44 @@ class SoundComponentElement extends ComponentElement {
72
122
  return this._positional;
73
123
  }
74
124
 
125
+ /**
126
+ * Sets the reference distance for reducing volume as the sound source moves further from the listener. Defaults to 1.
127
+ * @param value - The ref distance.
128
+ */
129
+ set refDistance(value: number) {
130
+ this._refDistance = value;
131
+ if (this.component) {
132
+ this.component.refDistance = value;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Gets the reference distance for reducing volume as the sound source moves further from the listener.
138
+ * @returns The ref distance.
139
+ */
140
+ get refDistance() {
141
+ return this._refDistance;
142
+ }
143
+
144
+ /**
145
+ * Sets the factor used in the falloff equation. Defaults to 1.
146
+ * @param value - The roll-off factor.
147
+ */
148
+ set rollOffFactor(value: number) {
149
+ this._rollOffFactor = value;
150
+ if (this.component) {
151
+ this.component.rollOffFactor = value;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Gets the factor used in the falloff equation.
157
+ * @returns The roll-off factor.
158
+ */
159
+ get rollOffFactor() {
160
+ return this._rollOffFactor;
161
+ }
162
+
75
163
  /**
76
164
  * Sets the volume of the sound.
77
165
  * @param value - The volume.
@@ -92,19 +180,40 @@ class SoundComponentElement extends ComponentElement {
92
180
  }
93
181
 
94
182
  static get observedAttributes() {
95
- return [...super.observedAttributes, 'pitch', 'positional', 'volume'];
183
+ return [
184
+ ...super.observedAttributes,
185
+ 'distance-model',
186
+ 'max-distance',
187
+ 'pitch',
188
+ 'positional',
189
+ 'ref-distance',
190
+ 'roll-off-factor',
191
+ 'volume'
192
+ ];
96
193
  }
97
194
 
98
195
  attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
99
196
  super.attributeChangedCallback(name, _oldValue, newValue);
100
197
 
101
198
  switch (name) {
199
+ case 'distance-model':
200
+ this.distanceModel = newValue as 'exponential' | 'inverse' | 'linear';
201
+ break;
202
+ case 'max-distance':
203
+ this.maxDistance = parseFloat(newValue);
204
+ break;
102
205
  case 'pitch':
103
206
  this.pitch = parseFloat(newValue);
104
207
  break;
105
208
  case 'positional':
106
209
  this.positional = this.hasAttribute('positional');
107
210
  break;
211
+ case 'ref-distance':
212
+ this.refDistance = parseFloat(newValue);
213
+ break;
214
+ case 'roll-off-factor':
215
+ this.rollOffFactor = parseFloat(newValue);
216
+ break;
108
217
  case 'volume':
109
218
  this.volume = parseFloat(newValue);
110
219
  break;
package/src/model.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { ContainerResource, Entity } from 'playcanvas';
2
+
1
3
  import { AssetElement } from './asset';
2
4
  import { AsyncElement } from './async-element';
3
5
 
@@ -7,51 +9,77 @@ import { AsyncElement } from './async-element';
7
9
  class ModelElement extends AsyncElement {
8
10
  private _asset: string = '';
9
11
 
10
- async connectedCallback() {
11
- await this.closestApp?.ready();
12
-
13
- const asset = this.getAttribute('asset');
14
- if (asset) {
15
- this.asset = asset;
16
- }
12
+ private _entity: Entity | null = null;
17
13
 
14
+ connectedCallback() {
15
+ this._loadModel();
18
16
  this._onReady();
19
17
  }
20
18
 
21
- _loadModel() {
22
- const asset = AssetElement.get(this._asset);
23
- if (!asset) {
24
- return;
25
- }
26
- const entity = asset.resource.instantiateRenderEntity();
19
+ disconnectedCallback() {
20
+ this._unloadModel();
21
+ }
22
+
23
+ private _instantiate(container: ContainerResource) {
24
+ this._entity = container.instantiateRenderEntity();
27
25
 
28
- if (asset.resource.animations.length > 0) {
29
- entity.addComponent('anim');
30
- entity.anim.assignAnimation('animation', asset.resource.animations[0].resource);
26
+ // @ts-ignore
27
+ if (container.animations.length > 0) {
28
+ this._entity.addComponent('anim');
29
+ // @ts-ignore
30
+ this._entity.anim.assignAnimation('animation', container.animations[0].resource);
31
31
  }
32
32
 
33
33
  const parentEntityElement = this.closestEntity;
34
34
  if (parentEntityElement) {
35
35
  parentEntityElement.ready().then(() => {
36
- parentEntityElement.entity!.addChild(entity);
36
+ parentEntityElement.entity!.addChild(this._entity!);
37
37
  });
38
38
  } else {
39
39
  const appElement = this.closestApp;
40
40
  if (appElement) {
41
41
  appElement.ready().then(() => {
42
- appElement.app!.root.addChild(entity);
42
+ appElement.app!.root.addChild(this._entity!);
43
43
  });
44
44
  }
45
45
  }
46
46
  }
47
47
 
48
+ private async _loadModel() {
49
+ this._unloadModel();
50
+
51
+ const appElement = await this.closestApp?.ready();
52
+ const app = appElement?.app;
53
+
54
+ const asset = AssetElement.get(this._asset);
55
+ if (!asset) {
56
+ return;
57
+ }
58
+
59
+ if (asset.loaded) {
60
+ this._instantiate(asset.resource);
61
+ } else {
62
+ asset.once('load', () => {
63
+ this._instantiate(asset.resource);
64
+ });
65
+ app!.assets.load(asset);
66
+ }
67
+ }
68
+
69
+ private _unloadModel() {
70
+ this._entity?.destroy();
71
+ this._entity = null;
72
+ }
73
+
48
74
  /**
49
75
  * Sets the asset ID of the model.
50
76
  * @param value - The asset ID.
51
77
  */
52
78
  set asset(value: string) {
53
79
  this._asset = value;
54
- this._loadModel();
80
+ if (this.isConnected) {
81
+ this._loadModel();
82
+ }
55
83
  }
56
84
 
57
85
  /**
package/src/module.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { WasmModule } from 'playcanvas';
1
+ import { basisInitialize, WasmModule } from 'playcanvas';
2
2
 
3
3
  class ModuleElement extends HTMLElement {
4
4
  private loadPromise: Promise<void>;
@@ -14,15 +14,23 @@ class ModuleElement extends HTMLElement {
14
14
  const wasm = this.getAttribute('wasm')!;
15
15
  const fallback = this.getAttribute('fallback')!;
16
16
 
17
- WasmModule.setConfig(name, {
18
- glueUrl: glue,
19
- wasmUrl: wasm,
20
- fallbackUrl: fallback
21
- });
22
-
23
- await new Promise<void>((resolve) => {
24
- WasmModule.getInstance(name, () => resolve());
25
- });
17
+ if (name === 'Basis') {
18
+ basisInitialize({
19
+ glueUrl: glue,
20
+ wasmUrl: wasm,
21
+ fallbackUrl: fallback
22
+ });
23
+ } else {
24
+ WasmModule.setConfig(name, {
25
+ glueUrl: glue,
26
+ wasmUrl: wasm,
27
+ fallbackUrl: fallback
28
+ });
29
+
30
+ await new Promise<void>((resolve) => {
31
+ WasmModule.getInstance(name, () => resolve());
32
+ });
33
+ }
26
34
  }
27
35
 
28
36
  public getLoadPromise(): Promise<void> {