@arraypress/waveform-bar 1.0.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 ADDED
@@ -0,0 +1,732 @@
1
+ # WaveformBar
2
+
3
+ A persistent bottom audio player bar for websites. Built
4
+ on [WaveformPlayer](https://github.com/arraypress/waveform-player), it provides site-wide playback with queue
5
+ management, volume control, favorites, cart integration, DJ mode with markers, repeat modes, session persistence, and
6
+ page state syncing.
7
+
8
+ Think Spotify's bottom player โ€” but lightweight, zero-config, and works on any site.
9
+
10
+ **[Live Demo](https://waveformplayer.com/bar)** | *
11
+ *[NPM Package](https://www.npmjs.com/package/@arraypress/waveform-bar)**
12
+
13
+ ![Version](https://img.shields.io/npm/v/@arraypress/waveform-bar)
14
+ ![License](https://img.shields.io/npm/l/@arraypress/waveform-bar)
15
+
16
+ ## Features
17
+
18
+ - ๐ŸŽต **Persistent Player** โ€” Fixed bottom bar that stays while users browse
19
+ - ๐Ÿ“‹ **Queue Management** โ€” Add, remove, skip, replay, clear. Now Playing/Up Next/Previously Played sections
20
+ - ๐Ÿ”Š **Volume Control** โ€” Popup vertical slider + mute toggle, persisted in localStorage
21
+ - ๐Ÿ” **Repeat Modes** โ€” Off, repeat all (loops queue), repeat one (loops current track)
22
+ - ๐Ÿท๏ธ **Metadata Tags** โ€” Display BPM, key, or custom data inline
23
+ - โค๏ธ **Favorites** โ€” Toggle favorites with server-side seeding via `data-wb-favorited`
24
+ - ๐Ÿ›’ **Cart Integration** โ€” Add to cart with REST callbacks and DOM events
25
+ - ๐ŸŽง **DJ Mode** โ€” Markers with title/artist fields that update the bar as a mix plays
26
+ - ๐Ÿ“ **Marker Navigation** โ€” Seek to markers by index or label via JavaScript API
27
+ - ๐Ÿ’พ **Session Persistence** โ€” Queue, position, and playback state survive page navigations
28
+ - ๐Ÿ”— **Product Links** โ€” Click track info to navigate to a product page
29
+ - ๐Ÿ”„ **Page State Sync** โ€” Trigger elements get CSS classes reflecting play state
30
+ - ๐ŸŽ›๏ธ **Data Attribute API** โ€” Just add `data-wb-play` to any element
31
+ - ๐ŸŽจ **Helper CSS** โ€” Icon swaps, equalizer bars, card highlights, favorite/cart visibility
32
+ - ๐Ÿ–ผ๏ธ **Default Artwork** โ€” Configurable fallback artwork when tracks have no cover image
33
+ - ๐Ÿ“œ **Auto-Scroll Text** โ€” Long titles/artists bounce-scroll smoothly
34
+ - ๐ŸŒ— **Theme Support** โ€” Dark/light via CSS custom properties
35
+ - ๐Ÿ“ฑ **Responsive** โ€” Stacked layout on mobile, full-width queue panel
36
+ - ๐Ÿชถ **Lightweight** โ€” ~6KB gzipped (JS + CSS)
37
+
38
+ ## Installation
39
+
40
+ ### CDN
41
+
42
+ ```html
43
+ <!-- WaveformPlayer (required dependency) -->
44
+ <link rel="stylesheet" href="https://unpkg.com/@arraypress/waveform-player@latest/dist/waveform-player.css">
45
+ <script src="https://unpkg.com/@arraypress/waveform-player@latest/dist/waveform-player.js"></script>
46
+
47
+ <!-- WaveformBar -->
48
+ <link rel="stylesheet" href="https://unpkg.com/@arraypress/waveform-bar@latest/dist/waveform-bar.css">
49
+ <script src="https://unpkg.com/@arraypress/waveform-bar@latest/dist/waveform-bar.js"></script>
50
+ ```
51
+
52
+ ### NPM
53
+
54
+ ```bash
55
+ npm install @arraypress/waveform-player @arraypress/waveform-bar
56
+ ```
57
+
58
+ ## Quick Start
59
+
60
+ ```html
61
+ <!-- 1. A play button โ€” that's all you need -->
62
+ <button data-wb-play
63
+ data-url="song.mp3"
64
+ data-title="My Song"
65
+ data-artist="Artist Name">
66
+ โ–ถ Play
67
+ </button>
68
+
69
+ <!-- 2. Initialize -->
70
+ <script>
71
+ WaveformBar.init();
72
+ </script>
73
+ ```
74
+
75
+ Click the button โ†’ the bar slides up from the bottom โ†’ music plays. Add more buttons anywhere on the page and they all
76
+ share the same player bar.
77
+
78
+ ## Data Attributes
79
+
80
+ ### Play Trigger (`data-wb-play`)
81
+
82
+ Add to any HTML element to make it play a track when clicked.
83
+
84
+ ```html
85
+ <!-- Simple button -->
86
+ <button data-wb-play
87
+ data-url="audio/track.mp3"
88
+ data-title="Track Title"
89
+ data-artist="Artist Name">
90
+ Play
91
+ </button>
92
+
93
+ <!-- Card with full metadata -->
94
+ <div data-wb-play
95
+ data-url="audio/beat.mp3"
96
+ data-id="product-42"
97
+ data-title="Trap Beat"
98
+ data-artist="Producer"
99
+ data-bpm="140"
100
+ data-key="Cm"
101
+ data-artwork="covers/beat.jpg"
102
+ data-link="/beats/trap-beat"
103
+ data-wb-favorited="true">
104
+ <img src="covers/beat.jpg">
105
+ <h3>Trap Beat</h3>
106
+ </div>
107
+
108
+ <!-- Table row -->
109
+ <tr data-wb-play
110
+ data-url="samples/kick.wav"
111
+ data-title="808 Kick"
112
+ data-artist="Drum Kit Vol. 3"
113
+ data-bpm="128">
114
+ <td>808 Kick</td>
115
+ <td>128 BPM</td>
116
+ </tr>
117
+ ```
118
+
119
+ ### Queue Trigger (`data-wb-queue`)
120
+
121
+ Add to any element to queue a track without immediately playing it.
122
+
123
+ ```html
124
+
125
+ <button data-wb-queue
126
+ data-url="audio/track.mp3"
127
+ data-title="Queued Track"
128
+ data-artist="Artist">
129
+ + Add to Queue
130
+ </button>
131
+ ```
132
+
133
+ ### Pre-Generated Waveform Data
134
+
135
+ Skip client-side audio analysis by providing pre-generated waveform peaks.
136
+ Use [waveform-gen](https://github.com/arraypress/waveform-gen) to generate the data.
137
+
138
+ ```html
139
+
140
+ <div data-wb-play
141
+ data-url="song.mp3"
142
+ data-title="My Song"
143
+ data-wb-waveform='[0.12,0.45,0.89,0.34,0.67,0.92,0.15,0.78]'>
144
+ </div>
145
+ ```
146
+
147
+ The waveform displays instantly on load without downloading and decoding the audio file.
148
+
149
+ ### DJ Mode Markers
150
+
151
+ Add time-stamped markers with title/artist fields. As the mix plays, the bar updates the displayed track name, artist,
152
+ and metadata at each marker boundary.
153
+
154
+ ```html
155
+
156
+ <div data-wb-play
157
+ data-url="audio/guestmix.mp3"
158
+ data-title="Guest Mix"
159
+ data-artist="Various Artists"
160
+ data-wb-markers='[
161
+ {"time": 0, "label": "Intro", "title": "Opening Track", "artist": "DJ One"},
162
+ {"time": 180, "label": "Drop", "title": "Big Tune", "artist": "Producer X", "bpm": "174", "key": "Am"},
163
+ {"time": 360, "label": "Chill", "title": "Downtempo", "artist": "Ambient Artist"}
164
+ ]'>
165
+ Play Mix
166
+ </div>
167
+ ```
168
+
169
+ Markers can include: `time` (seconds, required), `label` (required), `title`, `artist`, `artwork`, `bpm`, `key`,
170
+ `color`.
171
+
172
+ The active marker on the waveform gently pulses to indicate the current section.
173
+
174
+ ### Attribute Reference
175
+
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) |
195
+
196
+ All attributes also accept `data-wb-` prefixed versions (`data-wb-url`, `data-wb-title`, etc.) to avoid conflicts with
197
+ other libraries.
198
+
199
+ ## Configuration
200
+
201
+ ```javascript
202
+ WaveformBar.init({
203
+ // Persistence
204
+ persist: true, // Save queue/position to sessionStorage
205
+ autoResume: true, // Auto-resume playback after page navigation
206
+
207
+ // Playback
208
+ continuous: true, // Auto-advance to next track in queue
209
+ repeat: 'off', // Repeat mode: 'off', 'all', 'one'
210
+ volume: 1, // Initial volume (0-1)
211
+
212
+ // UI visibility
213
+ showQueue: true, // Show queue toggle button
214
+ showPrevNext: true, // Show prev/next skip buttons
215
+ showRepeat: true, // Show repeat mode button
216
+ showVolume: true, // Show volume popup slider
217
+ showMute: true, // Show mute button
218
+ showTime: true, // Show elapsed/total time display
219
+ showTrackLink: true, // Make track info clickable (navigates to data-link)
220
+ showMeta: true, // Show metadata tags (BPM, key, custom)
221
+ maxMeta: 3, // Max number of metadata tags to display
222
+
223
+ // Artwork
224
+ defaultArtwork: null, // URL to fallback artwork (shown when track has no artwork)
225
+
226
+ // Waveform display (passed to WaveformPlayer)
227
+ waveformStyle: 'mirror', // 'bars', 'mirror', 'line', 'blocks', 'dots', 'seekbar'
228
+ waveformHeight: 32, // Waveform height in pixels
229
+ barWidth: 2, // Width of waveform bars
230
+ barSpacing: 0, // Space between waveform bars
231
+ waveformColor: null, // Waveform color (null = auto-detect from theme)
232
+ progressColor: null, // Progress color (null = auto-detect from theme)
233
+ markerColor: 'rgba(255, 255, 255, 0.25)', // Default marker line color
234
+
235
+ // Storage
236
+ storageKey: 'waveform-bar', // Key prefix for sessionStorage/localStorage
237
+
238
+ // Server-side actions (REST callbacks)
239
+ actions: {
240
+ favorite: {
241
+ endpoint: '/api/favorites', // POST URL
242
+ method: 'POST'
243
+ },
244
+ cart: {
245
+ endpoint: '/api/cart', // POST URL
246
+ method: 'POST'
247
+ }
248
+ },
249
+
250
+ // Callbacks
251
+ onPlay: (track) => {
252
+ },
253
+ onPause: (track) => {
254
+ },
255
+ onTrackChange: (track, index) => {
256
+ },
257
+ onQueueChange: (queue, currentIndex) => {
258
+ },
259
+ onVolumeChange: (volume) => {
260
+ },
261
+ onFavorite: (track, favorited) => {
262
+ },
263
+ onCart: (track) => {
264
+ }
265
+ });
266
+ ```
267
+
268
+ ## JavaScript API
269
+
270
+ ### Playback
271
+
272
+ ```javascript
273
+ // Play a track object
274
+ WaveformBar.play({
275
+ url: 'audio/song.mp3',
276
+ title: 'My Song',
277
+ artist: 'Artist',
278
+ bpm: '128',
279
+ key: 'Am',
280
+ artwork: 'cover.jpg',
281
+ link: '/products/my-song'
282
+ });
283
+
284
+ // Play by URL shorthand
285
+ WaveformBar.play('audio/song.mp3');
286
+
287
+ // Playback controls
288
+ WaveformBar.togglePlay();
289
+ WaveformBar.pause();
290
+ WaveformBar.next(); // Next track (wraps if repeat: 'all')
291
+ WaveformBar.previous(); // Previous track (restarts if >3s in)
292
+ WaveformBar.skipTo(3); // Jump to queue index 3
293
+ ```
294
+
295
+ ### Repeat
296
+
297
+ ```javascript
298
+ WaveformBar.cycleRepeat(); // Cycles: off โ†’ all โ†’ one โ†’ off
299
+ WaveformBar.setRepeat('all'); // Set directly: 'off', 'all', 'one'
300
+ ```
301
+
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
+ ### Markers / DJ Mode
307
+
308
+ ```javascript
309
+ // Seek to marker by index (0-based) on current track
310
+ WaveformBar.seekToMarker(3);
311
+
312
+ // Seek to marker by label name on current track
313
+ WaveformBar.seekToMarkerByLabel('Horizon');
314
+ ```
315
+
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
+ ### Volume
320
+
321
+ ```javascript
322
+ WaveformBar.setVolume(0.5); // Set to 50%
323
+ WaveformBar.getVolume(); // Returns 0.5
324
+ WaveformBar.toggleMute();
325
+ WaveformBar.isMutedState(); // true/false
326
+ ```
327
+
328
+ Volume and mute state persist in localStorage across sessions.
329
+
330
+ ### Queue
331
+
332
+ ```javascript
333
+ // Add to end of queue
334
+ WaveformBar.addToQueue({url: 'track.mp3', title: 'Next Up', artist: 'Someone'});
335
+
336
+ // Remove by index
337
+ 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
+ WaveformBar.clearQueue();
344
+
345
+ // Clear play history
346
+ WaveformBar.clearHistory();
347
+ ```
348
+
349
+ The queue panel shows three sections: **Now Playing** (click to toggle play/pause), **Up Next**, and **Previously Played
350
+ **. Tracks can be removed individually from the queue via the ร— button on hover.
351
+
352
+ ### Favorites
353
+
354
+ ```javascript
355
+ WaveformBar.toggleFavorite(); // Toggle current track's favorite state
356
+ WaveformBar.isFavorited('beat-001'); // Check by track ID
357
+ ```
358
+
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
+ ### State
378
+
379
+ ```javascript
380
+ WaveformBar.getCurrentTrack(); // { url, title, artist, bpm, key, ... }
381
+ WaveformBar.isCurrentlyPlaying('song.mp3'); // true if this URL is actively playing
382
+ WaveformBar.isCurrentTrack('song.mp3'); // true if current (playing or paused)
383
+ WaveformBar.getQueue(); // Full queue array
384
+ WaveformBar.getHistory(); // Previously played tracks
385
+ WaveformBar.getPlayer(); // Underlying WaveformPlayer instance
386
+ ```
387
+
388
+ ### UI
389
+
390
+ ```javascript
391
+ WaveformBar.show(); // Show the bar
392
+ WaveformBar.hide(); // Hide the bar
393
+ WaveformBar.toggleQueuePanel(); // Toggle queue panel visibility
394
+ WaveformBar.toggleVolumePopup(); // Toggle volume popup
395
+ WaveformBar.closeQueuePanel();
396
+ WaveformBar.closeVolumePopup();
397
+ WaveformBar.destroy(); // Remove bar and clean up
398
+ ```
399
+
400
+ ## DOM Events
401
+
402
+ All events bubble from the bar element and are prefixed with `waveformbar:`.
403
+
404
+ ```javascript
405
+ document.addEventListener('waveformbar:play', (e) => {
406
+ console.log('Playing:', e.detail.track);
407
+ });
408
+
409
+ document.addEventListener('waveformbar:trackchange', (e) => {
410
+ console.log('Track changed:', e.detail.track, 'Index:', e.detail.index);
411
+ });
412
+ ```
413
+
414
+ | Event | Detail |
415
+ |----------------------------|----------------------------|
416
+ | `waveformbar:play` | `{ track }` |
417
+ | `waveformbar:pause` | `{ track }` |
418
+ | `waveformbar:trackchange` | `{ track, index }` |
419
+ | `waveformbar:markerchange` | `{ marker, index, track }` |
420
+ | `waveformbar:favorite` | `{ track, favorited }` |
421
+ | `waveformbar:cart` | `{ track }` |
422
+ | `waveformbar:queuechange` | `{ queue, currentIndex }` |
423
+ | `waveformbar:volumechange` | `{ volume }` |
424
+ | `waveformbar:repeatchange` | `{ mode }` |
425
+
426
+ ## Page State Sync
427
+
428
+ WaveformBar automatically adds CSS classes to trigger elements on the page:
429
+
430
+ | Class | Applied When |
431
+ |-----------------|---------------------------------------------------|
432
+ | `.wb-current` | The element's track URL matches the current track |
433
+ | `.wb-playing` | The element's track is actively playing |
434
+ | `.wb-favorited` | The element's track is favorited |
435
+ | `.wb-in-cart` | The element's track is in the cart |
436
+
437
+ These update in real-time as the user interacts with the bar.
438
+
439
+ ## Helper CSS Classes
440
+
441
+ Ready-made utility classes for common UI patterns. Add them to your trigger elements.
442
+
443
+ ### Icon Swap (`wb-icon-swap`)
444
+
445
+ Swaps play/pause content automatically based on playback state.
446
+
447
+ ```html
448
+
449
+ <button data-wb-play data-url="song.mp3" class="wb-icon-swap">
450
+ <span class="wb-show-play">โ–ถ Play</span>
451
+ <span class="wb-show-pause">โธ Playing</span>
452
+ </button>
453
+ ```
454
+
455
+ ### Equalizer Bars (`wb-eq-bars`)
456
+
457
+ Animated equalizer bars that activate when the track is playing.
458
+
459
+ ```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
+ ```
470
+
471
+ ### Card Highlight (`wb-card-highlight`)
472
+
473
+ Adds accent border and glow when the element's track is current.
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
+ ```
483
+
484
+ ### Accent Text (`wb-accent-current`)
485
+
486
+ Colors text with the accent color when the parent track is current.
487
+
488
+ ```html
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.
498
+
499
+ ```html
500
+
501
+ <div data-wb-play data-url="song.mp3" class="wb-pulse-playing">
502
+ <img src="cover.jpg">
503
+ </div>
504
+ ```
505
+
506
+ ### Favorite/Cart Visibility
507
+
508
+ Show or hide content based on favorite/cart state.
509
+
510
+ ```html
511
+
512
+ <div data-wb-play data-url="song.mp3" data-id="beat-001">
513
+ <button>
514
+ <span class="wb-hide-if-fav">โ™ก Save</span>
515
+ <span class="wb-show-if-fav">โค Saved</span>
516
+ </button>
517
+ <button>
518
+ <span class="wb-hide-if-cart">๐Ÿ›’ Add to Cart</span>
519
+ <span class="wb-show-if-cart">โœ“ In Cart</span>
520
+ </button>
521
+ </div>
522
+ ```
523
+
524
+ ## Persistence
525
+
526
+ WaveformBar uses two storage mechanisms:
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):
536
+
537
+ - Volume level
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.
543
+
544
+ Cart state is intentionally NOT persisted โ€” it seeds from `data-wb-in-cart` attributes on page load, making the server
545
+ the source of truth.
546
+
547
+ ## Custom Styling
548
+
549
+ Override CSS custom properties to theme the bar:
550
+
551
+ ```css
552
+ .waveform-bar,
553
+ .wb-queue-panel {
554
+ --wb-bg: rgba(20, 20, 20, 0.98);
555
+ --wb-border: rgba(255, 255, 255, 0.1);
556
+ --wb-text: #ffffff;
557
+ --wb-text-muted: rgba(255, 255, 255, 0.5);
558
+ --wb-accent: #1db954; /* e.g. Spotify green */
559
+ --wb-accent-light: #1ed760;
560
+ --wb-hover: rgba(255, 255, 255, 0.08);
561
+ --wb-tag-bg: rgba(29, 185, 84, 0.12);
562
+ --wb-tag-text: #1db954;
563
+ --wb-fav-color: #ef4444;
564
+ --wb-cart-color: #4ade80;
565
+ }
566
+ ```
567
+
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
+ ## Browser Support
714
+
715
+ - Chrome/Edge 90+
716
+ - Firefox 88+
717
+ - Safari 14+
718
+ - Mobile browsers (iOS Safari, Chrome Android)
719
+
720
+ ## Dependencies
721
+
722
+ - [WaveformPlayer](https://github.com/arraypress/waveform-player) โ‰ฅ1.3.5 โ€” must be loaded before WaveformBar
723
+
724
+ ## License
725
+
726
+ MIT ยฉ [ArrayPress](https://github.com/arraypress)
727
+
728
+ ## Related
729
+
730
+ - [WaveformPlayer](https://github.com/arraypress/waveform-player) โ€” Core audio player with waveform visualization
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