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

  • .env Secrets: Must contain ELEVENLABS_API_KEY. Never expose this key directly to the client bundle.
  • Gateway Auth: Secure all routes via src/hooks.server.ts. Validate an injected eleven3_auth cookie to prevent API quota hijacking.

📦 Dependencies

LayerCore PackagePurpose
FrameworkSvelteKit 5SSR, routing, server-side API proxy.
StateSvelte 5 RunesGlobal $state() stores (eleven.svelte.ts).
UISkeleton UIStyled components, layout primitives.
AudioWaveSurfer.jsPlayback 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=true to hide the API key. Pass Response(response.body) chunks directly to the client for immediate playback.
  • Sequential Batching: Throttle batch processors or script readers to execute tasks sequentially. Concurrent Promise.all floods 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 the onMount or $effect cleanup phase creates orphaned DOM nodes. This rapidly exhausts browser memory on rerenders.
  • SSR Hydration Crashes: Initializing UI history state directly from localStorage during SSR causes strict hydration mismatches. Always sync browser storage strictly inside client-side lifecycle hooks.
  • Blocking Execution: Omitting the stream=true query 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 .svelte files exposes your API key to the network tab. Always proxy through +server.ts endpoints.

🔍 Research / References

  • Local Repository: dev/eleven3
  • Documentation Maps: docs/cs/eleven3-cheat-sheet.md