@arraypress/waveform-bar 1.2.0 → 1.3.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/README.md +173 -334
- package/dist/waveform-bar-icons.css +14 -5
- package/dist/waveform-bar.esm.js +101 -14
- package/dist/waveform-bar.js +101 -14
- package/dist/waveform-bar.min.js +8 -8
- package/package.json +1 -1
- package/src/css/waveform-bar-icons.css +14 -5
- package/src/js/core.js +132 -17
package/README.md
CHANGED
|
@@ -47,6 +47,9 @@ Think Spotify's bottom player — but lightweight, zero-config, and works on any
|
|
|
47
47
|
<!-- WaveformBar -->
|
|
48
48
|
<link rel="stylesheet" href="https://unpkg.com/@arraypress/waveform-bar@latest/dist/waveform-bar.css">
|
|
49
49
|
<script src="https://unpkg.com/@arraypress/waveform-bar@latest/dist/waveform-bar.js"></script>
|
|
50
|
+
|
|
51
|
+
<!-- Optional: Page icons (play/pause overlays, hearts, carts, etc.) -->
|
|
52
|
+
<link rel="stylesheet" href="https://unpkg.com/@arraypress/waveform-bar@latest/dist/waveform-bar-icons.css">
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
### NPM
|
|
@@ -75,6 +78,33 @@ npm install @arraypress/waveform-player @arraypress/waveform-bar
|
|
|
75
78
|
Click the button → the bar slides up from the bottom → music plays. Add more buttons anywhere on the page and they all
|
|
76
79
|
share the same player bar.
|
|
77
80
|
|
|
81
|
+
## Inline WaveformPlayer integration (v1.3+)
|
|
82
|
+
|
|
83
|
+
When `@arraypress/waveform-player` 1.6+ instances are mounted on the same page with `audioMode: 'external'`, WaveformBar discovers them automatically and treats them as **synchronized visual surfaces**:
|
|
84
|
+
|
|
85
|
+
- Click the inline player's play button → playback happens in the bar
|
|
86
|
+
- The bar's audio progress mirrors into the inline canvas in real time (scrubber moves, play/pause icon flips)
|
|
87
|
+
- When the bar switches tracks, the previously-active inline player resets to paused
|
|
88
|
+
|
|
89
|
+
No configuration on the bar side — the discovery scan runs on init + MutationObserver tick, listening for `waveformplayer:request-play|pause|seek` events at the document level. Any inline player whose URL matches the bar's current track gets `setPlayingState(...)` and `setProgress(...)` calls pumped to it.
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
<!-- The same element doubles as a bar trigger (data-wb-play) AND an
|
|
93
|
+
inline visual surface (data-waveform-player + audio-mode). Single
|
|
94
|
+
audio source (the bar), multiple visual surfaces (bar + every
|
|
95
|
+
matching inline player). -->
|
|
96
|
+
<div data-waveform-player
|
|
97
|
+
data-audio-mode="external"
|
|
98
|
+
data-url="song.mp3"
|
|
99
|
+
data-waveform-style="bars"
|
|
100
|
+
|
|
101
|
+
data-wb-play
|
|
102
|
+
data-wb-url="song.mp3"
|
|
103
|
+
data-wb-title="..."></div>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
This is the SoundCloud / Bandcamp pattern — the persistent bar owns playback, but every place a track surfaces on the page gets its own playable, progress-aware visualization.
|
|
107
|
+
|
|
78
108
|
## Data Attributes
|
|
79
109
|
|
|
80
110
|
### Play Trigger (`data-wb-play`)
|
|
@@ -130,21 +160,62 @@ Add to any element to queue a track without immediately playing it.
|
|
|
130
160
|
</button>
|
|
131
161
|
```
|
|
132
162
|
|
|
133
|
-
### Pre-Generated
|
|
163
|
+
### Pre-Generated Waveforms
|
|
134
164
|
|
|
135
|
-
Skip client-side audio analysis by providing pre-generated waveform
|
|
136
|
-
|
|
165
|
+
Skip client-side audio analysis by providing pre-generated waveform data. The `data-wb-waveform` attribute accepts three
|
|
166
|
+
formats:
|
|
167
|
+
|
|
168
|
+
| Format | Example | Description |
|
|
169
|
+
|---------------|--------------------------|--------------------------------------------------|
|
|
170
|
+
| JSON file URL | `waveforms/song.json` | Fetches peaks from `{ peaks: [...] }` or `[...]` |
|
|
171
|
+
| Inline array | `[0.2, 0.37, 0.41, ...]` | JSON array string |
|
|
172
|
+
| CSV string | `0.2,0.37,0.41,...` | Comma-separated values |
|
|
137
173
|
|
|
138
174
|
```html
|
|
175
|
+
<!-- JSON file — fetched automatically by the player -->
|
|
176
|
+
<div data-wb-play
|
|
177
|
+
data-url="audio/song.mp3"
|
|
178
|
+
data-title="My Song"
|
|
179
|
+
data-wb-waveform="waveforms/song.json">
|
|
180
|
+
</div>
|
|
139
181
|
|
|
182
|
+
<!-- Inline peaks -->
|
|
140
183
|
<div data-wb-play
|
|
141
|
-
data-url="song.mp3"
|
|
184
|
+
data-url="audio/song.mp3"
|
|
142
185
|
data-title="My Song"
|
|
143
|
-
data-wb-waveform=
|
|
186
|
+
data-wb-waveform="[0.12,0.45,0.89,0.34,0.67]">
|
|
144
187
|
</div>
|
|
145
188
|
```
|
|
146
189
|
|
|
147
|
-
|
|
190
|
+
Generate JSON files with [WaveformGen](https://github.com/arraypress/waveform-gen):
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
npx @arraypress/waveform-gen ./audio/*.mp3 --output ./waveforms/ --bpm
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
JSON waveform files can also include markers, which are loaded automatically if none are set via data attributes:
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"peaks": [
|
|
201
|
+
0.12,
|
|
202
|
+
0.45,
|
|
203
|
+
0.89,
|
|
204
|
+
0.34,
|
|
205
|
+
...
|
|
206
|
+
],
|
|
207
|
+
"markers": [
|
|
208
|
+
{
|
|
209
|
+
"time": 0,
|
|
210
|
+
"label": "Intro"
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"time": 30,
|
|
214
|
+
"label": "Chorus"
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
```
|
|
148
219
|
|
|
149
220
|
### DJ Mode Markers
|
|
150
221
|
|
|
@@ -166,32 +237,31 @@ and metadata at each marker boundary.
|
|
|
166
237
|
</div>
|
|
167
238
|
```
|
|
168
239
|
|
|
169
|
-
Markers can include: `time` (seconds, required), `label` (required), `title`, `artist`, `artwork`, `bpm`, `key
|
|
170
|
-
`color`.
|
|
240
|
+
Markers can include: `time` (seconds, required), `label` (required), `title`, `artist`, `artwork`, `bpm`, `key`,`color`.
|
|
171
241
|
|
|
172
242
|
The active marker on the waveform gently pulses to indicate the current section.
|
|
173
243
|
|
|
174
244
|
### Attribute Reference
|
|
175
245
|
|
|
176
|
-
| Attribute | Description
|
|
177
|
-
|
|
178
|
-
| `data-wb-play` | Makes element a play trigger (click to play)
|
|
179
|
-
| `data-wb-queue` | Makes element a queue trigger (click to add to queue)
|
|
180
|
-
| `data-url` | Audio file URL (required)
|
|
181
|
-
| `data-id` | Unique track identifier (defaults to URL)
|
|
182
|
-
| `data-title` | Track title
|
|
183
|
-
| `data-artist` | Artist or subtitle
|
|
184
|
-
| `data-artwork` | Album artwork URL
|
|
185
|
-
| `data-album` | Album name (for Media Session API)
|
|
186
|
-
| `data-link` | URL to navigate when clicking track info in the bar
|
|
187
|
-
| `data-duration` | Display duration string
|
|
188
|
-
| `data-bpm` | BPM value — displayed as a tag in the bar
|
|
189
|
-
| `data-key` | Musical key — displayed as a tag in the bar
|
|
190
|
-
| `data-meta` | JSON object of custom metadata (e.g. `'{"genre":"Trap"}'`)
|
|
191
|
-
| `data-wb-waveform` | Pre-generated waveform peaks JSON array
|
|
192
|
-
| `data-wb-markers` | JSON array of marker objects for DJ mode
|
|
193
|
-
| `data-wb-favorited` | `"true"` to pre-set favorite state (server-side seeding)
|
|
194
|
-
| `data-wb-in-cart` | `"true"` to pre-set cart state (server-side seeding)
|
|
246
|
+
| Attribute | Description |
|
|
247
|
+
|---------------------|---------------------------------------------------------------------------|
|
|
248
|
+
| `data-wb-play` | Makes element a play trigger (click to play) |
|
|
249
|
+
| `data-wb-queue` | Makes element a queue trigger (click to add to queue) |
|
|
250
|
+
| `data-url` | Audio file URL (required) |
|
|
251
|
+
| `data-id` | Unique track identifier (defaults to URL) |
|
|
252
|
+
| `data-title` | Track title |
|
|
253
|
+
| `data-artist` | Artist or subtitle |
|
|
254
|
+
| `data-artwork` | Album artwork URL |
|
|
255
|
+
| `data-album` | Album name (for Media Session API) |
|
|
256
|
+
| `data-link` | URL to navigate when clicking track info in the bar |
|
|
257
|
+
| `data-duration` | Display duration string |
|
|
258
|
+
| `data-bpm` | BPM value — displayed as a tag in the bar |
|
|
259
|
+
| `data-key` | Musical key — displayed as a tag in the bar |
|
|
260
|
+
| `data-meta` | JSON object of custom metadata (e.g. `'{"genre":"Trap"}'`) |
|
|
261
|
+
| `data-wb-waveform` | Pre-generated waveform peaks: JSON array, CSV string, or `.json` file URL |
|
|
262
|
+
| `data-wb-markers` | JSON array of marker objects for DJ mode |
|
|
263
|
+
| `data-wb-favorited` | `"true"` to pre-set favorite state (server-side seeding) |
|
|
264
|
+
| `data-wb-in-cart` | `"true"` to pre-set cart state (server-side seeding) |
|
|
195
265
|
|
|
196
266
|
All attributes also accept `data-wb-` prefixed versions (`data-wb-url`, `data-wb-title`, etc.) to avoid conflicts with
|
|
197
267
|
other libraries.
|
|
@@ -238,11 +308,11 @@ WaveformBar.init({
|
|
|
238
308
|
// Server-side actions (REST callbacks)
|
|
239
309
|
actions: {
|
|
240
310
|
favorite: {
|
|
241
|
-
endpoint: '/api/favorites',
|
|
311
|
+
endpoint: '/api/favorites',
|
|
242
312
|
method: 'POST'
|
|
243
313
|
},
|
|
244
314
|
cart: {
|
|
245
|
-
endpoint: '/api/cart',
|
|
315
|
+
endpoint: '/api/cart',
|
|
246
316
|
method: 'POST'
|
|
247
317
|
}
|
|
248
318
|
},
|
|
@@ -270,7 +340,6 @@ WaveformBar.init({
|
|
|
270
340
|
### Playback
|
|
271
341
|
|
|
272
342
|
```javascript
|
|
273
|
-
// Play a track object
|
|
274
343
|
WaveformBar.play({
|
|
275
344
|
url: 'audio/song.mp3',
|
|
276
345
|
title: 'My Song',
|
|
@@ -281,15 +350,12 @@ WaveformBar.play({
|
|
|
281
350
|
link: '/products/my-song'
|
|
282
351
|
});
|
|
283
352
|
|
|
284
|
-
// Play by URL shorthand
|
|
285
353
|
WaveformBar.play('audio/song.mp3');
|
|
286
|
-
|
|
287
|
-
// Playback controls
|
|
288
354
|
WaveformBar.togglePlay();
|
|
289
355
|
WaveformBar.pause();
|
|
290
|
-
WaveformBar.next();
|
|
291
|
-
WaveformBar.previous();
|
|
292
|
-
WaveformBar.skipTo(3);
|
|
356
|
+
WaveformBar.next();
|
|
357
|
+
WaveformBar.previous();
|
|
358
|
+
WaveformBar.skipTo(3);
|
|
293
359
|
```
|
|
294
360
|
|
|
295
361
|
### Repeat
|
|
@@ -299,102 +365,57 @@ WaveformBar.cycleRepeat(); // Cycles: off → all → one → off
|
|
|
299
365
|
WaveformBar.setRepeat('all'); // Set directly: 'off', 'all', 'one'
|
|
300
366
|
```
|
|
301
367
|
|
|
302
|
-
- **off** — Stops at end of queue
|
|
303
|
-
- **all** — Loops back to first track after last; prev/next wrap around
|
|
304
|
-
- **one** — Replays the current track indefinitely
|
|
305
|
-
|
|
306
368
|
### Markers / DJ Mode
|
|
307
369
|
|
|
308
370
|
```javascript
|
|
309
|
-
// Seek to marker by index (0-based) on current track
|
|
310
371
|
WaveformBar.seekToMarker(3);
|
|
311
|
-
|
|
312
|
-
// Seek to marker by label name on current track
|
|
313
372
|
WaveformBar.seekToMarkerByLabel('Horizon');
|
|
314
373
|
```
|
|
315
374
|
|
|
316
|
-
Both methods auto-play if the player is paused. They only work on the currently loaded track's markers — if the track
|
|
317
|
-
with markers isn't loaded, they silently return.
|
|
318
|
-
|
|
319
375
|
### Volume
|
|
320
376
|
|
|
321
377
|
```javascript
|
|
322
|
-
WaveformBar.setVolume(0.5);
|
|
323
|
-
WaveformBar.getVolume();
|
|
378
|
+
WaveformBar.setVolume(0.5);
|
|
379
|
+
WaveformBar.getVolume();
|
|
324
380
|
WaveformBar.toggleMute();
|
|
325
|
-
WaveformBar.isMutedState(); // true/false
|
|
326
381
|
```
|
|
327
382
|
|
|
328
|
-
Volume and mute state persist in localStorage across sessions.
|
|
329
|
-
|
|
330
383
|
### Queue
|
|
331
384
|
|
|
332
385
|
```javascript
|
|
333
|
-
// Add to end of queue
|
|
334
386
|
WaveformBar.addToQueue({url: 'track.mp3', title: 'Next Up', artist: 'Someone'});
|
|
335
|
-
|
|
336
|
-
// Remove by index
|
|
337
387
|
WaveformBar.removeFromQueue(2);
|
|
338
|
-
|
|
339
|
-
// Replay a previously played track (by URL)
|
|
340
|
-
WaveformBar.replay('audio/old-track.mp3');
|
|
341
|
-
|
|
342
|
-
// Clear upcoming tracks
|
|
343
388
|
WaveformBar.clearQueue();
|
|
344
|
-
|
|
345
|
-
// Clear play history
|
|
346
|
-
WaveformBar.clearHistory();
|
|
347
389
|
```
|
|
348
390
|
|
|
349
|
-
|
|
350
|
-
**. Tracks can be removed individually from the queue via the × button on hover.
|
|
351
|
-
|
|
352
|
-
### Favorites
|
|
391
|
+
### Favorites & Cart
|
|
353
392
|
|
|
354
393
|
```javascript
|
|
355
|
-
WaveformBar.toggleFavorite();
|
|
356
|
-
WaveformBar.isFavorited('beat-001');
|
|
394
|
+
WaveformBar.toggleFavorite();
|
|
395
|
+
WaveformBar.isFavorited('beat-001');
|
|
396
|
+
WaveformBar.addToCart();
|
|
397
|
+
WaveformBar.isInCart('beat-001');
|
|
357
398
|
```
|
|
358
399
|
|
|
359
|
-
Favorites persist in localStorage. Server-side state can be seeded via `data-wb-favorited="true"` on trigger elements —
|
|
360
|
-
this is authoritative and overrides localStorage on page load.
|
|
361
|
-
|
|
362
|
-
When a track is favorited/unfavorited, the `.wb-favorited` class is toggled on all matching trigger elements on the
|
|
363
|
-
page.
|
|
364
|
-
|
|
365
|
-
### Cart
|
|
366
|
-
|
|
367
|
-
```javascript
|
|
368
|
-
WaveformBar.addToCart(); // Add current track to cart
|
|
369
|
-
WaveformBar.isInCart('beat-001'); // Check by track ID
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
Cart state is NOT persisted to localStorage — it's server-authoritative. Seed from your server via
|
|
373
|
-
`data-wb-in-cart="true"`. The `.wb-in-cart` class is toggled on matching trigger elements.
|
|
374
|
-
|
|
375
|
-
If an `actions.cart.endpoint` is configured, a POST request fires automatically with the track data.
|
|
376
|
-
|
|
377
400
|
### State
|
|
378
401
|
|
|
379
402
|
```javascript
|
|
380
|
-
WaveformBar.getCurrentTrack();
|
|
381
|
-
WaveformBar.isCurrentlyPlaying('song.mp3');
|
|
382
|
-
WaveformBar.isCurrentTrack('song.mp3');
|
|
383
|
-
WaveformBar.getQueue();
|
|
384
|
-
WaveformBar.
|
|
385
|
-
WaveformBar.getPlayer();
|
|
403
|
+
WaveformBar.getCurrentTrack();
|
|
404
|
+
WaveformBar.isCurrentlyPlaying('song.mp3');
|
|
405
|
+
WaveformBar.isCurrentTrack('song.mp3');
|
|
406
|
+
WaveformBar.getQueue();
|
|
407
|
+
WaveformBar.getCurrentIndex();
|
|
408
|
+
WaveformBar.getPlayer();
|
|
386
409
|
```
|
|
387
410
|
|
|
388
411
|
### UI
|
|
389
412
|
|
|
390
413
|
```javascript
|
|
391
|
-
WaveformBar.show();
|
|
392
|
-
WaveformBar.hide();
|
|
393
|
-
WaveformBar.toggleQueuePanel();
|
|
394
|
-
WaveformBar.toggleVolumePopup();
|
|
395
|
-
WaveformBar.
|
|
396
|
-
WaveformBar.closeVolumePopup();
|
|
397
|
-
WaveformBar.destroy(); // Remove bar and clean up
|
|
414
|
+
WaveformBar.show();
|
|
415
|
+
WaveformBar.hide();
|
|
416
|
+
WaveformBar.toggleQueuePanel();
|
|
417
|
+
WaveformBar.toggleVolumePopup();
|
|
418
|
+
WaveformBar.destroy();
|
|
398
419
|
```
|
|
399
420
|
|
|
400
421
|
## DOM Events
|
|
@@ -405,10 +426,6 @@ All events bubble from the bar element and are prefixed with `waveformbar:`.
|
|
|
405
426
|
document.addEventListener('waveformbar:play', (e) => {
|
|
406
427
|
console.log('Playing:', e.detail.track);
|
|
407
428
|
});
|
|
408
|
-
|
|
409
|
-
document.addEventListener('waveformbar:trackchange', (e) => {
|
|
410
|
-
console.log('Track changed:', e.detail.track, 'Index:', e.detail.index);
|
|
411
|
-
});
|
|
412
429
|
```
|
|
413
430
|
|
|
414
431
|
| Event | Detail |
|
|
@@ -434,16 +451,10 @@ WaveformBar automatically adds CSS classes to trigger elements on the page:
|
|
|
434
451
|
| `.wb-favorited` | The element's track is favorited |
|
|
435
452
|
| `.wb-in-cart` | The element's track is in the cart |
|
|
436
453
|
|
|
437
|
-
These update in real-time as the user interacts with the bar.
|
|
438
|
-
|
|
439
454
|
## Helper CSS Classes
|
|
440
455
|
|
|
441
|
-
Ready-made utility classes for common UI patterns. Add them to your trigger elements.
|
|
442
|
-
|
|
443
456
|
### Icon Swap (`wb-icon-swap`)
|
|
444
457
|
|
|
445
|
-
Swaps play/pause content automatically based on playback state.
|
|
446
|
-
|
|
447
458
|
```html
|
|
448
459
|
|
|
449
460
|
<button data-wb-play data-url="song.mp3" class="wb-icon-swap">
|
|
@@ -454,100 +465,74 @@ Swaps play/pause content automatically based on playback state.
|
|
|
454
465
|
|
|
455
466
|
### Equalizer Bars (`wb-eq-bars`)
|
|
456
467
|
|
|
457
|
-
Animated equalizer bars that activate when the track is playing.
|
|
458
|
-
|
|
459
468
|
```html
|
|
460
|
-
|
|
461
|
-
<tr data-wb-play data-url="song.mp3">
|
|
462
|
-
<td>
|
|
463
|
-
<span class="wb-eq-bars">
|
|
464
|
-
<span></span><span></span><span></span><span></span>
|
|
465
|
-
</span>
|
|
466
|
-
</td>
|
|
467
|
-
<td>Track Title</td>
|
|
468
|
-
</tr>
|
|
469
|
+
<span class="wb-eq-bars"><span></span><span></span><span></span><span></span></span>
|
|
469
470
|
```
|
|
470
471
|
|
|
471
472
|
### Card Highlight (`wb-card-highlight`)
|
|
472
473
|
|
|
473
|
-
Adds accent border
|
|
474
|
-
|
|
475
|
-
```html
|
|
476
|
-
|
|
477
|
-
<div data-wb-play data-url="song.mp3"
|
|
478
|
-
class="wb-card-highlight"
|
|
479
|
-
style="border: 1px solid transparent; border-radius: 8px;">
|
|
480
|
-
<h3>Track Title</h3>
|
|
481
|
-
</div>
|
|
482
|
-
```
|
|
474
|
+
Adds accent border when the element's track is current.
|
|
483
475
|
|
|
484
476
|
### Accent Text (`wb-accent-current`)
|
|
485
477
|
|
|
486
478
|
Colors text with the accent color when the parent track is current.
|
|
487
479
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
<div data-wb-play data-url="song.mp3">
|
|
491
|
-
<span class="wb-accent-current">Track Title</span>
|
|
492
|
-
</div>
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
### Pulse Animation (`wb-pulse-playing`)
|
|
496
|
-
|
|
497
|
-
Subtle opacity pulse on playing elements.
|
|
480
|
+
### Favorite/Cart Visibility
|
|
498
481
|
|
|
499
482
|
```html
|
|
500
|
-
|
|
501
|
-
<
|
|
502
|
-
|
|
503
|
-
</
|
|
483
|
+
<span class="wb-hide-if-fav">♡ Save</span>
|
|
484
|
+
<span class="wb-show-if-fav">❤ Saved</span>
|
|
485
|
+
<span class="wb-hide-if-cart">🛒 Add</span>
|
|
486
|
+
<span class="wb-show-if-cart">✓ In Cart</span>
|
|
504
487
|
```
|
|
505
488
|
|
|
506
|
-
|
|
489
|
+
## Page Icons
|
|
507
490
|
|
|
508
|
-
|
|
491
|
+
The optional `waveform-bar-icons.css` provides a lightweight SVG icon set for use in your page elements (play/pause
|
|
492
|
+
overlays, hearts, carts, etc.):
|
|
509
493
|
|
|
510
494
|
```html
|
|
511
495
|
|
|
512
|
-
<
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
496
|
+
<link rel="stylesheet" href="https://unpkg.com/@arraypress/waveform-bar@latest/dist/waveform-bar-icons.css">
|
|
497
|
+
|
|
498
|
+
<span class="wbi wbi-play"></span>
|
|
499
|
+
<span class="wbi wbi-pause"></span>
|
|
500
|
+
<span class="wbi wbi-heart"></span>
|
|
501
|
+
<span class="wbi wbi-heart-filled"></span>
|
|
502
|
+
<span class="wbi wbi-cart"></span>
|
|
503
|
+
<span class="wbi wbi-cart-check"></span>
|
|
504
|
+
<span class="wbi wbi-queue"></span>
|
|
505
|
+
<span class="wbi wbi-skip-back"></span>
|
|
506
|
+
<span class="wbi wbi-skip-forward"></span>
|
|
507
|
+
<span class="wbi wbi-volume-high"></span>
|
|
508
|
+
<span class="wbi wbi-volume-low"></span>
|
|
509
|
+
<span class="wbi wbi-volume-mute"></span>
|
|
510
|
+
<span class="wbi wbi-repeat"></span>
|
|
511
|
+
<span class="wbi wbi-repeat-one"></span>
|
|
512
|
+
<span class="wbi wbi-close"></span>
|
|
513
|
+
<span class="wbi wbi-check"></span>
|
|
514
|
+
<span class="wbi wbi-link"></span>
|
|
515
|
+
<span class="wbi wbi-download"></span>
|
|
516
|
+
<span class="wbi wbi-share"></span>
|
|
517
|
+
<span class="wbi wbi-music-note"></span>
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
Icons inherit `color` from their parent and scale with `font-size`. Size variants: `.wbi-sm`, `.wbi-lg`, `.wbi-xl`,
|
|
521
|
+
`.wbi-2x`, `.wbi-3x`.
|
|
522
|
+
|
|
523
|
+
These are for your page elements only — the bar itself uses its own internal SVG icons and does not require this file.
|
|
523
524
|
|
|
524
525
|
## Persistence
|
|
525
526
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
**sessionStorage** (cleared when browser closes):
|
|
529
|
-
|
|
530
|
-
- Queue contents and order
|
|
531
|
-
- Current track index
|
|
532
|
-
- Playback position
|
|
533
|
-
- Playing state
|
|
534
|
-
|
|
535
|
-
**localStorage** (persists across sessions):
|
|
527
|
+
**sessionStorage** (cleared when browser closes): queue, current track index, playback position, playing state.
|
|
536
528
|
|
|
537
|
-
|
|
538
|
-
- Mute state
|
|
539
|
-
- Favorite track IDs
|
|
540
|
-
|
|
541
|
-
When a user navigates between pages, the bar restores the queue, seeks to the saved position, and optionally resumes
|
|
542
|
-
playback (if `autoResume: true`). Position is saved on every page unload for accuracy.
|
|
529
|
+
**localStorage** (persists across sessions): volume level, mute state, favorite track IDs.
|
|
543
530
|
|
|
544
531
|
Cart state is intentionally NOT persisted — it seeds from `data-wb-in-cart` attributes on page load, making the server
|
|
545
532
|
the source of truth.
|
|
546
533
|
|
|
547
534
|
## Custom Styling
|
|
548
535
|
|
|
549
|
-
Override CSS custom properties to theme the bar:
|
|
550
|
-
|
|
551
536
|
```css
|
|
552
537
|
.waveform-bar,
|
|
553
538
|
.wb-queue-panel {
|
|
@@ -555,178 +540,32 @@ Override CSS custom properties to theme the bar:
|
|
|
555
540
|
--wb-border: rgba(255, 255, 255, 0.1);
|
|
556
541
|
--wb-text: #ffffff;
|
|
557
542
|
--wb-text-muted: rgba(255, 255, 255, 0.5);
|
|
558
|
-
--wb-accent: #1db954;
|
|
543
|
+
--wb-accent: #1db954;
|
|
559
544
|
--wb-accent-light: #1ed760;
|
|
560
545
|
--wb-hover: rgba(255, 255, 255, 0.08);
|
|
561
|
-
--wb-tag-bg: rgba(29, 185, 84, 0.12);
|
|
562
|
-
--wb-tag-text: #1db954;
|
|
563
546
|
--wb-fav-color: #ef4444;
|
|
564
547
|
--wb-cart-color: #4ade80;
|
|
565
548
|
}
|
|
566
549
|
```
|
|
567
550
|
|
|
568
|
-
A `.wb-light` class is available for light backgrounds:
|
|
569
|
-
|
|
570
|
-
```css
|
|
571
|
-
.waveform-bar.wb-light {
|
|
572
|
-
--wb-bg: rgba(255, 255, 255, 0.95);
|
|
573
|
-
--wb-text: #1a1a1a;
|
|
574
|
-
--wb-text-muted: rgba(0, 0, 0, 0.5);
|
|
575
|
-
}
|
|
576
|
-
```
|
|
577
|
-
|
|
578
|
-
## Layout
|
|
579
|
-
|
|
580
|
-
The bar uses a three-zone flex layout:
|
|
581
|
-
|
|
582
|
-
```
|
|
583
|
-
[Left: controls + track info] — [Centre: waveform + time] — [Right: meta + actions + volume + queue]
|
|
584
|
-
```
|
|
585
|
-
|
|
586
|
-
- **Left zone** — Prev, Play/Pause, Next, Repeat buttons + artwork + title/artist
|
|
587
|
-
- **Centre zone** — Full-width waveform visualization + elapsed/total time
|
|
588
|
-
- **Right zone** — BPM/key tags, favorite/cart buttons, volume popup, queue toggle
|
|
589
|
-
|
|
590
|
-
On mobile (≤768px):
|
|
591
|
-
|
|
592
|
-
- Left + Right share the top row
|
|
593
|
-
- Waveform drops to a full-width second row
|
|
594
|
-
- Meta tags, actions, and time display are hidden
|
|
595
|
-
- Queue panel becomes full-width
|
|
596
|
-
|
|
597
|
-
On small mobile (≤480px):
|
|
598
|
-
|
|
599
|
-
- Prev/Next and Repeat buttons are hidden
|
|
600
|
-
- Volume is hidden
|
|
601
|
-
- Only play button, track info, and waveform remain
|
|
602
|
-
|
|
603
|
-
## Use Cases
|
|
604
|
-
|
|
605
|
-
### Beat Store
|
|
606
|
-
|
|
607
|
-
```html
|
|
608
|
-
|
|
609
|
-
<div class="beat-card wb-card-highlight"
|
|
610
|
-
data-wb-play
|
|
611
|
-
data-url="beats/trap-42.mp3"
|
|
612
|
-
data-id="beat-42"
|
|
613
|
-
data-title="Trap Beat #42"
|
|
614
|
-
data-artist="ProducerName"
|
|
615
|
-
data-bpm="140"
|
|
616
|
-
data-key="Cm"
|
|
617
|
-
data-artwork="covers/trap-42.jpg"
|
|
618
|
-
data-link="/beats/trap-42"
|
|
619
|
-
data-wb-favorited="true">
|
|
620
|
-
<img src="covers/trap-42.jpg">
|
|
621
|
-
<h3 class="wb-accent-current">Trap Beat #42</h3>
|
|
622
|
-
<p>140 BPM · Cm · $29.99</p>
|
|
623
|
-
<span class="wb-eq-bars"><span></span><span></span><span></span><span></span></span>
|
|
624
|
-
<button>
|
|
625
|
-
<span class="wb-hide-if-fav">♡ Save</span>
|
|
626
|
-
<span class="wb-show-if-fav">❤ Saved</span>
|
|
627
|
-
</button>
|
|
628
|
-
</div>
|
|
629
|
-
<button data-wb-queue data-url="beats/trap-42.mp3" data-title="Trap Beat #42">+ Queue</button>
|
|
630
|
-
```
|
|
631
|
-
|
|
632
|
-
### Sample Library Table
|
|
633
|
-
|
|
634
|
-
```html
|
|
635
|
-
|
|
636
|
-
<table>
|
|
637
|
-
<tr data-wb-play
|
|
638
|
-
data-url="samples/kick.wav"
|
|
639
|
-
data-title="808 Kick"
|
|
640
|
-
data-artist="Drum Kit Vol. 3"
|
|
641
|
-
data-bpm="128"
|
|
642
|
-
data-meta='{"format":"WAV"}'>
|
|
643
|
-
<td><span class="wb-eq-bars"><span></span><span></span><span></span><span></span></span></td>
|
|
644
|
-
<td class="wb-accent-current">808 Kick</td>
|
|
645
|
-
<td>128 BPM</td>
|
|
646
|
-
<td>WAV</td>
|
|
647
|
-
</tr>
|
|
648
|
-
</table>
|
|
649
|
-
```
|
|
650
|
-
|
|
651
|
-
### DJ Mix with Clickable Tracklist
|
|
652
|
-
|
|
653
|
-
```html
|
|
654
|
-
<!-- Mix trigger with markers -->
|
|
655
|
-
<div data-wb-play
|
|
656
|
-
data-url="mixes/guestmix.mp3"
|
|
657
|
-
data-title="Guest Mix"
|
|
658
|
-
data-artist="Various Artists"
|
|
659
|
-
data-wb-waveform='[0.1,0.3,0.5,...]'
|
|
660
|
-
data-wb-markers='[
|
|
661
|
-
{"time":0,"label":"Intro","title":"Opening","artist":"DJ One"},
|
|
662
|
-
{"time":180,"label":"Drop","title":"Big Tune","artist":"Producer X"},
|
|
663
|
-
{"time":360,"label":"Chill","title":"Wind Down","artist":"Ambient Co"}
|
|
664
|
-
]'>
|
|
665
|
-
🎧 Play Guest Mix
|
|
666
|
-
</div>
|
|
667
|
-
|
|
668
|
-
<!-- Clickable tracklist buttons -->
|
|
669
|
-
<button onclick="WaveformBar.seekToMarkerByLabel('Intro')">00:00 — DJ One — Opening</button>
|
|
670
|
-
<button onclick="WaveformBar.seekToMarkerByLabel('Drop')">03:00 — Producer X — Big Tune</button>
|
|
671
|
-
<button onclick="WaveformBar.seekToMarkerByLabel('Chill')">06:00 — Ambient Co — Wind Down</button>
|
|
672
|
-
```
|
|
673
|
-
|
|
674
|
-
### Podcast
|
|
675
|
-
|
|
676
|
-
```html
|
|
677
|
-
|
|
678
|
-
<button data-wb-play
|
|
679
|
-
data-url="episodes/ep42.mp3"
|
|
680
|
-
data-title="Ep 42: The Future of AI"
|
|
681
|
-
data-artist="with Dr. Sarah Chen"
|
|
682
|
-
data-artwork="ep42-cover.jpg"
|
|
683
|
-
data-link="/episodes/42"
|
|
684
|
-
class="wb-icon-swap">
|
|
685
|
-
<span class="wb-show-play">▶ Listen</span>
|
|
686
|
-
<span class="wb-show-pause">⏸ Playing</span>
|
|
687
|
-
</button>
|
|
688
|
-
```
|
|
689
|
-
|
|
690
|
-
## Pre-Generating Waveforms
|
|
691
|
-
|
|
692
|
-
Use [@arraypress/waveform-gen](https://github.com/arraypress/waveform-gen) to batch-generate waveform data:
|
|
693
|
-
|
|
694
|
-
```bash
|
|
695
|
-
# Generate JSON files for all audio
|
|
696
|
-
npx @arraypress/waveform-gen ./audio/*.mp3 --output ./waveforms/
|
|
697
|
-
|
|
698
|
-
# Generate ready-to-paste HTML markup
|
|
699
|
-
npx @arraypress/waveform-gen ./audio/*.mp3 --format html --output ./
|
|
700
|
-
```
|
|
701
|
-
|
|
702
|
-
Then reference the data in your HTML:
|
|
703
|
-
|
|
704
|
-
```html
|
|
705
|
-
|
|
706
|
-
<div data-wb-play
|
|
707
|
-
data-url="song.mp3"
|
|
708
|
-
data-title="My Song"
|
|
709
|
-
data-wb-waveform='[0.12,0.45,0.89,0.34,0.67]'>
|
|
710
|
-
</div>
|
|
711
|
-
```
|
|
712
|
-
|
|
713
551
|
## Browser Support
|
|
714
552
|
|
|
715
|
-
|
|
716
|
-
- Firefox 88+
|
|
717
|
-
- Safari 14+
|
|
718
|
-
- Mobile browsers (iOS Safari, Chrome Android)
|
|
553
|
+
Chrome/Edge 90+, Firefox 88+, Safari 14+, iOS Safari, Chrome Android
|
|
719
554
|
|
|
720
555
|
## Dependencies
|
|
721
556
|
|
|
722
|
-
- [WaveformPlayer](https://github.com/arraypress/waveform-player) ≥1.
|
|
557
|
+
- [WaveformPlayer](https://github.com/arraypress/waveform-player) ≥1.5.0 — must be loaded before WaveformBar
|
|
723
558
|
|
|
724
|
-
##
|
|
559
|
+
## Ecosystem
|
|
725
560
|
|
|
726
|
-
|
|
561
|
+
| Package | Description |
|
|
562
|
+
|-------------------------------------------------------------------------|-------------------------------------------------------------------|
|
|
563
|
+
| **[WaveformPlayer](https://github.com/arraypress/waveform-player)** | Core audio player with waveform visualization |
|
|
564
|
+
| **[WaveformBar](https://github.com/arraypress/waveform-bar)** | Persistent bottom-bar player with queue, favorites, cart, DJ mode |
|
|
565
|
+
| **[WaveformGen](https://github.com/arraypress/waveform-generator)** | CLI tool to pre-generate waveform JSON from audio files |
|
|
566
|
+
| **[WaveformPlaylist](https://github.com/arraypress/waveform-playlist)** | Playlist and chapter support addon |
|
|
567
|
+
| **[WaveformTracker](https://github.com/arraypress/waveform-tracker)** | Audio engagement analytics |
|
|
727
568
|
|
|
728
|
-
##
|
|
569
|
+
## License
|
|
729
570
|
|
|
730
|
-
|
|
731
|
-
- [WaveformPlaylist](https://github.com/arraypress/waveform-playlist) — On-page playlist and chapter navigation
|
|
732
|
-
- [WaveformGen](https://github.com/arraypress/waveform-generator) — CLI tool for batch waveform data generation
|
|
571
|
+
MIT © [ArrayPress](https://github.com/arraypress)
|