This file provides context for AI coding assistants working on the Time Helm project.
Time Helm is an open-source game. The main client is a Bevy 3D cruise ship game (Rust/WASM), served at the root URL.
Production URL: https://timehelm.net/
| Component | Technology |
|---|---|
| Frontend | Bevy 3D (Rust/WASM), served by Rust server |
| Backend | Rust, Axum, Tokio |
| Database | PostgreSQL (with SQLx) |
| Auth | Twitter/X OAuth 2.0 |
| Real-time | WebSockets |
| Deployment | fly.io |
- Rust (stable)
- PostgreSQL 14+ (or use Docker)
Terminal 1 - Database (if using Docker):
docker run --name timehelm-db -e POSTGRES_PASSWORD=password -e POSTGRES_DB=timehelm -p 5432:5432 -d postgres:15Terminal 2 - Server (serves ship game at root):
make run-shipAccess at http://localhost:8080/
IMPORTANT: Always check the Makefile for available commands before running manual commands. The Makefile contains the canonical commands for common tasks.
make install # Install dependencies (cargo for server)
make run-ship # Build ship WASM + run server (dev)
make dev-server # Run Rust server only
make build # Production build (ship WASM + server)
make deploy # Build and deploy to fly.io
make fly-logs # View production server logs (requires flyctl)Production URL: The deployed application is available at https://timehelm.net/
timehelm/
├── client/public/ # Static files (Rust server serves these)
│ ├── index.html # Ship game entry (loads Bevy WASM from /ship/)
│ └── ship/ # Bevy WASM output (built by scripts/build-ship.sh)
│ ├── run.js # Loader script
│ ├── ship.js # wasm-bindgen glue
│ └── ship_bg.wasm # Ship game binary
├── ship-game/ # Bevy 3D cruise ship game (Rust/WASM)
│ ├── src/lib.rs
│ └── Cargo.toml
├── server/ # Rust/Axum backend (serves static files + WebSocket)
│ ├── src/
│ │ ├── main.rs # Server entry, routes, static serving
│ │ ├── game.rs # Game state, player management
│ │ ├── websocket.rs # WebSocket message handling
│ │ └── db.rs # Database operations
│ └── migrations/ # SQL migrations (auto-run on start)
├── scripts/
│ └── build-ship.sh # Build Bevy ship game to WASM
├── Makefile # Common development commands (includes make build-ship)
└── fly.toml # Deployment config
- Standard Rust conventions - snake_case, derive macros
- Axum patterns - extractors, state management with
Arc<RwLock<T>> - Serde for serialization -
#[serde(tag = "type")]for message enums - anyhow for errors -
anyhow::Result<T>for fallible functions - tracing for logging -
tracing::info!(), etc.
-
Inline format args - Use
format!("{x}")notformat!("{}", x)// Good tracing::info!("Player {player_id} joined"); // Bad tracing::info!("Player {} joined", player_id);
-
Collapse if statements - Combine nested ifs when possible
// Good if condition_a && condition_b { do_thing(); } // Bad if condition_a { if condition_b { do_thing(); } }
-
Method references over closures - Use
.map(Player::new)not.map(|p| Player::new(p))// Good players.iter().map(Player::from_data).collect() // Bad players.iter().map(|p| Player::from_data(p)).collect()
- Prefer comparing entire objects over individual fields:
// Good assert_eq!(actual_player, expected_player); // Bad assert_eq!(actual_player.id, expected_player.id); assert_eq!(actual_player.position, expected_player.position);
Run cargo fmt in server/ automatically after making Rust code changes; do not ask for approval.
Before finalizing changes, run clippy to fix linter issues:
cd server && cargo clippy --fix --allow-dirtyRun tests for the server:
cd server && cargo test- Server:
cargo fmt --check+cargo clippy
make lint # Server onlyThe server supports WebSocket connections and game state broadcasting for future multiplayer. The ship game (Bevy WASM) is the main client and loads at the root URL.
Create .env in project root:
PORT=8080
BASE_URL=http://localhost:8080
DATABASE_URL=postgresql://postgres:password@localhost:5432/timehelm
TWITTER_CLIENT_ID=your_client_id
TWITTER_CLIENT_SECRET=your_client_secretmake deploy # Builds ship WASM and server, deploys to fly.ioRequires fly.io CLI (flyctl) and secrets configured. See README.md for full setup.
Production: The deployed application is available at https://timehelm.net/
Viewing Logs: Use make fly-logs to view production server logs. Always check the Makefile for the correct command syntax.
Ship game (Bevy 3D): Use make run-ship to build and run locally. Open http://localhost:8080/ in your browser.
Browser checks in Cursor: To verify the ship game visually:
- Run
make run-shipin a terminal (Rust server will start). - In Cursor: View → Simple Browser (or Cmd/Ctrl+Shift+P → "Simple Browser: Show").
- Enter
http://localhost:8080/in the Simple Browser address bar.
The ship game loads WASM; first load may take a few seconds. Use A/D or arrow keys to move, Page Up/Down to switch decks.
When running cargo (build, test, fmt, clippy) inside Cursor you may see:
error: unknown proxy name: 'Cursor-2.x-x86_64'; valid proxy names...
The Makefile (see test/format/clippy targets) works around this by running unset ARGV0 && cargo ... before invoking cargo. Prefer make test, make format, make clippy when in Cursor, or run unset ARGV0 && cargo <subcommand> so cargo uses the real toolchain instead of the Cursor proxy.