TurboShells
Real-time turtle racing simulation with genetic breeding and procedural rendering
The Problem
Create a full-stack web application that simulates turtle racing with genetic breeding mechanics. Turtles evolve shell patterns through Mendelian inheritance while racing in real-time. The challenge was syncing a real-time simulation (30Hz server-side) with a smooth 60Hz web frontend without overwhelming the network.
My Approach
- → Hexagonal architecture separating presentation, domain logic, and data layers
- → React + Vite frontend with PixiJS for efficient 2D rendering
- → FastAPI + SQLModel backend with WebSocket real-time communication
- → Genetic algorithm for turtle trait inheritance (shell patterns, speed)
- → SQLite persistence for race history and breeding records
- → Protocol Buffers for efficient binary serialization over WebSocket
Key Highlights
- Fully deployable to Vercel (frontend) and Railway (backend)
- Real-time simulation: 30Hz server physics → 60Hz client render
- Clean hexagonal architecture (easy to extend and test)
- Complete documentation with architecture diagrams
- SQLite database tracks 1000+ races without slowdown
How It Works
TurboShells is my showcase project for full-stack web architecture. It’s a deceptively simple idea—turtles race and breed—implemented with production-grade patterns.
The Concept
Imagine a racing game where victory doesn’t make you fast; it makes your offspring fast. Each turtle inherits traits (shell pattern, speed, acceleration) from parents. Winners breed, creating a population that evolves toward faster racers. Watch as the web UI displays real-time evolution.
Why This Project?
TurboShells demonstrates:
- Full-stack competence: I can build from database schema to React components
- Real-time systems: WebSocket sync at scale without race conditions
- Architecture thinking: Hexagonal design = code that’s easy to test and extend
- Deployment: Everything deploys to free tiers (Vercel + Railway)
Architecture Deep Dive
Backend (FastAPI):
- Manages turtle state and race simulation (30 ticks per second)
- SQLModel ORM for clean database queries
- WebSocket endpoint broadcasts race events in real-time
- Genetic algorithm applies Mendelian inheritance rules
Frontend (React + PixiJS):
- Renders turtles, tracks, shell patterns at 60 FPS
- WebSocket listener updates state incrementally
- Vite bundler keeps bundle size under 150KB
- Responsive design works on mobile
Sync Protocol: Server sends turtle positions at 30Hz. Client interpolates to 60Hz rendering. This decoupling prevents “choppy” animation while keeping network bandwidth reasonable.
Genetic Mechanics
Each turtle has traits: shell color, shell pattern, speed, acceleration. When turtles breed, offspring inherit:
- Dominant/recessive genes (60% Dad’s speed, 40% Mom’s)
- Mutation chance (5% to randomly vary inherited traits)
- Phenotype = visible shell pattern, expressed behavior
Mathematically accurate without being tedious. Players intuitively understand “fast parents = faster kids.”
Deployment
Frontend: npm run build → Deploy /dist to Vercel. Free tier, auto-redeploy on git push.
Backend: Docker image → Railway container. Free tier includes 5GB persistent storage for SQLite.
Result: Production-grade full-stack app costs $0/month to run.
Why Hexagonal Architecture?
Traditional MVC couples everything. Hexagonal (ports & adapters) separates:
- Domain: Business logic (genetics, physics)—language agnostic
- Adapters: React (web), FastAPI (API), SQLModel (database)
- Ports: Abstract interfaces that adapters implement
This means I can swap out React for Vue, FastAPI for Django, without touching domain logic. Tests run 100x faster because they don’t hit the database.
Lessons Learned
This project taught me that architecture isn’t overhead—it’s acceleration. The first 10% of features took 60% of the time (architecture design). The remaining 90% took 40% (architecture pays off).
WebSocket real-time systems are deceptively hard. Naive approaches create race conditions. Proper sync requires idempotent state updates and careful ordering.
Full-stack ownership is powerful. I controlled every layer, which meant I could optimize end-to-end instead of fighting interfaces.