Eleven3 is a self-hosted SvelteKit 5 tinker bench for voice design and script generation. It proxies ElevenLabs APIs to deliver real-time TTS streaming, multivoice dialogue parsing, and UI-driven audio testing.
🚀 Quick Start
# Clone/enter directory and spin up local playground
cd /home/dv/dev/eleven3
npm install && npm run dev🔧 Configuration
.envSecrets: Must containELEVENLABS_API_KEY. Never expose this key directly to the client bundle.- Gateway Auth: Secure all routes via
src/hooks.server.ts. Validate an injectedeleven3_authcookie to prevent API quota hijacking.
📦 Dependencies
| Layer | Core Package | Purpose |
|---|---|---|
| Framework | SvelteKit 5 | SSR, routing, server-side API proxy. |
| State | Svelte 5 Runes | Global $state() stores (eleven.svelte.ts). |
| UI | Skeleton UI | Styled components, layout primitives. |
| Audio | WaveSurfer.js | Playback engine, waveform visualization. |
💡 Best Practices (Patterns)
- Centralized Rune State: Isolate all UI states into modular stores (e.g.,
voiceState,playerState) using Svelte 5$state()primitives. This ensures UI-wide reactivity without prop-drilling. - Stream Proxies: Route requests through
/api/elevenlabs/tts?stream=trueto hide the API key. PassResponse(response.body)chunks directly to the client for immediate playback. - Sequential Batching: Throttle batch processors or script readers to execute tasks sequentially. Concurrent
Promise.allfloods trigger hard ElevenLabs rate limits. - Script Syntaxing: Map character names to voice IDs dynamically using regex
^(.+?):\s*(.+)$. Leverage inline mood tags (e.g.,[angry]) to push model emotiveness. - Voice Caching: Fetch the massive ElevenLabs voice payload strictly once upon application mount. Cache it globally to eliminate network thrashing during component navigation.
🚨 Gotchas / Warnings (Anti-patterns)
- Waveform Memory Leaks: Forgetting to return
wavesurfer.destroy()inside theonMountor$effectcleanup phase creates orphaned DOM nodes. This rapidly exhausts browser memory on rerenders. - SSR Hydration Crashes: Initializing UI history state directly from
localStorageduring SSR causes strict hydration mismatches. Always sync browser storage strictly inside client-side lifecycle hooks. - Blocking Execution: Omitting the
stream=truequery parameter forces the server to download the entire audio payload before sending it. This destroys real-time UI responsiveness. - Frontend Quota Leaks: Directly querying the ElevenLabs API from
.sveltefiles exposes your API key to the network tab. Always proxy through+server.tsendpoints.
🔍 Research / References
- Local Repository:
dev/eleven3 - Documentation Maps:
docs/cs/eleven3-cheat-sheet.md