Skip to content

AayuStark007/EvacSim-Public

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

EvacSim

Real-time crowd evacuation simulator for FIFA World Cup stadiums, built at HackCU 12 (March 2026).

Drop 500 people into a stadium. Start a fire. Watch them evacuate. AI responder agents β€” powered by Google Gemini β€” autonomously detect bottlenecks and reroute the crowd. A stadium PA system (ElevenLabs) announces emergencies in real-time. You control the chaos.


Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   FRONTEND  (Next.js + Canvas)                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Stadium    β”‚  β”‚  Control     β”‚  β”‚  Metrics  β”‚  β”‚  Gemini   β”‚ β”‚
β”‚  β”‚  Canvas     β”‚  β”‚  Panel       β”‚  β”‚  Dashboardβ”‚  β”‚  Chat     β”‚ β”‚
β”‚  β”‚  (rAF+Lerp)β”‚  β”‚  (Obstacles) β”‚  β”‚  (Stats)  β”‚  β”‚  (NL Q&A) β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚
β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β”‚
β”‚                          β”‚ WebSocket (20fps)                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   BACKEND  (Python FastAPI)                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚                   Simulation Engine                       β”‚    β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚    β”‚
β”‚  β”‚  β”‚ Crowd Agents β”‚  β”‚  Responder   β”‚  β”‚   Obstacle     β”‚ β”‚    β”‚
β”‚  β”‚  β”‚ (Flow Fields β”‚  β”‚  Agents (5-10β”‚  β”‚   Manager      β”‚ β”‚    β”‚
β”‚  β”‚  β”‚  + Steering) β”‚  β”‚  Gemini AI)  β”‚  β”‚   (Fire, Block)β”‚ β”‚    β”‚
β”‚  β”‚  β”‚  500 agents  β”‚  β”‚              β”‚  β”‚                β”‚ β”‚    β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                              β”‚                                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  WebSocket    β”‚  β”‚  Gemini API    β”‚  β”‚   ElevenLabs API   β”‚  β”‚
β”‚  β”‚  Manager      β”‚  β”‚  (5 endpoints) β”‚  β”‚   (PA + Narration) β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                    MongoDB Atlas                           β”‚   β”‚
β”‚  β”‚  (Scenarios, Runs, Responder Decisions)                   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Two-Tier Agent System

This is the defining feature that makes EvacSim a genuine multi-agent AI system:

Tier 1 β€” Crowd Agents (200-500, algorithmic): Lightweight particles following Dijkstra-based flow fields + steering behaviors. Each cell stores a direction vector toward the nearest exit β€” O(1) per agent per tick. Cheap to compute, smooth to render.

Tier 2 β€” Responder Agents (5-10, Gemini-powered): Autonomous AI decision-makers. Every ~3 seconds, each responder observes its local sector, calls Gemini for a tactical decision, and executes actions that directly mutate the simulation grid β€” causing hundreds of crowd agents to change direction. Actions include: redirect crowd flow, open emergency exits, deploy barricades (rendered as amber X-hatched barriers), or hold position. Responders spread across different bottlenecks using nearest-available assignment rather than all rushing to the same exit.


Tech Stack

Layer Technology
Frontend Next.js 14, React 18, TypeScript, Tailwind CSS v4, HTML5 Canvas, CSS Animations
Backend Python 3.12, FastAPI, async WebSocket, numpy
AI Google Gemini API β€” gemini-2.5-flash (real-time), gemini-2.5-pro (reports)
Voice ElevenLabs TTS API β€” streaming + pre-generated announcements
Database MongoDB Atlas via motor (async driver)
Pathfinding Dijkstra-based flow fields + A* fallback for stuck agents. Agents in fire immediately trapped.
Dev Tools Cursor, Google Antigravity

Quick Start

Backend

cd backend
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env    # Add your API keys
uvicorn main:app --reload --port 8000

Frontend

cd frontend
npm install
cp .env.example .env    # Defaults to localhost:8000
npm run dev

Open http://localhost:3000.

Environment Variables

backend/.env (copy from backend/.env.example):

GEMINI_API_KEY=your_gemini_api_key
ELEVENLABS_API_KEY=your_elevenlabs_api_key
ELEVENLABS_PA_VOICE_ID=pNInz6obpgDQGcFmaJgB
ELEVENLABS_NARRATOR_VOICE_ID=EXAVITQu4vr4xnSDxMaL
MONGODB_URI=mongodb+srv://user:password@cluster.mongodb.net/evacsim

frontend/.env (copy from frontend/.env.example):

NEXT_PUBLIC_WS_URL=ws://localhost:8000/ws
NEXT_PUBLIC_API_URL=http://localhost:8000

Project Structure

backend/
  main.py                   # FastAPI app, CORS, lifespan
  requirements.txt
  simulation/
    engine.py               # Fixed-timestep loop, state management, scenarios
    agent.py                # Crowd agent: position, velocity, steering, mobility types
    responder.py            # Responder agent: Gemini-powered AI decision-maker
    grid.py                 # Stadium grid: walls, exits, obstacles, flow weights
    pathfinding.py          # Dijkstra flow fields + A* fallback
    events.py               # Fire spread, timed obstacle injection
  routes/
    simulation.py           # WebSocket endpoint, sim control, responder loop
    scenarios.py            # Scenario + Run CRUD
    analysis.py             # Gemini analysis + NL query endpoints
    voice.py                # ElevenLabs TTS endpoints
  services/
    gemini.py               # Gemini API wrapper (5 integration points)
    elevenlabs.py           # ElevenLabs TTS wrapper
    db.py                   # MongoDB Atlas connection + operations
    analysis.py             # Structured analysis service
frontend/
  src/
    app/
      page.tsx              # Main simulation page
      layout.tsx            # Root layout, fonts, metadata
      globals.css           # Tailwind base + custom styles
    components/
      SimulationCanvas.tsx  # 2D stadium renderer (Canvas)
      ControlPanel.tsx      # Play/pause, speed, obstacle injection
      MetricsDashboard.tsx  # Evacuation stats, flow rates
      ResponderLog.tsx      # Live feed of AI responder decisions
      GeminiChat.tsx        # Natural language query interface
      VoiceStatus.tsx       # PA speaker indicator, audio controls
      ScenarioSelector.tsx  # Preset scenario dropdown
    hooks/
      useSimulation.ts      # WebSocket connection + ref-based state buffer
      useCanvas.ts          # requestAnimationFrame loop + lerp interpolation
      useAudio.ts           # Web Audio API playback for ElevenLabs
    lib/
      api.ts                # REST API client
      ws.ts                 # WebSocket client with auto-reconnect
      types.ts              # Shared TypeScript interfaces

API Reference

REST Endpoints

Method Path Description
GET /scenarios List built-in + saved scenarios
POST /scenarios Create a new scenario
GET /scenarios/{id} Load a specific scenario
GET /runs List past simulation runs
POST /runs Save a completed run
POST /analyze Trigger Gemini tactical analysis
GET /analysis Get structured analysis (JSON)
POST /query Natural language query to Gemini
POST /announce Generate ElevenLabs PA announcement
POST /generate-scenario Generate scenario from text description
POST /report Generate post-run Gemini Pro report
GET /health Health check with DB status

WebSocket Protocol

All messages are JSON with a type field.

Backend to Frontend:

Type Description
state_update Agent positions, responder positions, metrics (20fps)
responder_action Responder decision with action, params, reasoning
gemini_analysis Tactical analysis or query response text
audio_chunk Base64-encoded ElevenLabs audio
pa_announcement Text-only PA announcement (fallback)
simulation_complete Evacuation finished with final metrics

Frontend to Backend:

Type Description
start_simulation Start with { scenarioId }
pause_simulation Pause the tick loop
resume_simulation Resume from pause
inject_obstacle Add fire/blockage at position
remove_obstacle Remove obstacle at position
set_speed Set simulation speed multiplier
toggle_astar Enable/disable A* fallback for stuck agents
reset_simulation Reset to initial state
load_scenario Load a built-in scenario
load_custom_scenario Load a Gemini-generated scenario
query_gemini Ask a question about the simulation

Gemini API Integration (5 Points)

  1. Responder Agent Brain β€” Each responder calls Gemini Flash every ~3s with its local observation. Returns JSON action that directly mutates the simulation grid. This is autonomous AI action, not analysis.

  2. Tactical Analyst β€” Periodic dashboard-level analysis of evacuation state including responder performance evaluation.

  3. Natural Language Query β€” Chat interface where users ask about simulation state and responder behavior.

  4. Scenario Generator β€” Generates disaster scenarios from text descriptions as structured JSON.

  5. Post-Run Report β€” After-action review using Gemini Pro including responder agent performance analysis.

ElevenLabs Integration (2 Points)

  1. Stadium PA System β€” Male PA voice. Pre-generated common announcements at startup for zero latency. Dynamic event-triggered announcements streamed over WebSocket.

  2. Live Narration β€” Female narrator voice calls out every responder decision in real-time (~3-second cadence). Distinct from the PA voice so judges hear a steady stream of AI decision commentary during the demo.

MongoDB Atlas Integration (3 Points)

  1. Scenario Store β€” Stadium layouts, obstacle configurations, agent spawn points.
  2. Run History β€” Every simulation run saved with full metrics, bottleneck data, and responder logs.
  3. Responder Decision Log β€” Individual responder decisions with reasoning for analysis and replay.

Demo Scenarios

Scenario Agents Events Description
Standard Evacuation 300 None Baseline β€” normal evacuation, no incidents
North Stand Fire 400 2 fires Fire breaks out in the north stand at two ignition points
Exit B Collapse 500 Exit closure + fire Exit B collapses at tick 0, fire starts near south stand at tick 60

Key Design Decisions

Canvas Performance: Agent positions are written to a mutable useRef, never useState. A standalone requestAnimationFrame loop reads from the ref and draws to the Canvas with lerp interpolation (20fps server data rendered at 60fps). This prevents React virtual DOM reconciliation from freezing the browser.

Pure Tick Loop: The simulation tick is pure computation β€” no await, no I/O. Gemini calls, ElevenLabs, and MongoDB writes run in separate async tasks. The tick loop stays at a consistent 20fps.

Pydantic Validation: Every Gemini response passes through a ResponderDecision Pydantic model. On validation failure, responders fall back to hold_position. Raw LLM output never touches the simulation grid.

Parallel Decide, Sequential Apply: Responders call Gemini in parallel via asyncio.gather, but decisions are applied one at a time with conflict checks to prevent contradictory actions.

Responder Spatial Awareness: Idle responders are dispatched to the nearest unclaimed bottleneck rather than all converging on the worst one. Responders issuing redirect or open-exit commands stay in their sector β€” only barricade deployment physically moves a responder to the target location.

Fire Trapping: Agents on a fire cell are immediately marked trapped. Non-fire stuck agents get A* pathfinding rescue at 50 ticks, then are marked trapped at 200 ticks (~10 seconds) if still stuck.


Team

Built in 24 hours at HackCU 12 by a team of 4.

Side Prizes: Google Antigravity | Best Use of Gemini API | Best Use of ElevenLabs | Best Use of MongoDB Atlas

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors