{"_id":"@audiowave/react","_rev":"8-f858588ae1910d3cef8bb4cf6de76040","name":"@audiowave/react","dist-tags":{"latest":"0.6.2"},"versions":{"0.2.0":{"name":"@audiowave/react","version":"0.2.0","keywords":["react","audio","visualization","waveform","real-time","canvas","web-audio"],"author":{"name":"teomyth","email":"teomyth@gmail.com"},"license":"MIT","_id":"@audiowave/react@0.2.0","maintainers":[{"name":"teomyth","email":"teomyth@gmail.com"}],"homepage":"https://github.com/teomyth/audiowave#readme","bugs":{"url":"https://github.com/teomyth/audiowave/issues"},"dist":{"shasum":"c77de9db0f4e7f33d8f64466b92e7a085c945140","tarball":"https://registry.npmjs.org/@audiowave/react/-/react-0.2.0.tgz","fileCount":28,"integrity":"sha512-5VnXCYrowJgemIzmZQY7ybZJQ1w+ITCE/jwudH5p+81B/QCbQy00lHsJ01iae6tHCcH+1sCAdUgj+DKMrRBWIQ==","signatures":[{"sig":"MEQCIGp/HrEluXurAwnVY9F5yHrHwL2vcKI5563y6D+ruePZAiA8vxfZimxIrA5ScMcyLQlz/MlU4f8SDC0vcEoObAVJeQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":304271},"main":"dist/index.js","_from":"file:audiowave-react-0.2.0.tgz","types":"dist/index.d.ts","module":"dist/index.esm.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.js"}},"scripts":{"dev":"vite build --watch","test":"vitest --run","build":"vite build","clean":"rm -rf dist","test:ui":"vitest --ui","test:watch":"vitest","type-check":"tsc --noEmit","test:coverage":"vitest --coverage --run"},"_npmUser":{"name":"teomyth","email":"teomyth@gmail.com"},"_resolved":"/tmp/0f30651d14b598927913ff74e29e5613/audiowave-react-0.2.0.tgz","_integrity":"sha512-5VnXCYrowJgemIzmZQY7ybZJQ1w+ITCE/jwudH5p+81B/QCbQy00lHsJ01iae6tHCcH+1sCAdUgj+DKMrRBWIQ==","repository":{"url":"git+https://github.com/teomyth/audiowave.git","type":"git","directory":"packages/react"},"_npmVersion":"10.8.2","description":"React audio visualization component","directories":{},"_nodeVersion":"18.20.8","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0","jsdom":"^26.1.0","vitest":"^2.1.0","@vitest/ui":"^2.1.0","release-it":"^19.0.4","typescript":"^5.8.3","@types/node":"^24.1.0","@types/react":"^19.1.8","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.1.6","@vitest/coverage-v8":"^2.1.0","@vitejs/plugin-react":"^4.7.0","@testing-library/react":"^16.3.0","@testing-library/jest-dom":"^6.6.3","@testing-library/user-event":"^14.6.1"},"peerDependencies":{"react":">=16.8.0","react-dom":">=16.8.0"},"_npmOperationalInternal":{"tmp":"tmp/react_0.2.0_1753530121620_0.8809801758399589","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@audiowave/react","version":"0.2.1","keywords":["react","audio","visualization","waveform","real-time","canvas","web-audio"],"author":{"name":"teomyth","email":"teomyth@gmail.com"},"license":"MIT","_id":"@audiowave/react@0.2.1","maintainers":[{"name":"teomyth","email":"teomyth@gmail.com"}],"homepage":"https://github.com/teomyth/audiowave#readme","bugs":{"url":"https://github.com/teomyth/audiowave/issues"},"dist":{"shasum":"ad274448bb7c2a6d867b03193ff432a7694a6b93","tarball":"https://registry.npmjs.org/@audiowave/react/-/react-0.2.1.tgz","fileCount":28,"integrity":"sha512-MZO4WDlc2mkTQKXfhswuYGuzarcE251M7SAjwx/nRaD6tUtWma1DehAgpd3rtS2HkcEi/+RiUxTQ1Hv2MEX6sg==","signatures":[{"sig":"MEYCIQCSU5GIRbTjj1pN1qLGaz92pygiqV2SL4RCxdJRFnluwwIhAMJKORlT0FVA1wrSPFe5g/E1w0VxglrhGI41WLCdKi6o","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":306834},"main":"dist/index.js","_from":"file:audiowave-react-0.2.1.tgz","types":"dist/index.d.ts","module":"dist/index.esm.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.js"}},"scripts":{"dev":"vite build --watch","test":"vitest --run","build":"vite build","clean":"rm -rf dist","test:ui":"vitest --ui","test:watch":"vitest","type-check":"tsc --noEmit","test:coverage":"vitest --coverage --run"},"_npmUser":{"name":"teomyth","email":"teomyth@gmail.com"},"_resolved":"/tmp/1680291eacde3e9c879c3a0cc6ce8f6f/audiowave-react-0.2.1.tgz","_integrity":"sha512-MZO4WDlc2mkTQKXfhswuYGuzarcE251M7SAjwx/nRaD6tUtWma1DehAgpd3rtS2HkcEi/+RiUxTQ1Hv2MEX6sg==","repository":{"url":"git+https://github.com/teomyth/audiowave.git","type":"git","directory":"packages/react"},"_npmVersion":"10.8.2","description":"React audio visualization component","directories":{},"_nodeVersion":"18.20.8","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0","jsdom":"^26.1.0","vitest":"^2.1.0","@vitest/ui":"^2.1.0","release-it":"^19.0.4","typescript":"^5.8.3","@types/node":"^24.1.0","@types/react":"^19.1.8","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.1.6","@vitest/coverage-v8":"^2.1.0","@vitejs/plugin-react":"^4.7.0","@testing-library/react":"^16.3.0","@testing-library/jest-dom":"^6.6.3","@testing-library/user-event":"^14.6.1"},"peerDependencies":{"react":">=16.8.0","react-dom":">=16.8.0"},"_npmOperationalInternal":{"tmp":"tmp/react_0.2.1_1753539762102_0.08846385819095803","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@audiowave/react","version":"0.3.0","keywords":["react","audio","visualization","waveform","real-time","canvas","web-audio"],"author":{"name":"teomyth","email":"teomyth@gmail.com"},"license":"MIT","_id":"@audiowave/react@0.3.0","maintainers":[{"name":"teomyth","email":"teomyth@gmail.com"}],"homepage":"https://github.com/teomyth/audiowave#readme","bugs":{"url":"https://github.com/teomyth/audiowave/issues"},"dist":{"shasum":"3972a81510f3327e84e32d118334536b8117e5d9","tarball":"https://registry.npmjs.org/@audiowave/react/-/react-0.3.0.tgz","fileCount":28,"integrity":"sha512-1/Jz46K4N616u0ZZR5F8H4oq6R7honyzGaL7TBwaRoWWXz9PiMlNndClUVBkGerGxFWDtB7f3ExK66oLKJu4Aw==","signatures":[{"sig":"MEUCIQC5Q56/OyxIWXSxKz2F9m5cKaHIl1xXLGWWoR/+2GY6dgIgX/C0TtMl7CWvmEUlTezrP899z/tuN5/aS/6lfsrY57s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":324240},"main":"dist/index.js","_from":"file:audiowave-react-0.3.0.tgz","types":"dist/index.d.ts","module":"dist/index.esm.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.js"}},"scripts":{"dev":"vite build --watch","test":"vitest --run","build":"vite build","clean":"rm -rf dist","test:ui":"vitest --ui","test:watch":"vitest","type-check":"tsc --noEmit","test:coverage":"vitest --coverage --run"},"_npmUser":{"name":"teomyth","email":"teomyth@gmail.com"},"_resolved":"/tmp/645770942844766be20b56655fabec24/audiowave-react-0.3.0.tgz","_integrity":"sha512-1/Jz46K4N616u0ZZR5F8H4oq6R7honyzGaL7TBwaRoWWXz9PiMlNndClUVBkGerGxFWDtB7f3ExK66oLKJu4Aw==","repository":{"url":"git+https://github.com/teomyth/audiowave.git","type":"git","directory":"packages/react"},"_npmVersion":"10.8.2","description":"React audio visualization component","directories":{},"_nodeVersion":"18.20.8","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0","jsdom":"^26.1.0","vitest":"^2.1.0","@vitest/ui":"^2.1.0","release-it":"^19.0.4","typescript":"^5.8.3","@types/node":"^24.1.0","@types/react":"^19.1.8","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.1.6","@vitest/coverage-v8":"^2.1.0","@vitejs/plugin-react":"^4.7.0","@testing-library/react":"^16.3.0","@testing-library/jest-dom":"^6.6.3","@testing-library/user-event":"^14.6.1"},"peerDependencies":{"react":">=16.8.0","react-dom":">=16.8.0"},"_npmOperationalInternal":{"tmp":"tmp/react_0.3.0_1753976059336_0.38992379584291914","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@audiowave/react","version":"0.4.0","keywords":["react","audio","visualization","waveform","real-time","canvas","web-audio"],"author":{"name":"teomyth","email":"teomyth@gmail.com"},"license":"MIT","_id":"@audiowave/react@0.4.0","maintainers":[{"name":"teomyth","email":"teomyth@gmail.com"}],"homepage":"https://github.com/teomyth/audiowave#readme","bugs":{"url":"https://github.com/teomyth/audiowave/issues"},"dist":{"shasum":"5f2409864c1f5f54cb9d03bf61ce41391004eeba","tarball":"https://registry.npmjs.org/@audiowave/react/-/react-0.4.0.tgz","fileCount":28,"integrity":"sha512-e46q0k/G5GI7LTUMGLjPppgVjG2WGI2kqFeM7Vdy01XFM5xdjynxRJAfn10S+WqlglU9dxkZFXyLwR4JdsUOSg==","signatures":[{"sig":"MEYCIQC6HUpTd78rF4vZp61zWljz9HyCRuttrbrVWHTAmqBQnAIhAJHRY5aqRKTsdzOEGcXeA7uCfqirXFCoF323/jyiCxdY","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":326827},"main":"dist/index.js","_from":"file:audiowave-react-0.4.0.tgz","types":"dist/index.d.ts","module":"dist/index.esm.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.js"}},"scripts":{"dev":"vite build --watch","test":"vitest --run","build":"vite build","clean":"rm -rf dist","test:ui":"vitest --ui","test:watch":"vitest","type-check":"tsc --noEmit","test:coverage":"vitest --coverage --run"},"_npmUser":{"name":"teomyth","email":"teomyth@gmail.com"},"_resolved":"/tmp/de902f2e765c54ceca79f26471295d32/audiowave-react-0.4.0.tgz","_integrity":"sha512-e46q0k/G5GI7LTUMGLjPppgVjG2WGI2kqFeM7Vdy01XFM5xdjynxRJAfn10S+WqlglU9dxkZFXyLwR4JdsUOSg==","repository":{"url":"git+https://github.com/teomyth/audiowave.git","type":"git","directory":"packages/react"},"_npmVersion":"10.8.2","description":"React audio visualization component","directories":{},"_nodeVersion":"18.20.8","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0","jsdom":"^26.1.0","vitest":"^2.1.0","@vitest/ui":"^2.1.0","release-it":"^19.0.4","typescript":"^5.8.3","@types/node":"^24.1.0","@types/react":"^19.1.8","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.1.6","@vitest/coverage-v8":"^2.1.0","@vitejs/plugin-react":"^4.7.0","@testing-library/react":"^16.3.0","@testing-library/jest-dom":"^6.6.3","@testing-library/user-event":"^14.6.1"},"peerDependencies":{"react":">=16.8.0","react-dom":">=16.8.0"},"_npmOperationalInternal":{"tmp":"tmp/react_0.4.0_1754031826447_0.31619910678288576","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@audiowave/react","version":"0.5.0","keywords":["react","audio","visualization","waveform","real-time","canvas","web-audio"],"author":{"name":"teomyth","email":"teomyth@gmail.com"},"license":"MIT","_id":"@audiowave/react@0.5.0","maintainers":[{"name":"teomyth","email":"teomyth@gmail.com"}],"homepage":"https://github.com/teomyth/audiowave#readme","bugs":{"url":"https://github.com/teomyth/audiowave/issues"},"dist":{"shasum":"ced90c27ac6b634d76ff82b2c0277681706db6e4","tarball":"https://registry.npmjs.org/@audiowave/react/-/react-0.5.0.tgz","fileCount":30,"integrity":"sha512-2GbsCY2UUXhjPQB4UggnR1S/h/TLz7R7wA7JPq1jVdCVSnq/TNpk1AoU35XZo568R6M8yVIioM4IJQ6OwVWIBg==","signatures":[{"sig":"MEQCIHvQSiZuXuwYLeCTRrGmhAzqvm7ybUCAzJ4FGDIblPB0AiBZwD922ReL/lQ+oUFXMJzHr6fIKFAz0sS8cwpFStTFmQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":339162},"main":"dist/index.js","_from":"file:audiowave-react-0.5.0.tgz","types":"dist/index.d.ts","module":"dist/index.esm.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.js"}},"scripts":{"dev":"vite build --watch","test":"vitest --run","build":"vite build","clean":"rm -rf dist","test:ui":"vitest --ui","test:watch":"vitest","type-check":"tsc --noEmit","test:coverage":"vitest --coverage --run"},"_npmUser":{"name":"teomyth","email":"teomyth@gmail.com"},"_resolved":"/tmp/589fa7c2ab630d6ba33f8a0d8bd2845b/audiowave-react-0.5.0.tgz","_integrity":"sha512-2GbsCY2UUXhjPQB4UggnR1S/h/TLz7R7wA7JPq1jVdCVSnq/TNpk1AoU35XZo568R6M8yVIioM4IJQ6OwVWIBg==","repository":{"url":"git+https://github.com/teomyth/audiowave.git","type":"git","directory":"packages/react"},"_npmVersion":"10.8.2","description":"React audio visualization component","directories":{},"_nodeVersion":"18.20.8","dependencies":{"@audiowave/core":"0.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0","jsdom":"^26.1.0","vitest":"^2.1.0","@vitest/ui":"^2.1.0","release-it":"^19.0.4","typescript":"^5.8.3","@types/node":"^24.1.0","@types/react":"^19.1.8","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.1.6","@vitest/coverage-v8":"^2.1.0","@vitejs/plugin-react":"^4.7.0","@testing-library/react":"^16.3.0","@testing-library/jest-dom":"^6.6.3","@testing-library/user-event":"^14.6.1"},"peerDependencies":{"react":">=16.8.0","react-dom":">=16.8.0"},"_npmOperationalInternal":{"tmp":"tmp/react_0.5.0_1754061566089_0.4693130070004865","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@audiowave/react","version":"0.6.0","keywords":["react","audio","visualization","waveform","real-time","canvas","web-audio"],"author":{"name":"teomyth","email":"teomyth@gmail.com"},"license":"MIT","_id":"@audiowave/react@0.6.0","maintainers":[{"name":"teomyth","email":"teomyth@gmail.com"}],"homepage":"https://github.com/teomyth/audiowave#readme","bugs":{"url":"https://github.com/teomyth/audiowave/issues"},"dist":{"shasum":"fbbd93087776939855dc4ae385d364f18e09566e","tarball":"https://registry.npmjs.org/@audiowave/react/-/react-0.6.0.tgz","fileCount":30,"integrity":"sha512-NDZqiNbcxkTgNDWK+L8VDSgdh6+9yWtEbTHtxdqI+KXJ1QI2d5fxfXxrDGNFtCaCGBjq5W2jBu7SJvZuFZOgGQ==","signatures":[{"sig":"MEUCIBrOFnGK8eiyy7aXJWVli4OGMGwN/TnqVijEaeWqQcWKAiEAkAFVbqw0SRI99ui20Lm2A/UJ73iC/ZmktlUsmbaByu8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":345248},"main":"dist/index.js","_from":"file:audiowave-react-0.6.0.tgz","types":"dist/index.d.ts","module":"dist/index.esm.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.js"}},"scripts":{"dev":"vite build --watch","test":"vitest --run","build":"vite build","clean":"rm -rf dist","test:ui":"vitest --ui","test:watch":"vitest","type-check":"tsc --noEmit","test:coverage":"vitest --coverage --run"},"_npmUser":{"name":"teomyth","email":"teomyth@gmail.com"},"_resolved":"/tmp/0cb13c0aee39da04b237cc15bea1542b/audiowave-react-0.6.0.tgz","_integrity":"sha512-NDZqiNbcxkTgNDWK+L8VDSgdh6+9yWtEbTHtxdqI+KXJ1QI2d5fxfXxrDGNFtCaCGBjq5W2jBu7SJvZuFZOgGQ==","repository":{"url":"git+https://github.com/teomyth/audiowave.git","type":"git","directory":"packages/react"},"_npmVersion":"10.8.2","description":"React audio visualization component","directories":{},"_nodeVersion":"18.20.8","dependencies":{"@audiowave/core":"0.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0","jsdom":"^26.1.0","vitest":"^2.1.0","@vitest/ui":"^2.1.0","release-it":"^19.0.4","typescript":"^5.8.3","@types/node":"^24.1.0","@types/react":"^19.1.8","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.1.6","@vitest/coverage-v8":"^2.1.0","@vitejs/plugin-react":"^4.7.0","@testing-library/react":"^16.3.0","@testing-library/jest-dom":"^6.6.3","@testing-library/user-event":"^14.6.1"},"peerDependencies":{"react":">=16.8.0","react-dom":">=16.8.0"},"_npmOperationalInternal":{"tmp":"tmp/react_0.6.0_1754131895619_0.0558653517350427","host":"s3://npm-registry-packages-npm-production"}},"0.6.1":{"name":"@audiowave/react","version":"0.6.1","keywords":["react","audio","visualization","waveform","real-time","canvas","web-audio"],"author":{"name":"teomyth","email":"teomyth@gmail.com"},"license":"MIT","_id":"@audiowave/react@0.6.1","maintainers":[{"name":"teomyth","email":"teomyth@gmail.com"}],"homepage":"https://github.com/teomyth/audiowave#readme","bugs":{"url":"https://github.com/teomyth/audiowave/issues"},"dist":{"shasum":"9f3b2fb65edfd83d0686e4cfe172aa4f71d1029c","tarball":"https://registry.npmjs.org/@audiowave/react/-/react-0.6.1.tgz","fileCount":30,"integrity":"sha512-iM0KAx3Nm4xcZhH++hfBb34Yl5ReZxo9GV9sucgoEfuC0aEmoqS6mC8DKCMPDVVt59Nk+yZDDDYbYZQ3jFMjRw==","signatures":[{"sig":"MEUCIQDExJMpcrLfXZSJL8cWHXKFNPl0hrCNEzE3ioYyuS0SQwIgO/Ln+YaE+OMOPb7A+KvUE7XjShL0rtc6+ohxfBrMlzc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":341883},"main":"dist/index.js","_from":"file:audiowave-react-0.6.1.tgz","types":"dist/index.d.ts","module":"dist/index.esm.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.js"}},"scripts":{"dev":"vite build --watch","test":"vitest --run","build":"vite build","clean":"rm -rf dist","test:ui":"vitest --ui","test:watch":"vitest","type-check":"tsc --noEmit","test:coverage":"vitest --coverage --run"},"_npmUser":{"name":"teomyth","email":"teomyth@gmail.com"},"_resolved":"/tmp/6caae65c260825e0457941eb07a0942d/audiowave-react-0.6.1.tgz","_integrity":"sha512-iM0KAx3Nm4xcZhH++hfBb34Yl5ReZxo9GV9sucgoEfuC0aEmoqS6mC8DKCMPDVVt59Nk+yZDDDYbYZQ3jFMjRw==","repository":{"url":"git+https://github.com/teomyth/audiowave.git","type":"git","directory":"packages/react"},"_npmVersion":"10.8.2","description":"React audio visualization component","directories":{},"_nodeVersion":"18.20.8","dependencies":{"@audiowave/core":"0.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0","jsdom":"^26.1.0","vitest":"^2.1.0","@vitest/ui":"^2.1.0","release-it":"^19.0.4","typescript":"^5.8.3","@types/node":"^24.1.0","@types/react":"^19.1.8","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.1.6","@vitest/coverage-v8":"^2.1.0","@vitejs/plugin-react":"^4.7.0","@testing-library/react":"^16.3.0","@testing-library/jest-dom":"^6.6.3","@testing-library/user-event":"^14.6.1"},"peerDependencies":{"react":">=16.8.0","react-dom":">=16.8.0"},"_npmOperationalInternal":{"tmp":"tmp/react_0.6.1_1754827137601_0.8525486765408361","host":"s3://npm-registry-packages-npm-production"}},"0.6.2":{"name":"@audiowave/react","version":"0.6.2","description":"React audio visualization component","keywords":["react","audio","visualization","waveform","real-time","canvas","web-audio"],"author":{"name":"teomyth","email":"teomyth@gmail.com"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/teomyth/audiowave.git","directory":"packages/react"},"main":"dist/index.js","module":"dist/index.esm.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.js"}},"dependencies":{"@audiowave/core":"0.3.1"},"peerDependencies":{"react":">=16.8.0","react-dom":">=16.8.0"},"devDependencies":{"@testing-library/jest-dom":"^6.9.1","@testing-library/react":"^16.3.0","@testing-library/user-event":"^14.6.1","@types/node":"^24.9.2","@types/react":"^19.2.2","@types/react-dom":"^19.2.2","@vitejs/plugin-react":"^5.1.0","@vitest/coverage-v8":"^4.0.5","@vitest/ui":"^4.0.5","jsdom":"^27.1.0","release-it":"^19.0.5","typescript":"^5.9.3","vite":"^7.1.12","vite-plugin-dts":"^4.5.4","vitest":"^4.0.5"},"scripts":{"build":"vite build","dev":"vite build --watch","clean":"rm -rf dist","type-check":"tsc --noEmit","test":"vitest --run","test:watch":"vitest","test:ui":"vitest --ui","test:coverage":"vitest --coverage --run"},"_id":"@audiowave/react@0.6.2","bugs":{"url":"https://github.com/teomyth/audiowave/issues"},"homepage":"https://github.com/teomyth/audiowave#readme","_integrity":"sha512-hajG2Iv3mVxived9wXad8L0ZQF+HmYnB3IrfOkIdkTv4RxOJDXwFWMAd0zb7ZU1Qz0IEYZXCbASFWyuxEQ7PAw==","_resolved":"/tmp/af434152ecb18653a6f976a7aa66cba8/audiowave-react-0.6.2.tgz","_from":"file:audiowave-react-0.6.2.tgz","_nodeVersion":"22.20.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-hajG2Iv3mVxived9wXad8L0ZQF+HmYnB3IrfOkIdkTv4RxOJDXwFWMAd0zb7ZU1Qz0IEYZXCbASFWyuxEQ7PAw==","shasum":"2940a26c52c69c63beddc88df0418ef6b0ecb701","tarball":"https://registry.npmjs.org/@audiowave/react/-/react-0.6.2.tgz","fileCount":30,"unpackedSize":342056,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDAQtCG/C77pCknYM03wgtFOkyhHrKl+P/wC3GMbUggnQIhAKwO4XZk1Do3/SbnYJK21jWhXURYodr+PK/xT5+D38nD"}]},"_npmUser":{"name":"teomyth","email":"teomyth@gmail.com"},"directories":{},"maintainers":[{"name":"teomyth","email":"teomyth@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react_0.6.2_1761895409463_0.795429287365623"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-26T11:42:01.515Z","modified":"2025-10-31T07:23:29.861Z","0.2.0":"2025-07-26T11:42:01.846Z","0.2.1":"2025-07-26T14:22:42.306Z","0.3.0":"2025-07-31T15:34:19.511Z","0.4.0":"2025-08-01T07:03:46.649Z","0.5.0":"2025-08-01T15:19:26.500Z","0.6.0":"2025-08-02T10:51:35.803Z","0.6.1":"2025-08-10T11:58:57.825Z","0.6.2":"2025-10-31T07:23:29.644Z"},"bugs":{"url":"https://github.com/teomyth/audiowave/issues"},"author":{"name":"teomyth","email":"teomyth@gmail.com"},"license":"MIT","homepage":"https://github.com/teomyth/audiowave#readme","keywords":["react","audio","visualization","waveform","real-time","canvas","web-audio"],"repository":{"type":"git","url":"git+https://github.com/teomyth/audiowave.git","directory":"packages/react"},"description":"React audio visualization component","maintainers":[{"name":"teomyth","email":"teomyth@gmail.com"}],"readme":"# @audiowave/react\n\n**Lightweight React components for real-time audio visualization**\n\n## Inspiration and Key Differences\n\nThis project is inspired by [react-audio-visualizer](https://github.com/Wolfy64/react-audio-visualize) but takes a different, more focused approach:\n\n**What makes us different:**\n- **Visualization only** - No built-in playback or recording functionality\n- **No control buttons** - Pure visualization components without UI controls\n- **Lightweight** - Minimal bundle size with focused feature set\n- **Easy integration** - Drop into existing audio applications without conflicts\n- **Flexible** - Works with any audio source you provide\n\n**Perfect for these scenarios:**\n- **Existing audio apps** - Add visualization to apps that already handle audio\n- **Recording software** - Visualize microphone input without audio conflicts\n- **Music players** - Add waveforms to audio/video playback\n- **Custom audio workflows** - Integrate with any audio source or processing pipeline\n- **Lightweight projects** - Minimal bundle size when you only need visualization\n\n## Installation\n\n```bash\nnpm install @audiowave/react\n```\n\n## Quick Start\n\n**Basic usage with microphone input:**\n\n```tsx\nimport { AudioWave, useMediaAudio } from '@audiowave/react';\nimport { useRef, useState, useMemo, useCallback } from 'react';\n\nexport default function App() {\n  const [mediaStream, setMediaStream] = useState<MediaStream | null>(null);\n  const [isRecording, setIsRecording] = useState(false);\n\n  // AudioWave handles visualization, you control the audio source\n  // Note: For dynamic audio sources, memoize the options object (see Important Usage Notes)\n  const handleError = useCallback((error: Error) => {\n    console.error('Audio error:', error);\n  }, []);\n\n  const audioOptions = useMemo(() => ({\n    source: mediaStream,\n    onError: handleError,\n  }), [mediaStream, handleError]);\n\n  const { source, error } = useMediaAudio(audioOptions);\n  const audioWaveRef = useRef<AudioWaveController>(null);\n\n  const startRecording = async () => {\n    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n    setMediaStream(stream);\n    setIsRecording(true);\n  };\n\n  const stopRecording = () => {\n    mediaStream?.getTracks().forEach(track => track.stop());\n    setMediaStream(null);\n    setIsRecording(false);\n  };\n\n  return (\n    <div>\n      {error && <div>Error: {error.message}</div>}\n      <AudioWave ref={audioWaveRef} source={source} height={100} />\n\n      {/* You provide the controls - AudioWave just visualizes */}\n      <button onClick={isRecording ? stopRecording : startRecording}>\n        {isRecording ? 'Stop Recording' : 'Start Recording'}\n      </button>\n\n      {/* Optional: Control visualization display */}\n      <button onClick={() => audioWaveRef.current?.pause()}>Pause Waveform</button>\n      <button onClick={() => audioWaveRef.current?.resume()}>Resume Waveform</button>\n      <button onClick={() => audioWaveRef.current?.clear()}>Clear Waveform</button>\n    </div>\n  );\n}\n```\n\n**Works with any audio source:**\n\n```tsx\n// With audio file\nconst audioElement = useRef<HTMLAudioElement>(null);\nconst { source } = useAudioSource({ source: audioElement.current });\n\n// With video file\nconst videoElement = useRef<HTMLVideoElement>(null);\nconst { source } = useAudioSource({ source: videoElement.current });\n\n// With Web Audio API nodes\nconst { source } = useAudioSource({ source: audioNode });\n\n// With custom audio data (Electron, Node.js, etc.)\nconst { source } = useCustomAudio();\n```\n\n## API Reference\n\n### AudioWave Component\n\nThe main visualization component - pure display, no audio control.\n\n```tsx\n<AudioWave\n  // === AUDIO SOURCE ===\n  source={source}            // AudioSource from useAudioSource\n\n  // === DIMENSIONS ===\n  width=\"100%\"               // Component width (string | number)\n  height={200}               // Component height in pixels\n\n  // === VISUAL STYLING ===\n  backgroundColor=\"transparent\" // Background color\n  barColor=\"#ffffff\"         // Primary bar color\n  secondaryBarColor=\"#5e5e5e\" // Secondary/inactive bar color\n  barWidth={2}               // Width of each frequency bar\n  gap={1}                    // Gap between bars in pixels\n  rounded={0}                // Border radius for rounded bars\n\n  // === BORDER STYLING ===\n  showBorder={false}         // Show border around visualization\n  borderColor=\"#333333\"      // Border color\n  borderWidth={1}            // Border width in pixels\n  borderRadius={0}           // Border radius for rounded corners\n\n  // === AMPLITUDE CALCULATION ===\n  amplitudeMode=\"peak\"       // Amplitude calculation: 'peak' | 'rms' | 'adaptive'\n\n  // === ANIMATION & RENDERING ===\n  speed={3}                  // Animation speed (1-6, higher = slower)\n  animateCurrentPick={true}  // Enable smooth bar transitions\n  fullscreen={false}         // Fill entire parent container\n  onlyActive={false}         // Show visualization only when active\n  gain={1.0}                 // Audio gain multiplier (0.1-10.0, default: 1.0)\n\n  // === STATE CONTROL ===\n  isPaused={false}           // Pause visualization (freeze display)\n\n  // === ADVANCED CUSTOMIZATION ===\n  customRenderer={(context) => {\n    // Custom rendering function for advanced visualizations\n    // context: { canvas, audioData, width, height, ... }\n  }}\n\n  // === PLACEHOLDER CONTENT ===\n  placeholder={<div>No audio source</div>} // Custom placeholder content\n  showPlaceholderBackground={true}         // Show background in placeholder state\n\n  // === CSS CLASSES ===\n  className=\"my-waveform\"    // CSS class for main container\n  canvasClassName=\"my-canvas\" // CSS class for canvas element\n\n  // === CALLBACKS ===\n  onStateChange={(state) => console.log('State:', state)} // State change callback\n  onRenderStart={() => console.log('Rendering started')}  // Render start callback\n  onRenderStop={() => console.log('Rendering stopped')}   // Render stop callback\n  onError={(error) => console.error('Error:', error)}     // Error callback\n/>\n```\n\n#### Essential Props\n\n**Audio Source:**\n- `source` - AudioSource from `useMediaAudio` or `useCustomAudio` hook (required for visualization)\n\n**Dimensions:**\n- `width` - Component width, supports CSS units and numbers (default: `\"100%\"`)\n- `height` - Component height in pixels (default: `200`)\n\n**Visual Styling:**\n- `backgroundColor` - Background color (default: `\"transparent\"`)\n- `barColor` - Primary color for active audio bars (default: `\"#ffffff\"`)\n- `secondaryBarColor` - Color for inactive/past bars (default: `\"#5e5e5e\"`)\n- `barWidth` - Width of each frequency bar in pixels (default: `2`)\n- `gap` - Gap between bars in pixels (default: `1`)\n- `rounded` - Border radius for rounded bars (default: `0`)\n\n#### Advanced Props\n\n**Border Styling:**\n- `showBorder` - Show border around visualization area (default: `false`)\n- `borderColor` - Border color (default: `\"#333333\"`)\n- `borderWidth` - Border width in pixels (default: `1`)\n- `borderRadius` - Border radius for rounded corners (default: `0`)\n\n**Animation & Rendering:**\n- `speed` - Animation speed from 1-6, higher numbers are slower (default: `3`)\n- `animateCurrentPick` - Enable smooth bar transitions (default: `true`)\n- `fullscreen` - Fill entire parent container (default: `false`)\n- `onlyActive` - Show visualization only when audio is active (default: `false`)\n\n**State Control:**\n- `isPaused` - Pause visualization display without affecting audio (default: `false`)\n\n**Advanced Customization:**\n- `customRenderer` - Custom rendering function for advanced visualizations\n- `placeholder` - Custom React component to show when no audio source\n- `showPlaceholderBackground` - Whether to show background in placeholder state\n\n**CSS Classes:**\n- `className` - CSS class for the main container\n- `canvasClassName` - CSS class for the canvas element\n\n**Event Callbacks:**\n- `onStateChange` - Called when visualization state changes\n- `onRenderStart` - Called when rendering starts\n- `onRenderStop` - Called when rendering stops\n- `onError` - Called on render errors\n\n### useMediaAudio Hook (Recommended)\n\nConverts media sources into visualization data. This is the main hook for most use cases.\n\n```tsx\nconst { source, error } = useMediaAudio({\n  source: mediaStream  // MediaStream | HTMLAudioElement | HTMLVideoElement | AudioNode\n});\n```\n\n> **⚠️ Important:** When using lazy-loaded audio sources (starting as `null`), you must memoize the options object to prevent flickering. See [Important Usage Notes](#important-usage-notes) for details.\n\n**Supported Sources:**\n- `MediaStream` - Microphone, recording software\n- `HTMLAudioElement` - Audio files\n- `HTMLVideoElement` - Video files\n- `AudioNode` - Web Audio API nodes\n\n**Returns:**\n- `source` - AudioSource instance for AudioWave component\n- `error` - Any processing errors (Error | null)\n\n### useAudioSource Hook (Legacy)\n\n> **Note:** `useAudioSource` is an alias for `useMediaAudio` maintained for backward compatibility. New projects should use `useMediaAudio`.\n\n### Specialized Hooks\n\nFor better type safety and convenience, you can use specialized hooks:\n\n```tsx\n// For microphone or recording software\nconst { source, error } = useMediaStreamSource(mediaStream);\n\n// For audio/video files\nconst { source, error } = useMediaElementSource(audioElement);\n\n// For Web Audio API nodes\nconst { source, error } = useAudioNodeSource(audioNode);\n\n// For custom audio data (Electron, Node.js, etc.)\nconst { source } = useCustomAudio({ provider: myProvider });\n```\n\n### useCustomAudio Hook\n\nFor advanced use cases where you need to provide custom audio data (Electron apps, Node.js audio processing, custom audio pipelines), use the `useCustomAudio` hook with a custom provider:\n\n```tsx\nimport { useCustomAudio } from '@audiowave/react';\nimport { useMemo } from 'react';\n\nfunction CustomAudioApp() {\n  // Create audio data provider\n  const audioProvider = useMemo(() => ({\n    onAudioData: (callback: (data: Uint8Array) => void) => {\n      // Your audio data subscription logic\n      const unsubscribe = yourAudioSource.subscribe(callback);\n      return unsubscribe; // Return cleanup function\n    },\n    onAudioError: (callback: (error: string) => void) => {\n      // Optional error handling\n      const unsubscribe = yourAudioSource.onError(callback);\n      return unsubscribe;\n    }\n  }), []);\n\n  const { source, error } = useCustomAudio({\n    provider: audioProvider,\n    deviceId: 'default'\n  });\n\n  return (\n    <div>\n      {error && <div>Error: {error}</div>}\n      <AudioWave source={source} height={120} />\n    </div>\n  );\n}\n```\n\n**Parameters:**\n- `provider` - AudioDataProvider implementation (required)\n- `deviceId` - Device identifier (optional, default: 'default')\n\n**Returns:**\n- `source` - AudioSource instance for AudioWave component\n- `status` - Current status: 'idle' | 'active' | 'paused'\n- `error` - Error message if any\n- `isActive` - Boolean indicating if audio is active\n- `clearError` - Function to clear error state\n\n**Audio Data Format:**\n- `Uint8Array` with values in range [0, 255]\n- 128 represents silence (center value)\n- Values above 128 represent positive amplitude\n- Values below 128 represent negative amplitude\n- Array length should match your desired visualization resolution\n\n## Electron Integration Guide\n\nFor Electron applications, use `useCustomAudio` with a custom provider for native audio processing:\n\n### Best Practice: Main Process Audio Processing\n\nProcess audio in the main process for optimal performance:\n\n**Main Process (`main.js`):**\n\n```typescript\nimport { AudioProcessor } from '@audiowave/core';\nimport { ipcMain } from 'electron';\n\nclass ElectronAudioCapture {\n  private audioProcessor: AudioProcessor;\n\n  constructor() {\n    this.audioProcessor = new AudioProcessor({\n      bufferSize: 1024,\n      skipInitialFrames: 2,\n      inputBitsPerSample: 32,  // naudiodon uses 32-bit\n      inputChannels: 2,        // stereo input\n    });\n\n    this.setupAudioCapture();\n  }\n\n  private setupAudioCapture() {\n    // Setup your audio capture (naudiodon, etc.)\n    audioCapture.on('data', (buffer: Buffer) => {\n      // Process audio in main process\n      const result = this.audioProcessor.process(buffer);\n\n      if (result) {\n        // Send processed data to renderer\n        mainWindow.webContents.send('audio-data', result.timeDomainData);\n      }\n    });\n  }\n}\n\n// IPC handlers\nipcMain.handle('start-audio-capture', async () => {\n  // Start audio capture logic\n});\n\nipcMain.handle('stop-audio-capture', async () => {\n  // Stop audio capture logic\n});\n```\n\n**Renderer Process (`renderer.tsx`):**\n\n```tsx\nimport { useCustomAudio } from '@audiowave/react';\nimport { useMemo } from 'react';\n\nfunction ElectronAudioApp() {\n  // Create provider for Electron IPC communication\n  const electronProvider = useMemo(() => ({\n    onAudioData: (callback: (data: Uint8Array) => void) => {\n      const handleAudioData = (_event: any, audioData: Uint8Array) => {\n        callback(audioData);\n      };\n\n      window.electronAPI.onAudioData(handleAudioData);\n\n      return () => {\n        window.electronAPI.removeAudioDataListener?.(handleAudioData);\n      };\n    },\n    onAudioError: (callback: (error: string) => void) => {\n      const handleError = (_event: any, error: string) => {\n        callback(error);\n      };\n\n      window.electronAPI.onAudioError?.(handleError);\n\n      return () => {\n        window.electronAPI.removeAudioErrorListener?.(handleError);\n      };\n    }\n  }), []);\n\n  const { source, error } = useCustomAudio({\n    provider: electronProvider,\n    deviceId: 'default'\n  });\n\n  const startCapture = () => {\n    window.electronAPI.startAudioCapture();\n  };\n\n  const stopCapture = () => {\n    window.electronAPI.stopAudioCapture();\n  };\n\n  return (\n    <div>\n      {error && <div>Error: {error}</div>}\n      <AudioWave source={source} height={120} />\n      <button onClick={startCapture}>Start</button>\n      <button onClick={stopCapture}>Stop</button>\n    </div>\n  );\n}\n```\n\n**Preload Script (`preload.js`):**\n\n```typescript\nimport { contextBridge, ipcRenderer } from 'electron';\n\ncontextBridge.exposeInMainWorld('electronAPI', {\n  startAudioCapture: () => ipcRenderer.invoke('start-audio-capture'),\n  stopAudioCapture: () => ipcRenderer.invoke('stop-audio-capture'),\n  onAudioData: (callback: (event: any, data: Uint8Array) => void) => {\n    ipcRenderer.on('audio-data', callback);\n  },\n  onAudioError: (callback: (event: any, error: string) => void) => {\n    ipcRenderer.on('audio-error', callback);\n  },\n  removeAudioDataListener: (callback: Function) => {\n    ipcRenderer.removeListener('audio-data', callback);\n  },\n  removeAudioErrorListener: (callback: Function) => {\n    ipcRenderer.removeListener('audio-error', callback);\n  }\n});\n```\n\n**Benefits of this approach:**\n- Optimal performance with minimal data transfer\n- UI responsiveness maintained\n- Single processing instance for multiple windows\n\n## Visualization Control\n\nAudioWave provides simple controls for the visualization display (not the audio itself):\n\n### Using Ref (Imperative)\n\n```tsx\nconst audioWaveRef = useRef<AudioWaveController>(null);\n\n// Basic visualization controls\naudioWaveRef.current?.pause();  // Freeze display\naudioWaveRef.current?.resume(); // Resume display\naudioWaveRef.current?.clear();  // Clear waveform data\n\n// State inspection methods\nconst isPaused = audioWaveRef.current?.isPaused(); // Check if paused\nconst state = audioWaveRef.current?.getState();    // Get current state: 'idle' | 'visualizing' | 'paused'\nconst audioData = audioWaveRef.current?.getAudioData(); // Get current audio data (Uint8Array)\n```\n\n#### AudioWaveController Methods\n\n**Control Methods:**\n- `pause()` - Pause visualization (freeze waveform display)\n- `resume()` - Resume visualization from paused state\n- `clear()` - Clear all waveform data and reset display\n\n**State Methods:**\n- `isPaused()` - Returns boolean indicating if visualization is paused\n- `getState()` - Returns current state: `'idle'` | `'visualizing'` | `'paused'`\n- `getAudioData()` - Returns current audio data as Uint8Array\n\n### Using Props (Declarative)\n\n```tsx\nconst [isPaused, setIsPaused] = useState(false);\n\n<AudioWave\n  source={source}\n  isPaused={isPaused}  // Control via props\n/>\n```\n\n**Important:** These controls only affect the visualization display, not your audio source.\n\n## Amplitude Calculation Modes\n\nAudioWave supports three different amplitude calculation methods for different visualization needs:\n\n### Peak Mode (Default)\n\n```tsx\n<AudioWave source={source} amplitudeMode=\"peak\" />\n```\n\n- **Best for**: General-purpose visualization, music, dynamic content\n- **Behavior**: Uses peak amplitude values from frequency data\n- **Characteristics**: High responsiveness, shows all audio peaks clearly\n- **Backward compatible**: Default mode, maintains existing behavior\n\n### RMS Mode (Perceptual Loudness)\n\n```tsx\n<AudioWave source={source} amplitudeMode=\"rms\" />\n```\n\n- **Best for**: Voice analysis, broadcast audio, perceptual loudness matching\n- **Behavior**: Root Mean Square calculation represents how humans perceive loudness\n- **Characteristics**: Smoother visualization, better represents perceived volume\n- **Quiet environments**: Enhanced with smooth noise floor transition\n  - Range 1-9: Quiet signals with exponential scaling\n  - Range 10+: Audible signals with logarithmic scaling\n  - Natural baseline (1) represents environmental noise floor\n\n### Adaptive Mode (Dynamic Scaling)\n\n```tsx\n<AudioWave source={source} amplitudeMode=\"adaptive\" />\n```\n\n- **Best for**: Varying audio levels, automatic gain adjustment, mixed content\n- **Behavior**: Dynamically adjusts scaling based on recent audio levels\n- **Characteristics**: Automatically compensates for quiet or loud audio sources\n- **Use case**: When audio levels vary significantly or are unpredictable\n\n### Mode Switching Example\n\n```tsx\nimport { useState } from 'react';\nimport { AudioWave, useAudioSource } from '@audiowave/react';\n\nfunction AmplitudeModeDemo() {\n  const [mediaStream, setMediaStream] = useState<MediaStream | null>(null);\n  const [amplitudeMode, setAmplitudeMode] = useState<'peak' | 'rms' | 'adaptive'>('peak');\n\n  const { source } = useAudioSource({ source: mediaStream });\n\n  return (\n    <div>\n      <AudioWave\n        source={source}\n        amplitudeMode={amplitudeMode}\n        height={120}\n        barWidth={2}\n        gap={1}\n      />\n\n      <div>\n        <label>Amplitude Mode:</label>\n        <select\n          value={amplitudeMode}\n          onChange={(e) => setAmplitudeMode(e.target.value as any)}\n        >\n          <option value=\"peak\">Peak (Default)</option>\n          <option value=\"rms\">RMS (Perceptual)</option>\n          <option value=\"adaptive\">Adaptive (Auto-scaling)</option>\n        </select>\n      </div>\n    </div>\n  );\n}\n```\n\n## Best Practices\n\n### Error Handling\n\n```tsx\nconst { source, error } = useAudioSource({ source: mediaStream });\n\nif (error) {\n  return <div>Visualization error: {error.message}</div>;\n}\n```\n\n### Important Usage Notes\n\n#### Lazy Loading Audio Sources (Required for Proper Functionality)\n\nWhen your audio source starts as `null` and is set later (common in user-initiated scenarios), you **must** memoize the `useAudioSource` options. Without this, the visualization will flicker and restart continuously, making it unusable:\n\n**❌ WRONG - This will cause flickering:**\n\n```tsx\nfunction MyAudioApp() {\n  const [mediaStream, setMediaStream] = useState<MediaStream | null>(null);\n\n  // This creates a new options object on every render!\n  const { source } = useMediaAudio({\n    source: mediaStream,\n    onError: (error) => console.error('Audio error:', error)\n  });\n\n  // ... rest of component\n}\n```\n\n**✅ CORRECT - Memoize the options object:**\n\n```tsx\nfunction MyAudioApp() {\n  const [mediaStream, setMediaStream] = useState<MediaStream | null>(null);\n\n  // Step 1: Memoize the onError callback\n  const handleAudioError = useCallback((error: Error) => {\n    console.error('Audio error:', error);\n  }, []);\n\n  // Step 2: Memoize the entire options object\n  const audioSourceOptions = useMemo(() => ({\n    source: mediaStream,\n    onError: handleAudioError,\n  }), [mediaStream, handleAudioError]);\n\n  // Step 3: Use the memoized options\n  const { source } = useMediaAudio(audioSourceOptions);\n\n  const startRecording = async () => {\n    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n    setMediaStream(stream); // This triggers re-render with new source\n  };\n\n  return (\n    <div>\n      <button onClick={startRecording}>Start Recording</button>\n      <AudioWave source={source} />\n    </div>\n  );\n}\n```\n\n**Why is this required?**\n- Each render creates a new options object `{ source: mediaStream, onError: ... }`\n- `useMediaAudio` sees this as a \"change\" and reinitializes the audio processing\n- This causes the visualization to flicker and restart repeatedly, making it unusable\n- This is not a performance issue - it's a functional requirement for proper operation\n\n**Quick Reference - Copy this pattern:**\n\n```tsx\n// Always use this pattern for lazy-loaded audio sources\nconst handleError = useCallback((error: Error) => {\n  console.error('Audio error:', error);\n}, []);\n\nconst options = useMemo(() => ({\n  source: yourAudioSource, // MediaStream | HTMLAudioElement | etc.\n  onError: handleError,\n}), [yourAudioSource, handleError]);\n\nconst { source } = useMediaAudio(options);\n```\n\n### Performance Optimization\n\n#### Memoizing Component Props\n\n```tsx\n// Memoize AudioWave props for better performance\nconst audioWaveProps = useMemo(() => ({\n  source,\n  height: 200,\n  barWidth: 2,\n  gap: 1,\n  backgroundColor: 'transparent',\n  barColor: '#ffffff'\n}), [source]);\n\nreturn <AudioWave {...audioWaveProps} />;\n```\n\n### Responsive Design\n\n```tsx\n<AudioWave\n  source={source}\n  width=\"100%\"\n  height={window.innerWidth < 768 ? 80 : 120}\n  style={{ maxWidth: '100%' }}\n/>\n```\n\n## TypeScript Support\n\nFull TypeScript support with comprehensive types:\n\n```tsx\nimport type {\n  AudioWaveProps,\n  AudioWaveController,\n  AudioSource,\n  UseAudioSourceOptions\n} from '@audiowave/react';\n```\n\n## Browser Support\n\n- Chrome 66+ (March 2018)\n- Firefox 60+ (May 2018)\n- Safari 14+ (September 2020)\n- Edge 79+ (January 2020)\n\nRequires Web Audio API and MediaStream API support.\n\n## License\n\nMIT © [teomyth](https://github.com/teomyth)\n","readmeFilename":"README.md"}