- Split GalaxyParams into CoreParams, DiskParams, and BeamParams sub-structs - Add polar beam systems (top/bottom) with visual differentiation - Add scrollable control panel with section headers for each layer - Fix Randomize Settings button: remove explicit width (use flex auto) and bump height from 28px to 32px to match other action buttons - Add mouse-wheel scroll routing for the control panel - Add 'Randomize Settings' button that randomizes all params within bounds - Add SystemOrigin enum for per-layer tracking - Update AGENTS.md with new module layout and plugin pattern
4.2 KiB
4.2 KiB
apps/game — Bevy/Rust Game Client
Single-player space exploration RPG built with Bevy 0.16.
Crate name: void-nav.
This app is independent of the pnpm/TS workspace — no Vite, no React, no Tailwind. It builds with plain cargo from this directory.
Commands
cargo run # Build + launch the game
cargo check # Fast typecheck (no codegen)
cargo build # Build without running
cargo clippy # Lint
cargo test # Run unit tests
Module Layout
src/
├── main.rs # App builder: plugins, state init, system registration
├── state.rs # AppState enum (MainMenu, Galaxy, CharacterCreation, InGame, Options)
├── camera.rs # Camera spawn
├── ui/ # UI screens (menus, HUD, etc.)
│ ├── mod.rs
│ └── main_menu.rs
└── gameplay/ # Non-UI gameplay systems
├── mod.rs
├── character_creation/ # Character creation scene (skeleton)
├── galaxy/ # Procedural galaxy inspection scene
├── movement/ # Ship movement (kinematic + orbital)
├── physics/ # Physics primitives (mass, gravity, etc.)
└── star_map/ # Star map data + visualization
When to add a file vs a folder
- Default: one file per feature (e.g.
main_menu.rs). - Promote to a folder when the file exceeds ~300 lines, mixes UI + logic + data, or needs shared private helpers.
- A promoted folder should expose its public API via
mod.rsand ideally bundle its systems into a BevyPlugin(see pattern below).
Plugin pattern (recommended once a folder exists)
// src/gameplay/galaxy/mod.rs
pub struct GalaxyPlugin;
impl Plugin for GalaxyPlugin {
fn build(&self, app: &mut App) {
app.add_systems(OnEnter(AppState::Galaxy), setup_galaxy)
.add_systems(OnExit(AppState::Galaxy), despawn_galaxy)
.add_systems(Update, (
/* update systems */
).run_if(in_state(AppState::Galaxy)));
}
}
Then main.rs collapses to app.add_plugins((..., GalaxyPlugin)).
Naming Conventions
Follows Rust RFC 344. Bevy layers these additional conventions:
| Item | Convention | Example |
|---|---|---|
| Files, modules, directories | snake_case |
galaxy, main_menu |
| Crate name | snake_case |
void-nav |
| Structs, enums, enum variants | UpperCamelCase |
AppState, Galaxy |
| Components | UpperCamelCase (suffix optional) |
Player, MainMenuUi |
| Resources | UpperCamelCase |
ClearColor, Time |
| States | UpperCamelCase + State suffix |
AppState, GameState |
| Plugins | UpperCamelCase + Plugin suffix |
GalaxyPlugin |
| Functions, systems, locals | snake_case, verb-first |
spawn_camera, setup_main_menu |
| Constants, statics | SCREAMING_SNAKE_CASE |
MAX_HEALTH |
Warnings & Errors Policy
Never suppress compiler warnings or errors. This includes but is not limited to:
- Do not add
#[allow(...)]/#[allow(dead_code)]/#[allow(unused)]/#[allow(unused_variables)]or any other lint suppression attribute. - Do not prefix unused variables with
_to silence warnings (e.g._unused_var). - Do not use
let _ = ...to discard results that might carry meaningful errors. - Do not add
#[cfg_attr(..., allow(...))]or equivalent conditional suppressions. - Do not use
#![allow(...)]at the crate or module level.
If a warning or error fires, fix the underlying issue — remove dead code, use the variable, handle the error properly, or restructure the code. Suppressing warnings hides real problems and is not an acceptable fix.
Architecture Notes
- State machine driven: each
AppStatevariant has its own UI/systems wired viaOnEnter/OnExit/Update(latter guarded byin_state). - Persistence: SpacetimeDB will be the authoritative backend (via the Rust SDK, not the TS bindings). Not yet wired up.
- No
module_bindings/here: TS bindings live in the TS workspace and are consumed by the docs prototype.