# Architecture This document explains how Oxide is structured and the principles that govern how it is built. For per-system detail, see the topic documents (e.g. [math.md](math.md)). ## Goals Oxide is a general-purpose 3D game engine written in Rust, built to make **any** 3D game — scaling from stylized low-poly to realistic graphics — and to **ship only what each game uses**. It is built in two phases: a **general-purpose engine** (Phase 1, scene graph, render pass pipeline, input, UI, physics, scripting, animation, particles, shaders, audio, content kit, and game export) and a set of optional, feature-gated **built-in modules** (Phase 2: ray-traced sound, developer console, procedural toolkit, terrain, open world, pathfinding/AI, water). The guiding idea is **build tools, not games**, all driven through a first-class **in-engine editor**. See [`PLAN.md`](../PLAN.md) for the staged roadmap. ## Design philosophy These principles are non-negotiable and shape every decision: 1. **Build in stages.** Each stage produces a usable, standalone artifact and must be fully tested and stable before the next begins. See [development.md](development.md) and [`PLAN.md`](../PLAN.md). 2. **Composability.** Every system should be usable independently of the others. You should be able to pull in the math module, or the scene graph, without dragging in the renderer. 3. **Correctness and clarity over premature optimization.** Optimize when a benchmark says to, not before. 4. **Minimal public surface.** Internal complexity is fine; the external API should be small and clean. Modules expose a curated set of types through `pub use`, not their whole internal structure. 5. **No feature creep between stages.** New ideas go to the backlog, not into the current stage. 6. **The editor grows with the engine.** `oxide-editor` is a first-class deliverable, gaining panels and tools as each stage adds systems. 7. **Build tools, not games.** Ship composable building blocks; genre-specific behavior belongs in game code or optional modules. 8. **Ship only what's used.** Subsystems are feature-gated **modules** (from Stage 5); an exported game compiles in only the modules it registers. 9. **Scalable fidelity.** A data-driven render pass pipeline lets a project run anything from a flat low-poly/stylized look to a full realistic stack, paying only for the passes it enables. 10. **Modules are the primary extension point.** A module registers engine logic *and* editor UI *and* its own settings through one documented API; anyone — including AI agents — can write one. ## Workspace layout Oxide is a single Cargo workspace. Crates share version, edition, license, and dependency versions through `[workspace.package]` and `[workspace.dependencies]` in the root `Cargo.toml`. ``` Oxide/ ├── engine/ # oxide-engine — the core library (all engine systems) ├── editor/ # oxide-editor — the in-engine editor binary ├── examples/ # oxide-examples — runnable examples, one+ per stage ├── tests/ # oxide-tests — integration / end-to-end test harness ├── docs/ # this documentation ├── assets/ # logos and shared assets ├── install.sh # release build + system install ├── PLAN.md # authoritative staged roadmap ├── README.md # short project overview └── CLAUDE.md # rules and context for AI-assisted development ``` ### Crate responsibilities - **`oxide-engine`** — the library that contains every engine system. It is organized as one module per system (`math`, and later `scene`, `render`, `physics`, …). Each module is independently usable and re-exports its public types. A `prelude` module collects the most common imports. - **`oxide-editor`** — the binary users run. It depends on `oxide-engine` and builds a UI on top of engine systems (its own window with a placeholder viewport since Stage 2; egui panels from Stage 3). It never contains engine logic itself; it is a consumer of the engine. - **`oxide-examples`** — small, focused programs that each demonstrate one stage's capabilities. They double as manual-review artifacts and as living documentation. `publish = false`; they are never installed. - **`oxide-tests`** — integration tests that exercise the engine the way a real consumer would, including cross-module scenarios and fuzz/property tests. ## Engine module structure Inside `oxide-engine`, each system is a module under `engine/src/`. The pattern, established by the math module, is: ``` engine/src/ ├── lib.rs # declares modules, defines the prelude ├── math/ │ ├── mod.rs # module docs + curated `pub use` re-exports │ ├── transform.rs # one type/concept per file, with its own tests │ ├── aabb.rs │ └── ... ├── render/ # Stage 2: GPU acquisition + surface clear loop │ ├── mod.rs # RenderError, clear_view, re-exports │ ├── gpu.rs # Gpu (instance/adapter/device/queue) │ └── context.rs # RenderContext (surface, resize, render_frame) └── window/ # Stage 2: window + event loop + App trait ├── mod.rs # WindowConfig, `event` re-export module ├── app.rs # App trait, AppCtx └── runner.rs # winit ApplicationHandler internals ``` Rules of thumb: - **One concept per file.** Prefer many small focused files over a few large ones. - **Tests live with the code.** Each file has a `#[cfg(test)] mod tests` block covering core behavior and edge cases. - **The module root curates the API.** `mod.rs` decides what is public via `pub use`; submodules are private (`mod foo;`, not `pub mod foo;`) unless there is a reason to expose the path. - **The prelude is the front door.** `oxide_engine::prelude::*` brings in the types a typical consumer needs, including re-exported third-party math types so downstream code needs only one dependency for everyday work. ## Key dependencies Chosen for portability and a lightweight footprint: | Concern | Crate | Notes | |---------|-------|-------| | Math | [`glam`](https://docs.rs/glam) | SIMD-friendly vectors/quats/matrices; `serde` feature enabled | | Graphics | [`wgpu`](https://docs.rs/wgpu) | Portable across Vulkan/Metal/DX12 (since Stage 2; re-exported as `oxide_engine::wgpu`) | | Windowing | [`winit`](https://docs.rs/winit) | Cross-platform windows and events (since Stage 2; re-exported as `oxide_engine::winit`) | | ECS | [`hecs`](https://docs.rs/hecs) | Lightweight archetypal ECS (Stage 3+) | | Physics | [`rapier3d`](https://docs.rs/rapier3d) | Rigid bodies and collision (Stage 6+) | | Editor UI | [`egui`](https://docs.rs/egui) | Immediate-mode UI (Stage 3+) | | Logging | `log` + `env_logger` | Facade + env-driven backend | | Errors | `anyhow` + `thiserror` | Application vs. library error handling | | Serialization | `serde` + `ron` | Scene/asset (de)serialization (Stage 3+) | ## Error handling and logging - **Libraries (`oxide-engine`)** define their own error types with `thiserror` so callers can match on failure modes. - **Binaries (`oxide-editor`, examples)** use `anyhow` for ergonomic error propagation at the top level. - **Logging** uses the `log` facade throughout the engine; binaries initialize a backend (`env_logger`). Control verbosity with `RUST_LOG`, e.g. `RUST_LOG=oxide_engine=debug cargo run -p oxide-examples --bin math_demo`. ## Installability Oxide must remain installable as a Linux package at all times. `install.sh` builds in release mode and installs the `oxide-editor` binary and assets under a prefix (`/usr/local` by default, overridable with `PREFIX`). Any new installed binary or asset must be reflected in `install.sh` in the same change. ## See also - [conventions.md](conventions.md) — coordinate system, units, color space - [development.md](development.md) — workflow, testing, and how stages progress - [`PLAN.md`](../PLAN.md) — the full staged roadmap