pebble-engine 0.13.0

A modular, ECS-style graphics/app framework for Rust.
Documentation
# Opening a Window

Everything up to this point has run headless, no window at all — Part I's examples are all tested that way (`ecs_basics` sets its own runner and calls `app.update()` in a plain loop). Real graphics needs three things: a window, a GPU device, and a render loop tied to the two. `pebble::wgpu::backend::WGPUPlugin` sets up all three at once.

## `WGPUPlugin`

```rust
use pebble::prelude::*;
use pebble::wgpu::backend::WGPUPlugin;

fn main() {
    App::new()
        .add_plugin(WGPUPlugin::new(WindowConfig {
            title: "My Game".to_string(),
            width: 1280,
            height: 720,
        }))
        .add_system(SystemStage::Render, render)
        .build()
        .run();
}

fn render(mut frame: ResMut<CurrentFrame<WGPUBackend>>) {
    if let Some(mut active) = frame.active() {
        let mut _pass = active.render_context([0.05, 0.05, 0.08, 1.0]);
        // draw calls go here
    }
}
```

`WGPUPlugin` is a convenience bundle — under the hood it registers a window plugin, the graphics backend, the render loop, *and* every asset pipeline this book's Part II uses (mesh, material, material instance, texture, texture array, cubemap, compute, sampler). One plugin instead of one `add_plugin` call per asset type.

## Why `Option`-shaped access to the frame

`frame.active()` returns `Option<ActiveFrame<...>>`, not the frame directly. Backend initialization is asynchronous (creating a `wgpu::Device` is itself an async operation, and on native it may also be handed off to a background thread) — for the first several ticks after `build()`, there simply isn't a frame yet. `render` just does nothing on those ticks; there's no error to handle, because nothing has gone wrong. This is the same `Option<Res<T>>` pattern from Chapter 2, applied to the one resource (`CurrentFrame<B>`) that's guaranteed to start out absent in every graphical app.

`render_context(clear_color)` is a shortcut for the common case: one color attachment, cleared to `clear_color`, no depth buffer. [Camera, Depth, and Lazy Resources](./ch10-camera-and-depth.md) uses the more general `begin_pass` once a depth attachment enters the picture.

## What you should see

Run this and you get a window, cleared every frame to a dark blue-gray — nothing drawn yet, because nothing has been given to draw. That's [Your First Triangle](./ch08-first-triangle.md).