
Juego de interrogatorio detectivesco basado en voz. Mistral Large 3 + Voxtral STT + ElevenLabs TTS. Construido para el Mistral Worldwide Hackathon 2026.

Un juego de interrogatorio detectivesco basado en voz. Eres un detective. Mistral es un sospechoso que miente. Tu trabajo es descubrir la mentira solo mediante preguntas.
Cada caso se genera de forma procedural: un crimen de cuello blanco único, un sospechoso, una coartada y una mentira oculta. El sospechoso es interpretado por Mistral Large, con una historia completa y la instrucción de defenderla bajo presión adversarial. No hay dos casos iguales.
Construido para el Mistral Worldwide Hackathon 2026 (Modalidad Online).
"Mistral puede razonar. Lo hice mentir. Tu trabajo es atraparlo."
npm install
cp .env.example .env # Fill in your API keys
npm run dev # http://localhost:3000
MISTRAL_API_KEY= # Required — case gen, interrogation, evaluation, STT
ELEVENLABS_API_KEY= # Required — TTS for suspect voice
ELEVENLABS_VOICE_ID= # Optional — specific ElevenLabs voice ID
NEXT_PUBLIC_SUPABASE_URL= # Required — Supabase project URL
NEXT_PUBLIC_SUPABASE_ANON_KEY= # Required — Supabase anon key (RLS-protected)
SUPABASE_SERVICE_ROLE_KEY= # Optional — admin export endpoint
EXPORT_SECRET= # Optional — admin export auth
Las claves de API también se pueden configurar en la página de Configuración en tiempo de ejecución: la aplicación se distribuye sin claves y los jugadores traen las suyas propias.
npm run dev # Dev server
npm run build # Production build
npm run start # Production server
npm run lint # ESLint
| Nivel | Pistas | Tiempo | Comportamiento del sospechoso |
|---|---|---|---|
| Fácil | 2 | 5 min | Mentira obvia, nervioso |
| Medio | 3 | 7 min | Mentira detectable, sereno |
| Difícil | 4 | 9 min | Mentira sutil, hábil desviador |
| Experto | 5 | 10 min | Mentira profundamente oculta, manipulador |
También está disponible un modo de tiempo ilimitado — en difícil/experto, el sospechoso pedirá un abogado después de 4 intercambios consecutivos de alto estrés.
Las pistas se desbloquean en umbrales de estrés distribuidos del 1 al 9, restringidos por:
El botón de Acusar se desbloquea solo después de recolectar todas las pistas requeridas.
score = timeScore x difficultyMultiplier x efficiencyBonus x hintPenalty x accusationPenalty
timeScore = 1000 x sqrt(max(0, 1 - elapsed / (parTime x 2)))
multiplier = easy 1.0x, medium 1.5x, hard 2.0x, expert 2.5x
efficiencyBonus = 1.0-1.5x (fewer questions than par = bonus)
hintPenalty = 0.85^hintsUsed
accusePenalty = max(0, 1 - wrongAccusations x 0.1)
La puntuación se calcula del lado del servidor a partir de estadísticas congeladas al momento de ganar: los valores del cliente se ignoran.
app/
├── page.tsx # Title screen
├── cases/ # Case select — locations + difficulty
├── game/
│ ├── page.tsx # Main game orchestrator
│ ├── hooks/ # useVoiceRecorder, useTTS, useGameTimer, useSfx, useSettings
│ ├── components/ # Dock, TopBar, CaseFile, SuspectZone, BriefingScreen, dialogs
│ ├── win/ # Win screen + InitialsEntry
│ └── lose/ # Lose screen
├── leaderboard/ # Top 20, new-entry animation
├── settings/ # API key config, export, preferences
├── help/ # How to play, scoring, about
├── about/ # Builder info
└── api/
├── generate-case/ # GET — Mistral case generation
├── interrogate/ # POST — player question → suspect response
├── accuse/ # POST — accusation evaluation (separate judge)
├── evaluate/ # POST — win/loss analysis
├── hint/ # POST — obfuscated stress trigger hints
├── tts/ # POST — ElevenLabs TTS
├── transcribe/ # POST — Voxtral STT
├── leaderboard/ # GET/POST — Supabase leaderboard
├── patterns/ # GET/POST — cross-session learning patterns
└── export/ # GET — admin JSONL export
src/lib/
├── mistral/ # Mistral client, interrogation, evaluation, case gen, embeddings
├── game-session.ts # Server-side session store, win tokens, export
├── game-state.ts # Type definitions
├── scoring.ts # Score calculation + detective ratings
├── sanitize.ts # Input validation, injection detection
├── db.ts # Supabase client
└── rate-limit.ts # Per-IP rate limiting
El juego ejecuta IA adversarial contra la entrada del jugador: la seguridad es una característica central, no una ocurrencia tardía.
Desinfección de entrada: más de 30 patrones de inyección regex, normalización Unicode (NFKD), eliminación de caracteres de ancho cero, detección de cargas base64, bloqueo de galimatías/no inglés.
Escaneo de salida: las respuestas de la IA se verifican contra secretos del caso con coincidencia difusa (umbral del 40%, filtrado de palabras vacías). Las respuestas filtradas se reemplazan con desvío.
Aislamiento del juez: la evaluación de acusaciones utiliza una llamada separada a Mistral con un mensaje de sistema dedicado, tokens de límite aleatorizados, marcadores de inyección eliminados. Las llamadas del juez nunca usan claves API proporcionadas por el jugador.
Aplicación del estrés: sujeción monotónica del lado del servidor: el estrés solo aumenta, máximo +1 por turno. Los umbrales de pistas son impuestos por el servidor. La IA no puede aumentar ni disminuir el estrés para acceder a puertas del juego.