@playcanvas/web-components 0.1.0 → 0.1.2

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.
@@ -0,0 +1,117 @@
1
+ import { RenderComponent } from 'playcanvas';
2
+
3
+ import { ComponentElement } from './component';
4
+
5
+ /**
6
+ * Represents a render component in the PlayCanvas engine.
7
+ *
8
+ * @category Components
9
+ */
10
+ class RenderComponentElement extends ComponentElement {
11
+ private _type: 'asset' | 'box' | 'capsule' | 'cone' | 'cylinder' | 'plane' | 'sphere' = 'asset';
12
+
13
+ private _castShadows = true;
14
+
15
+ private _receiveShadows = true;
16
+
17
+ constructor() {
18
+ super('render');
19
+ }
20
+
21
+ getInitialComponentData() {
22
+ return {
23
+ type: this._type,
24
+ castShadows: this._castShadows,
25
+ receiveShadows: this._receiveShadows
26
+ };
27
+ }
28
+
29
+ /**
30
+ * Gets the render component.
31
+ * @returns The render component.
32
+ */
33
+ get component(): RenderComponent | null {
34
+ return super.component as RenderComponent | null;
35
+ }
36
+
37
+ /**
38
+ * Sets the type of the render component.
39
+ * @param value - The type.
40
+ */
41
+ set type(value: 'asset' | 'box' | 'capsule' | 'cone' | 'cylinder' | 'plane' | 'sphere') {
42
+ this._type = value;
43
+ if (this.component) {
44
+ this.component.type = value;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Gets the type of the render component.
50
+ * @returns The type.
51
+ */
52
+ get type(): 'asset' | 'box' | 'capsule' | 'cone' | 'cylinder' | 'plane' | 'sphere' {
53
+ return this._type;
54
+ }
55
+
56
+ /**
57
+ * Sets the cast shadows flag of the render component.
58
+ * @param value - The cast shadows flag.
59
+ */
60
+ set castShadows(value: boolean) {
61
+ this._castShadows = value;
62
+ if (this.component) {
63
+ this.component.castShadows = value;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Gets the cast shadows flag of the render component.
69
+ * @returns The cast shadows flag.
70
+ */
71
+ get castShadows(): boolean {
72
+ return this._castShadows;
73
+ }
74
+
75
+ /**
76
+ * Sets the receive shadows flag of the render component.
77
+ * @param value - The receive shadows flag.
78
+ */
79
+ set receiveShadows(value: boolean) {
80
+ this._receiveShadows = value;
81
+ if (this.component) {
82
+ this.component.receiveShadows = value;
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Gets the receive shadows flag of the render component.
88
+ * @returns The receive shadows flag.
89
+ */
90
+ get receiveShadows(): boolean {
91
+ return this._receiveShadows;
92
+ }
93
+
94
+ static get observedAttributes() {
95
+ return [...super.observedAttributes, 'cast-shadows', 'receive-shadows', 'type'];
96
+ }
97
+
98
+ attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
99
+ super.attributeChangedCallback(name, _oldValue, newValue);
100
+
101
+ switch (name) {
102
+ case 'type':
103
+ this.type = newValue as 'asset' | 'box' | 'capsule' | 'cone' | 'cylinder' | 'plane' | 'sphere';
104
+ break;
105
+ case 'cast-shadows':
106
+ this.castShadows = newValue !== 'false';
107
+ break;
108
+ case 'receive-shadows':
109
+ this.receiveShadows = newValue !== 'false';
110
+ break;
111
+ }
112
+ }
113
+ }
114
+
115
+ customElements.define('pc-render', RenderComponentElement);
116
+
117
+ export { RenderComponentElement };
@@ -0,0 +1,226 @@
1
+ import { RigidBodyComponent, Vec3 } from 'playcanvas';
2
+
3
+ import { ComponentElement } from './component';
4
+ import { parseVec3 } from '../utils';
5
+
6
+ /**
7
+ * Represents a rigidbody component in the PlayCanvas engine.
8
+ *
9
+ * @category Components
10
+ */
11
+ class RigidBodyComponentElement extends ComponentElement {
12
+ /**
13
+ * The angular damping of the rigidbody.
14
+ */
15
+ private _angularDamping: number = 0;
16
+
17
+ /**
18
+ * The angular factor of the rigidbody.
19
+ */
20
+ private _angularFactor: Vec3 = new Vec3(1, 1, 1);
21
+
22
+ /**
23
+ * The friction of the rigidbody.
24
+ */
25
+ private _friction: number = 0.5;
26
+
27
+ /**
28
+ * The linear damping of the rigidbody.
29
+ */
30
+ private _linearDamping: number = 0;
31
+
32
+ /**
33
+ * The linear factor of the rigidbody.
34
+ */
35
+ private _linearFactor: Vec3 = new Vec3(1, 1, 1);
36
+
37
+ /**
38
+ * The mass of the rigidbody.
39
+ */
40
+ private _mass: number = 1;
41
+
42
+ /**
43
+ * The restitution of the rigidbody.
44
+ */
45
+ private _restitution: number = 0;
46
+
47
+ /**
48
+ * The rolling friction of the rigidbody.
49
+ */
50
+ private _rollingFriction: number = 0;
51
+
52
+ /**
53
+ * The type of the rigidbody.
54
+ */
55
+ private _type: string = 'static';
56
+
57
+ /**
58
+ * Creates a new RigidBodyComponentElement.
59
+ */
60
+ constructor() {
61
+ super('rigidbody');
62
+ }
63
+
64
+ getInitialComponentData() {
65
+ return {
66
+ angularDamping: this._angularDamping,
67
+ angularFactor: this._angularFactor,
68
+ friction: this._friction,
69
+ linearDamping: this._linearDamping,
70
+ linearFactor: this._linearFactor,
71
+ mass: this._mass,
72
+ restitution: this._restitution,
73
+ rollingFriction: this._rollingFriction,
74
+ type: this._type
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Gets the collision component.
80
+ * @returns The collision component.
81
+ */
82
+ get component(): RigidBodyComponent | null {
83
+ return super.component as RigidBodyComponent | null;
84
+ }
85
+
86
+ set angularDamping(value: number) {
87
+ this._angularDamping = value;
88
+ if (this.component) {
89
+ this.component.angularDamping = value;
90
+ }
91
+ }
92
+
93
+ get angularDamping() {
94
+ return this._angularDamping;
95
+ }
96
+
97
+ set angularFactor(value: Vec3) {
98
+ this._angularFactor = value;
99
+ if (this.component) {
100
+ this.component.angularFactor = value;
101
+ }
102
+ }
103
+
104
+ get angularFactor() {
105
+ return this._angularFactor;
106
+ }
107
+
108
+ set friction(value: number) {
109
+ this._friction = value;
110
+ if (this.component) {
111
+ this.component.friction = value;
112
+ }
113
+ }
114
+
115
+ get friction() {
116
+ return this._friction;
117
+ }
118
+
119
+ set linearDamping(value: number) {
120
+ this._linearDamping = value;
121
+ if (this.component) {
122
+ this.component.linearDamping = value;
123
+ }
124
+ }
125
+
126
+ get linearDamping() {
127
+ return this._linearDamping;
128
+ }
129
+
130
+ set linearFactor(value: Vec3) {
131
+ this._linearFactor = value;
132
+ if (this.component) {
133
+ this.component.linearFactor = value;
134
+ }
135
+ }
136
+
137
+ get linearFactor() {
138
+ return this._linearFactor;
139
+ }
140
+
141
+ set mass(value: number) {
142
+ this._mass = value;
143
+ if (this.component) {
144
+ this.component.mass = value;
145
+ }
146
+ }
147
+
148
+ get mass() {
149
+ return this._mass;
150
+ }
151
+
152
+ set restitution(value: number) {
153
+ this._restitution = value;
154
+ if (this.component) {
155
+ this.component.restitution = value;
156
+ }
157
+ }
158
+
159
+ get restitution() {
160
+ return this._restitution;
161
+ }
162
+
163
+ set rollingFriction(value: number) {
164
+ this._rollingFriction = value;
165
+ if (this.component) {
166
+ this.component.rollingFriction = value;
167
+ }
168
+ }
169
+
170
+ get rollingFriction() {
171
+ return this._rollingFriction;
172
+ }
173
+
174
+ set type(value: string) {
175
+ this._type = value;
176
+ if (this.component) {
177
+ this.component.type = value;
178
+ }
179
+ }
180
+
181
+ get type() {
182
+ return this._type;
183
+ }
184
+
185
+ static get observedAttributes() {
186
+ return [...super.observedAttributes, 'angular-damping', 'angular-factor', 'friction', 'linear-damping', 'linear-factor', 'mass', 'restitution', 'rolling-friction', 'type'];
187
+ }
188
+
189
+ attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
190
+ super.attributeChangedCallback(name, _oldValue, newValue);
191
+
192
+ switch (name) {
193
+ case 'angular-damping':
194
+ this.angularDamping = parseFloat(newValue);
195
+ break;
196
+ case 'angular-factor':
197
+ this.angularFactor = parseVec3(newValue);
198
+ break;
199
+ case 'friction':
200
+ this.friction = parseFloat(newValue);
201
+ break;
202
+ case 'linear-damping':
203
+ this.linearDamping = parseFloat(newValue);
204
+ break;
205
+ case 'linear-factor':
206
+ this.linearFactor = parseVec3(newValue);
207
+ break;
208
+ case 'mass':
209
+ this.mass = parseFloat(newValue);
210
+ break;
211
+ case 'restitution':
212
+ this.restitution = parseFloat(newValue);
213
+ break;
214
+ case 'rolling-friction':
215
+ this.rollingFriction = parseFloat(newValue);
216
+ break;
217
+ case 'type':
218
+ this.type = newValue;
219
+ break;
220
+ }
221
+ }
222
+ }
223
+
224
+ customElements.define('pc-rigidbody', RigidBodyComponentElement);
225
+
226
+ export { RigidBodyComponentElement };
@@ -0,0 +1,145 @@
1
+ import { ScriptComponent, ScriptType } from 'playcanvas';
2
+
3
+ import { ComponentElement } from './component';
4
+ import { ScriptElement } from './script';
5
+
6
+ // Add these interfaces at the top of the file, after the imports
7
+ interface ScriptAttributesChangeEvent extends CustomEvent {
8
+ detail: { attributes: any };
9
+ }
10
+
11
+ interface ScriptEnableChangeEvent extends CustomEvent {
12
+ detail: { enabled: boolean };
13
+ }
14
+
15
+ // Add this interface before the ScriptComponentElement class
16
+ declare global {
17
+ interface HTMLElementEventMap {
18
+ 'scriptattributeschange': ScriptAttributesChangeEvent;
19
+ 'scriptenablechange': ScriptEnableChangeEvent;
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Represents a script component in the PlayCanvas engine.
25
+ *
26
+ * @category Components
27
+ */
28
+ class ScriptComponentElement extends ComponentElement {
29
+ private observer: MutationObserver;
30
+
31
+ constructor() {
32
+ super('script');
33
+
34
+ // Create mutation observer to watch for child script elements
35
+ this.observer = new MutationObserver(this.handleMutations.bind(this));
36
+ this.observer.observe(this, {
37
+ childList: true
38
+ });
39
+
40
+ // Listen for script attribute and enable changes
41
+ this.addEventListener('scriptattributeschange', this.handleScriptAttributesChange.bind(this));
42
+ this.addEventListener('scriptenablechange', this.handleScriptEnableChange.bind(this));
43
+ }
44
+
45
+ async connectedCallback() {
46
+ await super.connectedCallback();
47
+
48
+ // Handle initial script elements
49
+ this.querySelectorAll<ScriptElement>(':scope > pc-script').forEach((scriptElement) => {
50
+ const scriptName = scriptElement.getAttribute('name');
51
+ const attributes = scriptElement.getAttribute('attributes');
52
+ if (scriptName) {
53
+ this.createScript(scriptName, attributes);
54
+ }
55
+ });
56
+ }
57
+
58
+ private applyAttributes(script: ScriptType, attributes: string | null) {
59
+ try {
60
+ // Parse the attributes string into an object and set them on the script
61
+ const attributesObject = attributes ? JSON.parse(attributes) : {};
62
+ Object.assign(script, attributesObject);
63
+ } catch (error) {
64
+ console.error(`Error parsing attributes JSON string ${attributes}:`, error);
65
+ }
66
+ }
67
+
68
+ private handleScriptAttributesChange(event: ScriptAttributesChangeEvent) {
69
+ const scriptElement = event.target as ScriptElement;
70
+ const scriptName = scriptElement.getAttribute('name');
71
+ if (!scriptName || !this.component) return;
72
+
73
+ const script = this.component.get(scriptName);
74
+ if (script) {
75
+ this.applyAttributes(script, event.detail.attributes);
76
+ }
77
+ }
78
+
79
+ private handleScriptEnableChange(event: ScriptEnableChangeEvent) {
80
+ const scriptElement = event.target as ScriptElement;
81
+ const scriptName = scriptElement.getAttribute('name');
82
+ if (!scriptName || !this.component) return;
83
+
84
+ const script = this.component.get(scriptName);
85
+ if (script) {
86
+ script.enabled = event.detail.enabled;
87
+ }
88
+ }
89
+
90
+ private createScript(name: string, attributes: string | null): ScriptType | null {
91
+ if (!this.component) return null;
92
+
93
+ this.component.on(`create:${name}`, (script) => {
94
+ this.applyAttributes(script, attributes);
95
+ });
96
+ return this.component.create(name);
97
+ }
98
+
99
+ private destroyScript(name: string): void {
100
+ if (!this.component) return;
101
+ this.component.destroy(name);
102
+ }
103
+
104
+ private handleMutations(mutations: MutationRecord[]) {
105
+ for (const mutation of mutations) {
106
+ // Handle added nodes
107
+ mutation.addedNodes.forEach((node) => {
108
+ if (node instanceof HTMLElement && node.tagName.toLowerCase() === 'pc-script') {
109
+ const scriptName = node.getAttribute('name');
110
+ const attributes = node.getAttribute('attributes');
111
+ if (scriptName) {
112
+ this.createScript(scriptName, attributes);
113
+ }
114
+ }
115
+ });
116
+
117
+ // Handle removed nodes
118
+ mutation.removedNodes.forEach((node) => {
119
+ if (node instanceof HTMLElement && node.tagName.toLowerCase() === 'pc-script') {
120
+ const scriptName = node.getAttribute('name');
121
+ if (scriptName) {
122
+ this.destroyScript(scriptName);
123
+ }
124
+ }
125
+ });
126
+ }
127
+ }
128
+
129
+ disconnectedCallback() {
130
+ this.observer.disconnect();
131
+ super.disconnectedCallback?.();
132
+ }
133
+
134
+ /**
135
+ * Gets the script component.
136
+ * @returns The script component.
137
+ */
138
+ get component(): ScriptComponent | null {
139
+ return super.component as ScriptComponent | null;
140
+ }
141
+ }
142
+
143
+ customElements.define('pc-scripts', ScriptComponentElement);
144
+
145
+ export { ScriptComponentElement };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Represents a script in the PlayCanvas engine.
3
+ */
4
+ class ScriptElement extends HTMLElement {
5
+ private _attributes: string = '{}';
6
+
7
+ private _enabled: boolean = true;
8
+
9
+ private _name: string = '';
10
+
11
+ /**
12
+ * Sets the attributes of the script.
13
+ * @param value - The attributes of the script.
14
+ */
15
+ set scriptAttributes(value: string) {
16
+ this._attributes = value;
17
+ this.dispatchEvent(new CustomEvent('scriptattributeschange', {
18
+ detail: { attributes: value },
19
+ bubbles: true
20
+ }));
21
+ }
22
+
23
+ /**
24
+ * Gets the attributes of the script.
25
+ * @returns The attributes of the script.
26
+ */
27
+ get scriptAttributes() {
28
+ return this._attributes;
29
+ }
30
+
31
+ /**
32
+ * Sets the enabled state of the script.
33
+ * @param value - The enabled state of the script.
34
+ */
35
+ set enabled(value: boolean) {
36
+ this._enabled = value;
37
+ this.dispatchEvent(new CustomEvent('scriptenablechange', {
38
+ detail: { enabled: value },
39
+ bubbles: true
40
+ }));
41
+ }
42
+
43
+ /**
44
+ * Gets the enabled state of the script.
45
+ * @returns The enabled state of the script.
46
+ */
47
+ get enabled() {
48
+ return this._enabled;
49
+ }
50
+
51
+ /**
52
+ * Sets the name of the script to create.
53
+ * @param value - The name.
54
+ */
55
+ set name(value: string) {
56
+ this._name = value;
57
+ }
58
+
59
+ /**
60
+ * Gets the name of the script.
61
+ * @returns The name.
62
+ */
63
+ get name() {
64
+ return this._name;
65
+ }
66
+
67
+ static get observedAttributes() {
68
+ return ['attributes', 'enabled', 'name'];
69
+ }
70
+
71
+ attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
72
+ switch (name) {
73
+ case 'attributes':
74
+ this.scriptAttributes = newValue;
75
+ break;
76
+ case 'enabled':
77
+ this.enabled = newValue !== 'false';
78
+ break;
79
+ case 'name':
80
+ this.name = newValue;
81
+ break;
82
+ }
83
+ }
84
+ }
85
+
86
+ customElements.define('pc-script', ScriptElement);
87
+
88
+ export { ScriptElement };
@@ -0,0 +1,117 @@
1
+ import { SoundComponent } from 'playcanvas';
2
+
3
+ import { ComponentElement } from './component';
4
+
5
+ /**
6
+ * Represents a sound component in the PlayCanvas engine.
7
+ *
8
+ * @category Components
9
+ */
10
+ class SoundComponentElement extends ComponentElement {
11
+ private _pitch: number = 1;
12
+
13
+ private _positional: boolean = false;
14
+
15
+ private _volume: number = 1;
16
+
17
+ constructor() {
18
+ super('sound');
19
+ }
20
+
21
+ getInitialComponentData() {
22
+ return {
23
+ pitch: this._pitch,
24
+ positional: this._positional,
25
+ volume: this._volume
26
+ };
27
+ }
28
+
29
+ /**
30
+ * Gets the sound component.
31
+ * @returns The sound component.
32
+ */
33
+ get component(): SoundComponent | null {
34
+ return super.component as SoundComponent | null;
35
+ }
36
+
37
+ /**
38
+ * Sets the pitch of the sound.
39
+ * @param value - The pitch.
40
+ */
41
+ set pitch(value: number) {
42
+ this._pitch = value;
43
+ if (this.component) {
44
+ this.component.pitch = value;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Gets the pitch of the sound.
50
+ * @returns The pitch.
51
+ */
52
+ get pitch() {
53
+ return this._pitch;
54
+ }
55
+
56
+ /**
57
+ * Sets the positional flag of the sound.
58
+ * @param value - The positional flag.
59
+ */
60
+ set positional(value: boolean) {
61
+ this._positional = value;
62
+ if (this.component) {
63
+ this.component.positional = value;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Gets the positional flag of the sound.
69
+ * @returns The positional flag.
70
+ */
71
+ get positional() {
72
+ return this._positional;
73
+ }
74
+
75
+ /**
76
+ * Sets the volume of the sound.
77
+ * @param value - The volume.
78
+ */
79
+ set volume(value: number) {
80
+ this._volume = value;
81
+ if (this.component) {
82
+ this.component.volume = value;
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Gets the volume of the sound.
88
+ * @returns The volume.
89
+ */
90
+ get volume() {
91
+ return this._volume;
92
+ }
93
+
94
+ static get observedAttributes() {
95
+ return [...super.observedAttributes, 'pitch', 'positional', 'volume'];
96
+ }
97
+
98
+ attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
99
+ super.attributeChangedCallback(name, _oldValue, newValue);
100
+
101
+ switch (name) {
102
+ case 'pitch':
103
+ this.pitch = parseFloat(newValue);
104
+ break;
105
+ case 'positional':
106
+ this.positional = this.hasAttribute('positional');
107
+ break;
108
+ case 'volume':
109
+ this.volume = parseFloat(newValue);
110
+ break;
111
+ }
112
+ }
113
+ }
114
+
115
+ customElements.define('pc-sounds', SoundComponentElement);
116
+
117
+ export { SoundComponentElement };