9eead719b0
Full project snapshot migrated to new Gitea remote without history: engine, editor, physics, script, examples, tests, docs, and assets. Relicensed from GPLv3 to MIT and updated repo URLs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
158 lines
7.9 KiB
Markdown
158 lines
7.9 KiB
Markdown
# 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
|