War ends only when the General dies.
A live tactical judgement engine where every order you issue is evaluated by Cixus, an AI Meta-Intelligence. Cowardice is punished. Brilliance is rewarded with Authority. There are no respawns. There is no undo.
- Overview
- Architecture
- Tech Stack
- Getting Started
- Environment Variables
- API Reference
- Project Structure
- Key Features
- Deployment
Cixus RAGE is a browser-based real-time war strategy game. Players are identified automatically by IP address — no registration required. Each war session is evaluated turn-by-turn by a Gemini-powered AI that scores your commands on tactical soundness, ethical weight, and risk profile.
Your Authority Level is the only resource that matters. Lose it all and the war ends.
Browser (React + Vite)
│
├── /api/v1/players/identify ← IP-based auth (no login required)
├── /api/v1/war/* ← War session management + command submission
└── /api/v1/players/* ← Player profile + reputation
│
FastAPI (Python)
│
SQLAlchemy (async)
│
┌────┴─────┐
│ SQLite │ (PostgreSQL to be implemented later on)
└──────────┘
│
Gemini AI (google-generativeai)
├── Tactic Orchestrator ← Parses & evaluates commands
├── Narrator ← Generates lore, preludes, commentary
└── Enemy AI ← Adversarial response generation
| Layer | Technology |
|---|---|
| Frontend | React 18, Vite, Framer Motion, Tailwind CSS, Lucide React |
| Backend | FastAPI, SQLAlchemy (async), Pydantic, Uvicorn |
| Database | PostgreSQL (production) / SQLite (local dev) |
| AI | Google Gemini (google-generativeai) |
| Auth | IP-based identity (no accounts, no passwords) |
| Hosting | Vercel (frontend) + Railway/Render (backend) |
Prerequisites: Python 3.11+
# 1. Install dependencies
pip install -r requirements.txt
# 2. Copy and fill in environment variables
cp .env.example .env # see Environment Variables section below
# 3. Initialise the database (creates cixus.db for local SQLite dev)
python init_db.py
# 4. Start the development server
uvicorn app.main:app --reloadThe API will be available at http://localhost:8000.
Interactive docs: http://localhost:8000/docs
SQLite note: The default
DATABASE_URLfalls back tosqlite+aiosqlite:///./cixus.dbfor zero-config local development. For production, always setDATABASE_URLto a persistent PostgreSQL connection string.
Prerequisites: Node.js 18+
cd frontend_app
# Install dependencies
npm install
# Start the dev server (proxies API to localhost:8000)
npm run devFrontend runs at http://localhost:5173.
Create a .env file in the project root:
# ── Database ──────────────────────────────────────────────────────────────────
# Leave blank to use local SQLite (development only — NOT persistent on serverless)
DATABASE_URL=postgresql+asyncpg://user:password@host:5432/cixus_rage
# ── AI ────────────────────────────────────────────────────────────────────────
GEMINI_API_KEY=AIza...
# ── Security ──────────────────────────────────────────────────────────────────
SECRET_KEY=change_me_in_production
⚠️ Important: IfDATABASE_URLis not set, the app falls back to a local SQLite file. On serverless platforms (Vercel, Railway ephemeral instances), this file is wiped on every cold start, causing players to lose their identity. Always configure a persistent Postgres database for production.
Full interactive docs: http://localhost:8000/docs
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/players/identify |
IP-based login/register. Accepts optional { player_id } body. |
GET |
/api/v1/players/whoami |
Debug: shows the IP + headers the server detects. |
GET |
/api/v1/players/{player_id} |
Fetch player profile. |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/war/ |
Start a new war session. |
GET |
/api/v1/war/active?player_id=… |
List active wars for a player. |
GET |
/api/v1/war/{war_id}/state |
Get current battlefield state. |
POST |
/api/v1/war/{war_id}/command |
Submit a command ({ type, content }). |
The /identify endpoint uses a 3-layer lookup:
player_idfrom the request body (most reliable — survives IP changes and VPN)- IP address (fallback — normalises IPv4-mapped IPv6, strips ports, supports Cloudflare)
- Create new player — only if both lookups fail
cixus/
├── app/
│ ├── api/v1/
│ │ ├── player.py # IP-based auth, /identify, /whoami
│ │ └── war.py # War session CRUD + command submission
│ ├── core/
│ │ └── config.py # Pydantic settings, DATABASE_URL fallback
│ ├── db/
│ │ └── base.py # Async engine + session factory
│ ├── models/
│ │ ├── player.py # Player model (ip_address, authority, reputation)
│ │ └── war.py # WarSession model
│ ├── services/ai/
│ │ ├── orchestrator.py # Tactic parsing + Cixus judgment
│ │ └── narrator.py # Lore generation, preludes, commentary
│ └── main.py # FastAPI app + lifespan + DB migration
│
├── frontend_app/
│ └── src/
│ ├── pages/
│ │ ├── Landing.jsx # Landing page with tactics showcase
│ │ ├── Dashboard.jsx # Player hub, active wars, reputation
│ │ └── GameContainer.jsx # War room (map, logs, commands, tactics)
│ ├── components/
│ │ ├── TacticsShowcase.jsx # Landing page tactics section (31 tactics)
│ │ ├── TacticsPanel.jsx # War room tactics sidebar/tab
│ │ ├── TypewriterText.jsx # Typewriter animation component
│ │ └── ErrorToast.jsx # Toast notification system
│ └── utils/
│ └── SoundEngine.js # Web Audio API synthesized sound effects
│
├── init_db.py
├── requirements.txt
└── README.md
No accounts, no passwords. Your IP is your identity. Includes fallback by stored player_id from localStorage so returning players survive IP changes, VPN toggling, and DHCP reassignment.
Every command is parsed and evaluated by Gemini AI (orchestrator.py). The AI extracts:
- Intent pattern (e.g. Feigned Retreat, Deep Maneuver, Encirclement)
- Risk profile (low / elevated / high / critical)
- Ethical weight (standard / controversial / war crime)
- Authority delta — how many AP you gain or lose for this move
Available on both the Landing page and in the War Room:
- 5 prominently displayed "pinned" tactics with goal, required attribute, and difficulty bar
- 26 additional tactics accessible via search + dropdown
- Hover dossier tooltips with historical examples and when-to-use guidance
Web Audio API synthesized sounds (no external files):
- War start, command transmit, Cixus judgment, authority gain/loss, enemy comms intercept, low-authority alarm, tactic select
- Mute toggle (🔊/🔇) in the war room header; preference persists in
localStorage
Players build reputation through warfare. Reputation metrics (traits + percentages) are stored in the Player model and displayed on the Dashboard with animated progress bars.
- Set
DATABASE_URLto a persistent Postgres connection string - Set
GEMINI_API_KEY - Set
SECRET_KEY - Deploy with:
uvicorn app.main:app --host 0.0.0.0 --port $PORT
The Procfile is already configured for Heroku-compatible platforms:
web: uvicorn app.main:app --host 0.0.0.0 --port $PORT
- Connect the GitHub repository
- Set Root Directory to
frontend_app - Build command:
npm run build - Output directory:
dist - Set
VITE_API_URLenv var (if your API is not on the same origin)
| Tool | Purpose |
|---|---|
GET /api/v1/players/whoami |
Check what IP the server detects (production debug) |
GET /api/v1/war/{war_id}/state |
Inspect raw battlefield JSON |
python debug_request.py |
Test API locally |
python test_db_connection.py |
Verify database connectivity |
Server logs (print statements in player.py) |
Show IP + player_id resolution path |