The game architecture follows a client-server model with Rust handling the backend game logic and TypeScript managing the frontend rendering and user interactions.
Backend Architecture
The Rust server implements a real-time game engine using async WebSocket connections. One of the most innovative aspects is the dynamic unit loading system. Game units are defined as JSON files in a dedicated units directory, which are processed at compile time using a custom build script. This script reads all unit definitions and embeds them as static strings that are lazily deserialized into Unit structs when first accessed.
In the User struct, every player owns their WebSocket write channel, allowing the server to efficiently broadcast game state updates without complex routing logic. This design enables centralized read handling while maintaining direct, optimized write paths to each connected client.
Game Systems
The game features comprehensive tower defense mechanics including:
- Strategic unit placement with unique attributes (power, health, speed)
- Cooldown-based attack systems
- Economy and resource management
- Real-time multiplayer synchronization
Frontend Implementation
The TypeScript frontend uses the canvas for all rendering. It owns one end of the Client's websocket, and responds to enemy spawn events and damage ticks accordingly. Because we're using emojis for everything, that also means we don't need to handle any sprite or animation logic other than applying a cosine function to a text element for each unit.