A simple yet powerful 3D game engine in Rust
ECS, wgpu rendering, physics, and audio, production-ready error handling and surface recovery
Overview • Quick start • How to use / API • Requirements • Installation • Project Structure • Documentation • Contributing
Pixli is a 3D game engine built in Rust with wgpu for cross-platform graphics (Vulkan, DirectX 12, Metal). It provides an entity-component system (ECS), PBR lighting with shadows, SSAO, bloom, unlit/lit pipelines, physics (AABB/sphere colliders, rigid bodies), and audio via rodio.
- Rendering — Lit and unlit pipelines, directional shadows, SSAO, bloom, MSAA, sky gradient, fog
- ECS — Entity/component world, queries, spawn/despawn
- Physics — Box, sphere, and capsule colliders, rigid bodies, collision events, raycasting
- Audio — Sound loading and playback (rodio)
- Input — Keyboard, mouse, cursor capture
- Production-ready —
Result-based API, no unwraps on user paths, GPU/surface loss handling (Lost, Outdated, Timeout, OutOfMemory)
- Rust 1.75 or later
- GPU with Vulkan 1.2, DirectX 12, or Metal support
- Windows / Linux / macOS (wgpu backends)
git clone https://github.com/your-username/pixli.git
cd pixli
cargo build --releaseuse pixli::prelude::*;
fn main() -> pixli::Result<()> {
App::new()
.with_title("My Game")
.with_size(1280, 720)
.add_startup_system(setup)
.add_system(update)
.run()
}
fn setup(world: &mut World, renderer: &mut Renderer) {
world.spawn()
.with(Transform::from_position(Vec3::ZERO))
.with(Mesh::cube(1.0))
.with(Material::color(Color::RED));
renderer.camera.position = Vec3::new(0.0, 2.0, 5.0);
}
fn update(state: &mut GameState) {
let (world, input, time, renderer, ..) = (
state.world,
state.input,
state.time,
state.renderer,
(),
);
// Game logic
}cargo run --release --example shooterControls: WASD move, mouse aim, LMB fire, Space jump, ESC release mouse or quit.
App::run() returns Result<(), Error>. Handle initialization failures (no GPU, window creation, etc.) in main:
fn main() -> pixli::Result<()> {
App::new().with_title("Game").add_system(update).run()
}
// or
fn main() {
if let Err(e) = App::new().with_title("Game").add_system(update).run() {
eprintln!("Fatal: {}", e);
std::process::exit(1);
}
}pixli/
├── src/
│ ├── lib.rs # Library root, prelude
│ ├── app.rs # App builder, event loop, surface/device init
│ ├── error.rs # Error type and Result
│ ├── ecs/ # Entity, World, Query, components
│ ├── math/ # Vec2/3/4, Mat4, Quat, Transform, Color
│ ├── physics/ # Collider, RigidBody, Physics, raycast
│ ├── renderer/ # wgpu pipelines, meshes, materials, camera, light
│ ├── audio.rs # Audio, Sound, AudioSource
│ ├── input.rs # Input, KeyCode, MouseButton
│ ├── time.rs # Time, delta, frame count
│ └── window.rs # Window config
├── examples/
│ └── shooter/ # FPS example (config, meshes, systems)
├── docs/ # Documentation
└── README.md
- How to use / API guide — Start here: how to make a game, what’s in
GameState, ECS, physics, renderer, input, time, and a quick reference of what you can use - Overview — Philosophy and features
- System architecture — App loop, render pipeline, ECS
- Changelog — Version history
Full API reference (generated from code):
cargo doc --openTests: cargo test runs unit tests. Integration test that opens a window and runs 2 frames is ignored by default; run cargo test -- --ignored to execute it (e.g. locally with a display).
Contributions are welcome. Please read CONTRIBUTING.md for coding standards, testing, and the PR process.
This project is licensed under the MIT License — see the LICENSE file for details.
