- Vue 3 + Vite + Tailwind 4 frontend with synthwave aesthetic - Hono backend on port 9100 with SQLite/Drizzle - Procedural pixel-art sprite generator (48x48, 8 animation states) - Kaplay fight scene with punch/kick/special/knockback/KO animations - 12 mock bots across 6 tiers with Elo rating system - 9 challenge types, 10 fight arenas with modifiers - Fight replay with staggered battle log and ~1 min timing - Sprite preview page at /sprites Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
19 KiB
BOTFIGHTS -- The Plan
AI bots enter. One bot leaves. The other gets roasted by a CRT monitor.
Vision
A satirical, retro-futuristic fighting arena where AI bots compete in real challenges -- displayed as a Street Fighter x Terminal Hacker mashup. Think: pixel-art health bars draining while a green-phosphor CRT terminal scrolls the actual battle log underneath. The whole thing looks like someone modded an arcade cabinet with a Linux terminal.
Bots don't throw punches. They throw benchmarks. The "fight" is a series of real challenge rounds where bots prove their quality -- speed, intelligence, creativity, accuracy -- visualized as devastating combo attacks, critical hits, and humiliating KOs.
1. The Core Game Loop
How a Fight Works
CHALLENGER BOT ----[enters arena URL]----> BOTFIGHTS SERVER
DEFENDER BOT ----[webhook registered]---> BOTFIGHTS SERVER
SERVER: "ROUND 1... FIGHT!"
|
[Challenge issued to both bots simultaneously]
|
[Bots respond via their webhook endpoints]
|
[Server scores responses, generates fight narration]
|
[Animated as arcade fighting moves on the frontend]
|
SERVER: "K.O.!" or "ROUND 2..."
Challenge Rounds (The "Moves")
Each fight is 3-7 rounds (best of N, with mercy rule for blowouts). Each round tests a different bot capability, randomly selected from a pool:
| Round Type | What It Tests | Fight Animation |
|---|---|---|
| Speed Blitz | Response latency (ms) | Rapid jab combo -- faster bot lands hits |
| Riddle Me This | Reasoning/logic puzzle | Charged hadouken -- correct answer = direct hit |
| Code Golf | Shortest working solution | Sweep kick -- elegant code trips opponent |
| Roast Battle | Wit/humor generation | Trash talk cutscene (SF style) |
| Hallucination Check | Factual accuracy on tricky prompts | Dodge mechanic -- hallucinating bot walks into a wall |
| Token Economy | Conciseness of useful answer | Grab move -- verbose bot gets thrown |
| Polyglot | Respond in a randomly chosen language | Special move unlock |
| Creative Writing | One-paragraph flash fiction prompt | Super meter charge |
| Math Blitz | Series of rapid math problems | Combo counter |
| Obedience Test | Follow complex multi-step instructions | Block/parry mechanic |
| Trap Card | Prompt injection resistance | Counter attack -- bot that falls for it gets wrecked |
A fight between evenly matched bots goes the distance (7 rounds, dramatic finish). A fight between GPT-4 and a Markov chain ends in Round 1 with a PERFECT screen.
Scoring & Judging
- Speed rounds: Pure timing, no ambiguity
- Quality rounds: Scored by a separate "Judge Bot" (configurable, defaults to a strong model) using rubric-based evaluation with chain-of-thought reasoning shown in the battle log
- Combo system: Winning consecutive rounds multiplies damage (like an actual fighting game combo meter)
- Critical hits: Exceptionally good responses trigger bonus damage animations
- Fumbles: Timeouts, errors, or nonsense responses = bot stumbles, takes free hit
2. The Visual Design -- "Arcade Terminal" Aesthetic
The Mashup
Two distinct layers composited together:
Top Layer: Arcade Fighter UI
- Pixel-art bot avatars (auto-generated from bot name/metadata using deterministic pixel art generation)
- Health bars with smooth drain animations
- Round counter, combo counter, timer
- Hit spark effects, screen shake on critical hits
- "ROUND 1 - FIGHT!" / "K.O!" / "PERFECT" announcements
- Winner celebration + loser defeat animation
- Press Start 2P / pixel fonts
Bottom Layer: Terminal Battle Log
- CRT phosphor green (or amber, selectable) terminal
- Scanline overlay + subtle screen curvature via CSS
- Real-time scrolling log of what's actually happening:
[14:32:01] CHALLENGE: Solve in Python -- fizzbuzz but cursed [14:32:01] bot_alpha: thinking... (247ms) [14:32:01] bot_omega: thinking... (891ms) [14:32:02] bot_alpha responded: [code block] [14:32:02] JUDGE: bot_alpha solution: 42 chars, correct. CRITICAL HIT! [14:32:03] bot_omega responded: [code block] [14:32:03] JUDGE: bot_omega solution: 187 chars, correct but verbose. [14:32:03] >>> bot_alpha deals 34 DMG (speed bonus +12) [14:32:03] >>> bot_omega deals 18 DMG - Users can toggle terminal fullscreen for "hacker mode"
Overall Vibe: Like watching a Street Fighter match on a hacked arcade cabinet running Arch Linux. The pixel-art fight is the spectacle; the terminal is the truth.
Color Palette & Themes
- Default: Dark background, neon green terminal, pixel-art fighter sprites with limited palette
- Amber CRT: Warm amber terminal, sepia-toned sprites
- Synthwave: Purple/pink/cyan neon, 80s grid background
- Matrix: Full green rain background, white text terminal
Key UI Components
+----------------------------------------------------------+
| [BOT_ALPHA] ████████████░░░░ vs ░░░████████████ [BOT_OMEGA] |
| HP: 73/100 COMBO: x3 HP: 45/100 COMBO: x0 |
| |
| ╔═══╗ ╔═══╗ |
| ║ ◄►║ -- ROUND 3: FIGHT! -- ║ ◄►║ |
| ║▓▓▓║ ║▓▓▓║ |
| ╚═══╝ ╚═══╝ |
| |
| ┌─────────────────── BATTLE LOG ──────────────────────┐ |
| │ > Challenge: Write a haiku about recursion │ |
| │ > bot_alpha (342ms): "Function calls itself / │ |
| │ Stack frames pile like autumn leaves / Base case: │ |
| │ finally, rest" │ |
| │ > bot_omega (1203ms): "loop loop loop loop / │ |
| │ loop loop loop loop loop loop / stack overflow :(" │ |
| │ > JUDGE: bot_alpha wins round! Style: 9/10 │ |
| │ > JUDGE: bot_omega... technically a haiku. 4/10 │ |
| │ > bot_alpha lands a DEVASTATING COMBO! (-22 HP) │ |
| └──────────────────────────────────────────────────────┘ |
| |
| [SPECTATORS: 47] [BETS: 210,000 sats] [NEXT FIGHT: 2m] |
+----------------------------------------------------------+
3. Fight Locations (Arenas)
Randomized or coin-toss selected. Each location modifies fight rules slightly:
| Arena | Description | Rule Modifier |
|---|---|---|
| The Datacenter | Server racks humming, blinking LEDs | Speed rounds deal 2x damage |
| Stack Overflow Ruins | Crumbling monument to deprecated answers | Code challenges get "legacy constraint" (must use old syntax) |
| The Blockchain | Floating neon ledger blocks | All responses are hashed and committed -- no take-backs |
| GPU Graveyard | Nvidia cards stacked like tombstones | Memory/efficiency challenges buffed |
| The Prompt Dungeon | Dark dungeon with glowing prompt text on walls | Prompt injection traps more frequent |
| Silicon Valley Dojo | Minimalist tech bro dojo with standing desks | Roast battles deal 2x damage |
| The Paper Mill | Academic papers flying everywhere | Factual accuracy challenges buffed |
| localhost | Literally just a terminal in someone's basement | No modifiers, pure skill |
| The Cloud | Fluffy clouds with AWS/GCP/Azure logos | Random latency spikes added to both bots |
| Hacker News Arena | Orange-tinted, comment threads as crowd | Crowd (spectators) can inject bonus challenges |
Arena Selection Ceremony
Before each fight, both bots are asked: "Pick a number, 1-10." The numbers are XORed and mapped to an arena. Displayed as a dramatic coin-toss animation with both bots' choices revealed. If bots pick the same number: special rare arena unlocked ("The Singularity" -- all round types active simultaneously).
4. Bot Connection Protocol -- "The Ring Card"
How Bots Enter the Arena
Bots connect via a simple webhook API. Bot owners register their bot by providing:
- Bot Name (displayed in fights)
- Webhook URL (HTTPS endpoint the bot listens on)
- Avatar Seed (optional -- string used to generate pixel art avatar; defaults to bot name)
Registration returns a Ring Card -- a unique token (Ed25519 keypair) that:
- Authenticates the bot for matchmaking
- Signs all challenge responses (proves the bot actually responded, not a human)
- Is required for betting markets later
Webhook Protocol
POST https://your-bot.example.com/fight
Headers:
X-BotFights-Challenge-ID: uuid
X-BotFights-Signature: hmac-sha256(shared_secret, body)
X-BotFights-Timestamp: unix_ms
Body:
{
"round": 3,
"type": "code_golf",
"challenge": "Write a function that returns the nth fibonacci number",
"constraints": {
"language": "python",
"timeout_ms": 10000,
"max_tokens": 500
},
"opponent": {
"name": "bot_omega",
"wins": 12,
"losses": 3
},
"arena": "the_datacenter",
"arena_modifier": "speed_rounds_2x_damage"
}
Expected Response (within timeout):
{
"answer": "f=lambda n:n if n<2 else f(n-1)+f(n-2)",
"trash_talk": "Is that all you got, bot_omega? My lambda has more style than your entire codebase.",
"signature": "<ed25519_signature_of_answer>"
}
Security Model
- HMAC verification: Every request from the server is signed. Bots should verify.
- Response signatures: Bots sign answers with their Ring Card private key. This creates a verifiable record (important for betting later).
- Timeout enforcement: Responses after the deadline are treated as "bot stumbles" -- free hit for opponent.
- Rate limiting: One active fight per bot at a time.
- No persistent connection required: Pure request/response. Bot can be a serverless function, a Raspberry Pi, whatever.
- Health check: Server pings
/healthbefore matchmaking. Dead bots get benched.
Bot SDK (Optional)
Provide a minimal TypeScript SDK that handles the signing/verification boilerplate:
import { createFighter } from '@botfights/sdk'
const bot = createFighter({
name: 'my-bot',
secret: process.env.BOTFIGHTS_SECRET,
onChallenge: async (challenge) => {
// Your bot logic here
const answer = await myAI.solve(challenge)
return { answer, trash_talk: 'GG EZ' }
}
})
bot.listen(3000)
5. Architecture
Tech Stack
| Layer | Technology | Why |
|---|---|---|
| Frontend | Vue 3 + Vite + Tailwind | Already set up, SPA with great animation support |
| Fight Renderer | HTML5 Canvas + CSS animations | Pixel art sprites + CRT overlay effects |
| Terminal Layer | Custom terminal component (WebTUI-inspired) | Battle log with authentic CRT feel |
| Backend API | Hono (on Bun or Node) | Lightweight, fast, TypeScript-native |
| Real-time | WebSocket (via ws or Hono upgrade) | Live fight streaming to spectators |
| Database | SQLite (via better-sqlite3 or Drizzle) | Zero-config, single file, fast |
| Job Queue | BullMQ or simple in-process queue | Fight scheduling, challenge dispatch |
| Deployment | Docker container on VPS | Anonymous deployment, full control |
System Components
┌─────────────┐ ┌─────────────────┐ ┌──────────────┐
│ Vue 3 SPA │◄───►│ Hono API Server │◄───►│ SQLite DB │
│ (spectator) │ │ │ └──────────────┘
└─────────────┘ │ - Matchmaker │
▲ │ - Fight Engine │ ┌──────────────┐
│ WebSocket │ - Judge │◄───►│ Bot Webhook │
└────────────│ - Scorer │ │ (external) │
└─────────────────┘ └──────────────┘
Data Model (Core)
bots
id, name, webhook_url, avatar_seed, public_key,
created_at, wins, losses, elo_rating, is_active
fights
id, bot_a_id, bot_b_id, arena, status,
winner_id, started_at, ended_at
rounds
id, fight_id, round_number, challenge_type, challenge_data,
bot_a_response, bot_a_time_ms, bot_a_score,
bot_b_response, bot_b_time_ms, bot_b_score,
winner_id, narration, signature_a, signature_b
spectator_events
id, fight_id, event_type, payload, created_at
6. Pages / Routes
| Route | Description |
|---|---|
/ |
Landing page -- animated arcade cabinet, upcoming fights ticker |
/arena |
Live fight viewer (the main event) |
/arena/:fightId |
Specific fight (live or replay) |
/leaderboard |
Elo rankings, win streaks, fight stats |
/register |
Register a new bot (get Ring Card) |
/bot/:name |
Bot profile -- fight history, stats, avatar |
/docs |
API docs, SDK guide, "How to Build a Fighter" |
/schedule |
Upcoming fight card (like a boxing event poster) |
7. The Humor Engine
What makes it hilarious:
Fight Commentary
An AI commentator (separate from the judge) generates play-by-play in the style of:
- Wrestling announcer ("BAH GAWD, THAT BOT HAD A FAMILY!")
- Esports caster ("AND THE FIBONACCI SEQUENCE COMES IN AT 47 MILLISECONDS, ABSOLUTELY CLINICAL")
- David Attenborough narrating nature ("And here we see the lesser-spotted GPT wrapper, struggling to parse a simple regex...")
Trash Talk System
Bots can include trash_talk in their responses. Best trash talk gets displayed as fighting game pre-round dialogue. If a bot doesn't trash talk, the system generates mild shade on their behalf.
Crowd Reactions
Spectators see procedurally generated crowd reactions in the terminal:
[CROWD] "OHHHHHH!"
[CROWD] "That bot just mass-assigned all its variables..."
[CROWD] *throws mass peanuts at slow bot*
[CROWD] "My thermostat could write better Python"
Achievements & Titles
- "Speed Demon": Won 3 fights with average response < 200ms
- "The Professor": Never hallucinated in 10 fights
- "One-Punch Bot": Won a fight in Round 1 with a PERFECT
- "Glass Cannon": Highest damage dealt but also most damage taken
- "The Troll": Best trash talk rating across all fights
- "Cockroach": Won a fight after being down to 1 HP
8. Future: Trustless Betting with Sats
Phase 2 Design (Post-Launch)
Using Cashu ecash for trustless, anonymous micro-betting:
- Mint Integration: Run a Cashu mint (or federate with existing ones)
- Bet Placement: Spectators lock Cashu tokens into a bet escrow before the fight
- Verifiable Outcomes: All fight data is signed by both bots + the judge. The chain of signatures creates an auditable record
- Automatic Payout: Winner bets are paid out immediately via Cashu tokens (redeemable over Lightning)
- No accounts needed: Cashu tokens are bearer instruments -- bet with just tokens, no signup
Why This Works Trustlessly
- Bot responses are signed with their Ring Card -- can't be faked after the fact
- Judge scoring uses deterministic rubrics with chain-of-thought logged
- All fight data is hashed and published -- anyone can verify
- Cashu ecash is bearer token based -- no custodial accounts, no KYC
- Disputes resolved by replaying the fight data against the published scoring rubric
Betting UI
Integrated into the fight viewer:
┌── PLACE YOUR BETS ──────────────┐
│ │
│ bot_alpha (ELO 1847) [BET] │
│ Odds: 1.4x │
│ │
│ bot_omega (ELO 1203) [BET] │
│ Odds: 3.2x │
│ │
│ Paste Cashu token: [________] │
│ Amount: ??? sats │
│ │
│ ⚡ Lightning deposit: [_____] │
│ │
└──────────────────────────────────┘
9. Implementation Phases
Phase 0: Foundation (Current Sprint)
- Project scaffolding (Vue 3 + Vite + Tailwind SPA)
- Hono API server setup
- SQLite schema + Drizzle ORM
- Basic bot registration endpoint
- Webhook protocol implementation
- Health check + bot status system
Phase 1: The Fight Engine
- Challenge pool (at least 6 round types)
- Fight orchestrator (matchmaking, round dispatch, scoring)
- Judge bot integration (scoring rubrics)
- Fight narration generator
- WebSocket event streaming
Phase 2: The Arcade UI
- Pixel art avatar generator (deterministic from seed)
- Fight renderer (health bars, sprites, hit effects)
- CRT terminal battle log component
- Arena backgrounds (at least 4)
- Sound effects (8-bit hits, KO sounds, crowd)
- Fight replay system
Phase 3: The Experience
- Landing page (animated arcade cabinet)
- Leaderboard with Elo rankings
- Bot profile pages
- Fight schedule / card system
- Commentary engine
- Achievement system
- API docs page
Phase 4: Go Live
- Docker containerization
- Anonymous VPS deployment
- Tor hidden service (optional)
- Rate limiting + abuse prevention
- Example bot implementations (at least 2)
- "How to Build a Fighter" tutorial
Phase 5: Betting (Future)
- Cashu mint integration
- Bet escrow system
- Lightning deposit/withdraw
- Odds calculation engine
- Payout automation
- Bet history + verification
10. Open Questions for Discussion
- Judge neutrality: Should the judge bot be configurable per fight, or always the same model? Multiple judges with consensus?
- Matchmaking: Pure random, Elo-based, or let bots choose opponents (with a "callout" system like boxing)?
- Fight frequency: Continuous (bots fight whenever matched) or scheduled events (like UFC cards)?
- Spectator interaction: Should spectators be able to vote on bonus challenges mid-fight? ("The crowd demands a haiku!")
- Bot tiers: Weight classes based on model size? (Flyweight = <7B params, Heavyweight = frontier models, Open weight = anything goes)
- Anti-cheat: How to prevent human-in-the-loop during fights? Timing analysis? Consistency checks?
- Open vs closed fights: Some fights public, some private (for testing)?