@djangocfg/ui-nextjs 2.1.81 → 2.1.83

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.
Files changed (36) hide show
  1. package/package.json +4 -4
  2. package/src/tools/AudioPlayer/@refactoring3/00-IMPLEMENTATION-ROADMAP.md +1146 -0
  3. package/src/tools/AudioPlayer/@refactoring3/01-WAVESURFER-STREAMING-ANALYSIS.md +611 -0
  4. package/src/tools/AudioPlayer/@refactoring3/02-MEDIA-VIEWER-ANALYSIS.md +560 -0
  5. package/src/tools/AudioPlayer/@refactoring3/03-HYBRID-ARCHITECTURE-PROPOSAL.md +769 -0
  6. package/src/tools/AudioPlayer/@refactoring3/04-CRACKLING-ISSUE-DIAGNOSIS.md +373 -0
  7. package/src/tools/AudioPlayer/README.md +177 -205
  8. package/src/tools/AudioPlayer/components/AudioPlayer.tsx +9 -4
  9. package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +251 -0
  10. package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +291 -0
  11. package/src/tools/AudioPlayer/components/HybridWaveform.tsx +279 -0
  12. package/src/tools/AudioPlayer/components/SimpleAudioPlayer.tsx +16 -26
  13. package/src/tools/AudioPlayer/components/index.ts +6 -1
  14. package/src/tools/AudioPlayer/context/AudioProvider.tsx +16 -8
  15. package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +121 -0
  16. package/src/tools/AudioPlayer/context/index.ts +14 -2
  17. package/src/tools/AudioPlayer/hooks/index.ts +11 -0
  18. package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +387 -0
  19. package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +95 -0
  20. package/src/tools/AudioPlayer/hooks/useSharedWebAudio.ts +6 -3
  21. package/src/tools/AudioPlayer/index.ts +31 -0
  22. package/src/tools/AudioPlayer/progressive/ProgressiveAudioPlayer.tsx +8 -0
  23. package/src/tools/ImageViewer/hooks/useImageLoading.ts +33 -9
  24. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +13 -6
  25. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +38 -22
  26. package/src/tools/index.ts +22 -0
  27. package/src/tools/AudioPlayer/@refactoring/00-PLAN.md +0 -148
  28. package/src/tools/AudioPlayer/@refactoring/01-TYPES.md +0 -301
  29. package/src/tools/AudioPlayer/@refactoring/02-HOOKS.md +0 -281
  30. package/src/tools/AudioPlayer/@refactoring/03-CONTEXT.md +0 -328
  31. package/src/tools/AudioPlayer/@refactoring/04-COMPONENTS.md +0 -251
  32. package/src/tools/AudioPlayer/@refactoring/05-EFFECTS.md +0 -427
  33. package/src/tools/AudioPlayer/@refactoring/06-UTILS-AND-INDEX.md +0 -193
  34. package/src/tools/AudioPlayer/@refactoring/07-EXECUTION-CHECKLIST.md +0 -146
  35. package/src/tools/AudioPlayer/@refactoring2/ISSUE_ANALYSIS.md +0 -187
  36. package/src/tools/AudioPlayer/@refactoring2/PLAN.md +0 -372
@@ -0,0 +1,769 @@
1
+ # Hybrid Audio Player Architecture Proposal
2
+
3
+ **Date:** 2025-12-30
4
+ **Status:** Proposal
5
+ **Goal:** Combine native HTML5 audio playback with Web Audio API visualization and reactive effects
6
+
7
+ ---
8
+
9
+ ## Executive Summary
10
+
11
+ This proposal outlines a hybrid architecture that:
12
+ 1. Uses **native HTML5 `<audio>` element** for playback (eliminates crackling issues)
13
+ 2. Connects **Web Audio API AnalyserNode** to the audio element for real-time visualization
14
+ 3. Preserves all **reactive cover effects** (glow, orbs, spotlight, mesh)
15
+ 4. Supports **chunked/streaming audio** with proper Range request handling
16
+
17
+ ---
18
+
19
+ ## Problem Statement
20
+
21
+ ### Current Issues
22
+
23
+ 1. **WaveSurfer.js limitations with streaming:**
24
+ - Requires full file download before seek works properly
25
+ - Seek beyond buffered content (>2 minutes for 2MB chunks) breaks playback
26
+ - After failed seek, player state becomes corrupted
27
+
28
+ 2. **Audio crackling in pure Web Audio approach:**
29
+ - Direct AudioBufferSourceNode playback can cause crackling
30
+ - Manual buffer scheduling is complex and error-prone
31
+ - GC pauses during buffer transitions cause audible artifacts
32
+
33
+ 3. **Architecture complexity:**
34
+ - Current code has two separate players (WaveSurfer-based and Progressive)
35
+ - Duplication of state management and controls
36
+ - Reactive effects tightly coupled to WaveSurfer implementation
37
+
38
+ ---
39
+
40
+ ## Architecture Overview
41
+
42
+ ```
43
+ HYBRID AUDIO PLAYER ARCHITECTURE
44
+ +===============================================================================+
45
+ | |
46
+ | +-------------------------------------------------------------------------+ |
47
+ | | HybridAudioProvider | |
48
+ | | (React Context - manages all state and coordinates components) | |
49
+ | +-------------------------------------------------------------------------+ |
50
+ | | |
51
+ | +---------------------------+---------------------------+ |
52
+ | | | | |
53
+ | v v v |
54
+ | +---------------+ +----------------+ +------------------+ |
55
+ | | PLAYBACK | | VISUALIZATION | | REACTIVE FX | |
56
+ | | LAYER | | LAYER | | LAYER | |
57
+ | +---------------+ +----------------+ +------------------+ |
58
+ | | | | | | | |
59
+ | | HTML5 <audio> | ---> | MediaElement | ---> | useAudioAnalysis | |
60
+ | | (native) | | SourceNode | | (bass/mid/high) | |
61
+ | | | | | | | | | |
62
+ | | - Range req | | v | | v | |
63
+ | | - Buffering | | AnalyserNode | | AudioReactive | |
64
+ | | - Seek | | | | | Cover | |
65
+ | | - No crackling| | v | | - GlowEffect | |
66
+ | +-------+-------+ | Destination | | - OrbsEffect | |
67
+ | | +-------+--------+ | - SpotlightEffect| |
68
+ | | | | - MeshEffect | |
69
+ | v v +------------------+ |
70
+ | +-------+-------+ +-------+--------+ |
71
+ | | useAudioState | | useSharedWeb | |
72
+ | | - currentTime | | Audio | |
73
+ | | - duration | | (singleton | |
74
+ | | - buffered | | context) | |
75
+ | | - isPlaying | +----------------+ |
76
+ | +---------------+ |
77
+ | |
78
+ +===============================================================================+
79
+
80
+ DATA FLOW DIAGRAM
81
+
82
+ +-----------+ +-----------+ +--------------+ +---------------+
83
+ | Audio | | Browser | | Audio | | React State |
84
+ | Source | --> | Handles | --> | Element | --> | Updates |
85
+ | (URL) | | Range | | Events | | (60fps) |
86
+ +-----------+ | Requests | +--------------+ +---------------+
87
+ +-----------+ |
88
+ v
89
+ +--------------------------------------------------+
90
+ | Web Audio Graph |
91
+ | |
92
+ | [MediaElementSource] --> [AnalyserNode] --> [Destination]
93
+ | | |
94
+ | v |
95
+ | [getByteFrequencyData] |
96
+ | | |
97
+ | v |
98
+ | [AudioLevels State] |
99
+ | { bass, mid, high, overall }
100
+ +--------------------------------------------------+
101
+ ```
102
+
103
+ ---
104
+
105
+ ## Key Components
106
+
107
+ ### 1. HybridAudioProvider (Context)
108
+
109
+ **File:** `context/HybridAudioProvider.tsx`
110
+
111
+ **Responsibilities:**
112
+ - Manage audio element lifecycle
113
+ - Create and maintain Web Audio graph
114
+ - Provide unified state to all consumers
115
+ - Handle playback controls
116
+ - Coordinate visualization and effects
117
+
118
+ ```typescript
119
+ interface HybridAudioContextState {
120
+ // Core instances
121
+ audioElement: HTMLAudioElement | null;
122
+ audioContext: AudioContext | null;
123
+ sourceNode: MediaElementAudioSourceNode | null;
124
+ analyserNode: AnalyserNode | null;
125
+
126
+ // Playback state
127
+ isReady: boolean;
128
+ isPlaying: boolean;
129
+ currentTime: number;
130
+ duration: number;
131
+ volume: number;
132
+ isMuted: boolean;
133
+ isLooping: boolean;
134
+ buffered: TimeRanges | null;
135
+
136
+ // Audio analysis (for reactive effects)
137
+ audioLevels: AudioLevels;
138
+
139
+ // Actions
140
+ play: () => Promise<void>;
141
+ pause: () => void;
142
+ togglePlay: () => void;
143
+ seek: (time: number) => void;
144
+ seekTo: (progress: number) => void;
145
+ skip: (seconds: number) => void;
146
+ setVolume: (vol: number) => void;
147
+ toggleMute: () => void;
148
+ toggleLoop: () => void;
149
+ }
150
+ ```
151
+
152
+ ### 2. useHybridAudio (Core Hook)
153
+
154
+ **File:** `hooks/useHybridAudio.ts`
155
+
156
+ **Responsibilities:**
157
+ - Create HTML5 audio element
158
+ - Connect to Web Audio API for analysis only (not playback)
159
+ - Extract frequency data for visualizations
160
+ - Handle streaming/chunked audio sources
161
+
162
+ ```typescript
163
+ interface UseHybridAudioOptions {
164
+ src: string;
165
+ autoPlay?: boolean;
166
+ initialVolume?: number;
167
+ loop?: boolean;
168
+ crossOrigin?: 'anonymous' | 'use-credentials';
169
+
170
+ // Callbacks
171
+ onPlay?: () => void;
172
+ onPause?: () => void;
173
+ onEnded?: () => void;
174
+ onTimeUpdate?: (time: number) => void;
175
+ onError?: (error: Error) => void;
176
+ }
177
+
178
+ interface UseHybridAudioReturn {
179
+ // Refs
180
+ audioRef: RefObject<HTMLAudioElement>;
181
+
182
+ // State
183
+ state: AudioState;
184
+
185
+ // Controls
186
+ controls: AudioControls;
187
+
188
+ // Web Audio for visualization
189
+ webAudio: {
190
+ context: AudioContext | null;
191
+ analyser: AnalyserNode | null;
192
+ createAnalyser: (options?: AnalyserOptions) => AnalyserNode | null;
193
+ disconnectAnalyser: (analyser: AnalyserNode) => void;
194
+ };
195
+ }
196
+ ```
197
+
198
+ ### 3. useAudioAnalysis (Visualization Hook)
199
+
200
+ **File:** `hooks/useAudioAnalysis.ts` (existing, minor updates)
201
+
202
+ **Responsibilities:**
203
+ - Read frequency data from AnalyserNode
204
+ - Calculate bass, mid, high, and overall levels
205
+ - Provide smoothed values for animations
206
+ - Run at 60fps during playback
207
+
208
+ ```typescript
209
+ // Input: analyser node from useHybridAudio
210
+ // Output: AudioLevels { bass, mid, high, overall }
211
+
212
+ // Frequency bands:
213
+ // - Bass: 0-15% of spectrum (sub-bass to low-mids)
214
+ // - Mids: 15-50% of spectrum (vocals, instruments)
215
+ // - Highs: 50-100% of spectrum (cymbals, harmonics)
216
+ ```
217
+
218
+ ### 4. WaveformVisualization (Component)
219
+
220
+ **File:** `components/WaveformVisualization.tsx`
221
+
222
+ **Responsibilities:**
223
+ - Real-time waveform rendering using AnalyserNode
224
+ - Progress bar with buffered regions
225
+ - Click-to-seek functionality
226
+ - Responsive canvas rendering
227
+
228
+ **Two Modes:**
229
+ 1. **Frequency Bars Mode:** Real-time frequency visualization (like current equalizer)
230
+ 2. **Waveform Mode:** Pre-computed peaks (using Progressive player's approach)
231
+
232
+ ```typescript
233
+ interface WaveformVisualizationProps {
234
+ mode: 'frequency' | 'waveform';
235
+
236
+ // For waveform mode (pre-computed)
237
+ peaks?: number[];
238
+ loadedPercent?: number;
239
+
240
+ // Shared props
241
+ currentTime: number;
242
+ duration: number;
243
+ buffered: TimeRanges | null;
244
+ onSeek: (time: number) => void;
245
+
246
+ // Styling
247
+ style?: WaveformStyle;
248
+ className?: string;
249
+ }
250
+ ```
251
+
252
+ ### 5. AudioReactiveCover (Existing Component)
253
+
254
+ **File:** `components/ReactiveCover/AudioReactiveCover.tsx` (existing)
255
+
256
+ **No changes needed** - already consumes `audioLevels` from context.
257
+
258
+ Effects preserved:
259
+ - **GlowEffect:** Multi-layer glow responding to bass/mid/high
260
+ - **OrbsEffect:** Floating orbs with position/size based on frequencies
261
+ - **SpotlightEffect:** Rotating spotlight with color intensity
262
+ - **MeshEffect:** Morphing mesh gradients
263
+
264
+ ---
265
+
266
+ ## Web Audio Connection Architecture
267
+
268
+ ### The Key Insight
269
+
270
+ HTML5 `<audio>` handles playback natively while Web Audio API provides analysis capabilities:
271
+
272
+ ```
273
+ +-------------------+
274
+ | HTML5 <audio> | <-- Browser handles all playback
275
+ | - src loading | - Range requests
276
+ | - buffering | - Decoding
277
+ | - playback | - No crackling
278
+ +--------+----------+
279
+ |
280
+ | createMediaElementSource()
281
+ | (connects once, never disconnect)
282
+ v
283
+ +--------+----------+
284
+ | MediaElementSource| <-- Bridge between HTML5 audio and Web Audio
285
+ +--------+----------+
286
+ |
287
+ | connect()
288
+ v
289
+ +--------+----------+
290
+ | AnalyserNode | <-- For visualization only
291
+ | - fftSize: 256 | - getByteFrequencyData()
292
+ | - smoothing: 0.8| - getByteTimeDomainData()
293
+ +--------+----------+
294
+ |
295
+ | connect()
296
+ v
297
+ +--------+----------+
298
+ | AudioDestination | <-- Audio output (speakers)
299
+ +-------------------+
300
+
301
+ IMPORTANT: Audio flows THROUGH analyser to destination
302
+ This preserves audio output while enabling analysis
303
+ ```
304
+
305
+ ### Code Implementation
306
+
307
+ ```typescript
308
+ function connectWebAudio(audioElement: HTMLAudioElement): WebAudioGraph {
309
+ // Create or reuse AudioContext
310
+ const AudioContextClass = window.AudioContext ||
311
+ (window as any).webkitAudioContext;
312
+ const audioContext = new AudioContextClass();
313
+
314
+ // CRITICAL: Only create MediaElementSourceNode ONCE per audio element
315
+ // Attempting to create multiple sources throws InvalidStateError
316
+ const sourceNode = audioContext.createMediaElementSource(audioElement);
317
+
318
+ // Create analyser for visualization
319
+ const analyserNode = audioContext.createAnalyser();
320
+ analyserNode.fftSize = 256;
321
+ analyserNode.smoothingTimeConstant = 0.8;
322
+
323
+ // Connect the graph: source -> analyser -> destination
324
+ sourceNode.connect(analyserNode);
325
+ analyserNode.connect(audioContext.destination);
326
+
327
+ return { audioContext, sourceNode, analyserNode };
328
+ }
329
+ ```
330
+
331
+ ### Handling AudioContext Suspension
332
+
333
+ Browsers require user interaction before AudioContext can start:
334
+
335
+ ```typescript
336
+ useEffect(() => {
337
+ const handleUserInteraction = async () => {
338
+ if (audioContext?.state === 'suspended') {
339
+ await audioContext.resume();
340
+ }
341
+ };
342
+
343
+ // Resume on first play
344
+ audioElement?.addEventListener('play', handleUserInteraction);
345
+
346
+ return () => {
347
+ audioElement?.removeEventListener('play', handleUserInteraction);
348
+ };
349
+ }, [audioContext, audioElement]);
350
+ ```
351
+
352
+ ---
353
+
354
+ ## Streaming Audio Support
355
+
356
+ ### How HTML5 Audio Handles Streaming
357
+
358
+ ```
359
+ Browser Request: Server Response:
360
+ +------------------+ +------------------+
361
+ | GET /audio.mp3 | | 206 Partial |
362
+ | Range: bytes=0- | --> | Content-Range: |
363
+ +------------------+ | bytes 0-2MB/10MB |
364
+ +------------------+
365
+
366
+ Seek Request: Server Response:
367
+ +------------------+ +------------------+
368
+ | GET /audio.mp3 | | 206 Partial |
369
+ | Range: bytes=5MB-| --> | Content-Range: |
370
+ +------------------+ | bytes 5MB-7MB/ |
371
+ +------------------+
372
+
373
+ The browser automatically:
374
+ 1. Requests chunks as needed
375
+ 2. Buffers ahead for smooth playback
376
+ 3. Handles seek by requesting new ranges
377
+ 4. Reports buffered ranges via audio.buffered
378
+ ```
379
+
380
+ ### Visualizing Buffered Regions
381
+
382
+ ```typescript
383
+ function renderBufferedRegions(
384
+ ctx: CanvasRenderingContext2D,
385
+ buffered: TimeRanges,
386
+ duration: number,
387
+ width: number,
388
+ height: number
389
+ ) {
390
+ ctx.fillStyle = 'rgba(255, 255, 255, 0.1)';
391
+
392
+ for (let i = 0; i < buffered.length; i++) {
393
+ const start = (buffered.start(i) / duration) * width;
394
+ const end = (buffered.end(i) / duration) * width;
395
+ ctx.fillRect(start, height - 2, end - start, 2);
396
+ }
397
+ }
398
+ ```
399
+
400
+ ---
401
+
402
+ ## Implementation Steps
403
+
404
+ ### Phase 1: Core Infrastructure
405
+
406
+ **Files to create:**
407
+ - `hooks/useHybridAudio.ts`
408
+ - `context/HybridAudioProvider.tsx`
409
+
410
+ **Tasks:**
411
+ 1. Create `useHybridAudio` hook combining HTML5 audio + Web Audio API
412
+ 2. Build `HybridAudioProvider` context wrapper
413
+ 3. Integrate with existing `useSharedWebAudio` pattern (singleton source)
414
+ 4. Add comprehensive event handling (timeupdate, progress, seeking, etc.)
415
+
416
+ ### Phase 2: Visualization Integration
417
+
418
+ **Files to modify:**
419
+ - `hooks/useAudioAnalysis.ts` (minor updates)
420
+ - `components/AudioEqualizer.tsx` (connect to new context)
421
+
422
+ **Files to create:**
423
+ - `components/HybridWaveform.tsx`
424
+
425
+ **Tasks:**
426
+ 1. Update `useAudioAnalysis` to accept hybrid context
427
+ 2. Create `HybridWaveform` component with dual modes
428
+ 3. Integrate with existing canvas rendering from Progressive player
429
+
430
+ ### Phase 3: Player Component
431
+
432
+ **Files to create:**
433
+ - `components/HybridAudioPlayer.tsx`
434
+ - `components/HybridSimplePlayer.tsx`
435
+
436
+ **Tasks:**
437
+ 1. Build main `HybridAudioPlayer` component
438
+ 2. Create simplified `HybridSimplePlayer` wrapper
439
+ 3. Integrate all UI controls (play, pause, seek, volume, loop)
440
+ 4. Add keyboard shortcuts support
441
+
442
+ ### Phase 4: Reactive Cover Integration
443
+
444
+ **Files to modify:**
445
+ - `components/ReactiveCover/AudioReactiveCover.tsx` (minimal changes)
446
+
447
+ **Tasks:**
448
+ 1. Verify reactive effects work with new context
449
+ 2. Test all effect variants (glow, orbs, spotlight, mesh)
450
+ 3. Ensure smooth 60fps animations
451
+
452
+ ### Phase 5: Migration & Testing
453
+
454
+ **Tasks:**
455
+ 1. Create migration guide from WaveSurfer-based player
456
+ 2. Update all usages in application
457
+ 3. Performance testing with various audio formats/sizes
458
+ 4. Cross-browser testing (Chrome, Firefox, Safari, Edge)
459
+
460
+ ---
461
+
462
+ ## Component Hierarchy
463
+
464
+ ```
465
+ HybridSimplePlayer
466
+ |
467
+ +-- HybridAudioProvider (context)
468
+ |
469
+ +-- AudioReactiveCover (optional)
470
+ | |
471
+ | +-- GlowEffect / OrbsEffect / SpotlightEffect / MeshEffect
472
+ | |
473
+ | +-- Cover Art (children)
474
+ |
475
+ +-- HybridAudioPlayer
476
+ |
477
+ +-- HybridWaveform (canvas visualization)
478
+ |
479
+ +-- Timer (current / duration)
480
+ |
481
+ +-- Controls
482
+ |
483
+ +-- PlayPauseButton
484
+ +-- SkipButtons
485
+ +-- VolumeControl
486
+ +-- LoopToggle
487
+ +-- ShortcutsHelp
488
+ ```
489
+
490
+ ---
491
+
492
+ ## File Structure
493
+
494
+ ```
495
+ AudioPlayer/
496
+ +-- @refactoring3/
497
+ | +-- 03-HYBRID-ARCHITECTURE-PROPOSAL.md (this file)
498
+ |
499
+ +-- context/
500
+ | +-- AudioProvider.tsx (existing - WaveSurfer)
501
+ | +-- HybridAudioProvider.tsx (NEW)
502
+ | +-- index.ts
503
+ |
504
+ +-- hooks/
505
+ | +-- useSharedWebAudio.ts (existing - reuse pattern)
506
+ | +-- useAudioAnalysis.ts (existing - minor updates)
507
+ | +-- useHybridAudio.ts (NEW)
508
+ | +-- useAudioHotkeys.ts (existing - reuse)
509
+ | +-- index.ts
510
+ |
511
+ +-- components/
512
+ | +-- AudioPlayer.tsx (existing - WaveSurfer)
513
+ | +-- SimpleAudioPlayer.tsx (existing - WaveSurfer)
514
+ | +-- HybridAudioPlayer.tsx (NEW)
515
+ | +-- HybridSimplePlayer.tsx (NEW)
516
+ | +-- HybridWaveform.tsx (NEW)
517
+ | +-- AudioEqualizer.tsx (existing)
518
+ | +-- ReactiveCover/ (existing - no changes)
519
+ | +-- index.ts
520
+ |
521
+ +-- progressive/
522
+ | +-- ProgressiveAudioPlayer.tsx (existing - can be deprecated later)
523
+ | +-- useAudioElement.ts (existing - reference for useHybridAudio)
524
+ | +-- WaveformCanvas.tsx (existing - reuse for HybridWaveform)
525
+ | +-- ...
526
+ |
527
+ +-- types/
528
+ | +-- audio.ts (extend with hybrid types)
529
+ | +-- index.ts
530
+ |
531
+ +-- effects/
532
+ | +-- index.ts (existing - no changes)
533
+ ```
534
+
535
+ ---
536
+
537
+ ## API Design
538
+
539
+ ### Basic Usage
540
+
541
+ ```tsx
542
+ import { HybridSimplePlayer } from '@djangocfg/ui-nextjs/tools/AudioPlayer';
543
+
544
+ function MyComponent() {
545
+ return (
546
+ <HybridSimplePlayer
547
+ src="https://example.com/stream/audio.mp3"
548
+ title="Track Title"
549
+ artist="Artist Name"
550
+ coverArt="/path/to/cover.jpg"
551
+ reactiveCover
552
+ variant="spotlight"
553
+ />
554
+ );
555
+ }
556
+ ```
557
+
558
+ ### Advanced Usage with Context
559
+
560
+ ```tsx
561
+ import {
562
+ HybridAudioProvider,
563
+ HybridAudioPlayer,
564
+ AudioReactiveCover,
565
+ useHybridAudio
566
+ } from '@djangocfg/ui-nextjs/tools/AudioPlayer';
567
+
568
+ function CustomPlayer({ src }) {
569
+ const containerRef = useRef(null);
570
+
571
+ return (
572
+ <HybridAudioProvider src={src}>
573
+ <div className="flex gap-4">
574
+ <AudioReactiveCover variant="orbs">
575
+ <img src={coverUrl} alt="Cover" />
576
+ </AudioReactiveCover>
577
+
578
+ <HybridAudioPlayer
579
+ ref={containerRef}
580
+ showWaveform
581
+ showEqualizer={false}
582
+ />
583
+ </div>
584
+ </HybridAudioProvider>
585
+ );
586
+ }
587
+ ```
588
+
589
+ ### Using Hooks Directly
590
+
591
+ ```tsx
592
+ import { useHybridAudio, useAudioAnalysis } from '@djangocfg/ui-nextjs/tools/AudioPlayer';
593
+
594
+ function CustomVisualization({ src }) {
595
+ const { audioRef, state, controls, webAudio } = useHybridAudio({ src });
596
+ const levels = useAudioAnalysis(webAudio, state.isPlaying);
597
+
598
+ return (
599
+ <div>
600
+ <audio ref={audioRef} />
601
+ <CustomCanvas levels={levels} />
602
+ <button onClick={controls.togglePlay}>
603
+ {state.isPlaying ? 'Pause' : 'Play'}
604
+ </button>
605
+ </div>
606
+ );
607
+ }
608
+ ```
609
+
610
+ ---
611
+
612
+ ## Migration Path
613
+
614
+ ### From WaveSurfer-based Player
615
+
616
+ ```tsx
617
+ // Before (WaveSurfer)
618
+ <SimpleAudioPlayer
619
+ src={url}
620
+ showWaveform
621
+ reactiveCover
622
+ variant="spotlight"
623
+ />
624
+
625
+ // After (Hybrid)
626
+ <HybridSimplePlayer
627
+ src={url}
628
+ showWaveform
629
+ reactiveCover
630
+ variant="spotlight"
631
+ />
632
+ ```
633
+
634
+ ### From Progressive Player
635
+
636
+ ```tsx
637
+ // Before (Progressive)
638
+ <ProgressiveAudioPlayer
639
+ src={streamUrl}
640
+ showWaveform
641
+ />
642
+
643
+ // After (Hybrid)
644
+ <HybridSimplePlayer
645
+ src={streamUrl}
646
+ showWaveform
647
+ waveformMode="frequency" // or "waveform" for pre-computed peaks
648
+ />
649
+ ```
650
+
651
+ ---
652
+
653
+ ## Performance Considerations
654
+
655
+ ### Memory Usage
656
+
657
+ | Component | Memory Impact |
658
+ |-----------|--------------|
659
+ | HTML5 Audio | Browser-managed buffering (~5-20MB depending on format) |
660
+ | Web Audio Context | ~2-4KB per context |
661
+ | AnalyserNode | ~1KB + fftSize bytes for data arrays |
662
+ | Canvas | width * height * 4 bytes (RGBA) |
663
+ | Reactive Effects | Minimal (CSS transforms) |
664
+
665
+ ### CPU Usage
666
+
667
+ | Operation | Frequency | Cost |
668
+ |-----------|-----------|------|
669
+ | Audio decoding | On-demand | Browser-optimized |
670
+ | getByteFrequencyData | 60fps during playback | ~0.1ms |
671
+ | Canvas render | 60fps during playback | ~1-2ms |
672
+ | React state updates | 60fps during playback | ~0.5ms |
673
+ | Effect calculations | 60fps during playback | ~0.2ms |
674
+
675
+ ### Optimization Tips
676
+
677
+ 1. **Throttle state updates:** Use `requestAnimationFrame` for visualization updates
678
+ 2. **Avoid re-renders:** Memoize effect calculations, use refs for animation data
679
+ 3. **Canvas optimization:** Use `willReadFrequently: true` for 2D context
680
+ 4. **Web Audio:** Reuse AudioContext (singleton pattern)
681
+
682
+ ---
683
+
684
+ ## Browser Compatibility
685
+
686
+ | Feature | Chrome | Firefox | Safari | Edge |
687
+ |---------|--------|---------|--------|------|
688
+ | HTML5 Audio | Yes | Yes | Yes | Yes |
689
+ | Range Requests | Yes | Yes | Yes | Yes |
690
+ | AudioContext | Yes | Yes | Yes (webkit) | Yes |
691
+ | MediaElementSource | Yes | Yes | Yes | Yes |
692
+ | AnalyserNode | Yes | Yes | Yes | Yes |
693
+ | requestAnimationFrame | Yes | Yes | Yes | Yes |
694
+
695
+ **Note:** Safari requires `webkitAudioContext` prefix in older versions.
696
+
697
+ ---
698
+
699
+ ## Testing Strategy
700
+
701
+ ### Unit Tests
702
+
703
+ 1. `useHybridAudio` hook behavior
704
+ 2. Audio state transitions
705
+ 3. Web Audio graph creation
706
+ 4. Frequency data extraction
707
+
708
+ ### Integration Tests
709
+
710
+ 1. Full player component rendering
711
+ 2. Play/pause/seek operations
712
+ 3. Volume control
713
+ 4. Reactive effects updates
714
+
715
+ ### E2E Tests
716
+
717
+ 1. Streaming audio playback
718
+ 2. Seek beyond buffered content
719
+ 3. Cross-browser playback
720
+ 4. Mobile device support
721
+
722
+ ### Manual Testing Scenarios
723
+
724
+ 1. Play audio from streaming URL
725
+ 2. Seek to unbuffered position
726
+ 3. Verify no crackling during playback
727
+ 4. Verify reactive effects respond to music
728
+ 5. Test with various audio formats (MP3, AAC, OGG)
729
+ 6. Test with different file sizes (1MB - 100MB)
730
+
731
+ ---
732
+
733
+ ## Risks and Mitigations
734
+
735
+ | Risk | Likelihood | Impact | Mitigation |
736
+ |------|------------|--------|------------|
737
+ | Safari AudioContext issues | Medium | High | Fallback to webkit prefix, test thoroughly |
738
+ | CORS issues with streaming | Medium | Medium | Ensure crossOrigin="anonymous" and server headers |
739
+ | Memory leaks with context | Low | Medium | Proper cleanup in useEffect, singleton pattern |
740
+ | Performance on mobile | Medium | Medium | Reduce fftSize, lower frame rate on mobile |
741
+ | Breaking existing integrations | Medium | High | Provide migration guide, keep old components |
742
+
743
+ ---
744
+
745
+ ## Conclusion
746
+
747
+ This hybrid architecture provides the best of both worlds:
748
+
749
+ 1. **Native HTML5 Audio for Playback:**
750
+ - No crackling or audio glitches
751
+ - Browser-optimized decoding and buffering
752
+ - Native Range request handling for streaming
753
+
754
+ 2. **Web Audio API for Visualization:**
755
+ - Real-time frequency analysis
756
+ - Multiple analyzer nodes for different components
757
+ - Efficient data extraction for animations
758
+
759
+ 3. **Preserved Reactive Effects:**
760
+ - All existing effects continue to work
761
+ - Same audio levels data structure
762
+ - No changes needed to effect components
763
+
764
+ 4. **Streaming Support:**
765
+ - Works with chunked audio delivery
766
+ - Proper buffered region visualization
767
+ - Seek works even beyond initial buffer
768
+
769
+ The implementation can be done incrementally without breaking existing functionality, and the migration path is straightforward for consumers of the component library.