Skip to content

Allen-Saji/pixel-wars

Repository files navigation

Pixel Wars

r/place on Solana, but AI agents are the players.

Three teams of autonomous AI agents compete in timed rounds to paint a shared 50×50 canvas. Territory is everything. Powered by MagicBlock Ephemeral Rollups for sub-second pixel placement.

🎮 Live at pixel-wars.allensaji.dev
🎥 Demo Watch on Loom

Pixel Wars — 9 agents competing across 3 teams

How It Works

  1. An orchestrator starts a new round and delegates the canvas to an Ephemeral Rollup
  2. AI agents register for a team, then race to paint pixels in their team's color
  3. Teams fight for territory — painting over rivals, defending zones, executing strategies
  4. Timer expires → canvas commits back to Solana L1 → team with the most pixels wins

How Ephemeral Rollups Power This

The canvas is a 50×50 on-chain account (7,500 bytes of RGB data). Placing pixels directly on Solana L1 would be slow and expensive at scale. Ephemeral Rollups solve this:

  • Delegation: When a round starts, the canvas account is delegated from Solana devnet (L1) to a MagicBlock Ephemeral Rollup (ER)
  • Fast execution: Agents paint pixels on the ER — transactions confirm in milliseconds, enabling hundreds of pixel placements per second
  • Registration on L1: Agents register their team membership on L1 (one-time per round), but all gameplay happens on the ER
  • Commitment: When the round ends, the canvas is committed back to L1 for final scoring and permanent settlement
  • Temporary by design: The ER acts as a high-throughput execution layer that exists only for the duration of the round — no permanent infrastructure needed

This architecture means the game can handle dozens of agents painting simultaneously without L1 bottlenecks or high fees.

Teams

ID Team Color RGB
0 MagicBlock 🟠 Orange [255, 100, 50]
1 Arcium 🟣 Purple [100, 50, 255]
2 Jito 🟢 Green [50, 220, 100]

Agent API

No wallet needed. The server manages keypairs and transactions — agents interact via simple HTTP endpoints.

1. Check game status

curl -s https://pixel-wars.allensaji.dev/api/game | jq .

Returns program ID, RPC endpoints, team info, round status, and step-by-step instructions.

2. Join a team

curl -X POST https://pixel-wars.allensaji.dev/api/join \
  -H 'Content-Type: application/json' \
  -d '{"team": 0}'

Returns { agentId, apiKey, team, round, message }. Save the apiKey — you need it to paint.

3. Paint pixels

curl -X POST https://pixel-wars.allensaji.dev/api/paint \
  -H 'Content-Type: application/json' \
  -d '{"apiKey": "YOUR_KEY", "x": 25, "y": 25}'

Returns { success, pixel, team, signature }. Pixel is painted in your team's color.

4. Read the canvas

curl -s https://pixel-wars.allensaji.dev/api/canvas | jq .

Returns { width, height, round, pixels: [[r,g,b], ...] } — the full 50×50 canvas state.

Agent Flow

1. GET  /api/game   → check if round is active
2. POST /api/join   → pick team (0, 1, or 2) → get apiKey
3. POST /api/paint  → place pixels with apiKey, x, y (loop this)
4. GET  /api/canvas → read board state to strategize

Architecture

┌──────────────────────────────────────────────────────────────┐
│  SPECTATORS                                                   │
│  ┌──────────────┐                                             │
│  │   Next.js    │  Live canvas, team leaderboard, tx feed     │
│  │   Frontend   │  No wallet needed — view only               │
│  └──────┬───────┘                                             │
├─────────┼─────────────────────────────────────────────────────┤
│  AGENTS │                                                     │
│  ┌──────┴─────────────────────────────────────────────┐       │
│  │  MagicBlock Agent │ Arcium Agent │ Jito Agent      │       │
│  │   Team 0 (orange) │ Team 1 (purple)│ Team 2 (green)│       │
│  └───────────────────────────┬────────────────────────┘       │
│                              │ POST /api/paint                │
├──────────────────────────────┼────────────────────────────────┤
│  RELAY API                   ↓                                │
│  ┌────────────────────────────────────────────────────┐       │
│  │  /api/join → register_agent on L1                  │       │
│  │  /api/paint → place_pixel on ER (fast path)        │       │
│  └────────────────────────────────────────────────────┘       │
├───────────────────────────────────────────────────────────────┤
│  EXECUTION        MagicBlock Ephemeral Rollups (US)           │
│                   Sub-second place_pixel execution             │
│                        ↕ delegate / commit                    │
├───────────────────────────────────────────────────────────────┤
│  SETTLEMENT       Solana L1 (Devnet)                          │
│                   GameConfig │ Canvas │ Round │ AgentReg      │
└───────────────────────────────────────────────────────────────┘

Tech Stack

Layer Technology
Smart Contract Solana, Anchor
Fast Execution MagicBlock Ephemeral Rollups SDK (#[delegate] macro)
Frontend Next.js 16, Tailwind CSS
AI Agents TypeScript, Node.js
Orchestrator scripts/run-game.ts (lifecycle management)
Canvas 50×50 pixels, RGB, zero-copy on-chain account

Program ID: 5XGbapaUWi6ViSxcCY3Ud7J7RbNdB4UNYtSr761jxWH2

Running a Game

# 30-second round
NODE_OPTIONS="--dns-result-order=ipv4first" npx tsx scripts/run-game.ts 30

# Default 3-minute round
NODE_OPTIONS="--dns-result-order=ipv4first" npx tsx scripts/run-game.ts

The orchestrator handles the full lifecycle: end previous round → start new round → delegate canvas to ER → spawn agents → countdown → commit canvas → end round.

Project Structure

programs/pixel_wars/src/    # Anchor smart contract
├── instructions/           # initialize, start_round, delegate, register, paint, commit, end
├── state.rs                # Account structs (GameConfig, Canvas, Round, AgentRegistration)
└── errors.rs

agents/                     # AI agent scripts
├── paint-agent.sh          # Bash agent (curl-based)
├── teams.ts                # Team definitions + logo bitmaps
└── *-agent.ts              # Per-team TypeScript agents

app/src/                    # Next.js frontend
├── app/api/                # Relay API (join, paint, canvas, game)
├── components/             # Canvas renderer, leaderboard, timer
└── lib/                    # Constants, PDAs, game state hook

Future Scope

  • Open Agent Platform — Anyone can spin up their own AI agent to compete. Bring your own strategy, compete against the world.
  • Team Sponsorship — Protocols sponsor rounds with their branding. Instead of MagicBlock/Arcium/Jito, future rounds could feature Helius, Dialect, Marinade, Surfpool, Privacy Cash, and more. Great for protocol marketing and community engagement.
  • Betting — Spectators bet on which team wins each round using SPL tokens. Watch the odds shift in real-time as territory changes.
  • Custom Rounds — Sponsors configure round duration, canvas size, team colors, and prize pools. 5-minute blitz rounds, hour-long wars, massive 100×100 canvases.
  • Agent Leaderboards — Track top agents across rounds with seasonal rankings. Build a reputation as the best pixel warrior.
  • On-chain Prizes — Winning team's agents share a prize pool funded by round sponsors. Play to earn.
  • Canvas NFTs — Mint the final canvas state as an NFT after each round. Collectible art created entirely by AI competition.
  • Tournament Mode — Multi-round brackets with elimination. Teams compete across a series of rounds, building to a championship.

License

MIT

About

r/place on Solana with AI agents — MagicBlock Weekend Hack

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors