| title | RoadCaster |
|---|---|
| emoji | ๐๏ธ |
| colorFrom | blue |
| colorTo | red |
| sdk | docker |
| app_port | 7860 |
| pinned | false |
A 3D highway driving game powered by a real-time Computational Linguistics engine โ
where Natural Language Generation and Text-To-Speech bring every near-miss to life.
RoadCaster is a browser-based 3D highway driving game with a twist: it has a brain.
Every time you swerve, dodge, overtake, or crash, the game sends a structured event to a custom Natural Language Processing backend that determines what just happened, how exciting it is, and what the commentator should say โ all in real-time, delivered as synthesized voice audio.
This is not a chatbot. This is not a text summarizer. This is applied Computational Linguistics inside a game.
Built for LingHacks VII โ the world's first computational linguistics hackathon for high schoolers.
Most games play background music. RoadCaster plays live commentary.
The challenge: how do you generate commentary that feels natural, contextual, non-repetitive, and timely โ all from raw game physics data?
The answer: CASCE โ the Context-Aware Sports Commentary Engine.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CASCE: The NLP Pipeline โ
โ โ
โ ๐ฎ Gameplay ๐ท๏ธ Context ๐งฎ Narrative ๐ Voice โ
โ โโโโโโโโโ โโโโโโโโโ โโโโโโโโโโ โโโโโโ โ
โ Physics Data โ Classification โ State Engine โ TTS Output โ
โ (speed, lane, (event type, (momentum, (Kitten TTS โ
โ proximity, danger level, transitions, 15M Nano โ
โ combo, time) context tags) anti-repeat) model) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Every frame, the frontend sends a structured event payload to the Flask backend:
{
"event": "extreme_near_miss",
"speed": 187,
"combo": 7,
"timestamp": 42.3,
"lane": 1
}The NarrativeEngine ingests a sliding 18-second window of events and computes:
| Context Tag | Trigger Condition |
|---|---|
pressure_rising |
Traffic density jumps from low โ heavy |
masterclass_streak |
20+ seconds of clean, uninterrupted driving |
high_speed |
Average speed > 150 km/h |
combo_5 |
Combo chain โฅ 5 consecutive near-misses |
This is the heart of CASCE. A priority-ordered rule engine maps the 18-second event window to one of 20 named narrative states:
flowchart TD
A[๐ฎ New Events Window] --> B{Has Crash?}
B -->|Yes| C[๐ฅ Crash]
B -->|No| D{Extreme Near Miss?}
D -->|Yes| E[๐ฑ Extreme Near Miss]
D -->|No| F{Combo โฅ 10?}
F -->|Yes| G[๐ฅ High Combo]
F -->|No| H{Near Misses โฅ 3?}
H -->|Yes| I[๐ฏ Clutch Survival]
H -->|No| J{Speed > 150 + Overtakes โฅ 5?}
J -->|Yes| K[โก Dominant Run]
J -->|No| L{Clean Driving โฅ 30s?}
L -->|Yes| M[๐ Total Control]
L -->|No| N[... 15 more states ...]
style C fill:#ff4444,color:#fff
style E fill:#ff8800,color:#fff
style G fill:#ff6600,color:#fff
style I fill:#cc4400,color:#fff
style K fill:#6644ff,color:#fff
style M fill:#22aa44,color:#fff
๐ All 20 Narrative States (click to expand)
| Priority | State | Trigger |
|---|---|---|
| 1 | ๐ฅ Crash | Player collides |
| 2 | ๐ฑ Extreme Near Miss | Dangerously close dodge |
| 3 | ๐ฅ High Combo | Combo chain โฅ 10 |
| 4 | ๐ฏ Clutch Survival | 3+ near-misses in window |
| 5 | ๐ฐ Panic Driving | High events, low speed |
| 6 | ๐ช๏ธ Traffic Chaos | 6+ events, high speed |
| 7 | Near miss + speed > 140 | |
| 8 | โก Elite Reactions | Combo โฅ 5 |
| 9 | ๐ก๏ธ Untouchable | Clean 15s + 4 overtakes |
| 10 | ๐จ Dominant Run | Speed > 150 + 5 overtakes |
| 11 | ๐ง Highway Wizard | 3 lane changes + 3 overtakes |
| 12 | ๐ช Traffic Surgeon | 2 lane changes + 2 overtakes, no near-misses |
| 13 | ๐ฏ Precision Driving | Clean 15s + lane changes + overtakes |
| 14 | ๐ Total Control | 30+ seconds clean |
| 15 | ๐ Masterclass | 25+ seconds clean |
| 16 | ๐ Flow State | 20s clean + 2 overtakes |
| 17 | ๐ธ Controlled Aggression | 4+ overtakes, no near-misses |
| 18 | ๐ Record Pace | Speed > 175 km/h |
| 19 | ๐ Building Momentum | 3+ overtakes |
| 20 | ๐ Traffic Weaving | 2+ lane changes |
flowchart LR
A[Narrative State] --> B[Template Pool]
B --> C{Last 10 Lines\nCache Check}
C -->|Template recently used| D[Filter it out]
C -->|Template is fresh| E[Select It]
D --> F{Any eligible\ntemplates left?}
F -->|Yes| E
F -->|No| G[Fallback: any random]
E --> H[Apply Memory Prefix]
H --> I[Final Commentary Line]
style C fill:#333,color:#fff
style E fill:#22aa44,color:#fff
style D fill:#cc4400,color:#fff
The anti-repetition gate ensures no commentary line is repeated within the last 10 spoken lines โ making the experience feel dynamic and fresh across a full session.
Context Memory Prefixes are prepended when special conditions are detected:
"The pressure is rising now! "โ when traffic density spikes"This has been a masterclass in control! "โ after a sustained clean streak
The frontend enforces a 2.5-second cooldown between commentary lines with a priority queue:
CRASH > EXTREME NEAR MISS > HIGH COMBO > NEAR MISS > OVERTAKE > NORMAL
This prevents voice-over overlap and ensures the most dramatic moments always get airtime.
sequenceDiagram
participant FE as ๐ฎ Frontend
participant BE as ๐ Flask Backend
participant NE as ๐ง NarrativeEngine
participant CE as ๐ฌ CommentaryEngine
participant TTS as ๐๏ธ KittenTTS Nano
FE->>BE: POST /api/narrative {events, speed, combo}
BE->>NE: evaluate(events, time, speed, combo)
NE-->>BE: {state, should_speak, context_tags, stats}
BE->>CE: generate(narrative_result, mode, voice)
CE-->>BE: {commentary_text, excitement, momentum}
BE->>TTS: synthesize(text, voice="Jasper")
TTS-->>BE: WAV bytes (24kHz mono)
BE-->>FE: {commentary, voice, excitement}
FE->>FE: Play WAV audio + update NLP debugger
The KittenTTS Nano (15M parameter model) synthesizes each commentary line to a 24kHz mono WAV and streams it back to the browser for immediate playback.
| Mode | Voice | Style | Example |
|---|---|---|---|
| ๐๏ธ Sports Broadcast | Jasper | High-energy, reactive, excited | "OH NO! A COLLISION! AAAAAAH! HA HA HA! GAME OVER!" |
| ๐ฌ Dramatic Narrator | Hugo | Cinematic, dark, reflective | "The highway always wins. In the end. Ha... ha... ha..." |
| ๐ Savage Critic | Kiki | Sarcastic, witty jabs | "HA HA HA! Wrecked! Hope you have insurance, because that was pathetic!" |
Each personality has its own full template library, excitement level mappings, and transition commentary for state changes.
graph TB
subgraph Frontend ["๐ Frontend (Three.js)"]
G[3D Game Engine] --> EQ[Event Queue]
EQ --> PQ[Priority Queue\n& Rate Limiter]
PQ --> AC[Audio Controller\nWeb Audio API]
G --> DB[NLP Pipeline\nDebugger Panel]
end
subgraph Backend ["๐ Backend (Flask)"]
API["/api/narrative"] --> NE
NE[NarrativeEngine\n18s Sliding Window] --> CE
CE[CommentaryEngine\n+ Anti-Repeat Gate] --> TTS
TTS[KittenTTS Nano\n15M params ยท 24kHz]
end
subgraph Storage ["๐พ State"]
EH[Event History\nList]
L10[Last 10 Spoken\nCache]
ST[Narrative State\nTracker]
end
PQ -->|POST /api/narrative| API
TTS -->|WAV bytes| AC
NE <--> EH
CE <--> L10
NE <--> ST
style Frontend fill:#1a1a2e,color:#fff
style Backend fill:#16213e,color:#fff
style Storage fill:#0f3460,color:#fff
| Layer | Technology | Purpose |
|---|---|---|
| 3D Game | Three.js 0.184.0 | WebGL highway rendering, vehicle meshes, physics |
| Frontend | Vanilla JS (ES Modules) | Event detection, queue management, audio playback |
| Styling | CSS3 + Glassmorphism | Dark mode UI with NLP debugger panel |
| Backend | Python 3.12 + Flask 3.0 | REST API, NLP pipeline orchestration |
| NLG | Custom Rule Engine | Narrative state classification, template selection |
| TTS | KittenTTS Nano (15M) | PyTorch/ONNX neural voice synthesis |
| Audio | NumPy + soundfile | PCM โ WAV conversion (16-bit, 24kHz, mono) |
| Package Manager | uv | Fast Python dependency management |
- Python 3.12+
uvpackage manager
# Clone the repository
git clone https://github.com/your-username/RoadCaster.git
cd RoadCaster
# Install all dependencies (including KittenTTS from GitHub release)
uv pip install -e .Note: The KittenTTS Nano model (~35MB weights) will be downloaded automatically on first startup.
python app.pyThen open http://localhost:5000 in your browser.
The project ships with a Dockerfile targeting port 7860 for HuggingFace Spaces deployment.
| Control | Action |
|---|---|
A / โ Arrow |
Switch to the left lane |
D / โ Arrow |
Switch to the right lane |
Space / โ Arrow |
Speed boost (hold) |
R |
Restart after crash |
Scoring tips:
- Getting as close as possible to traffic without hitting it builds your combo multiplier
- Sustained clean driving builds toward Masterclass and Total Control states
- Weaving through dense traffic at high speed unlocks Highway Wizard commentary
Press the toggle arrow on the right side of the screen to expand the live debugger. It shows:
- Real-time event JSON payloads from the game
- Active narrative state and context tags
- Current commentator voice and excitement level
- Momentum trend (rising / calm / falling)
RoadCaster/
โโโ app.py # Flask server + API routes
โโโ narrative.py # NarrativeEngine โ sliding window + state machine
โโโ commentary.py # CommentaryEngine โ template library + anti-repeat
โโโ action_narrator.py # ActionNarrator โ play-by-play physical action lines
โโโ game.py # Event schema validation
โโโ tts_provider.py # KittenTTS integration + WAV encoding
โโโ pyproject.toml # Project metadata + dependencies
โโโ Dockerfile # Container setup for HF Spaces
โโโ templates/
โ โโโ index.html # Game UI + Three.js 3D engine
โโโ static/
โโโ ... # Assets
LingHacks VII challenges teams to build software that integrates computational linguistics to solve a scientific or social problem. RoadCaster addresses this by:
-
Natural Language Generation (NLG) โ A custom rule-based engine maps game physics to narrative prose. No LLM required; the language emerges from structured linguistic templates and contextual logic.
-
Pragmatics & Context โ The commentary system models discourse context (commentator memory, anti-repetition), prosody cues (excitement levels passed to TTS), and temporal grounding (18-second event windows for situational awareness).
-
Text-to-Speech Synthesis โ KittenTTS demonstrates applied speech synthesis: the same text spoken by Jasper (energetic), Hugo (cinematic), or Kiki (sardonic) feels completely different, showing how prosody and voice personality shape meaning.
-
Human-Computer Interaction โ The NLP debugger panel makes the linguistics pipeline visible and legible, turning an invisible backend into an educational showcase of how NLG works in real time.
- ๐ Hackathon: LingHacks VII on Devpost
- ๐ค Live Demo: HuggingFace Spaces
- ๐ฆ KittenTTS: KittenML/KittenTTS
Made with โก and way too much caffeine at LingHacks VII