[{"data":1,"prerenderedAt":989},["ShallowReactive",2],{"navigation_docs":3,"-core-api":81,"-core-api-surround":984},[4,41,62],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":40},"Guide","i-lucide-book-open","\u002Fguide","1.guide",[10,15,20,25,30,35],{"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",false,{"title":42,"icon":43,"path":44,"stem":45,"children":46,"page":40},"Core","i-lucide-box","\u002Fcore","2.core",[47,52,57],{"title":48,"path":49,"stem":50,"icon":51},"Installation","\u002Fcore\u002Finstallation","2.core\u002F1.installation","i-lucide-download",{"title":53,"path":54,"stem":55,"icon":56},"API reference","\u002Fcore\u002Fapi","2.core\u002F2.api","i-lucide-code",{"title":58,"path":59,"stem":60,"icon":61},"Audio engines","\u002Fcore\u002Faudio-engines","2.core\u002F3.audio-engines","i-lucide-audio-lines",{"title":63,"icon":64,"path":65,"stem":66,"children":67,"page":40},"Vue","i-simple-icons-vuedotjs","\u002Fvue","3.vue",[68,71,76],{"title":48,"path":69,"stem":70,"icon":51},"\u002Fvue\u002Finstallation","3.vue\u002F1.installation",{"title":72,"path":73,"stem":74,"icon":75},"Props, events & methods","\u002Fvue\u002Fprops","3.vue\u002F2.props","i-lucide-sliders-horizontal",{"title":77,"path":78,"stem":79,"icon":80},"Composables","\u002Fvue\u002Fcomposables","3.vue\u002F3.composables","i-lucide-plug",{"id":82,"title":53,"body":83,"description":977,"extension":978,"links":979,"meta":980,"navigation":981,"path":54,"seo":982,"stem":55,"__hash__":983},"docs\u002F2.core\u002F2.api.md",{"type":84,"value":85,"toc":967},"minimark",[86,106,111,195,261,276,280,359,363,509,516,542,604,608,618,708,790,796,862,868,915,932,936,963],[87,88,89,93,94,97,98,101,102,105],"p",{},[90,91,92],"code",{},"fft-visualizer-core"," exports the imperative ",[90,95,96],{},"FFTVisualizer"," class plus a ",[90,99,100],{},"parseCssColor","\nhelper. All configuration uses the shared option set documented in ",[103,104,26],"a",{"href":27},".",[107,108,110],"h2",{"id":109},"constructor","Constructor",[112,113,118],"pre",{"className":114,"code":115,"language":116,"meta":117,"style":117},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { FFTVisualizer, type FFTVisualizerOptions } from 'fft-visualizer-core'\n\nconst viz = new FFTVisualizer(canvas, options)\n","ts","",[90,119,120,161,168],{"__ignoreMap":117},[121,122,125,129,133,137,140,143,146,149,152,155,158],"span",{"class":123,"line":124},"line",1,[121,126,128],{"class":127},"s7zQu","import",[121,130,132],{"class":131},"sMK4o"," {",[121,134,136],{"class":135},"sTEyZ"," FFTVisualizer",[121,138,139],{"class":131},",",[121,141,142],{"class":127}," type",[121,144,145],{"class":135}," FFTVisualizerOptions",[121,147,148],{"class":131}," }",[121,150,151],{"class":127}," from",[121,153,154],{"class":131}," '",[121,156,92],{"class":157},"sfazB",[121,159,160],{"class":131},"'\n",[121,162,164],{"class":123,"line":163},2,[121,165,167],{"emptyLinePlaceholder":166},true,"\n",[121,169,171,175,178,181,184,187,190,192],{"class":123,"line":170},3,[121,172,174],{"class":173},"spNyl","const",[121,176,177],{"class":135}," viz ",[121,179,180],{"class":131},"=",[121,182,183],{"class":131}," new",[121,185,136],{"class":186},"s2Zo4",[121,188,189],{"class":135},"(canvas",[121,191,139],{"class":131},[121,193,194],{"class":135}," options)\n",[196,197,198,214],"table",{},[199,200,201],"thead",{},[202,203,204,208,211],"tr",{},[205,206,207],"th",{},"Parameter",[205,209,210],{},"Type",[205,212,213],{},"Description",[215,216,217,238],"tbody",{},[202,218,219,225,230],{},[220,221,222],"td",{},[90,223,224],{},"canvas",[220,226,227],{},[90,228,229],{},"HTMLCanvasElement",[220,231,232,233,237],{},"The canvas to render into. The visualizer sizes to the canvas's ",[234,235,236],"strong",{},"parent element"," and observes it for resizes",[202,239,240,245,255],{},[220,241,242],{},[90,243,244],{},"options",[220,246,247,250,251],{},[90,248,249],{},"FFTVisualizerOptions"," ",[252,253,254],"em",{},"(optional)",[220,256,257,258],{},"Any of the ",[103,259,260],{"href":27},"shared options",[87,262,263,264,267,268,271,272,275],{},"Constructing the instance initializes WebGL and ",[234,265,266],{},"connects immediately"," using ",[90,269,270],{},"options.mode","\n(local capture starts, a WebSocket opens, or external mode begins rendering). If WebGL fails\nto initialize, an ",[90,273,274],{},"error"," event is emitted instead.",[107,277,279],{"id":278},"getters","Getters",[196,281,282,293],{},[199,283,284],{},[202,285,286,289,291],{},[205,287,288],{},"Getter",[205,290,210],{},[205,292,213],{},[215,294,295,310,325,344],{},[202,296,297,302,307],{},[220,298,299],{},[90,300,301],{},"isConnected",[220,303,304],{},[90,305,306],{},"boolean",[220,308,309],{},"Whether the data source is currently active",[202,311,312,317,322],{},[220,313,314],{},[90,315,316],{},"fps",[220,318,319],{},[90,320,321],{},"number",[220,323,324],{},"Frames processed in the last second",[202,326,327,332,337],{},[220,328,329],{},[90,330,331],{},"audioDevices",[220,333,334],{},[90,335,336],{},"AudioDevice[]",[220,338,339,340,343],{},"Known audio input devices (populated after ",[90,341,342],{},"getAudioDevices()"," or local capture)",[202,345,346,351,356],{},[220,347,348],{},[90,349,350],{},"activeAudioDeviceId",[220,352,353],{},[90,354,355],{},"string | undefined",[220,357,358],{},"The device ID currently in use for local mic capture",[107,360,362],{"id":361},"methods","Methods",[196,364,365,377],{},[199,366,367],{},[202,368,369,372,375],{},[205,370,371],{},"Method",[205,373,374],{},"Signature",[205,376,213],{},[215,378,379,398,412,427,458,480,495],{},[202,380,381,386,391],{},[220,382,383],{},[90,384,385],{},"connect",[220,387,388],{},[90,389,390],{},"() => void",[220,392,393,394,397],{},"Start the current ",[90,395,396],{},"mode"," (open the WebSocket, start capture, or begin external rendering). Called automatically by the constructor",[202,399,400,405,409],{},[220,401,402],{},[90,403,404],{},"disconnect",[220,406,407],{},[90,408,390],{},[220,410,411],{},"Stop the data source and rendering",[202,413,414,419,424],{},[220,415,416],{},[90,417,418],{},"setOptions",[220,420,421],{},[90,422,423],{},"(patch: Partial\u003CFFTVisualizerOptions>) => void",[220,425,426],{},"Apply a partial options update at runtime (see below)",[202,428,429,434,439],{},[220,430,431],{},[90,432,433],{},"feedData",[220,435,436],{},[90,437,438],{},"(data: Uint8Array, left?: Uint8Array, right?: Uint8Array) => void",[220,440,441,442,445,446,449,450,453,454,457],{},"Feed FFT magnitudes (0–255) in ",[90,443,444],{},"external"," mode. The data is ",[234,447,448],{},"copied",", so reusing one buffer per frame is safe. Pass ",[90,451,452],{},"left"," and ",[90,455,456],{},"right"," for stereo",[202,459,460,465,469],{},[220,461,462],{},[90,463,464],{},"refreshGradient",[220,466,467],{},[90,468,390],{},[220,470,471,472,475,476,479],{},"Rebuild the gradient LUT after mutating custom stops ",[234,473,474],{},"in place"," (not needed when you assign a new ",[90,477,478],{},"gradient",")",[202,481,482,487,492],{},[220,483,484],{},[90,485,486],{},"getAudioDevices",[220,488,489],{},[90,490,491],{},"() => Promise\u003CAudioDevice[]>",[220,493,494],{},"Enumerate audio input devices (prompts for mic permission if needed)",[202,496,497,502,506],{},[220,498,499],{},[90,500,501],{},"destroy",[220,503,504],{},[90,505,390],{},[220,507,508],{},"Disconnect, stop observing resize, remove all listeners, and free every WebGL resource",[510,511,513],"h3",{"id":512},"setoptionspatch",[90,514,515],{},"setOptions(patch)",[87,517,518,519,521,522,525,526,529,530,521,533,535,536,538,539,105],{},"Only keys whose value actually changed take effect. Changing ",[90,520,396],{}," or ",[90,523,524],{},"websocketUrl","\nreconnects; changing ",[90,527,528],{},"bands"," reallocates buffers; changing ",[90,531,532],{},"background",[90,534,478],{}," reuploads\nthe relevant texture. To reload a gradient whose stops you mutated in place, either pass a new\n",[90,537,478],{}," reference or call ",[90,540,541],{},"refreshGradient()",[112,543,545],{"className":114,"code":544,"language":116,"meta":117,"style":117},"viz.setOptions({ ledBars: true, gradient: 'sunset', bands: 20 })\n",[90,546,547],{"__ignoreMap":117},[121,548,549,552,554,556,559,562,566,569,573,575,578,580,582,585,588,590,593,595,599,601],{"class":123,"line":124},[121,550,551],{"class":135},"viz",[121,553,105],{"class":131},[121,555,418],{"class":186},[121,557,558],{"class":135},"(",[121,560,561],{"class":131},"{",[121,563,565],{"class":564},"swJcz"," ledBars",[121,567,568],{"class":131},":",[121,570,572],{"class":571},"sfNiH"," true",[121,574,139],{"class":131},[121,576,577],{"class":564}," gradient",[121,579,568],{"class":131},[121,581,154],{"class":131},[121,583,584],{"class":157},"sunset",[121,586,587],{"class":131},"'",[121,589,139],{"class":131},[121,591,592],{"class":564}," bands",[121,594,568],{"class":131},[121,596,598],{"class":597},"sbssI"," 20",[121,600,148],{"class":131},[121,602,603],{"class":135},")\n",[107,605,607],{"id":606},"events","Events",[87,609,610,611,614,615,105],{},"Subscribe with ",[90,612,613],{},"on()",", which returns an unsubscribe function; or remove a handler with ",[90,616,617],{},"off()",[112,619,621],{"className":114,"code":620,"language":116,"meta":117,"style":117},"const stop = viz.on('frame', ({ data, left, right }) => {\n  \u002F\u002F data: Uint8Array — one 0–255 magnitude per bar (length = bands)\n  \u002F\u002F left \u002F right: per-channel arrays in stereo mode, else null\n})\nstop() \u002F\u002F unsubscribe\n",[90,622,623,677,683,688,696],{"__ignoreMap":117},[121,624,625,627,630,632,635,637,640,642,644,647,649,651,654,658,660,663,665,668,671,674],{"class":123,"line":124},[121,626,174],{"class":173},[121,628,629],{"class":135}," stop ",[121,631,180],{"class":131},[121,633,634],{"class":135}," viz",[121,636,105],{"class":131},[121,638,639],{"class":186},"on",[121,641,558],{"class":135},[121,643,587],{"class":131},[121,645,646],{"class":157},"frame",[121,648,587],{"class":131},[121,650,139],{"class":131},[121,652,653],{"class":131}," ({",[121,655,657],{"class":656},"sHdIc"," data",[121,659,139],{"class":131},[121,661,662],{"class":656}," left",[121,664,139],{"class":131},[121,666,667],{"class":656}," right",[121,669,670],{"class":131}," })",[121,672,673],{"class":173}," =>",[121,675,676],{"class":131}," {\n",[121,678,679],{"class":123,"line":163},[121,680,682],{"class":681},"sHwdD","  \u002F\u002F data: Uint8Array — one 0–255 magnitude per bar (length = bands)\n",[121,684,685],{"class":123,"line":170},[121,686,687],{"class":681},"  \u002F\u002F left \u002F right: per-channel arrays in stereo mode, else null\n",[121,689,691,694],{"class":123,"line":690},4,[121,692,693],{"class":131},"}",[121,695,603],{"class":135},[121,697,699,702,705],{"class":123,"line":698},5,[121,700,701],{"class":186},"stop",[121,703,704],{"class":135},"() ",[121,706,707],{"class":681},"\u002F\u002F unsubscribe\n",[196,709,710,723],{},[199,711,712],{},[202,713,714,717,720],{},[205,715,716],{},"Event",[205,718,719],{},"Payload",[205,721,722],{},"Fires when",[215,724,725,738,750,764,778],{},[202,726,727,732,735],{},[220,728,729],{},[90,730,731],{},"connected",[220,733,734],{},"—",[220,736,737],{},"The data source became active",[202,739,740,745,747],{},[220,741,742],{},[90,743,744],{},"disconnected",[220,746,734],{},[220,748,749],{},"The data source stopped",[202,751,752,756,761],{},[220,753,754],{},[90,755,274],{},[220,757,758],{},[90,759,760],{},"string",[220,762,763],{},"A WebSocket error, capture failure, or WebGL init failure",[202,765,766,770,775],{},[220,767,768],{},[90,769,646],{},[220,771,772],{},[90,773,774],{},"FrameEvent",[220,776,777],{},"Once per processed audio frame, with the display bar magnitudes",[202,779,780,785,787],{},[220,781,782],{},[90,783,784],{},"audiostate",[220,786,734],{},[220,788,789],{},"Local-audio state changed (capture started\u002Fstopped, or the device list updated)",[87,791,792,793,795],{},"The ",[90,794,646],{}," event is a ready-made feed for external hardware (LED strips, flip-dot displays)\n— it hands you exactly what the shader draws, without re-implementing any FFT. It's\nlistener-gated, so it costs nothing when no handler is attached.",[112,797,799],{"className":114,"code":798,"language":116,"meta":117,"style":117},"interface FrameEvent {\n  data: Uint8Array          \u002F\u002F per-bar magnitudes (in stereo, the per-bar max of both channels)\n  left: Uint8Array | null   \u002F\u002F per-channel in stereo, else null\n  right: Uint8Array | null\n}\n",[90,800,801,812,825,843,857],{"__ignoreMap":117},[121,802,803,806,810],{"class":123,"line":124},[121,804,805],{"class":173},"interface",[121,807,809],{"class":808},"sBMFI"," FrameEvent",[121,811,676],{"class":131},[121,813,814,817,819,822],{"class":123,"line":163},[121,815,816],{"class":564},"  data",[121,818,568],{"class":131},[121,820,821],{"class":808}," Uint8Array",[121,823,824],{"class":681},"          \u002F\u002F per-bar magnitudes (in stereo, the per-bar max of both channels)\n",[121,826,827,830,832,834,837,840],{"class":123,"line":170},[121,828,829],{"class":564},"  left",[121,831,568],{"class":131},[121,833,821],{"class":808},[121,835,836],{"class":131}," |",[121,838,839],{"class":808}," null",[121,841,842],{"class":681},"   \u002F\u002F per-channel in stereo, else null\n",[121,844,845,848,850,852,854],{"class":123,"line":690},[121,846,847],{"class":564},"  right",[121,849,568],{"class":131},[121,851,821],{"class":808},[121,853,836],{"class":131},[121,855,856],{"class":808}," null\n",[121,858,859],{"class":123,"line":698},[121,860,861],{"class":131},"}\n",[107,863,865],{"id":864},"parsecsscolorcolor",[90,866,867],{},"parseCssColor(color)",[112,869,871],{"className":114,"code":870,"language":116,"meta":117,"style":117},"import { parseCssColor } from 'fft-visualizer-core'\n\nparseCssColor('rgba(10, 10, 10, 0.5)') \u002F\u002F => [r, g, b, a] normalized 0–1\n",[90,872,873,892,896],{"__ignoreMap":117},[121,874,875,877,879,882,884,886,888,890],{"class":123,"line":124},[121,876,128],{"class":127},[121,878,132],{"class":131},[121,880,881],{"class":135}," parseCssColor",[121,883,148],{"class":131},[121,885,151],{"class":127},[121,887,154],{"class":131},[121,889,92],{"class":157},[121,891,160],{"class":131},[121,893,894],{"class":123,"line":163},[121,895,167],{"emptyLinePlaceholder":166},[121,897,898,900,902,904,907,909,912],{"class":123,"line":170},[121,899,100],{"class":186},[121,901,558],{"class":135},[121,903,587],{"class":131},[121,905,906],{"class":157},"rgba(10, 10, 10, 0.5)",[121,908,587],{"class":131},[121,910,911],{"class":135},") ",[121,913,914],{"class":681},"\u002F\u002F => [r, g, b, a] normalized 0–1\n",[87,916,917,918,453,921,924,925,928,929,931],{},"Parses any CSS color (including ",[90,919,920],{},"rgba()",[90,922,923],{},"'transparent'",") into a normalized ",[90,926,927],{},"[r, g, b, a]","\ntuple via a 1×1 canvas — the same routine the visualizer uses for the ",[90,930,532],{}," option.",[107,933,935],{"id":934},"types","Types",[87,937,938,941,942,945,946,941,949,952,953,955,956,959,960,962],{},[90,939,940],{},"VisualizerMode"," (",[90,943,944],{},"'websocket' | 'local' | 'external'","), ",[90,947,948],{},"BandCount",[90,950,951],{},"10 | 20 | 40 | 80","),\n",[90,954,249],{},", ",[90,957,958],{},"FFTVisualizerEventMap",", and ",[90,961,774],{}," are all exported for typing\nyour own code.",[964,965,966],"style",{},"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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":117,"searchDepth":163,"depth":163,"links":968},[969,970,971,974,975,976],{"id":109,"depth":163,"text":110},{"id":278,"depth":163,"text":279},{"id":361,"depth":163,"text":362,"children":972},[973],{"id":512,"depth":170,"text":515},{"id":606,"depth":163,"text":607},{"id":864,"depth":163,"text":867},{"id":934,"depth":163,"text":935},"The FFTVisualizer class — constructor, getters, methods, events, and helpers.","md",null,{},{"icon":56},{"title":53,"description":977},"MCk34L8YTX-DgMT7xkE4lq_LMPs2fujyvQS9df_zkiM",[985,987],{"title":48,"path":49,"stem":50,"description":986,"icon":51,"children":-1},"Install fft-visualizer-core and render a spectrum onto a canvas — no framework required.",{"title":58,"path":59,"stem":60,"description":988,"icon":61,"children":-1},"Standalone FFT pipelines — local capture, client-side FFT of a PCM stream, PCM decoding, and the raw WASM processor.",1784963433242]