codecraft 0.1.1

A minimalist 3D game engine built on parts of Bevy (ECS, color) with wgpu and winit: OpenPBR materials, clustered lighting, an immediate-mode UI, audio and gamepad haptics
Documentation
//! The smallest scene worth looking at: a lit cube turning on a grid, and a
//! camera to fly around it.
//!
//! ```text
//! cargo run --example cube
//! ```
//!
//! Right-drag orbits, WASD walks, the wheel dollies. F12 turns dev mode on:
//! the `DEV` badge opens a menu, F11 lists what is in the scene.
use codecraft::ecs::Entity;
use codecraft::glam::Vec3;
use codecraft::prelude::*;
use codecraft::sceneobjects::lights::default_lights;
use codecraft::{Light, OrbitCamera, Transform, gizmos, primitives};

struct Cube {
    /// The cube, kept so `update` can turn it.
    spinning: Option<Entity>,
}

impl Scene for Cube {
    fn setup(&mut self, app: &mut AppState) {
        // A line to the metre over the ground, for a sense of scale.
        app.spawn(gizmos::grid());

        // Lights are entities, so the outliner lists them and a scene that
        // spawns none has none. This is the stock pair: a warm key that casts
        // a shadow and a cool rim that does not.
        let [key, rim] = default_lights();
        app.spawn_entity((key, Light::item("Key Light")));
        app.spawn_entity((rim, Light::item("Rim Light")));

        // Shapes the code builds for itself: the mesh is uploaded once per
        // size and shared. A primitive sits on the ground at its own origin.
        self.spinning = Some(app.spawn_primitive(
            primitives::Box::cube(1.0)
                .at(0.0, 0.5, 0.0)
                .color(Color::srgb(0.9, 0.45, 0.2)),
        ));
        app.spawn_primitive(
            primitives::Sphere::new(0.4)
                .at(1.8, 0.4, -0.6)
                .color(Color::srgb(0.3, 0.6, 0.9)),
        );

        // The rig drives the frame while it exists; a scene that wants a
        // fixed shot calls `app.set_camera` instead and never spawns one.
        app.spawn_entity(OrbitCamera::new(Vec3::new(0.0, 0.5, 0.0), 5.0).touchpad());
    }

    fn update(&mut self, app: &mut AppState) {
        let turn = app.time().elapsed * 0.6;
        if let Some(cube) = self.spinning {
            app.edit::<Transform>(cube, |transform| transform.set_yaw(turn));
        }
    }
}

fn main() {
    App::new("cube").scene(Cube { spinning: None }).run();
}