Real voice, one key, one build.
Every mega-prompt in this repo uses the same pattern, because it's the only pattern that lets a Lovable account ship a streaming ElevenLabs demo in one shot.
Why ElevenLabs and not a stock browser voice?
The browser's built-in speechSynthesis sounds like 2007. ElevenLabs gives you broadcast-grade voices, multilingual models, low-latency turbo streaming, conversational agents over WebRTC, realtime scribe transcripts with word timestamps, and on-demand music + sound effects — all behind one HTTP API and one secret. That is the difference between a demo and a presentation that actually opens with sound.
The recipe
# 1. In your Lovable project, add the single required secret (Settings -> Secrets): ELEVENLABS_API_KEY=sk_... # https://elevenlabs.io/app/settings/api-keys # 2. Copy a mega-prompt from this repo into Lovable. One paste: # - scaffolds the React + TanStack Start app # - writes a server function that proxies ElevenLabs (TTS / agents / scribe / music) # - wires the client hook (useConversation / useScribe / <audio>) for the chosen kernel # - includes the hackathon credit in the footer and in JSDoc on the server fn # 3. Hit play. Your demo is streaming real voice from ElevenLabs.
1. The TTS server function
Every prompt in the library follows the same shape: keep the API key on the server with a TanStack createServerFn, forward the body to ElevenLabs, return base64 audio (or pipe the SSE stream) to the client.
// src/lib/tts.functions.ts — TanStack server function that streams ElevenLabs TTS
// Built during the Creative AI & Quantum Hackathon — StreetKode Fam · Indian Krump Festival 14
import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
export const speak = createServerFn({ method: "POST" })
.inputValidator((d) => z.object({ text: z.string().min(1).max(4000) }).parse(d))
.handler(async ({ data }) => {
const r = await fetch(
"https://api.elevenlabs.io/v1/text-to-speech/JBFqnCBsd6RMkjVDRZzb/stream?output_format=mp3_44100_128",
{
method: "POST",
headers: {
"xi-api-key": process.env.ELEVENLABS_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({ text: data.text, model_id: "eleven_turbo_v2_5" }),
},
);
if (!r.ok) throw new Error(`TTS failed: ${r.status}`);
const buf = await r.arrayBuffer();
return { audio: Buffer.from(buf).toString("base64") };
});
2. Conversational agent on the client
// src/components/voice-agent.tsx — useConversation over WebRTC
import { useConversation } from "@elevenlabs/react";
import { useServerFn } from "@tanstack/react-start";
import { mintAgentToken } from "@/lib/agent.functions";
export function VoiceAgent({ agentId }: { agentId: string }) {
const getToken = useServerFn(mintAgentToken);
const c = useConversation();
const start = async () => {
await navigator.mediaDevices.getUserMedia({ audio: true });
const { token } = await getToken({ data: { agentId } });
await c.startSession({ conversationToken: token, connectionType: "webrtc" });
};
return c.status === "connected"
? <button onClick={() => c.endSession()}>End conversation</button>
: <button onClick={start}>Start conversation</button>;
}
3. Music & SFX on demand
// src/lib/music.functions.ts — generate music or a sound effect on demand
import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
export const conjureSfx = createServerFn({ method: "POST" })
.inputValidator((d) => z.object({ prompt: z.string(), seconds: z.number().min(0.5).max(22).optional() }).parse(d))
.handler(async ({ data }) => {
const r = await fetch("https://api.elevenlabs.io/v1/sound-generation", {
method: "POST",
headers: { "xi-api-key": process.env.ELEVENLABS_API_KEY!, "Content-Type": "application/json" },
body: JSON.stringify({ text: data.prompt, duration_seconds: data.seconds ?? 5, prompt_influence: 0.3 }),
});
const buf = await r.arrayBuffer();
return { audio: Buffer.from(buf).toString("base64") };
});
Hackathon rules of thumb
- · One mega-prompt = one build message. Don't iterate the architecture, iterate the UI.
- · Keep the API key on the server. Browsers do not touch
xi-api-key. - · Stream by default.
eleven_turbo_v2_5for chat-speed playback,eleven_multilingual_v2when quality matters more than latency. - · Always show a microphone permission UX before opening realtime hooks, or browsers will silently block them.
- · Add a "Built during the Creative AI & Quantum Hackathon — StreetKode Fam · Indian Krump Festival 14" line to your footer.