[{"data":1,"prerenderedAt":1618},["ShallowReactive",2],{"navigation_docs":3,"-guides-audio":412,"-guides-audio-surround":1613},[4,38,84,326,386],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":37},"Getting started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,15,20,24,28,32],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction","i-lucide-book-open",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":6},"Quick start: Nuxt","\u002Fgetting-started\u002Fquick-start-nuxt","1.getting-started\u002F3.quick-start-nuxt",{"title":25,"path":26,"stem":27,"icon":6},"Quick start: plain Vue","\u002Fgetting-started\u002Fquick-start-vue","1.getting-started\u002F4.quick-start-vue",{"title":29,"path":30,"stem":31,"icon":6},"Quick start: React","\u002Fgetting-started\u002Fquick-start-react","1.getting-started\u002F5.quick-start-react",{"title":33,"path":34,"stem":35,"icon":36},"Glossary","\u002Fgetting-started\u002Fglossary","1.getting-started\u002F6.glossary","i-lucide-book-a",false,{"title":39,"icon":40,"path":41,"stem":42,"children":43,"page":37},"Tutorial","i-lucide-graduation-cap","\u002Ftutorial","2.tutorial",[44,49,54,59,64,69,74,79],{"title":45,"path":46,"stem":47,"icon":48},"Tutorial: overview","\u002Ftutorial\u002Foverview","2.tutorial\u002F1.overview","i-lucide-map",{"title":50,"path":51,"stem":52,"icon":53},"Chapter 2: A simple editor","\u002Ftutorial\u002Fsimple-editor","2.tutorial\u002F2.simple-editor","i-lucide-pencil",{"title":55,"path":56,"stem":57,"icon":58},"Chapter 3: Compose features","\u002Ftutorial\u002Fcompose-features","2.tutorial\u002F3.compose-features","i-lucide-blocks",{"title":60,"path":61,"stem":62,"icon":63},"Chapter 4: Your own block, path A","\u002Ftutorial\u002Fown-block-path-a","2.tutorial\u002F4.own-block-path-a","i-lucide-square-plus",{"title":65,"path":66,"stem":67,"icon":68},"Chapter 5: Your own feature, path B","\u002Ftutorial\u002Fown-feature-path-b","2.tutorial\u002F5.own-feature-path-b","i-lucide-puzzle",{"title":70,"path":71,"stem":72,"icon":73},"Chapter 6: Backend and collaboration","\u002Ftutorial\u002Fbackend-and-collaboration","2.tutorial\u002F6.backend-and-collaboration","i-lucide-users",{"title":75,"path":76,"stem":77,"icon":78},"Chapter 7: AI","\u002Ftutorial\u002Fai","2.tutorial\u002F7.ai","i-lucide-sparkles",{"title":80,"path":81,"stem":82,"icon":83},"Chapter 8: The React surface","\u002Ftutorial\u002Freact-surface","2.tutorial\u002F8.react-surface","i-lucide-atom",{"title":85,"icon":14,"path":86,"stem":87,"children":88,"page":37},"Guides","\u002Fguides","3.guides",[89,93,98,103,108,112,116,121,126,130,134,139,144,149,154,159,164,169,174,179,184,189,194,199,204,209,213,218,223,228,233,237,242,247,251,256,261,266,271,276,281,286,291,295,302,307,311,316,321],{"title":90,"path":91,"stem":92,"icon":58},"Feature composition and entries","\u002Fguides\u002Fcomposition","3.guides\u002F1.composition",{"title":94,"path":95,"stem":96,"icon":97},"Media, mentions and transcript features","\u002Fguides\u002Fmedia-mentions-transcript","3.guides\u002F10.media-mentions-transcript","i-lucide-image",{"title":99,"path":100,"stem":101,"icon":102},"Authors and comments","\u002Fguides\u002Fauthors-and-comments","3.guides\u002F11.authors-and-comments","i-lucide-message-square-text",{"title":104,"path":105,"stem":106,"icon":107},"Themes (Obsidian)","\u002Fguides\u002Fthemes","3.guides\u002F12.themes","i-lucide-palette",{"title":109,"path":110,"stem":111,"icon":58},"Composites and the settings UI","\u002Fguides\u002Fcomposites","3.guides\u002F13.composites",{"title":113,"path":114,"stem":115,"icon":78},"AI","\u002Fguides\u002Fai","3.guides\u002F14.ai",{"title":117,"path":118,"stem":119,"icon":120},"Document tree","\u002Fguides\u002Fdocument-tree","3.guides\u002F15.document-tree","i-lucide-folder-tree",{"title":122,"path":123,"stem":124,"icon":125},"Markdown and code","\u002Fguides\u002Fmarkdown-and-code","3.guides\u002F16.markdown-and-code","i-lucide-file-code",{"title":127,"path":128,"stem":129,"icon":83},"Advanced editor in React","\u002Fguides\u002Fadvanced-react","3.guides\u002F17.advanced-react",{"title":131,"path":132,"stem":133,"icon":6},"Kitchen sink: learning path","\u002Fguides\u002Fadvanced-nuxt-example","3.guides\u002F18.advanced-nuxt-example",{"title":135,"path":136,"stem":137,"icon":138},"Production","\u002Fguides\u002Fproduction","3.guides\u002F19.production","i-lucide-server",{"title":140,"path":141,"stem":142,"icon":143},"Register the Nuxt module","\u002Fguides\u002Fnuxt-module","3.guides\u002F2.nuxt-module","i-lucide-package",{"title":145,"path":146,"stem":147,"icon":148},"Storage adapters, comment stores, Nitro host","\u002Fguides\u002Fstorage-adapters","3.guides\u002F20.storage-adapters","i-lucide-database",{"title":150,"path":151,"stem":152,"icon":153},"Migrating from #tiptap-editor","\u002Fguides\u002Fmigration","3.guides\u002F21.migration","i-lucide-arrow-right-left",{"title":155,"path":156,"stem":157,"icon":158},"Content tree mechanics","\u002Fguides\u002Fcontent-tree","3.guides\u002F22.content-tree","i-lucide-git-fork",{"title":160,"path":161,"stem":162,"icon":163},"Block capabilities, abilities and actions","\u002Fguides\u002Fblock-capabilities","3.guides\u002F23.block-capabilities","i-lucide-shield-check",{"title":165,"path":166,"stem":167,"icon":168},"Block types in code and JSON","\u002Fguides\u002Fblock-types","3.guides\u002F24.block-types","i-lucide-shapes",{"title":170,"path":171,"stem":172,"icon":173},"Derive methods and the Derivation index","\u002Fguides\u002Fderive-methods","3.guides\u002F25.derive-methods","i-lucide-git-branch-plus",{"title":175,"path":176,"stem":177,"icon":178},"Block properties and Property definitions","\u002Fguides\u002Fblock-properties","3.guides\u002F26.block-properties","i-lucide-sliders-horizontal",{"title":180,"path":181,"stem":182,"icon":183},"Image studio","\u002Fguides\u002Fimage-studio","3.guides\u002F27.image-studio","i-lucide-image-plus",{"title":185,"path":186,"stem":187,"icon":188},"Prüfung and Freigabestatus","\u002Fguides\u002Fpruefung","3.guides\u002F28.pruefung","i-lucide-stamp",{"title":190,"path":191,"stem":192,"icon":193},"Workspace: find, read, reference and embed Blocks across Documents","\u002Fguides\u002Fworkspace","3.guides\u002F29.workspace","i-lucide-network",{"title":195,"path":196,"stem":197,"icon":198},"EditorPorts: auth and storage","\u002Fguides\u002Feditor-ports","3.guides\u002F3.editor-ports","i-lucide-plug",{"title":200,"path":201,"stem":202,"icon":203},"Collections: an ordered list of Blocks","\u002Fguides\u002Fcollections","3.guides\u002F30.collections","i-lucide-list-checks",{"title":205,"path":206,"stem":207,"icon":208},"Data views: a query shown as table, list or board","\u002Fguides\u002Fdata-views","3.guides\u002F31.data-views","i-lucide-table-properties",{"title":210,"path":211,"stem":212,"icon":193},"Explore: backlinks, related Blocks and the trail","\u002Fguides\u002Fexplore","3.guides\u002F32.explore",{"title":214,"path":215,"stem":216,"icon":217},"Render: export a Block or a Document to a file","\u002Fguides\u002Frender","3.guides\u002F33.render","i-lucide-file-output",{"title":219,"path":220,"stem":221,"icon":222},"Importers: what a dropped file becomes","\u002Fguides\u002Fimporters","3.guides\u002F34.importers","i-lucide-file-input",{"title":224,"path":225,"stem":226,"icon":227},"Templates: start a Document from a Dokumentvorlage","\u002Fguides\u002Ftemplates","3.guides\u002F35.templates","i-lucide-file-stack",{"title":229,"path":230,"stem":231,"icon":232},"Citations","\u002Fguides\u002Fcitations","3.guides\u002F36.citations","i-lucide-quote",{"title":234,"path":235,"stem":236,"icon":163},"AI proposals and the export check","\u002Fguides\u002Fexport-check","3.guides\u002F37.export-check",{"title":238,"path":239,"stem":240,"icon":241},"Query: filter, sort, group and total Blocks","\u002Fguides\u002Fquery","3.guides\u002F38.query","i-lucide-list-filter",{"title":243,"path":244,"stem":245,"icon":246},"Edges: backlinks and authored connections","\u002Fguides\u002Fedges","3.guides\u002F39.edges","i-lucide-link-2",{"title":248,"path":249,"stem":250,"icon":163},"Server routes and authentication","\u002Fguides\u002Froutes-and-auth","3.guides\u002F4.routes-and-auth",{"title":252,"path":253,"stem":254,"icon":255},"Speech: text to audio, and subtitle files","\u002Fguides\u002Fspeech","3.guides\u002F41.speech","i-lucide-audio-lines",{"title":257,"path":258,"stem":259,"icon":260},"Graph: the Edges around a Block","\u002Fguides\u002Fgraph","3.guides\u002F42.graph","i-lucide-waypoints",{"title":262,"path":263,"stem":264,"icon":265},"PDF viewer: passages, anchors and quotes","\u002Fguides\u002Fpdf-viewer","3.guides\u002F43.pdf-viewer","i-lucide-file-search",{"title":267,"path":268,"stem":269,"icon":270},"Obsidian: import and export a vault","\u002Fguides\u002Fobsidian","3.guides\u002F44.obsidian","i-lucide-folder-input",{"title":272,"path":273,"stem":274,"icon":275},"Typst: render a Document as a PDF with citations","\u002Fguides\u002Ftypst","3.guides\u002F45.typst","i-lucide-file-text",{"title":277,"path":278,"stem":279,"icon":280},"Audio: read aloud, mixdown and ElevenLabs","\u002Fguides\u002Faudio","3.guides\u002F46.audio","i-lucide-audio-waveform",{"title":282,"path":283,"stem":284,"icon":285},"Slides: decks, slide layouts and exports","\u002Fguides\u002Fslides","3.guides\u002F47.slides","i-lucide-presentation",{"title":287,"path":288,"stem":289,"icon":290},"Knowledge graph: sources and concepts beside the Documents","\u002Fguides\u002Fknowledge-graph","3.guides\u002F49.knowledge-graph","i-lucide-share-2",{"title":292,"path":293,"stem":294,"icon":78},"AI configuration and secrets","\u002Fguides\u002Fai-configuration","3.guides\u002F5.ai-configuration",{"title":296,"path":297,"stem":298,"children":299,"icon":301},"Index on Postgres: typos, meaning and SQL pushdown","\u002Fguides\u002Findex-pg","3.guides\u002F50.index-pg",[300],{"title":296,"path":297,"stem":298,"icon":301},"i-lucide-database-zap",{"title":303,"path":304,"stem":305,"icon":306},"Charts: bar, line, pie and scatter over a query","\u002Fguides\u002Fcharts","3.guides\u002F51.charts","i-lucide-chart-column",{"title":308,"path":309,"stem":310,"icon":73},"Collaboration on the client","\u002Fguides\u002Fcollaboration","3.guides\u002F6.collaboration",{"title":312,"path":313,"stem":314,"icon":315},"Block UI (drag handle, hover actions)","\u002Fguides\u002Fblock-ui","3.guides\u002F7.block-ui","i-lucide-grip-vertical",{"title":317,"path":318,"stem":319,"icon":320},"Settings and app lifetime","\u002Fguides\u002Fsettings","3.guides\u002F8.settings","i-lucide-settings",{"title":322,"path":323,"stem":324,"icon":325},"Language","\u002Fguides\u002Flanguage","3.guides\u002F9.language","i-lucide-languages",{"title":327,"icon":14,"path":328,"stem":329,"children":330,"page":37},"Reference","\u002Freference","4.reference",[331,335,339,344,348,352,356,360,364,368,373,378,382],{"title":332,"path":333,"stem":334,"icon":143},"Public exports","\u002Freference\u002Fexports","4.reference\u002F1.exports",{"title":336,"path":337,"stem":338,"icon":173},"Derive method contract","\u002Freference\u002Fderive-methods","4.reference\u002F10.derive-methods",{"title":340,"path":341,"stem":342,"icon":343},"Changelog","\u002Freference\u002Fchangelog","4.reference\u002F11.changelog","i-lucide-history",{"title":345,"path":346,"stem":347,"icon":217},"Renderer port","\u002Freference\u002Frenderer-port","4.reference\u002F12.renderer-port",{"title":349,"path":350,"stem":351,"icon":255},"Speech port","\u002Freference\u002Fspeech-port","4.reference\u002F13.speech-port",{"title":353,"path":354,"stem":355,"icon":58},"Presets and features","\u002Freference\u002Fpresets-and-features","4.reference\u002F2.presets-and-features",{"title":357,"path":358,"stem":359,"icon":68},"Feature contract","\u002Freference\u002Ffeature-contract","4.reference\u002F3.feature-contract",{"title":361,"path":362,"stem":363,"icon":107},"CSS and UI-provider requirements","\u002Freference\u002Fcss-and-ui","4.reference\u002F4.css-and-ui",{"title":365,"path":366,"stem":367,"icon":148},"Vue-free advanced schema","\u002Freference\u002Fadvanced-schema","4.reference\u002F5.advanced-schema",{"title":369,"path":370,"stem":371,"icon":372},"Dependency rules","\u002Freference\u002Fdependency-rules","4.reference\u002F6.dependency-rules","i-lucide-git-branch",{"title":374,"path":375,"stem":376,"icon":377},"Commands","\u002Freference\u002Fcommands","4.reference\u002F7.commands","i-lucide-terminal",{"title":379,"path":380,"stem":381,"icon":163},"Block capability contract","\u002Freference\u002Fblock-capabilities","4.reference\u002F8.block-capabilities",{"title":383,"path":384,"stem":385,"icon":168},"Block type contract","\u002Freference\u002Fblock-types","4.reference\u002F9.block-types",{"title":387,"path":388,"stem":389,"children":390,"icon":393},"AI agents","\u002Fai-agents","5.ai-agents\u002F1.index",[391,394,398,402,407],{"title":392,"path":388,"stem":389,"icon":393},"Overview","i-lucide-bot",{"title":395,"path":396,"stem":397,"icon":198},"Integrate the editor","\u002Fai-agents\u002Fintegrate","5.ai-agents\u002F2.integrate",{"title":399,"path":400,"stem":401,"icon":68},"Add a block or feature","\u002Fai-agents\u002Fextend","5.ai-agents\u002F3.extend",{"title":403,"path":404,"stem":405,"icon":406},"Pitfalls and invariants","\u002Fai-agents\u002Finvariants","5.ai-agents\u002F4.invariants","i-lucide-shield-alert",{"title":408,"path":409,"stem":410,"icon":411},"Verify","\u002Fai-agents\u002Fverify","5.ai-agents\u002F5.verify","i-lucide-check-check",{"id":413,"title":277,"body":414,"description":1606,"extension":1607,"links":1608,"meta":1609,"navigation":1610,"path":278,"seo":1611,"stem":279,"__hash__":1612},"docs\u002F3.guides\u002F46.audio.md",{"type":415,"value":416,"toc":1596},"minimark",[417,435,548,563,568,750,764,773,895,944,948,1048,1090,1097,1103,1116,1200,1214,1220,1239,1242,1316,1334,1443,1448,1481,1488,1562,1579,1593],[418,419,420,421,425,426,430,431,434],"p",{},"The add-on ",[422,423,424],"code",{},"@skaile\u002Fforge-editor-audio"," builds on the library's ",[427,428,429],"a",{"href":253},"speech port"," and ",[427,432,433],{"href":215},"render port",". It adds three things:",[436,437,438,454],"table",{},[439,440,441],"thead",{},[442,443,444,448,451],"tr",{},[445,446,447],"th",{},"Piece",[445,449,450],{},"What it does",[445,452,453],{},"Needs",[455,456,457,479,511],"tbody",{},[442,458,459,465,476],{},[460,461,462],"td",{},[422,463,464],{},"createElevenLabsSpeech",[460,466,467,468,471,472,475],{},"a ",[422,469,470],{},"SpeechProvider"," over ElevenLabs: engine ",[422,473,474],{},"elevenlabs"," with the voices of the account",[460,477,478],{},"an ElevenLabs API key",[442,480,481,486,497],{},[460,482,483],{},[422,484,485],{},"audioMixdownTarget",[460,487,488,489,492,493,496],{},"the render target ",[422,490,491],{},"audio-mixdown"," (",[422,494,495],{},"audio\u002Fmpeg",")",[460,498,499,502,503,506,507,510],{},[422,500,501],{},"ffmpeg"," on the ",[422,504,505],{},"PATH"," of the server, the ",[422,508,509],{},"assets"," port",[442,512,513,518,538],{},[460,514,515],{},[422,516,517],{},"audioFeature",[460,519,520,521,524,525,492,529,532,533,492,536,496],{},"the ",[427,522,523],{"href":171},"derive methods"," ",[526,527,528],"strong",{},"„Als Sprache vorlesen“",[422,530,531],{},"audio-tts",") and ",[526,534,535],{},"„Mixdown erzeugen“",[422,537,491],{},[460,539,520,540,543,544,547],{},[422,541,542],{},"speech"," and the ",[422,545,546],{},"render"," capability of the backend",[418,549,550,551,554,555,558,559,562],{},"Both derive methods make a Typed block of the Block type ",[422,552,553],{},"recording"," and record its ",[427,556,557],{"href":171},"Derivation"," with ",[526,560,561],{},"named inputs",". That is what lets the library tell when an input changed.",[564,565,567],"h2",{"id":566},"wire-the-server","Wire the server",[569,570,575],"pre",{"className":571,"code":572,"language":573,"meta":574,"style":574},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { createRenderer, markdownTarget } from '@skaile\u002Fforge-editor\u002Fadapters\u002Frender'\nimport { audioMixdownTarget, createElevenLabsSpeech } from '@skaile\u002Fforge-editor-audio\u002Fserver'\n\n\u002F\u002F installEditorServer({ ports: { assets, speech, render } })\nexport const speech = createElevenLabsSpeech({ apiKey: process.env.ELEVENLABS_API_KEY! })\nexport const render = createRenderer([markdownTarget(), audioMixdownTarget({ assets })])\n","ts","",[422,576,577,616,642,649,656,710],{"__ignoreMap":574},[578,579,582,586,590,594,597,600,603,606,609,613],"span",{"class":580,"line":581},"line",1,[578,583,585],{"class":584},"s7zQu","import",[578,587,589],{"class":588},"sMK4o"," {",[578,591,593],{"class":592},"sTEyZ"," createRenderer",[578,595,596],{"class":588},",",[578,598,599],{"class":592}," markdownTarget",[578,601,602],{"class":588}," }",[578,604,605],{"class":584}," from",[578,607,608],{"class":588}," '",[578,610,612],{"class":611},"sfazB","@skaile\u002Fforge-editor\u002Fadapters\u002Frender",[578,614,615],{"class":588},"'\n",[578,617,619,621,623,626,628,631,633,635,637,640],{"class":580,"line":618},2,[578,620,585],{"class":584},[578,622,589],{"class":588},[578,624,625],{"class":592}," audioMixdownTarget",[578,627,596],{"class":588},[578,629,630],{"class":592}," createElevenLabsSpeech",[578,632,602],{"class":588},[578,634,605],{"class":584},[578,636,608],{"class":588},[578,638,639],{"class":611},"@skaile\u002Fforge-editor-audio\u002Fserver",[578,641,615],{"class":588},[578,643,645],{"class":580,"line":644},3,[578,646,648],{"emptyLinePlaceholder":647},true,"\n",[578,650,652],{"class":580,"line":651},4,[578,653,655],{"class":654},"sHwdD","\u002F\u002F installEditorServer({ ports: { assets, speech, render } })\n",[578,657,659,662,666,669,672,675,678,681,685,688,691,694,697,699,702,705,707],{"class":580,"line":658},5,[578,660,661],{"class":584},"export",[578,663,665],{"class":664},"spNyl"," const",[578,667,668],{"class":592}," speech ",[578,670,671],{"class":588},"=",[578,673,630],{"class":674},"s2Zo4",[578,676,677],{"class":592},"(",[578,679,680],{"class":588},"{",[578,682,684],{"class":683},"swJcz"," apiKey",[578,686,687],{"class":588},":",[578,689,690],{"class":592}," process",[578,692,693],{"class":588},".",[578,695,696],{"class":592},"env",[578,698,693],{"class":588},[578,700,701],{"class":592},"ELEVENLABS_API_KEY",[578,703,704],{"class":588},"!",[578,706,602],{"class":588},[578,708,709],{"class":592},")\n",[578,711,713,715,717,720,722,724,727,730,733,735,737,739,741,744,747],{"class":580,"line":712},6,[578,714,661],{"class":584},[578,716,665],{"class":664},[578,718,719],{"class":592}," render ",[578,721,671],{"class":588},[578,723,593],{"class":674},[578,725,726],{"class":592},"([",[578,728,729],{"class":674},"markdownTarget",[578,731,732],{"class":592},"()",[578,734,596],{"class":588},[578,736,625],{"class":674},[578,738,677],{"class":592},[578,740,680],{"class":588},[578,742,743],{"class":592}," assets ",[578,745,746],{"class":588},"}",[578,748,749],{"class":592},")])\n",[418,751,752,753,756,757,759,760,763],{},"The server code is the ",[422,754,755],{},"\u002Fserver"," entry (it starts ",[422,758,501],{}," through ",[422,761,762],{},"node:child_process","); the root entry of the package is browser-safe and holds the Feature and the pure pieces of a Derivation, as in the other add-ons.",[418,765,766,768,769,772],{},[422,767,509],{}," is the host's ",[422,770,771],{},"AssetStore",": the target reads the takes' audio from it, and the render route stores the mixdown in it.",[436,774,775,787],{},[439,776,777],{},[442,778,779,784],{},[445,780,781,782],{},"Option of ",[422,783,464],{},[445,785,786],{},"Meaning",[455,788,789,803,821,834,863,885],{},[442,790,791,796],{},[460,792,793],{},[422,794,795],{},"apiKey",[460,797,798,799,802],{},"sent as ",[422,800,801],{},"xi-api-key","; the key stays on the server",[442,804,805,810],{},[460,806,807],{},[422,808,809],{},"endpoint",[460,811,812,813,816,817,820],{},"base URL, default ",[422,814,815],{},"https:\u002F\u002Fapi.elevenlabs.io","; a regional host such as ",[422,818,819],{},"https:\u002F\u002Fapi.eu.residency.elevenlabs.io"," goes here",[442,822,823,828],{},[460,824,825],{},[422,826,827],{},"modelId",[460,829,830,831],{},"the speech model, default ",[422,832,833],{},"eleven_multilingual_v2",[442,835,836,841],{},[460,837,838],{},[422,839,840],{},"voiceSettings",[460,842,843,846,847,850,851,850,854,850,857,850,860,496],{},[422,844,845],{},"voice_settings"," of every synthesis (",[422,848,849],{},"stability",", ",[422,852,853],{},"similarity_boost",[422,855,856],{},"style",[422,858,859],{},"speed",[422,861,862],{},"use_speaker_boost",[442,864,865,873],{},[460,866,867,850,870],{},[422,868,869],{},"id",[422,871,872],{},"label",[460,874,875,876,879,880,850,882,496],{},"the engine's id and label in ",[422,877,878],{},"engines()"," (default ",[422,881,474],{},[422,883,884],{},"ElevenLabs",[442,886,887,892],{},[460,888,889],{},[422,890,891],{},"voiceCacheMs",[460,893,894],{},"how long the voice list is kept (default five minutes)",[418,896,897,899,900,903,904,907,908,911,912,915,916,919,920,923,924,927,928,931,932,935,936,939,940,943],{},[422,898,878],{}," lists the voices of the account (",[422,901,902],{},"GET \u002Fv2\u002Fvoices",", every page up to a limit). A voice's ",[422,905,906],{},"lang"," is the locale of its first verified language, else that language, else its ",[422,909,910],{},"language"," label, else ",[422,913,914],{},"und",". ",[422,917,918],{},"synthesize"," posts the text to ",[422,921,922],{},"\u002Fv1\u002Ftext-to-speech\u002F{voice_id}"," as MP3 (",[422,925,926],{},"mp3_44100_128",") or WAV (",[422,929,930],{},"wav_24000",") and answers with the audio and the MIME type ElevenLabs sent. An engine or voice the account does not have is refused with ",[422,933,934],{},"404"," before any call. An error answer of ElevenLabs reaches the client with its own words (",[422,937,938],{},"ElevenLabs: 401 Invalid API key","). ",[422,941,942],{},"transcribe"," is not offered. The daily character budget of the speech route applies as for every provider.",[564,945,947],{"id":946},"wire-the-client","Wire the client",[569,949,951],{"className":571,"code":950,"language":573,"meta":574,"style":574},"import { audioFeature } from '@skaile\u002Fforge-editor-audio'\n\n\u002F\u002F Add it to the preset after the composites feature (it requires it).\nconst audio = audioFeature({ voice: { engine: 'elevenlabs', voice: '\u003Cvoice_id>' }, mixdownMode: 'concat' })\n",[422,952,953,972,976,981],{"__ignoreMap":574},[578,954,955,957,959,962,964,966,968,970],{"class":580,"line":581},[578,956,585],{"class":584},[578,958,589],{"class":588},[578,960,961],{"class":592}," audioFeature",[578,963,602],{"class":588},[578,965,605],{"class":584},[578,967,608],{"class":588},[578,969,424],{"class":611},[578,971,615],{"class":588},[578,973,974],{"class":580,"line":618},[578,975,648],{"emptyLinePlaceholder":647},[578,977,978],{"class":580,"line":644},[578,979,980],{"class":654},"\u002F\u002F Add it to the preset after the composites feature (it requires it).\n",[578,982,983,986,989,991,993,995,997,1000,1002,1004,1007,1009,1011,1013,1016,1018,1020,1022,1024,1027,1029,1032,1035,1037,1039,1042,1044,1046],{"class":580,"line":651},[578,984,985],{"class":664},"const",[578,987,988],{"class":592}," audio ",[578,990,671],{"class":588},[578,992,961],{"class":674},[578,994,677],{"class":592},[578,996,680],{"class":588},[578,998,999],{"class":683}," voice",[578,1001,687],{"class":588},[578,1003,589],{"class":588},[578,1005,1006],{"class":683}," engine",[578,1008,687],{"class":588},[578,1010,608],{"class":588},[578,1012,474],{"class":611},[578,1014,1015],{"class":588},"'",[578,1017,596],{"class":588},[578,1019,999],{"class":683},[578,1021,687],{"class":588},[578,1023,608],{"class":588},[578,1025,1026],{"class":611},"\u003Cvoice_id>",[578,1028,1015],{"class":588},[578,1030,1031],{"class":588}," },",[578,1033,1034],{"class":683}," mixdownMode",[578,1036,687],{"class":588},[578,1038,608],{"class":588},[578,1040,1041],{"class":611},"concat",[578,1043,1015],{"class":588},[578,1045,602],{"class":588},[578,1047,709],{"class":592},[436,1049,1050,1059],{},[439,1051,1052],{},[442,1053,1054,1057],{},[445,1055,1056],{},"Option",[445,1058,786],{},[455,1060,1061,1074],{},[442,1062,1063,1068],{},[460,1064,1065],{},[422,1066,1067],{},"voice",[460,1069,1070,1071,1073],{},"the voice ",[422,1072,531],{}," reads with; absent, or not offered by the service: the first voice of the surface's language, else the first voice",[442,1075,1076,1081],{},[460,1077,1078],{},[422,1079,1080],{},"mixdownMode",[460,1082,1083,1085,1086,1089],{},[422,1084,1041],{}," (default, one after the other) or ",[422,1087,1088],{},"overlay"," (all at once, as long as the longest)",[418,1091,1092,1093,1096],{},"The add-on carries its own small German and English tables for its notices (",[422,1094,1095],{},"audioTranslator(locale)","): the library's catalog is a closed set of keys.",[564,1098,1100,1101],{"id":1099},"read-aloud-audio-tts","Read aloud: ",[422,1102,531],{},[418,1104,1105,1106,1108,1109,1111,1112],{},"Offered on a Container block with a title whose body holds text, when the backend has a ",[422,1107,542],{}," capability. The body is read as plain text, one paragraph per body block. The result is a ",[422,1110,553],{}," block right after the text block, titled „Sprache: ",[1113,1114,1115],"title",{},"“, that holds the audio as its source. Its Derivation:",[436,1117,1118,1128],{},[439,1119,1120],{},[442,1121,1122,1125],{},[445,1123,1124],{},"Field",[445,1126,1127],{},"Value",[455,1129,1130,1142,1152,1162,1175,1188],{},[442,1131,1132,1137],{},[460,1133,1134],{},[422,1135,1136],{},"method",[460,1138,1139],{},[422,1140,1141],{},"tts",[442,1143,1144,1149],{},[460,1145,1146],{},[422,1147,1148],{},"from",[460,1150,1151],{},"the text block",[442,1153,1154,1159],{},[460,1155,1156],{},[422,1157,1158],{},"inputs.text",[460,1160,1161],{},"the text block, with the hash of its body Markdown at the time it was read",[442,1163,1164,1169],{},[460,1165,1166],{},[422,1167,1168],{},"inputs.voice",[460,1170,1171,1174],{},[422,1172,1173],{},"{ asset: 'voice:\u003Cengine>\u002F\u003Cvoice>' }"," with the hash of engine and voice; no block holds that asset, so the library reads the voice as unknown, never as changed",[442,1176,1177,1182],{},[460,1178,1179],{},[422,1180,1181],{},"inputHash",[460,1183,1184,1187],{},[422,1185,1186],{},"derivationFingerprint"," of method and input hashes",[442,1189,1190,1195],{},[460,1191,1192],{},[422,1193,1194],{},"activity",[460,1196,1197],{},[422,1198,1199],{},"{ id, agent: \u003Cengine>, at }",[418,1201,1202,1203,1206,1207,492,1210,1213],{},"Edit the text block and the recording reads ",[526,1204,1205],{},"veraltet",". Edit the recording's body and it reads ",[526,1208,1209],{},"bearbeitet",[422,1211,1212],{},"outputHash"," is sealed).",[564,1215,1217,1218],{"id":1216},"mixdown-audio-mixdown","Mixdown: ",[422,1219,491],{},[418,1221,1222,1223,1226,1227,1229,1230,1232,1233,1235,1236],{},"Offered on a Container block with at least two ",[526,1224,1225],{},"takes",": ",[422,1228,553],{}," blocks among its direct children that hold stored audio or video, in document order. A recording that is itself a mixdown is no take, so a second mixdown in the same container does not mix the first one in again. The method renders the block through the target ",[422,1231,491],{}," and adds the result as the last ",[422,1234,553],{}," child of the container, titled „Mixdown: ",[1113,1237,1238],{},"“.",[418,1240,1241],{},"The Derivation names one input per take:",[436,1243,1244,1252],{},[439,1245,1246],{},[442,1247,1248,1250],{},[445,1249,1124],{},[445,1251,1127],{},[455,1253,1254,1265,1274,1305],{},[442,1255,1256,1260],{},[460,1257,1258],{},[422,1259,1136],{},[460,1261,1262],{},[422,1263,1264],{},"mixdown",[442,1266,1267,1271],{},[460,1268,1269],{},[422,1270,1148],{},[460,1272,1273],{},"the audio asset of the first take",[442,1275,1276,1281],{},[460,1277,1278],{},[422,1279,1280],{},"inputs",[460,1282,1283,1286,1287,1290,1291,850,1294,1297,1298,1300,1301,1304],{},[422,1284,1285],{},"take-1"," … ",[422,1288,1289],{},"take-n"," in mixing order: ",[422,1292,1293],{},"{ from: { asset }, hash }",[422,1295,1296],{},"hash"," being the ",[422,1299,1296],{}," the take's media block recorded (",[422,1302,1303],{},"''"," when it has none, which reads as unknown)",[442,1306,1307,1311],{},[460,1308,1309],{},[422,1310,1181],{},[460,1312,1313],{},[422,1314,1315],{},"derivationFingerprint({ method: 'mixdown', inputs })",[418,1317,1318,1319,1322,1323,1326,1327,1330,1331,693],{},"When the audio of a take is replaced, the hash of its media block changes and ",[422,1320,1321],{},"derivationState"," with an ",[422,1324,1325],{},"inputHashOf"," reports the mixdown as ",[526,1328,1329],{},"stale",". The library's chrome, tree dot and row badge do this for every Derived block. When the first take is deleted the state is ",[526,1332,1333],{},"missing",[569,1335,1337],{"className":571,"code":1336,"language":573,"meta":574,"style":574},"import { mixdownDerivation, takesOfNode } from '@skaile\u002Fforge-editor-audio'\n\nconst takes = takesOfNode(containerNode)\nconst derivation = mixdownDerivation({ takes, createdAt: new Date().toISOString(), activityId: crypto.randomUUID() })\n",[422,1338,1339,1363,1367,1381],{"__ignoreMap":574},[578,1340,1341,1343,1345,1348,1350,1353,1355,1357,1359,1361],{"class":580,"line":581},[578,1342,585],{"class":584},[578,1344,589],{"class":588},[578,1346,1347],{"class":592}," mixdownDerivation",[578,1349,596],{"class":588},[578,1351,1352],{"class":592}," takesOfNode",[578,1354,602],{"class":588},[578,1356,605],{"class":584},[578,1358,608],{"class":588},[578,1360,424],{"class":611},[578,1362,615],{"class":588},[578,1364,1365],{"class":580,"line":618},[578,1366,648],{"emptyLinePlaceholder":647},[578,1368,1369,1371,1374,1376,1378],{"class":580,"line":644},[578,1370,985],{"class":664},[578,1372,1373],{"class":592}," takes ",[578,1375,671],{"class":588},[578,1377,1352],{"class":674},[578,1379,1380],{"class":592},"(containerNode)\n",[578,1382,1383,1385,1388,1390,1392,1394,1396,1399,1401,1404,1406,1409,1412,1414,1416,1419,1421,1423,1426,1428,1431,1433,1436,1439,1441],{"class":580,"line":651},[578,1384,985],{"class":664},[578,1386,1387],{"class":592}," derivation ",[578,1389,671],{"class":588},[578,1391,1347],{"class":674},[578,1393,677],{"class":592},[578,1395,680],{"class":588},[578,1397,1398],{"class":592}," takes",[578,1400,596],{"class":588},[578,1402,1403],{"class":683}," createdAt",[578,1405,687],{"class":588},[578,1407,1408],{"class":588}," new",[578,1410,1411],{"class":674}," Date",[578,1413,732],{"class":592},[578,1415,693],{"class":588},[578,1417,1418],{"class":674},"toISOString",[578,1420,732],{"class":592},[578,1422,596],{"class":588},[578,1424,1425],{"class":683}," activityId",[578,1427,687],{"class":588},[578,1429,1430],{"class":592}," crypto",[578,1432,693],{"class":588},[578,1434,1435],{"class":674},"randomUUID",[578,1437,1438],{"class":592},"() ",[578,1440,746],{"class":588},[578,1442,709],{"class":592},[1444,1445,1447],"h3",{"id":1446},"the-render-target","The render target",[418,1449,1450,1453,1454,850,1457,430,1460,1463,1464,1467,1468,1471,1472,1475,1476,1478,1479,693],{},[422,1451,1452],{},"audioMixdownTarget({ assets, label?, accepts?, ffmpeg? })"," accepts ",[422,1455,1456],{},"document",[422,1458,1459],{},"section",[422,1461,1462],{},"folder"," by default. A render request holds the container's JSON, so the target finds the takes itself with the same rule as the client (",[422,1465,1466],{},"takesOf","). It refuses a take whose asset belongs to another Document (",[422,1469,1470],{},"foreign-take","), because a render may only read the assets of the Document the user is allowed to read. Request option ",[422,1473,1474],{},"options.mode"," is ",[422,1477,1088],{}," or the default ",[422,1480,1041],{},[418,1482,1483,1484,1487],{},"The block action ",[526,1485,1486],{},"„Erzeugen als …“"," of the library lists the target on every Block type it accepts, so a mixdown can also be started from there; the derive method adds the Derivation.",[436,1489,1490,1503],{},[439,1491,1492],{},[442,1493,1494,1500],{},[445,1495,1496,1497,496],{},"Error code (",[422,1498,1499],{},"AudioError.code",[445,1501,1502],{},"Cause",[455,1504,1505,1523,1533,1543,1553],{},[442,1506,1507,1512],{},[460,1508,1509],{},[422,1510,1511],{},"ffmpeg-missing",[460,1513,1514,1515,502,1517,1519,1520,1522],{},"no ",[422,1516,501],{},[422,1518,505],{}," (or at ",[422,1521,501],{}," of the options)",[442,1524,1525,1530],{},[460,1526,1527],{},[422,1528,1529],{},"ffmpeg-failed",[460,1531,1532],{},"ffmpeg exited with an error, for example an input that is no audio",[442,1534,1535,1540],{},[460,1536,1537],{},[422,1538,1539],{},"too-few-takes",[460,1541,1542],{},"fewer than two takes",[442,1544,1545,1550],{},[460,1546,1547],{},[422,1548,1549],{},"take-missing",[460,1551,1552],{},"the audio of a take is not in the asset store",[442,1554,1555,1559],{},[460,1556,1557],{},[422,1558,1470],{},[460,1560,1561],{},"the audio of a take is stored with another Document",[418,1563,1564,1565,492,1568,1571,1572,1575,1576,1578],{},"Takes are user uploads, and ffmpeg recognises a format by its content, not its file name. Every input therefore gets ",[422,1566,1567],{},"-format_whitelist",[422,1569,1570],{},"INPUT_FORMATS",": mp3, wav, ogg, flac, mov\u002Fmp4\u002Fm4a, matroska\u002Fwebm, aac, aiff, ac3, amr, caf, asf) and ",[422,1573,1574],{},"-protocol_whitelist file",": an HLS playlist, a concat script or a DASH manifest that names other files or URLs is refused with ",[422,1577,1529],{}," instead of followed.",[418,1580,1581,1582,1584,1585,1588,1589,1592],{},"ffmpeg brings every input to 44.1 kHz stereo before it joins (",[422,1583,1041],{},") or sums (",[422,1586,1587],{},"amix",") them, and writes MP3 with ",[422,1590,1591],{},"libmp3lame",". The inputs are written to a temporary directory that is removed again, also after a failure.",[856,1594,1595],{},"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 .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 .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 pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}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);}",{"title":574,"searchDepth":618,"depth":618,"links":1597},[1598,1599,1600,1602],{"id":566,"depth":618,"text":567},{"id":946,"depth":618,"text":947},{"id":1099,"depth":618,"text":1601},"Read aloud: audio-tts",{"id":1216,"depth":618,"text":1603,"children":1604},"Mixdown: audio-mixdown",[1605],{"id":1446,"depth":644,"text":1447},"The add-on @skaile\u002Fforge-editor-audio: an ElevenLabs SpeechProvider, the derive methods audio-tts and audio-mixdown that make recording blocks with named Derivation inputs, and the render target audio-mixdown that mixes takes through ffmpeg.","md",null,{},{"icon":280},{"title":277,"description":1606},"OSzh4t6yGlK4_DiMwJjf9Q8PyMTW0NBq2jfMamtpKkM",[1614,1616],{"title":272,"path":273,"stem":274,"description":1615,"icon":275,"children":-1},"The add-on @skaile\u002Fforge-editor-typst: the render target typst-pdf that turns a Document or a paper into Typst markup, writes the bibliography as BibTeX, and compiles a PDF in one of four citation styles.",{"title":282,"path":283,"stem":284,"description":1617,"icon":285,"children":-1},"The add-on @skaile\u002Fforge-editor-slides: the Block types deck and slide, the pure HTML render contract, the render targets reveal-html, pptx and marp-md, the transfer transforms that turn blocks into slides, and the slide preview in the inspector.",1793219829640]