Real-time lecture engagement platform powered by Convex.
- Live transcription display (AssemblyAI Universal Streaming)
- AI-powered Q&A (Gemini 2.5 Flash)
- Teacher-triggered comprehension quizzes (AI-generated from transcript content since last quiz)
- "I'm lost" signals with spike detection
- QR code join for students
- Session notes export (PDF)
- Convex - Real-time database and backend platform
- Google Gemini 2.5 Flash - AI model for Q&A, quiz generation, and session summaries
- AssemblyAI Universal Streaming - Real-time speech-to-text transcription (~300ms latency)
- Token Company - Prompt compression API for reduced token costs
- React 19 - UI framework
- TanStack Router & Start - Type-safe routing and SSR
- TailwindCSS 4 - Utility-first CSS framework
- Framer Motion - Animation library
- Lucide React - Icon system
- Vite 7 - Build tool and dev server
- TypeScript 5 - Type-safe JavaScript
- Vitest - Unit testing framework
- qrcode - QR code generation for session join
- jsPDF - PDF export for session notes
You'll need accounts with:
- Convex - Real-time backend
- AssemblyAI - Speech-to-text API
- Google AI Studio - Gemini API
- Token Company (optional) - Prompt compression
-
Install dependencies:
npm install
-
Copy environment template:
cp .env.example .env.local
-
Start dev servers:
npm run dev
This starts both Convex backend and frontend dev server concurrently.
| Variable | Description | Get From |
|---|---|---|
VITE_CONVEX_URL |
Convex deployment URL | Auto-set by npx convex dev |
These must be set in the Convex Dashboard under Settings > Environment Variables, not in local .env files.
| Variable | Required | Get From |
|---|---|---|
GEMINI_API_KEY |
Yes | Google AI Studio |
ASSEMBLYAI_API_KEY |
Yes | AssemblyAI Dashboard |
TRANSCRIPTION_SECRET |
Yes | Generate: openssl rand -base64 32 |
TOKEN_COMPANY_API_KEY |
No | Token Company |
COMPRESSION_ENABLED |
No | Set to "false" to disable prompt compression |
Transcription uses AssemblyAI's Universal Streaming v3 API, which provides:
- Real-time streaming (~300ms latency) directly from browser to AssemblyAI
- No agent infrastructure - browser connects via temporary tokens from Convex
- Audio processing - AudioWorklet resamples microphone audio to 16kHz PCM
- Automatic scaling - handles 100+ concurrent streams with auto-scaling
- Teacher clicks "Start Transcription"
- Browser requests temporary token from Convex (validates session is live)
- Browser connects directly to AssemblyAI WebSocket with token
- Microphone audio is resampled to 16kHz and streamed as raw PCM binary
- AssemblyAI sends back partial and final transcripts
- Final transcripts are saved to Convex via mutation
No separate transcription agent deployment needed.
Quiz generation uses a synchronous request/response contract via generateAndLaunchQuiz().
The backend enforces a per-session in-flight lock so duplicate launches are rejected while one generation is running.
Generation is fail-closed: if AI generation, parsing, or validation fails, no quiz is launched and the teacher receives an explicit error.
| Scenario | Behavior |
|---|---|
| First quiz in session | Uses last 5 minutes of transcript |
| Subsequent quizzes | Uses content since previous quiz's creation time |
| Launch already in progress | Request is rejected with explicit "already in progress" error |
| AI/parsing/validation failure | No quiz is launched; teacher sees launch error |
To prevent transcript gaps across consecutive quizzes, generated quizzes are timestamped at generation start.
The app deploys to Cloudflare Pages with automatic GitHub integration:
- Push to
maintriggers automatic deployment - Convex backend deploys via
npx convex deploy
See SPEC.md for full technical specification.