[{"data":1,"prerenderedAt":869},["ShallowReactive",2],{"navigation_docs":3,"-vue-nuxt":104,"-vue-nuxt-surround":864},[4,46,67,91],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":45},"Guide","i-lucide-book-open","\u002Fguide","1.guide",[10,15,20,25,30,35,40],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fguide\u002Fintroduction","1.guide\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"How it works","\u002Fguide\u002Fhow-it-works","1.guide\u002F2.how-it-works","i-lucide-workflow",{"title":21,"path":22,"stem":23,"icon":24},"Data modes","\u002Fguide\u002Fdata-modes","1.guide\u002F3.data-modes","i-lucide-git-fork",{"title":26,"path":27,"stem":28,"icon":29},"Options","\u002Fguide\u002Foptions","1.guide\u002F4.options","i-lucide-settings-2",{"title":31,"path":32,"stem":33,"icon":34},"Gradients","\u002Fguide\u002Fgradients","1.guide\u002F5.gradients","i-lucide-palette",{"title":36,"path":37,"stem":38,"icon":39},"WebSocket protocol","\u002Fguide\u002Fwebsocket-protocol","1.guide\u002F6.websocket-protocol","i-lucide-radio",{"title":41,"path":42,"stem":43,"icon":44},"AI tools","\u002Fguide\u002Fai-tools","1.guide\u002F7.ai-tools","i-lucide-bot",false,{"title":47,"icon":48,"path":49,"stem":50,"children":51,"page":45},"Core","i-lucide-box","\u002Fcore","2.core",[52,57,62],{"title":53,"path":54,"stem":55,"icon":56},"Installation","\u002Fcore\u002Finstallation","2.core\u002F1.installation","i-lucide-download",{"title":58,"path":59,"stem":60,"icon":61},"API reference","\u002Fcore\u002Fapi","2.core\u002F2.api","i-lucide-code",{"title":63,"path":64,"stem":65,"icon":66},"Audio engines","\u002Fcore\u002Faudio-engines","2.core\u002F3.audio-engines","i-lucide-audio-lines",{"title":68,"icon":69,"path":70,"stem":71,"children":72,"page":45},"Vue","i-simple-icons-vuedotjs","\u002Fvue","3.vue",[73,76,81,86],{"title":53,"path":74,"stem":75,"icon":56},"\u002Fvue\u002Finstallation","3.vue\u002F1.installation",{"title":77,"path":78,"stem":79,"icon":80},"Props, events & methods","\u002Fvue\u002Fprops","3.vue\u002F2.props","i-lucide-sliders-horizontal",{"title":82,"path":83,"stem":84,"icon":85},"Composables","\u002Fvue\u002Fcomposables","3.vue\u002F3.composables","i-lucide-plug",{"title":87,"path":88,"stem":89,"icon":90},"Nuxt","\u002Fvue\u002Fnuxt","3.vue\u002F4.nuxt","i-simple-icons-nuxtdotjs",{"title":92,"icon":93,"path":94,"stem":95,"children":96,"page":45},"React","i-simple-icons-react","\u002Freact","4.react",[97,100],{"title":53,"path":98,"stem":99,"icon":56},"\u002Freact\u002Finstallation","4.react\u002F1.installation",{"title":101,"path":102,"stem":103,"icon":80},"Props, callbacks & ref","\u002Freact\u002Fprops","4.react\u002F2.props",{"id":105,"title":87,"body":106,"description":857,"extension":858,"links":859,"meta":860,"navigation":861,"path":88,"seo":862,"stem":89,"__hash__":863},"docs\u002F3.vue\u002F4.nuxt.md",{"type":107,"value":108,"toc":851},"minimark",[109,140,149,154,179,186,250,254,508,514,526,530,539,580,590,594,609,828,848],[110,111,112,113,117,118,121,122,125,126,129,130,139],"p",{},"The Vue component works in Nuxt with no module and no plugin. It is SSR-safe — every\nbrowser API it touches (",[114,115,116],"code",{},"window",", ",[114,119,120],{},"navigator",", WebGL, ",[114,123,124],{},"AudioContext",") is behind ",[114,127,128],{},"onMounted","\n— so importing it never breaks a server render. But it draws nothing on the server, so it\nbelongs inside ",[131,132,136],"a",{"href":133,"rel":134},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002Fapi\u002Fcomponents\u002Fclient-only",[135],"nofollow",[114,137,138],{},"\u003CClientOnly>",".",[110,141,142,143,148],{},"Prefer to see it running first? The ",[131,144,147],{"href":145,"rel":146},"https:\u002F\u002Fdemo.fftvisualizer.com\u002Fnuxt\u002F",[135],"Nuxt playground","\nis this exact setup on a prerendered page.",[150,151,153],"h2",{"id":152},"install","Install",[155,156,162],"pre",{"className":157,"code":158,"filename":159,"language":160,"meta":161,"style":161},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add @fft-visualizer\u002Fvue\n","pnpm","bash","",[114,163,164],{"__ignoreMap":161},[165,166,169,172,176],"span",{"class":167,"line":168},"line",1,[165,170,159],{"class":171},"sBMFI",[165,173,175],{"class":174},"sfazB"," add",[165,177,178],{"class":174}," @fft-visualizer\u002Fvue\n",[110,180,181,182,185],{},"Then register the stylesheet in ",[114,183,184],{},"nuxt.config.ts"," — it sizes the canvas and styles the stats\noverlay, and the component renders unstyled without it:",[155,187,191],{"className":188,"code":189,"filename":184,"language":190,"meta":161,"style":161},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default defineNuxtConfig({\n  css: ['@fft-visualizer\u002Fvue\u002Fstyle.css'],\n})\n","ts",[114,192,193,214,241],{"__ignoreMap":161},[165,194,195,199,202,206,210],{"class":167,"line":168},[165,196,198],{"class":197},"s7zQu","export",[165,200,201],{"class":197}," default",[165,203,205],{"class":204},"s2Zo4"," defineNuxtConfig",[165,207,209],{"class":208},"sTEyZ","(",[165,211,213],{"class":212},"sMK4o","{\n",[165,215,217,221,224,227,230,233,235,238],{"class":167,"line":216},2,[165,218,220],{"class":219},"swJcz","  css",[165,222,223],{"class":212},":",[165,225,226],{"class":208}," [",[165,228,229],{"class":212},"'",[165,231,232],{"class":174},"@fft-visualizer\u002Fvue\u002Fstyle.css",[165,234,229],{"class":212},[165,236,237],{"class":208},"]",[165,239,240],{"class":212},",\n",[165,242,244,247],{"class":167,"line":243},3,[165,245,246],{"class":212},"}",[165,248,249],{"class":208},")\n",[150,251,253],{"id":252},"quick-start","Quick start",[155,255,260],{"className":256,"code":257,"filename":258,"language":259,"meta":161,"style":161},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cscript setup>\nimport { FFTVisualizer } from '@fft-visualizer\u002Fvue'\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv class=\"viz\">\n    \u003CClientOnly>\n      \u003CFFTVisualizer mode=\"local\" :bands=\"40\" gradient=\"aurora\" \u002F>\n    \u003C\u002FClientOnly>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cstyle>\n\u002F* The component fills its container — give it a height *\u002F\n.viz { width: 100%; height: 240px; }\n\u003C\u002Fstyle>\n","app.vue","vue",[114,261,262,277,303,312,319,329,354,365,413,423,433,442,447,457,464,499],{"__ignoreMap":161},[165,263,264,267,270,274],{"class":167,"line":168},[165,265,266],{"class":212},"\u003C",[165,268,269],{"class":219},"script",[165,271,273],{"class":272},"spNyl"," setup",[165,275,276],{"class":212},">\n",[165,278,279,282,285,288,291,294,297,300],{"class":167,"line":216},[165,280,281],{"class":197},"import",[165,283,284],{"class":212}," {",[165,286,287],{"class":208}," FFTVisualizer",[165,289,290],{"class":212}," }",[165,292,293],{"class":197}," from",[165,295,296],{"class":212}," '",[165,298,299],{"class":174},"@fft-visualizer\u002Fvue",[165,301,302],{"class":212},"'\n",[165,304,305,308,310],{"class":167,"line":243},[165,306,307],{"class":212},"\u003C\u002F",[165,309,269],{"class":219},[165,311,276],{"class":212},[165,313,315],{"class":167,"line":314},4,[165,316,318],{"emptyLinePlaceholder":317},true,"\n",[165,320,322,324,327],{"class":167,"line":321},5,[165,323,266],{"class":212},[165,325,326],{"class":219},"template",[165,328,276],{"class":212},[165,330,332,335,338,341,344,347,350,352],{"class":167,"line":331},6,[165,333,334],{"class":212},"  \u003C",[165,336,337],{"class":219},"div",[165,339,340],{"class":272}," class",[165,342,343],{"class":212},"=",[165,345,346],{"class":212},"\"",[165,348,349],{"class":174},"viz",[165,351,346],{"class":212},[165,353,276],{"class":212},[165,355,357,360,363],{"class":167,"line":356},7,[165,358,359],{"class":212},"    \u003C",[165,361,362],{"class":219},"ClientOnly",[165,364,276],{"class":212},[165,366,368,371,374,377,379,381,384,386,389,391,393,396,398,401,403,405,408,410],{"class":167,"line":367},8,[165,369,370],{"class":212},"      \u003C",[165,372,373],{"class":219},"FFTVisualizer",[165,375,376],{"class":272}," mode",[165,378,343],{"class":212},[165,380,346],{"class":212},[165,382,383],{"class":174},"local",[165,385,346],{"class":212},[165,387,388],{"class":272}," :bands",[165,390,343],{"class":212},[165,392,346],{"class":212},[165,394,395],{"class":174},"40",[165,397,346],{"class":212},[165,399,400],{"class":272}," gradient",[165,402,343],{"class":212},[165,404,346],{"class":212},[165,406,407],{"class":174},"aurora",[165,409,346],{"class":212},[165,411,412],{"class":212}," \u002F>\n",[165,414,416,419,421],{"class":167,"line":415},9,[165,417,418],{"class":212},"    \u003C\u002F",[165,420,362],{"class":219},[165,422,276],{"class":212},[165,424,426,429,431],{"class":167,"line":425},10,[165,427,428],{"class":212},"  \u003C\u002F",[165,430,337],{"class":219},[165,432,276],{"class":212},[165,434,436,438,440],{"class":167,"line":435},11,[165,437,307],{"class":212},[165,439,326],{"class":219},[165,441,276],{"class":212},[165,443,445],{"class":167,"line":444},12,[165,446,318],{"emptyLinePlaceholder":317},[165,448,450,452,455],{"class":167,"line":449},13,[165,451,266],{"class":212},[165,453,454],{"class":219},"style",[165,456,276],{"class":212},[165,458,460],{"class":167,"line":459},14,[165,461,463],{"class":462},"sHwdD","\u002F* The component fills its container — give it a height *\u002F\n",[165,465,467,469,471,473,477,479,483,486,489,491,494,496],{"class":167,"line":466},15,[165,468,139],{"class":212},[165,470,349],{"class":171},[165,472,284],{"class":212},[165,474,476],{"class":475},"sqsOY"," width",[165,478,223],{"class":212},[165,480,482],{"class":481},"sbssI"," 100%",[165,484,485],{"class":212},";",[165,487,488],{"class":475}," height",[165,490,223],{"class":212},[165,492,493],{"class":481}," 240px",[165,495,485],{"class":212},[165,497,498],{"class":212}," }\n",[165,500,502,504,506],{"class":167,"line":501},16,[165,503,307],{"class":212},[165,505,454],{"class":219},[165,507,276],{"class":212},[110,509,510,513],{},[114,511,512],{},"mode=\"local\""," captures the microphone and computes the FFT in the browser, so this needs no\nbackend. The browser prompts for permission on mount.",[515,516,517,518,522,523,525],"note",{},"Give the wrapper a height ",[519,520,521],"em",{},"outside"," ",[114,524,138],{},", as above. If the sized element only\nexists after hydration, the page reflows the moment the visualizer appears.",[150,527,529],{"id":528},"avoiding-layout-shift","Avoiding layout shift",[110,531,532,534,535,538],{},[114,533,138],{}," renders nothing on the server, which leaves a gap until hydration. Its\n",[114,536,537],{},"#fallback"," slot fills that gap with server-rendered markup:",[155,540,542],{"className":256,"code":541,"language":259,"meta":161,"style":161},"\u003CClientOnly>\n  \u003CFFTVisualizer mode=\"local\" :bands=\"40\" \u002F>\n  \u003Ctemplate #fallback>\n    \u003Cdiv class=\"viz-placeholder\" \u002F>\n  \u003C\u002Ftemplate>\n\u003C\u002FClientOnly>\n",[114,543,544,552,557,562,567,572],{"__ignoreMap":161},[165,545,546,548,550],{"class":167,"line":168},[165,547,266],{"class":212},[165,549,362],{"class":219},[165,551,276],{"class":212},[165,553,554],{"class":167,"line":216},[165,555,556],{"class":208},"  \u003CFFTVisualizer mode=\"local\" :bands=\"40\" \u002F>\n",[165,558,559],{"class":167,"line":243},[165,560,561],{"class":208},"  \u003Ctemplate #fallback>\n",[165,563,564],{"class":167,"line":314},[165,565,566],{"class":208},"    \u003Cdiv class=\"viz-placeholder\" \u002F>\n",[165,568,569],{"class":167,"line":321},[165,570,571],{"class":208},"  \u003C\u002Ftemplate>\n",[165,573,574,576,578],{"class":167,"line":331},[165,575,307],{"class":212},[165,577,362],{"class":219},[165,579,276],{"class":212},[110,581,582,583,585,586,589],{},"Hydration replaces the entire ",[114,584,138],{}," subtree, so anything you want to survive that\nswap — a heading, a toolbar — belongs outside it, or in ",[519,587,588],{},"both"," branches.",[150,591,593],{"id":592},"using-the-core-directly","Using the core directly",[110,595,596,597,602,603,605,606,223],{},"If you skip the component and drive ",[131,598,599],{"href":59},[114,600,601],{},"@fft-visualizer\u002Fcore"," yourself, construct it\nin ",[114,604,128],{}," and guard any module-scope browser access with ",[114,607,608],{},"import.meta.client",[155,610,612],{"className":256,"code":611,"language":259,"meta":161,"style":161},"\u003Cscript setup>\nimport { FFTVisualizer } from '@fft-visualizer\u002Fcore'\n\nconst canvas = useTemplateRef('canvas')\nlet viz\n\nonMounted(() => {\n  viz = new FFTVisualizer(canvas.value, { mode: 'local', bands: 40 })\n})\n\nonBeforeUnmount(() => viz?.destroy())\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Ccanvas ref=\"canvas\" \u002F>\n\u003C\u002Ftemplate>\n",[114,613,614,624,642,646,670,678,682,697,748,754,758,781,789,793,801,820],{"__ignoreMap":161},[165,615,616,618,620,622],{"class":167,"line":168},[165,617,266],{"class":212},[165,619,269],{"class":219},[165,621,273],{"class":272},[165,623,276],{"class":212},[165,625,626,628,630,632,634,636,638,640],{"class":167,"line":216},[165,627,281],{"class":197},[165,629,284],{"class":212},[165,631,287],{"class":208},[165,633,290],{"class":212},[165,635,293],{"class":197},[165,637,296],{"class":212},[165,639,601],{"class":174},[165,641,302],{"class":212},[165,643,644],{"class":167,"line":243},[165,645,318],{"emptyLinePlaceholder":317},[165,647,648,651,654,656,659,661,663,666,668],{"class":167,"line":314},[165,649,650],{"class":272},"const",[165,652,653],{"class":208}," canvas ",[165,655,343],{"class":212},[165,657,658],{"class":204}," useTemplateRef",[165,660,209],{"class":208},[165,662,229],{"class":212},[165,664,665],{"class":174},"canvas",[165,667,229],{"class":212},[165,669,249],{"class":208},[165,671,672,675],{"class":167,"line":321},[165,673,674],{"class":272},"let",[165,676,677],{"class":208}," viz\n",[165,679,680],{"class":167,"line":331},[165,681,318],{"emptyLinePlaceholder":317},[165,683,684,686,688,691,694],{"class":167,"line":356},[165,685,128],{"class":204},[165,687,209],{"class":208},[165,689,690],{"class":212},"()",[165,692,693],{"class":272}," =>",[165,695,696],{"class":212}," {\n",[165,698,699,702,705,708,710,712,714,716,719,722,724,726,728,730,732,734,736,739,741,744,746],{"class":167,"line":367},[165,700,701],{"class":208},"  viz",[165,703,704],{"class":212}," =",[165,706,707],{"class":212}," new",[165,709,287],{"class":204},[165,711,209],{"class":219},[165,713,665],{"class":208},[165,715,139],{"class":212},[165,717,718],{"class":208},"value",[165,720,721],{"class":212},",",[165,723,284],{"class":212},[165,725,376],{"class":219},[165,727,223],{"class":212},[165,729,296],{"class":212},[165,731,383],{"class":174},[165,733,229],{"class":212},[165,735,721],{"class":212},[165,737,738],{"class":219}," bands",[165,740,223],{"class":212},[165,742,743],{"class":481}," 40",[165,745,290],{"class":212},[165,747,249],{"class":219},[165,749,750,752],{"class":167,"line":415},[165,751,246],{"class":212},[165,753,249],{"class":208},[165,755,756],{"class":167,"line":425},[165,757,318],{"emptyLinePlaceholder":317},[165,759,760,763,765,767,769,772,775,778],{"class":167,"line":435},[165,761,762],{"class":204},"onBeforeUnmount",[165,764,209],{"class":208},[165,766,690],{"class":212},[165,768,693],{"class":272},[165,770,771],{"class":208}," viz",[165,773,774],{"class":212},"?.",[165,776,777],{"class":204},"destroy",[165,779,780],{"class":208},"())\n",[165,782,783,785,787],{"class":167,"line":444},[165,784,307],{"class":212},[165,786,269],{"class":219},[165,788,276],{"class":212},[165,790,791],{"class":167,"line":449},[165,792,318],{"emptyLinePlaceholder":317},[165,794,795,797,799],{"class":167,"line":459},[165,796,266],{"class":212},[165,798,326],{"class":219},[165,800,276],{"class":212},[165,802,803,805,807,810,812,814,816,818],{"class":167,"line":466},[165,804,334],{"class":212},[165,806,665],{"class":219},[165,808,809],{"class":272}," ref",[165,811,343],{"class":212},[165,813,346],{"class":212},[165,815,665],{"class":174},[165,817,346],{"class":212},[165,819,412],{"class":212},[165,821,822,824,826],{"class":167,"line":501},[165,823,307],{"class":212},[165,825,326],{"class":219},[165,827,276],{"class":212},[829,830,831,832,836,837,840,841,844,845,847],"warning",{},"The canvas is a ",[833,834,835],"strong",{},"constructor argument",", not a later ",[114,838,839],{},"init()"," call — the class has no such\nmethod, and ",[114,842,843],{},"connect()"," runs automatically on construction. See the\n",[131,846,58],{"href":59}," for the full surface.",[454,849,850],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sqsOY, html code.shiki .sqsOY{--shiki-light:#8796B0;--shiki-default:#B2CCD6;--shiki-dark:#B2CCD6}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":161,"searchDepth":216,"depth":216,"links":852},[853,854,855,856],{"id":152,"depth":216,"text":153},{"id":252,"depth":216,"text":253},{"id":528,"depth":216,"text":529},{"id":592,"depth":216,"text":593},"Use the Vue component in a Nuxt app — client-only rendering, the stylesheet, and avoiding layout shift.","md",null,{},{"icon":90},{"title":87,"description":857},"TX5PMiuMedyF1f1peQxuTEfbNVS33ZuGCxpL8ZrqtHY",[865,867],{"title":82,"path":83,"stem":84,"description":866,"icon":85,"children":-1},"Standalone Vue composables that wrap the core audio engines as refs.",{"title":53,"path":98,"stem":99,"description":868,"icon":56,"children":-1},"Install the package and render your first spectrum in under a minute.",1785144672368]