@playcanvas/web-components 0.1.5 → 0.1.6

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/README.md CHANGED
@@ -1,6 +1,34 @@
1
1
  # PlayCanvas Web Components
2
2
 
3
- Unleash the power of PlayCanvas in your HTML. PlayCanvas Web Components allows you to write PlayCanvas scenes using only HTML, enabling a clear and concise structure, and making it easier than ever to integrate with other web technologies. Just add tags for entities, components, and assets, and watch your 3D scene come to life!
3
+ [![NPM Version](https://img.shields.io/npm/v/@playcanvas/web-components.svg)](https://www.npmjs.com/package/@playcanvas/web-components)
4
+ [![NPM Downloads](https://img.shields.io/npm/dw/@playcanvas/web-components)](https://npmtrends.com/@playcanvas/web-components)
5
+ [![License](https://img.shields.io/npm/l/@playcanvas/web-components.svg)](https://github.com/playcanvas/web-components/blob/main/LICENSE)
6
+ [![GitHub Actions Build Status](https://github.com/playcanvas/web-components/actions/workflows/deploy.yml/badge.svg)](https://github.com/playcanvas/web-components/actions/workflows/deploy.yml)
7
+
8
+ PlayCanvas Web Components are a set of custom HTML elements for building 3D interactive web apps. Using the declarative nature of HTML makes it both easy and fun to incorporate 3D into your website.
9
+
10
+ ```html
11
+ <!-- A lit sphere -->
12
+ <pc-app>
13
+ <pc-scene>
14
+ <pc-entity name="camera" position="0,0,3">
15
+ <pc-camera></pc-camera>
16
+ </pc-entity>
17
+ <pc-entity name="light" rotation="45,45,0">
18
+ <pc-light></pc-light>
19
+ </pc-entity>
20
+ <pc-entity name="ball">
21
+ <pc-render type="sphere"></pc-render>
22
+ </pc-entity>
23
+ </pc-scene>
24
+ </pc-app>
25
+ ```
26
+
27
+ ## Examples
28
+
29
+ [![image](https://github.com/user-attachments/assets/4b708711-4ac1-4908-a254-cf89c2e206ce)](https://playcanvas.github.io/web-components/examples)
30
+
31
+ See PlayCanvas Web Components in action here: https://playcanvas.github.io/web-components/examples
4
32
 
5
33
  ## Usage 🚧
6
34
 
@@ -15,13 +43,13 @@ Or you can include it directly in your HTML file from a CDN.
15
43
  ES Modules:
16
44
 
17
45
  ```html
18
- <script type="module" src="https://cdn.jsdelivr.net/npm/@playcanvas/web-components@0.1.4/dist/pwc.mjs"></script>
46
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@playcanvas/web-components@0.1.5/dist/pwc.mjs"></script>
19
47
  ```
20
48
 
21
49
  UMD:
22
50
 
23
51
  ```html
24
- <script src="https://cdn.jsdelivr.net/npm/@playcanvas/web-components@0.1.4"></script>
52
+ <script src="https://cdn.jsdelivr.net/npm/@playcanvas/web-components@0.1.5"></script>
25
53
  ```
26
54
 
27
55
  ## Tag Reference 📖
@@ -54,7 +82,11 @@ The `pc-app` tag is the root element for your PlayCanvas application. It is used
54
82
 
55
83
  | Attribute | Description |
56
84
  | --- | --- |
57
- | `high-resolution` | Valueless attribute. If present, enables high-resolution mode. |
85
+ | `alpha` | Boolean attribute. Determines whether the application allocates an alpha channel in the frame buffer. Defaults to `true`. |
86
+ | `antialias` | Boolean attribute. Determines whether the application uses anti-aliasing. Defaults to `true`. |
87
+ | `depth` | Boolean attribute. Determines whether the application allocates a depth buffer. Defaults to `true`. |
88
+ | `high-resolution` | Boolean attribute. Determines whether the application renders using physical resolution or CSS resolution. Defaults to `true`. |
89
+ | `stencil` | Boolean attribute. Determines whether the application allocates a stencil buffer. Defaults to `true`. |
58
90
 
59
91
  ### pc-asset
60
92
 
@@ -272,8 +304,12 @@ The `pc-sounds` tag is used to define a sound component. It must be a direct chi
272
304
 
273
305
  | Attribute | Description |
274
306
  | --- | --- |
307
+ | `distance-model` | The distance model of the sound. Can be `exponential`, `inverse` or `linear`. If not specified, `linear` is used. |
275
308
  | `pitch` | The pitch of the sound. If not specified, `1` is used. |
309
+ | `max-distance` | The maximum distance from the listener at which audio falloff stops. If not specified, `10000` is used. |
276
310
  | `positional` | Valueless attribute. If present, the sound is positional. |
311
+ | `ref-distance` | The distance from the listener at which the volume will be at full volume. If not specified, `1` is used. |
312
+ | `roll-off-factor` | The factor used in the falloff equation. If not specified, `1` is used. |
277
313
  | `volume` | The volume of the sound. If not specified, `1` is used. |
278
314
 
279
315
  ### pc-splat
@@ -284,45 +320,3 @@ The `pc-splat` tag is used to define a splat component. It must be a direct chil
284
320
  | --- | --- |
285
321
  | `asset` | A string that should match the `id` of a `pc-asset` tag that has a type of `gsplat`. |
286
322
  | `enabled` | Enabled state of the splat component. If not specified, `true` is used. |
287
-
288
- ## Example
289
-
290
- Below is a basic example of how to use PlayCanvas Web Components to create a simple 3D scene (a humble sphere):
291
-
292
- ```html
293
- <!DOCTYPE html>
294
- <html lang="en">
295
- <head>
296
- <meta charset="UTF-8">
297
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
298
- <title>PlayCanvas Web Components - Sphere</title>
299
- <script type="importmap">
300
- {
301
- "imports": {
302
- "playcanvas": "https://esm.run/playcanvas@2.2.2"
303
- }
304
- }
305
- </script>
306
- <script type="module" src="https://cdn.jsdelivr.net/npm/@playcanvas/web-components@0.1.4/dist/pwc.mjs"></script>
307
- <link rel="stylesheet" href="styles.css">
308
- </head>
309
- <body>
310
- <pc-app>
311
- <pc-scene>
312
- <!-- Camera -->
313
- <pc-entity name="camera" position="0,0,3">
314
- <pc-camera clear-color="#8099e6"></pc-camera>
315
- </pc-entity>
316
- <!-- Light -->
317
- <pc-entity name="light" rotation="45,0,0">
318
- <pc-light></pc-light>
319
- </pc-entity>
320
- <!-- Sphere -->
321
- <pc-entity name="sphere">
322
- <pc-render type="sphere"></pc-render>
323
- </pc-entity>
324
- </pc-scene>
325
- </pc-app>
326
- </body>
327
- </html>
328
- ```
package/dist/app.d.ts CHANGED
@@ -8,6 +8,10 @@ declare class AppElement extends AsyncElement {
8
8
  * The canvas element.
9
9
  */
10
10
  private _canvas;
11
+ private _alpha;
12
+ private _antialias;
13
+ private _depth;
14
+ private _stencil;
11
15
  private _highResolution;
12
16
  /**
13
17
  * The PlayCanvas application instance.
@@ -20,6 +24,36 @@ declare class AppElement extends AsyncElement {
20
24
  connectedCallback(): Promise<void>;
21
25
  disconnectedCallback(): void;
22
26
  _onWindowResize(): void;
27
+ /**
28
+ * Sets the alpha flag.
29
+ * @param value - The alpha flag.
30
+ */
31
+ set alpha(value: boolean);
32
+ /**
33
+ * Gets the alpha flag.
34
+ * @returns The alpha flag.
35
+ */
36
+ get alpha(): boolean;
37
+ /**
38
+ * Sets the antialias flag.
39
+ * @param value - The antialias flag.
40
+ */
41
+ set antialias(value: boolean);
42
+ /**
43
+ * Gets the antialias flag.
44
+ * @returns The antialias flag.
45
+ */
46
+ get antialias(): boolean;
47
+ /**
48
+ * Sets the depth flag.
49
+ * @param value - The depth flag.
50
+ */
51
+ set depth(value: boolean);
52
+ /**
53
+ * Gets the depth flag.
54
+ * @returns The depth flag.
55
+ */
56
+ get depth(): boolean;
23
57
  /**
24
58
  * Sets the high resolution flag. When true, the application will render at the device's
25
59
  * physical resolution. When false, the application will render at CSS resolution.
@@ -31,7 +65,17 @@ declare class AppElement extends AsyncElement {
31
65
  * @returns The high resolution flag.
32
66
  */
33
67
  get highResolution(): boolean;
68
+ /**
69
+ * Sets the stencil flag.
70
+ * @param value - The stencil flag.
71
+ */
72
+ set stencil(value: boolean);
73
+ /**
74
+ * Gets the stencil flag.
75
+ * @returns The stencil flag.
76
+ */
77
+ get stencil(): boolean;
34
78
  static get observedAttributes(): string[];
35
- attributeChangedCallback(name: string, _oldValue: string, _newValue: string): void;
79
+ attributeChangedCallback(name: string, _oldValue: string, newValue: string): void;
36
80
  }
37
81
  export { AppElement };
@@ -6,13 +6,21 @@ import { ComponentElement } from './component';
6
6
  * @category Components
7
7
  */
8
8
  declare class SoundComponentElement extends ComponentElement {
9
+ private _distanceModel;
10
+ private _maxDistance;
9
11
  private _pitch;
10
12
  private _positional;
13
+ private _refDistance;
14
+ private _rollOffFactor;
11
15
  private _volume;
12
16
  constructor();
13
17
  getInitialComponentData(): {
18
+ distanceModel: "exponential" | "inverse" | "linear";
19
+ maxDistance: number;
14
20
  pitch: number;
15
21
  positional: boolean;
22
+ refDistance: number;
23
+ rollOffFactor: number;
16
24
  volume: number;
17
25
  };
18
26
  /**
@@ -20,6 +28,26 @@ declare class SoundComponentElement extends ComponentElement {
20
28
  * @returns The sound component.
21
29
  */
22
30
  get component(): SoundComponent | null;
31
+ /**
32
+ * Sets which algorithm to use to reduce the volume of the sound as it moves away from the listener.
33
+ * @param value - The distance model.
34
+ */
35
+ set distanceModel(value: 'exponential' | 'inverse' | 'linear');
36
+ /**
37
+ * Gets which algorithm to use to reduce the volume of the sound as it moves away from the listener.
38
+ * @returns The distance model.
39
+ */
40
+ get distanceModel(): 'exponential' | 'inverse' | 'linear';
41
+ /**
42
+ * Sets the maximum distance from the listener at which audio falloff stops.
43
+ * @param value - The max distance.
44
+ */
45
+ set maxDistance(value: number);
46
+ /**
47
+ * Gets the maximum distance from the listener at which audio falloff stops.
48
+ * @returns The max distance.
49
+ */
50
+ get maxDistance(): number;
23
51
  /**
24
52
  * Sets the pitch of the sound.
25
53
  * @param value - The pitch.
@@ -40,6 +68,26 @@ declare class SoundComponentElement extends ComponentElement {
40
68
  * @returns The positional flag.
41
69
  */
42
70
  get positional(): boolean;
71
+ /**
72
+ * Sets the reference distance for reducing volume as the sound source moves further from the listener. Defaults to 1.
73
+ * @param value - The ref distance.
74
+ */
75
+ set refDistance(value: number);
76
+ /**
77
+ * Gets the reference distance for reducing volume as the sound source moves further from the listener.
78
+ * @returns The ref distance.
79
+ */
80
+ get refDistance(): number;
81
+ /**
82
+ * Sets the factor used in the falloff equation. Defaults to 1.
83
+ * @param value - The roll-off factor.
84
+ */
85
+ set rollOffFactor(value: number);
86
+ /**
87
+ * Gets the factor used in the falloff equation.
88
+ * @returns The roll-off factor.
89
+ */
90
+ get rollOffFactor(): number;
43
91
  /**
44
92
  * Sets the volume of the sound.
45
93
  * @param value - The volume.
package/dist/pwc.cjs CHANGED
@@ -47,14 +47,23 @@ class ModuleElement extends HTMLElement {
47
47
  const glue = this.getAttribute('glue');
48
48
  const wasm = this.getAttribute('wasm');
49
49
  const fallback = this.getAttribute('fallback');
50
- playcanvas.WasmModule.setConfig(name, {
51
- glueUrl: glue,
52
- wasmUrl: wasm,
53
- fallbackUrl: fallback
54
- });
55
- await new Promise((resolve) => {
56
- playcanvas.WasmModule.getInstance(name, () => resolve());
57
- });
50
+ if (name === 'Basis') {
51
+ playcanvas.basisInitialize({
52
+ glueUrl: glue,
53
+ wasmUrl: wasm,
54
+ fallbackUrl: fallback
55
+ });
56
+ }
57
+ else {
58
+ playcanvas.WasmModule.setConfig(name, {
59
+ glueUrl: glue,
60
+ wasmUrl: wasm,
61
+ fallbackUrl: fallback
62
+ });
63
+ await new Promise((resolve) => {
64
+ playcanvas.WasmModule.getInstance(name, () => resolve());
65
+ });
66
+ }
58
67
  }
59
68
  getLoadPromise() {
60
69
  return this.loadPromise;
@@ -75,6 +84,10 @@ class AppElement extends AsyncElement {
75
84
  * The canvas element.
76
85
  */
77
86
  this._canvas = null;
87
+ this._alpha = true;
88
+ this._antialias = true;
89
+ this._depth = true;
90
+ this._stencil = true;
78
91
  this._highResolution = false;
79
92
  /**
80
93
  * The PlayCanvas application instance.
@@ -94,11 +107,15 @@ class AppElement extends AsyncElement {
94
107
  // Initialize the PlayCanvas application
95
108
  this.app = new playcanvas.Application(this._canvas, {
96
109
  graphicsDeviceOptions: {
97
- devicePixelRatio: this._highResolution ? window.devicePixelRatio : 1
110
+ alpha: this._alpha,
111
+ antialias: this._antialias,
112
+ depth: this._depth,
113
+ stencil: this._stencil
98
114
  },
99
115
  keyboard: new playcanvas.Keyboard(window),
100
116
  mouse: new playcanvas.Mouse(this._canvas)
101
117
  });
118
+ this.app.graphicsDevice.maxPixelRatio = this._highResolution ? window.devicePixelRatio : 1;
102
119
  this.app.setCanvasFillMode(playcanvas.FILLMODE_FILL_WINDOW);
103
120
  this.app.setCanvasResolution(playcanvas.RESOLUTION_AUTO);
104
121
  // Get all pc-asset elements that are direct children of the pc-app element
@@ -143,6 +160,48 @@ class AppElement extends AsyncElement {
143
160
  this.app.resizeCanvas();
144
161
  }
145
162
  }
163
+ /**
164
+ * Sets the alpha flag.
165
+ * @param value - The alpha flag.
166
+ */
167
+ set alpha(value) {
168
+ this._alpha = value;
169
+ }
170
+ /**
171
+ * Gets the alpha flag.
172
+ * @returns The alpha flag.
173
+ */
174
+ get alpha() {
175
+ return this._alpha;
176
+ }
177
+ /**
178
+ * Sets the antialias flag.
179
+ * @param value - The antialias flag.
180
+ */
181
+ set antialias(value) {
182
+ this._antialias = value;
183
+ }
184
+ /**
185
+ * Gets the antialias flag.
186
+ * @returns The antialias flag.
187
+ */
188
+ get antialias() {
189
+ return this._antialias;
190
+ }
191
+ /**
192
+ * Sets the depth flag.
193
+ * @param value - The depth flag.
194
+ */
195
+ set depth(value) {
196
+ this._depth = value;
197
+ }
198
+ /**
199
+ * Gets the depth flag.
200
+ * @returns The depth flag.
201
+ */
202
+ get depth() {
203
+ return this._depth;
204
+ }
146
205
  /**
147
206
  * Sets the high resolution flag. When true, the application will render at the device's
148
207
  * physical resolution. When false, the application will render at CSS resolution.
@@ -161,13 +220,39 @@ class AppElement extends AsyncElement {
161
220
  get highResolution() {
162
221
  return this._highResolution;
163
222
  }
223
+ /**
224
+ * Sets the stencil flag.
225
+ * @param value - The stencil flag.
226
+ */
227
+ set stencil(value) {
228
+ this._stencil = value;
229
+ }
230
+ /**
231
+ * Gets the stencil flag.
232
+ * @returns The stencil flag.
233
+ */
234
+ get stencil() {
235
+ return this._stencil;
236
+ }
164
237
  static get observedAttributes() {
165
- return ['high-resolution'];
238
+ return ['alpha', 'antialias', 'depth', 'stencil', 'high-resolution'];
166
239
  }
167
- attributeChangedCallback(name, _oldValue, _newValue) {
240
+ attributeChangedCallback(name, _oldValue, newValue) {
168
241
  switch (name) {
242
+ case 'alpha':
243
+ this.alpha = newValue !== 'false';
244
+ break;
245
+ case 'antialias':
246
+ this.antialias = newValue !== 'false';
247
+ break;
248
+ case 'depth':
249
+ this.depth = newValue !== 'false';
250
+ break;
169
251
  case 'high-resolution':
170
- this.highResolution = this.hasAttribute(name);
252
+ this.highResolution = newValue !== 'false';
253
+ break;
254
+ case 'stencil':
255
+ this.stencil = newValue !== 'false';
171
256
  break;
172
257
  }
173
258
  }
@@ -2245,6 +2330,9 @@ class ScreenComponentElement extends ComponentElement {
2245
2330
  }
2246
2331
  customElements.define('pc-screen', ScreenComponentElement);
2247
2332
 
2333
+ const tmpV2 = new playcanvas.Vec2();
2334
+ const tmpV3 = new playcanvas.Vec3();
2335
+ const tmpV4 = new playcanvas.Vec4();
2248
2336
  /**
2249
2337
  * Represents a script component in the PlayCanvas engine.
2250
2338
  *
@@ -2276,7 +2364,22 @@ class ScriptComponentElement extends ComponentElement {
2276
2364
  try {
2277
2365
  // Parse the attributes string into an object and set them on the script
2278
2366
  const attributesObject = attributes ? JSON.parse(attributes) : {};
2279
- Object.assign(script, attributesObject);
2367
+ for (const key in attributesObject) {
2368
+ const value = attributesObject[key];
2369
+ if (Array.isArray(value) && script[key] instanceof playcanvas.Vec2) {
2370
+ script[key] = tmpV2.set(value[0], value[1]);
2371
+ continue;
2372
+ }
2373
+ if (Array.isArray(value) && script[key] instanceof playcanvas.Vec3) {
2374
+ script[key] = tmpV3.set(value[0], value[1], value[2]);
2375
+ continue;
2376
+ }
2377
+ if (Array.isArray(value) && script[key] instanceof playcanvas.Vec4) {
2378
+ script[key] = tmpV4.set(value[0], value[1], value[2], value[3]);
2379
+ continue;
2380
+ }
2381
+ script[key] = value;
2382
+ }
2280
2383
  }
2281
2384
  catch (error) {
2282
2385
  console.error(`Error parsing attributes JSON string ${attributes}:`, error);
@@ -2440,14 +2543,22 @@ customElements.define('pc-script', ScriptElement);
2440
2543
  class SoundComponentElement extends ComponentElement {
2441
2544
  constructor() {
2442
2545
  super('sound');
2546
+ this._distanceModel = 'linear';
2547
+ this._maxDistance = 10000;
2443
2548
  this._pitch = 1;
2444
2549
  this._positional = false;
2550
+ this._refDistance = 1;
2551
+ this._rollOffFactor = 1;
2445
2552
  this._volume = 1;
2446
2553
  }
2447
2554
  getInitialComponentData() {
2448
2555
  return {
2556
+ distanceModel: this._distanceModel,
2557
+ maxDistance: this._maxDistance,
2449
2558
  pitch: this._pitch,
2450
2559
  positional: this._positional,
2560
+ refDistance: this._refDistance,
2561
+ rollOffFactor: this._rollOffFactor,
2451
2562
  volume: this._volume
2452
2563
  };
2453
2564
  }
@@ -2458,6 +2569,40 @@ class SoundComponentElement extends ComponentElement {
2458
2569
  get component() {
2459
2570
  return super.component;
2460
2571
  }
2572
+ /**
2573
+ * Sets which algorithm to use to reduce the volume of the sound as it moves away from the listener.
2574
+ * @param value - The distance model.
2575
+ */
2576
+ set distanceModel(value) {
2577
+ this._distanceModel = value;
2578
+ if (this.component) {
2579
+ this.component.distanceModel = value;
2580
+ }
2581
+ }
2582
+ /**
2583
+ * Gets which algorithm to use to reduce the volume of the sound as it moves away from the listener.
2584
+ * @returns The distance model.
2585
+ */
2586
+ get distanceModel() {
2587
+ return this._distanceModel;
2588
+ }
2589
+ /**
2590
+ * Sets the maximum distance from the listener at which audio falloff stops.
2591
+ * @param value - The max distance.
2592
+ */
2593
+ set maxDistance(value) {
2594
+ this._maxDistance = value;
2595
+ if (this.component) {
2596
+ this.component.maxDistance = value;
2597
+ }
2598
+ }
2599
+ /**
2600
+ * Gets the maximum distance from the listener at which audio falloff stops.
2601
+ * @returns The max distance.
2602
+ */
2603
+ get maxDistance() {
2604
+ return this._maxDistance;
2605
+ }
2461
2606
  /**
2462
2607
  * Sets the pitch of the sound.
2463
2608
  * @param value - The pitch.
@@ -2492,6 +2637,40 @@ class SoundComponentElement extends ComponentElement {
2492
2637
  get positional() {
2493
2638
  return this._positional;
2494
2639
  }
2640
+ /**
2641
+ * Sets the reference distance for reducing volume as the sound source moves further from the listener. Defaults to 1.
2642
+ * @param value - The ref distance.
2643
+ */
2644
+ set refDistance(value) {
2645
+ this._refDistance = value;
2646
+ if (this.component) {
2647
+ this.component.refDistance = value;
2648
+ }
2649
+ }
2650
+ /**
2651
+ * Gets the reference distance for reducing volume as the sound source moves further from the listener.
2652
+ * @returns The ref distance.
2653
+ */
2654
+ get refDistance() {
2655
+ return this._refDistance;
2656
+ }
2657
+ /**
2658
+ * Sets the factor used in the falloff equation. Defaults to 1.
2659
+ * @param value - The roll-off factor.
2660
+ */
2661
+ set rollOffFactor(value) {
2662
+ this._rollOffFactor = value;
2663
+ if (this.component) {
2664
+ this.component.rollOffFactor = value;
2665
+ }
2666
+ }
2667
+ /**
2668
+ * Gets the factor used in the falloff equation.
2669
+ * @returns The roll-off factor.
2670
+ */
2671
+ get rollOffFactor() {
2672
+ return this._rollOffFactor;
2673
+ }
2495
2674
  /**
2496
2675
  * Sets the volume of the sound.
2497
2676
  * @param value - The volume.
@@ -2510,17 +2689,38 @@ class SoundComponentElement extends ComponentElement {
2510
2689
  return this._volume;
2511
2690
  }
2512
2691
  static get observedAttributes() {
2513
- return [...super.observedAttributes, 'pitch', 'positional', 'volume'];
2692
+ return [
2693
+ ...super.observedAttributes,
2694
+ 'distance-model',
2695
+ 'max-distance',
2696
+ 'pitch',
2697
+ 'positional',
2698
+ 'ref-distance',
2699
+ 'roll-off-factor',
2700
+ 'volume'
2701
+ ];
2514
2702
  }
2515
2703
  attributeChangedCallback(name, _oldValue, newValue) {
2516
2704
  super.attributeChangedCallback(name, _oldValue, newValue);
2517
2705
  switch (name) {
2706
+ case 'distance-model':
2707
+ this.distanceModel = newValue;
2708
+ break;
2709
+ case 'max-distance':
2710
+ this.maxDistance = parseFloat(newValue);
2711
+ break;
2518
2712
  case 'pitch':
2519
2713
  this.pitch = parseFloat(newValue);
2520
2714
  break;
2521
2715
  case 'positional':
2522
2716
  this.positional = this.hasAttribute('positional');
2523
2717
  break;
2718
+ case 'ref-distance':
2719
+ this.refDistance = parseFloat(newValue);
2720
+ break;
2721
+ case 'roll-off-factor':
2722
+ this.rollOffFactor = parseFloat(newValue);
2723
+ break;
2524
2724
  case 'volume':
2525
2725
  this.volume = parseFloat(newValue);
2526
2726
  break;