# codecraft
A minimalist 3D game engine in Rust, built on parts of Bevy (`bevy_ecs`,
`bevy_color`) with `wgpu` and `winit`.
> **Experimental.** This is an early, in-progress engine. The API will change
> between releases without notice, and there are no stability promises yet.
> It is published so it can be used and looked at, not because it is done.
## Where it is at
Today codecraft is the renderer and app shell that grew inside a couple of
small games, pulled out into a crate of its own. What is in it:
- **Rendering** — physically based shading with [OpenPBR] materials, clustered
lighting, a shadow-casting sun plus a second directional light, tonemapping
to the display, and a wireframe/gizmo pass.
- **Scenes** — an `App` runs one `Scene` at a time; a scene owns what it
spawns and a scene change takes it all down. glTF meshes and code-built
primitives (boxes, spheres, extrusions).
- **UI** — an immediate-feeling, entity-backed UI: panels, buttons, headings,
text, progress bars, an outliner, a frame profiler. Icons are Phosphor,
the font is Monaspace; both are compiled in.
- **Input and feel** — keyboard and mouse, an orbit camera rig, DualSense
controllers over HID with haptics, trigger feedback, the lightbar and the
pad's own speaker.
- **Audio** — sound sets and looping voices through `rodio`.
- **Dev mode** — F12 puts up a `DEV` badge with a menu, F11 an outliner of
everything in the scene, F9 a profiler. A loopback control port can drive
the app from a script and take screenshots of the actual frame.
The longer-term aim is a 3D, structure-first code editor. None of that exists
yet; what is here is the engine underneath it.
[OpenPBR]: https://academysoftwarefoundation.github.io/OpenPBR/
## A first scene
```rust
use codecraft::glam::Vec3;
use codecraft::prelude::*;
use codecraft::sceneobjects::lights::default_lights;
use codecraft::{Light, OrbitCamera, gizmos, primitives};
struct Hello;
impl Scene for Hello {
fn setup(&mut self, app: &mut AppState) {
app.spawn(gizmos::grid());
// Lights are entities; a scene that spawns none has none.
let [key, rim] = default_lights();
app.spawn_entity((key, Light::item("Key Light")));
app.spawn_entity((rim, Light::item("Rim Light")));
app.spawn_primitive(
primitives::Box::cube(1.0)
.at(0.0, 0.5, 0.0)
.color(Color::srgb(0.9, 0.45, 0.2)),
);
// Right-drag orbits, WASD walks, the wheel dollies.
app.spawn_entity(OrbitCamera::new(Vec3::new(0.0, 0.5, 0.0), 5.0));
}
}
fn main() {
App::new("hello").scene(Hello).run();
}
```
## Examples
Small ones ship with the crate:
```text
cargo run --example cube # a lit cube turning on a grid
cargo run --example menu # two scenes and the buttons between them
```
Two games live in this repository as workspace members and are the real
test of the engine:
```text
cargo run -p tanks # two-player tank battle, pads and haptics
cargo run -p chess # 3D chess, playable on lichess
```
And `cargo run` on its own opens a blank scene with a grid, in dev mode.
Any app takes `--headless` to run without a window, and honours
`RENDERER_CONTROL_PORT=<port>` to accept commands (`screenshot <path>`,
`key F12`, `quit`, …) over loopback.
## License
Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
[MIT license](LICENSE-MIT) at your option.
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.