# Bevy User Guide

Bevy is a refreshingly simple, data-driven game engine built in Rust. It is free and open source forever. This guide shows you how to install Bevy, build your first app, and use the engine's day-to-day features — the Entity Component System (ECS), 2D and 3D rendering, assets, input, audio, UI, and more.

> [!NOTE]
> This guide documents the `0.19.0-dev` development line of Bevy (the `main` branch). Bevy ships a new release with breaking API changes roughly once every three months, accompanied by official [migration guides](https://bevy.org/learn/migration-guides/). When you depend on a published release (e.g. `0.18`), the concepts below apply, but a few type names may differ. Always pin a specific version in your `Cargo.toml`.

---

## 1. Quick Start

The smallest possible Bevy program opens a window with the default engine features enabled.

```rust
use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .run();
}
```

A more useful "Hello, World" runs a system every frame:

```rust
use bevy::prelude::*;

fn main() {
    App::new()
        .add_systems(Update, hello_world_system)
        .run();
}

fn hello_world_system() {
    println!("hello world");
}
```

The three building blocks you just used are the heart of every Bevy app:

| Concept | What it is |
|---------|-----------|
| **`App`** | The container that wires together plugins, systems, schedules, and the world. |
| **Plugins** | Self-contained bundles of engine functionality. `DefaultPlugins` gives you the "full engine". |
| **Systems** | Plain Rust functions that read and write game state. Added to a schedule such as `Update`. |

> [!TIP]
> Bevy prioritizes modularity as a core principle. **Every** engine feature — even rendering — is implemented as a plugin. You add only what you need.

---

## 2. Installation

### 2.1 Requirements

| Requirement | Detail |
|-------------|--------|
| **Rust toolchain** | A recent stable Rust. Bevy's Minimum Supported Rust Version (MSRV) tracks close to "the latest stable release", because the engine relies heavily on new language and compiler features. |
| **Edition** | Bevy crates use Rust **edition 2024**. |
| **Platform** | Windows, macOS, Linux, Web (WebAssembly), Android, and iOS are supported. |
| **GPU** | A GPU/driver supporting Vulkan, Metal, DirectX 12, or (on the web) WebGPU/WebGL2. |

> [!IMPORTANT]
> Bevy is still in active development. Important features are still being added and documentation is sparse in places. Use it if you are comfortable working in a fast-moving environment.

### 2.2 Add Bevy to a project

Create a new Rust binary project and add the `bevy` crate:

=== "cargo add"

    ```sh
    cargo new my_game
    cd my_game
    cargo add bevy
    ```

=== "Cargo.toml"

    ```toml
    [dependencies]
    bevy = "0.18"
    ```

Then build and run:

```sh
cargo run
```

```text
   Compiling bevy v0.18.0
   ...
    Finished `dev` profile [unoptimized + debuginfo] target(s)
     Running `target/debug/my_game`
```

> [!WARNING]
> The first build compiles the entire engine and can take several minutes. Subsequent builds are incremental and much faster. See [Fast Compiles](#26-fast-compiles) below to speed up iteration.

### 2.3 Run the official examples

The Bevy repository ships hundreds of runnable examples. Clone the repo and run one by name:

```sh
git clone https://github.com/bevyengine/bevy
cd bevy
# Switch to the latest released version (the default branch is main/development)
git checkout latest
cargo run --example breakout
```

```sh
# A few examples worth starting with:
cargo run --example 3d_scene       # A lit 3D scene
cargo run --example 2d_shapes      # 2D primitive shapes
cargo run --example ecs_guide      # A guided tour of the ECS
cargo run --example input_keyboard # Reading keyboard input
```

> [!TIP]
> Browse the full catalogue in the repository's [`examples/`](https://github.com/bevyengine/bevy/tree/latest/examples) directory. Each subfolder (`2d`, `3d`, `ui`, `audio`, `ecs`, `shader`, `animation`, …) is grouped by topic.

### 2.4 Optimizing release builds

Debug builds of a Bevy game can run slowly because dependencies are unoptimized. A common pattern is to optimize dependencies even in dev builds:

```toml
# Cargo.toml — optimize dependencies in dev, keep fast incremental builds for your code
[profile.dev.package."*"]
opt-level = 3

[profile.dev]
opt-level = 1
```

For shipping, always build with `--release`:

```sh
cargo run --release
```

### 2.5 Choosing only the features you need

Bevy is highly modular. You can disable default features and enable only the subset your game uses, which cuts compile times and shrinks your binary. For example, to build a 2D-only game:

```toml
[dependencies]
bevy = { version = "0.18", default-features = false, features = ["2d"] }
```

See [Section 12: Cargo Features](#12-cargo-features-cheat-sheet) for the full menu of profiles, collections, and individual feature flags.

### 2.6 Fast Compiles

Bevy builds fine on stable Rust with the default configuration. For *really* fast iterative compiles, enable the optional "fast compiles" setup (a faster linker plus the dynamic-linking feature). The canonical, up-to-date instructions live in the official [Setup guide](https://bevy.org/learn/quick-start/getting-started/setup).

The single biggest win is dynamic linking during development:

```sh
cargo run --features bevy/dynamic_linking
```

> [!CAUTION]
> Never ship a game with `dynamic_linking` enabled — it requires Bevy's shared library to be present at runtime. Use it only for local iteration. It is also unsupported on WebAssembly.

---

## 3. Your First Real App

Let's build something interactive: a 2D app that spawns a camera, draws a sprite, and moves it with the arrow keys. This touches the core workflow you'll use constantly.

```rust
use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .add_systems(Update, move_player)
        .run();
}

#[derive(Component)]
struct Player;

fn setup(mut commands: Commands) {
    // Spawn a 2D camera so we can see anything at all.
    commands.spawn(Camera2d);

    // Spawn the player: a colored square with our Player marker.
    commands.spawn((
        Sprite::from_color(Color::srgb(0.25, 0.5, 1.0), Vec2::new(50.0, 50.0)),
        Transform::from_xyz(0.0, 0.0, 0.0),
        Player,
    ));
}

fn move_player(
    keyboard: Res<ButtonInput<KeyCode>>,
    time: Res<Time>,
    mut players: Query<&mut Transform, With<Player>>,
) {
    let speed = 300.0;
    for mut transform in &mut players {
        let mut direction = Vec2::ZERO;
        if keyboard.pressed(KeyCode::ArrowLeft) {
            direction.x -= 1.0;
        }
        if keyboard.pressed(KeyCode::ArrowRight) {
            direction.x += 1.0;
        }
        if keyboard.pressed(KeyCode::ArrowUp) {
            direction.y += 1.0;
        }
        if keyboard.pressed(KeyCode::ArrowDown) {
            direction.y -= 1.0;
        }
        transform.translation += (direction.normalize_or_zero() * speed * time.delta_secs()).extend(0.0);
    }
}
```

Everything you need to understand this program is covered next.

> [!NOTE]
> Notice `time.delta_secs()` in the movement math. Multiplying movement by the frame's elapsed time makes motion **frame-rate independent**, so your player moves at the same real-world speed on a 30 FPS laptop and a 240 FPS desktop.

---

## 4. The ECS: Core Concepts

Bevy's data model is an **Entity Component System**. Instead of class hierarchies, you compose game objects out of plain data and operate on them with functions.

| Term | Definition |
|------|-----------|
| **Entity** | A lightweight ID. It owns no data itself — it's a key that components attach to. |
| **Component** | A piece of data attached to an entity (position, health, sprite, …). A Rust `struct`/`enum` with `#[derive(Component)]`. |
| **System** | A function that queries and mutates components and resources. Bevy runs systems for you, in parallel when safe. |
| **Resource** | Globally-unique data not tied to any entity (the clock, asset stores, settings). |
| **World** | The container that stores all entities, components, and resources. |
| **Schedule** | An ordered collection of systems (e.g. `Update`, `FixedUpdate`). |

### 4.1 Components

Define a component by deriving `Component`:

```rust
use bevy::prelude::*;

#[derive(Component)]
struct Health(f32);

#[derive(Component)]
struct Velocity {
    x: f32,
    y: f32,
}

// A "marker" component carries no data; it just tags entities.
#[derive(Component)]
struct Enemy;
```

### 4.2 Spawning entities

You create entities by spawning a **bundle** of components — any tuple of components is a bundle:

```rust
fn spawn_enemies(mut commands: Commands) {
    commands.spawn((
        Enemy,
        Health(100.0),
        Velocity { x: 1.0, y: 0.0 },
        Transform::from_xyz(10.0, 0.0, 0.0),
    ));
}
```

### 4.3 Required components

A component can declare other components it *requires*. When you add it, Bevy automatically inserts the required components (using their `Default`, or a custom constructor) if they aren't already present. Many engine components use this — for example, adding `Sprite` automatically brings in `Transform`.

```rust
use bevy::prelude::*;

#[derive(Component)]
#[require(Transform, Velocity)]
struct Projectile;

#[derive(Component, Default)]
struct Velocity(Vec2);

#[derive(Component, Default)]
struct Transform2;
# // (Transform is provided by the engine; shown here only for illustration)
```

You can also register requirements from a plugin or at app build time:

```rust
app.register_required_components::<Projectile, Velocity>();
// Or with a custom constructor:
app.register_required_components_with::<Projectile, Velocity>(|| Velocity(Vec2::X));
```

> [!NOTE]
> Required components must be registered *before* the component is first added to any entity. Doing this in a plugin's `build` is the safe, conventional place.

### 4.4 Systems and queries

A **system** is a function whose parameters describe the data it wants. Bevy inspects those parameters, fetches the data, and calls your function. The most important parameter is `Query`, which iterates entities matching a set of components.

```rust
// Move every entity that has both Transform and Velocity.
fn apply_velocity(mut query: Query<(&mut Transform, &Velocity)>, time: Res<Time>) {
    for (mut transform, velocity) in &mut query {
        transform.translation.x += velocity.x * time.delta_secs();
        transform.translation.y += velocity.y * time.delta_secs();
    }
}
```

Read access uses `&Component`; write access uses `&mut Component`. Bevy uses this information to run non-conflicting systems in parallel automatically.

### 4.5 Query filters

Filters narrow a query *without* fetching the component's data. Combine them in the second type parameter of `Query`.

| Filter | Meaning |
|--------|---------|
| `With<T>` | Entity must have component `T`. |
| `Without<T>` | Entity must **not** have component `T`. |
| `Added<T>` | `T` was added to the entity since this system last ran. |
| `Changed<T>` | `T` was added or mutated since this system last ran. |
| `Or<(A, B)>` | Matches if either filter `A` or `B` matches. |
| `AnyOf<(A, B)>` | Fetches whichever of the listed components are present (as `Option`s). |
| `Has<T>` | Fetches a `bool` indicating whether `T` is present (does not filter). |
| `Allow<T>` | Opt a query back into seeing entities hidden by a disabling component. |

```rust
// Only players, never enemies — and only react when their Health actually changed.
fn on_player_damaged(query: Query<&Health, (With<Player>, Without<Enemy>, Changed<Health>)>) {
    for health in &query {
        println!("player health is now {}", health.0);
    }
}
# #[derive(bevy::prelude::Component)] struct Player;
# #[derive(bevy::prelude::Component)] struct Enemy;
# #[derive(bevy::prelude::Component)] struct Health(f32);
```

> [!TIP]
> `Changed<T>` and `Added<T>` are the foundation of efficient, reactive logic. Instead of recomputing everything every frame, only do work for entities whose data actually changed.

### 4.6 Accessing a single entity

When you expect exactly one matching entity, `Single` and `Populated` are cleaner than looping:

```rust
// Panics/skips gracefully if there isn't exactly one player.
fn read_player(player: Single<&Transform, With<Player>>) {
    println!("player at {:?}", player.translation);
}
# #[derive(bevy::prelude::Component)] struct Player;
```

`Single<D>` requires exactly one match; `Option<Single<D>>` tolerates zero or one; `Populated<D>` is a query guaranteed to be non-empty (the system is skipped when empty).

### 4.7 Resources

Resources are global singletons. Define one with `#[derive(Resource)]` and insert it into the app:

```rust
use bevy::prelude::*;

#[derive(Resource)]
struct Score(u32);

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .insert_resource(Score(0))
        .add_systems(Update, award_points)
        .run();
}

fn award_points(mut score: ResMut<Score>) {
    score.0 += 1;
}
```

| Access | Use in a system |
|--------|-----------------|
| `Res<T>` | Shared, read-only access to resource `T`. |
| `ResMut<T>` | Exclusive, mutable access to resource `T`. |
| `Local<T>` | Per-system state that isn't shared with anyone else. |
| `NonSend<T>` / `NonSendMut<T>` | Access to thread-local (`!Send`) data; forces the system onto the main thread. |

Use `init_resource::<T>()` for resources that implement `Default` or `FromWorld`, and `insert_resource(value)` to provide an explicit value.

### 4.8 Commands: structural changes

Spawning, despawning, and adding/removing components are *structural* changes. They can't happen instantly mid-system (other systems might be reading the world in parallel), so you queue them with `Commands`. They are applied at the next synchronization point.

```rust
fn spawn_and_modify(mut commands: Commands, enemies: Query<Entity, With<Enemy>>) {
    // Spawn a new entity and keep its id.
    let id = commands.spawn((Player, Health(100.0))).id();

    // Add or remove components later.
    commands.entity(id).insert(Velocity { x: 0.0, y: 0.0 });
    commands.entity(id).remove::<Health>();

    // Despawn all enemies.
    for enemy in &enemies {
        commands.entity(enemy).despawn();
    }
}
# use bevy::prelude::*;
# #[derive(Component)] struct Player;
# #[derive(Component)] struct Enemy;
# #[derive(Component)] struct Health(f32);
# #[derive(Component)] struct Velocity { x: f32, y: f32 }
```

> [!IMPORTANT]
> Changes made through `Commands` are deferred. If a later system in the *same* schedule run needs to see a freshly spawned entity, insert an `ApplyDeferred` step between them, or do the read in a subsequent schedule.

---

## 5. Building the App: Plugins and Schedules

### 5.1 The App builder

`App::new()` creates an app with core engine scaffolding. You then chain builder methods:

| Method | Purpose |
|--------|---------|
| `add_plugins(...)` | Install a plugin or group of plugins. |
| `add_systems(schedule, systems)` | Add one or more systems to a schedule. |
| `insert_resource(value)` / `init_resource::<T>()` | Provide a resource. |
| `add_message::<M>()` | Enable a message (event) type `M`. |
| `add_observer(observer)` | Register a global observer (see §7). |
| `configure_sets(schedule, sets)` | Order and gate groups of systems. |
| `run()` | Build everything and start the main loop. |

### 5.2 Plugins

A plugin is any type implementing `Plugin`. Its `build` method receives `&mut App`, letting it register whatever it needs — systems, resources, types. This is how you organize a real game into modules.

```rust
use bevy::prelude::*;

pub struct CombatPlugin;

impl Plugin for CombatPlugin {
    fn build(&self, app: &mut App) {
        app.insert_resource(Score(0))
            .add_systems(Update, (apply_damage, check_deaths));
    }
}
# #[derive(Resource)] struct Score(u32);
# fn apply_damage() {}
# fn check_deaths() {}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(CombatPlugin)
        .run();
}
```

You can also pass a tuple of plugins: `.add_plugins((CombatPlugin, AudioPlugin, UiPlugin))`.

### 5.3 DefaultPlugins vs MinimalPlugins

Bevy ships two built-in plugin groups:

| Group | What it includes |
|-------|------------------|
| **`DefaultPlugins`** | The full windowed engine: logging, input, windowing, assets, rendering, audio, UI, scenes, gizmos, animation, gamepad support, picking, and more. This is what most games use. |
| **`MinimalPlugins`** | The bare minimum: a task pool, frame counter, time, and a schedule runner loop. No window, no rendering. Ideal for headless apps, servers, and tests. |

`DefaultPlugins` honors your Cargo feature flags — disabling a feature like `bevy_audio` removes the corresponding plugin automatically.

You can customize a group's plugins (reorder, replace settings, or disable one) with `.set(...)` and `.build()`:

```rust
use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins.set(WindowPlugin {
            primary_window: Some(Window {
                title: "My Game".into(),
                resolution: (1280.0, 720.0).into(),
                ..default()
            }),
            ..default()
        }))
        .run();
}
```

> [!NOTE]
> `MinimalPlugins` drives the app with a `ScheduleRunnerPlugin`. By default it loops as fast as possible (which pins a CPU core). For a headless server, set a fixed wait between iterations with `ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64(1.0 / 60.0))`, or run a single iteration with `run_once`.

### 5.4 The schedule pipeline

Each frame, Bevy runs the `Main` schedule, which runs a fixed sequence of sub-schedules. You add your systems to whichever one fits.

```text
Startup phase (runs ONCE at launch):
    PreStartup  →  Startup  →  PostStartup

Every frame, in order:
    First
    PreUpdate
    RunFixedMainLoop   ← runs the fixed-timestep schedules 0..N times (see §8.2)
    Update             ← most of your game logic goes here
    SpawnScene
    PostUpdate
    Last
```

| Schedule | Typical use |
|----------|-------------|
| `PreStartup` / `Startup` / `PostStartup` | One-time setup: spawn the camera, load assets, build the initial scene. |
| `First` | Very early per-frame bookkeeping (time is updated here). |
| `PreUpdate` | Ingest raw OS input into engine resources, before your logic reads it. |
| `Update` | Your per-frame gameplay logic. **Most systems live here.** |
| `SpawnScene` | Scene spawning is processed here. |
| `PostUpdate` | React to changes from `Update` (e.g. transform/hierarchy propagation, rendering extract). |
| `Last` | End-of-frame cleanup. |

The fixed-timestep schedules — `FixedFirst`, `FixedPreUpdate`, `FixedUpdate`, `FixedPostUpdate`, `FixedLast` — run inside `RunFixedMainLoop` (see §8.2).

### 5.5 Ordering systems

By default, systems in a schedule may run in **any order** (and in parallel). When order matters, declare it explicitly:

```rust
app.add_systems(Update, (
    read_input,
    apply_movement.after(read_input),
    detect_collisions.after(apply_movement),
));

// Or as an ordered chain:
app.add_systems(Update, (read_input, apply_movement, detect_collisions).chain());
```

Group related systems with **system sets** for coarse ordering and shared run conditions:

```rust
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
enum GameSet {
    Input,
    Logic,
    Render,
}

app.configure_sets(Update, (GameSet::Input, GameSet::Logic, GameSet::Render).chain());
app.add_systems(Update, read_input.in_set(GameSet::Input));
# use bevy::prelude::*;
# fn read_input() {}
```

### 5.6 Run conditions

Attach a `run_if` condition to skip a system unless a predicate holds:

```rust
app.add_systems(Update, pause_menu.run_if(in_state(GameState::Paused)));
app.add_systems(Update, autosave.run_if(on_timer(std::time::Duration::from_secs(30))));
# use bevy::prelude::*;
# #[derive(States, Clone, PartialEq, Eq, Hash, Debug, Default)] enum GameState { #[default] Paused }
# fn pause_menu() {}
# fn autosave() {}
```

Bevy provides many built-in conditions in `common_conditions` (re-exported in the prelude), including `resource_exists`, `resource_changed`, `any_with_component`, `on_event`/`on_message`, and `run_once`.

---

## 6. Messages (Events)

Messages let systems communicate without direct coupling: one system writes, another reads. (Earlier Bevy versions called these "events"; the buffered API is now `Message`.)

```rust
use bevy::prelude::*;

#[derive(Message)]
struct PlayerDied {
    score: u32,
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_message::<PlayerDied>()
        .add_systems(Update, (emit_death, on_death))
        .run();
}

fn emit_death(mut writer: MessageWriter<PlayerDied>) {
    writer.write(PlayerDied { score: 42 });
}

fn on_death(mut reader: MessageReader<PlayerDied>) {
    for ev in reader.read() {
        println!("player died with score {}", ev.score);
    }
}
```

| Type | Role |
|------|------|
| `MessageWriter<M>` | Send messages of type `M`. |
| `MessageReader<M>` | Read messages since this system last ran. |
| `Messages<M>` | The underlying double-buffered queue resource. |

> [!WARNING]
> Messages live for **two frames** by default (double-buffered). If a reader runs less often than messages are written, it can miss some. For guaranteed delivery, use observers (§7) or ensure your reader runs every frame.

---

## 7. Observers and Lifecycle Events

Observers react **immediately** to an event the moment it is triggered, rather than polling a queue. They're ideal for one-off reactions: an entity took damage, a button was clicked, a component was added.

```rust
use bevy::prelude::*;

#[derive(EntityEvent)]
struct Damage {
    entity: Entity,
    amount: f32,
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_observer(on_damage)
        .run();
}

// `On<Damage>` gives you the triggered event.
fn on_damage(event: On<Damage>, mut healths: Query<&mut Health>) {
    if let Ok(mut health) = healths.get_mut(event.entity) {
        health.0 -= event.amount;
    }
}
# #[derive(Component)] struct Health(f32);

// Trigger an observer from anywhere you have Commands:
fn deal_damage(mut commands: Commands, target: Entity) {
    commands.trigger(Damage { entity: target, amount: 10.0 });
}
```

### 7.1 Lifecycle events

Bevy automatically fires lifecycle events you can observe: `Add`, `Insert`, `Remove`, and `Despawn` for components. You can also detect removed components in a regular system with `RemovedComponents<T>`.

```rust
// Run cleanup whenever an Enemy component is removed this frame.
fn cleanup_on_enemy_removed(mut removed: RemovedComponents<Enemy>) {
    for entity in removed.read() {
        println!("enemy {entity} was removed");
    }
}
# use bevy::prelude::*;
# #[derive(Component)] struct Enemy;
```

> [!TIP]
> Reach for **observers** when you need an immediate, targeted reaction and **messages** when you want decoupled, batch-processed communication that several systems may consume.

---

## 8. Time and the Game Loop

### 8.1 The `Time` resource

The `Time` resource tracks elapsed time. Use it to make logic frame-rate independent.

```rust
fn tick(time: Res<Time>) {
    let dt: f32 = time.delta_secs();          // seconds since last frame
    let elapsed: f32 = time.elapsed_secs();   // seconds since startup
    println!("frame took {dt}s, total {elapsed}s");
}
# use bevy::prelude::*;
```

### 8.2 Fixed timestep

Physics and other simulations should advance in fixed-size steps for determinism, independent of render frame rate. Put that logic in `FixedUpdate`, which runs zero or more times per frame inside `RunFixedMainLoop` until the accumulated time is consumed.

```rust
app.add_systems(FixedUpdate, simulate_physics);

// Read fixed-step time inside FixedUpdate systems:
fn simulate_physics(time: Res<Time<Fixed>>) {
    let step = time.delta_secs(); // constant (default: 1/64th of a second)
    // ...advance the simulation by `step`...
}
# use bevy::prelude::*;
# fn _x() {}
```

You can change the fixed rate:

```rust
app.insert_resource(Time::<Fixed>::from_hz(60.0)); // 60 simulation steps per second
```

| Schedule (inside `RunFixedMainLoop`) | Use |
|--------------------------------------|-----|
| `FixedFirst` | Early fixed-step bookkeeping. |
| `FixedPreUpdate` | Prepare state before fixed logic. |
| `FixedUpdate` | Deterministic gameplay/physics. |
| `FixedPostUpdate` | React to fixed-step changes. |
| `FixedLast` | Fixed-step cleanup. |

> [!NOTE]
> A single render frame may run `FixedUpdate` zero times (if the frame was very fast) or several times (if it was slow). To render smoothly between fixed steps, interpolate using the "overstep" fraction available from `Time<Fixed>`.

---

## 9. Transforms and Hierarchy

### 9.1 Transform and GlobalTransform

Every visible entity has a `Transform` (its local position, rotation, and scale) and a `GlobalTransform` (its absolute world-space transform, computed by the engine each frame in `PostUpdate`).

```rust
use bevy::prelude::*;

fn spawn_object(mut commands: Commands) {
    commands.spawn((
        Transform::from_xyz(0.0, 1.0, 0.0)
            .with_rotation(Quat::from_rotation_y(std::f32::consts::FRAC_PI_4))
            .with_scale(Vec3::splat(2.0)),
        // ...mesh/sprite...
    ));
}
```

`Transform` is built on the **glam** math library (re-exported through `bevy_math` and the prelude), which Bevy uses with a right-handed, Y-up convention. The core math types you'll use constantly:

| Type | Use |
|------|-----|
| `Vec2` / `Vec3` / `Vec4` | 2D / 3D / 4D vectors. Constants: `Vec3::X`, `Vec3::Y`, `Vec3::Z`, `Vec3::ZERO`. |
| `Quat` | A unit quaternion rotation. Build with `Quat::from_rotation_y(angle)`, `Quat::from_axis_angle(axis, angle)`, or `Quat::from_euler(EulerRot::XYZ, x, y, z)`. |
| `Mat3` / `Mat4` | 3×3 / 4×4 matrices for projections and advanced transforms. |
| `Dir2` / `Dir3` | Normalized direction wrappers. |

```rust
// Common vector operations:
let a = Vec3::new(1.0, 2.0, 3.0);
let len = a.length();
let unit = a.normalize_or_zero();
let dot = a.dot(Vec3::Y);
let cross = Vec3::X.cross(Vec3::Y); // == Vec3::Z
let mid = Vec3::ZERO.lerp(a, 0.5);
# use bevy::prelude::*;
```

### 9.2 Parent–child relationships

Entities form hierarchies through the `ChildOf` / `Children` relationship. A child's `GlobalTransform` is its `Transform` combined with all of its ancestors' transforms.

```rust
use bevy::prelude::*;

fn spawn_hierarchy(mut commands: Commands) {
    commands
        .spawn(Transform::from_xyz(0.0, 0.0, 0.0)) // parent
        .with_children(|parent| {
            parent.spawn(Transform::from_xyz(1.0, 0.0, 0.0)); // child, offset from parent
            parent.spawn(Transform::from_xyz(-1.0, 0.0, 0.0));
        });
}
```

You can also set relationships explicitly with the `ChildOf` component, and query them with `Children` and `ChildOf`. Despawning a parent despawns its children.

---

## 10. Rendering

Bevy's renderer is built on **wgpu**, a cross-platform graphics API that runs on Vulkan, Metal, DirectX 12, OpenGL, and — on the web — WebGPU/WebGL2. For everyday game code you rarely touch wgpu directly; you spawn cameras and renderable entities and the engine does the rest.

### 10.1 Cameras

Nothing renders without a camera. Spawn `Camera2d` for 2D and `Camera3d` for 3D.

```rust
fn setup_2d(mut commands: Commands) {
    commands.spawn(Camera2d);
}

fn setup_3d(mut commands: Commands) {
    commands.spawn((
        Camera3d::default(),
        Transform::from_xyz(0.0, 5.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
    ));
}
# use bevy::prelude::*;
```

### 10.2 2D essentials

```rust
fn spawn_sprite(mut commands: Commands, assets: Res<AssetServer>) {
    // Image sprite loaded from assets/player.png
    commands.spawn(Sprite::from_image(assets.load("player.png")));

    // Solid-color rectangle
    commands.spawn(Sprite::from_color(Color::srgb(1.0, 0.0, 0.0), Vec2::new(64.0, 64.0)));
}
# use bevy::prelude::*;
```

### 10.3 3D essentials

A typical 3D scene needs a mesh, a material, a light, and a camera:

```rust
use bevy::prelude::*;

fn setup_scene(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    // A cuboid mesh with a PBR material.
    commands.spawn((
        Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
        MeshMaterial3d(materials.add(Color::srgb(0.8, 0.7, 0.6))),
        Transform::from_xyz(0.0, 0.5, 0.0),
    ));

    // A directional "sun" light.
    commands.spawn((
        DirectionalLight { shadows_enabled: true, ..default() },
        Transform::from_xyz(4.0, 8.0, 4.0).looking_at(Vec3::ZERO, Vec3::Y),
    ));

    // The camera.
    commands.spawn((
        Camera3d::default(),
        Transform::from_xyz(-3.0, 4.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y),
    ));
}
```

Bevy provides physically-based rendering (`bevy_pbr`) with `StandardMaterial`, point/spot/directional lights, shadows, and built-in mesh primitives (`Cuboid`, `Sphere`, `Plane3d`, `Cylinder`, `Capsule3d`, and more).

### 10.4 Colors

Construct colors in whichever space suits you:

```rust
let red = Color::srgb(1.0, 0.0, 0.0);
let translucent = Color::srgba(0.0, 0.0, 1.0, 0.5);
let hsl = Color::hsl(120.0, 1.0, 0.5);
let named = bevy::color::palettes::css::TOMATO;
# use bevy::prelude::*;
```

> [!TIP]
> If your 3D scene renders entirely pink, you most likely need the `tonemapping_luts` Cargo feature (or to change the camera's `Tonemapping` method). The look-up tables it bundles are required for the default tonemapper.

---

## 11. Common Tasks (Recipes)

### 11.1 Loading and using assets

The `AssetServer` loads files asynchronously from your `assets/` directory and hands back a `Handle<T>`. Stored assets live in the `Assets<T>` resource.

```rust
use bevy::prelude::*;

#[derive(Resource)]
struct GameAssets {
    player: Handle<Image>,
    music: Handle<AudioSource>,
}

fn load_assets(mut commands: Commands, assets: Res<AssetServer>) {
    commands.insert_resource(GameAssets {
        player: assets.load("sprites/player.png"),
        music: assets.load("audio/theme.ogg"),
    });
}
```

> [!NOTE]
> Handles are cheap, cloneable references. Loading is asynchronous: a freshly loaded asset may not be available for a frame or two. Query `Assets<T>` or use asset events/states to know when it's ready.

### 11.2 Playing audio

```rust
fn play_music(mut commands: Commands, assets: Res<AssetServer>) {
    commands.spawn((
        AudioPlayer::new(assets.load("audio/theme.ogg")),
        PlaybackSettings::LOOP,
    ));
}
# use bevy::prelude::*;
```

Audio requires the `bevy_audio` feature plus a format feature (`vorbis` for `.ogg`, `flac`, `mp3`, `wav`, …). The `audio` collection enables `bevy_audio` + `vorbis`; `audio-all-formats` enables every decoder.

### 11.3 Reading input

| Input | Resource / type |
|-------|-----------------|
| Keyboard | `Res<ButtonInput<KeyCode>>` |
| Mouse buttons | `Res<ButtonInput<MouseButton>>` |
| Mouse motion / wheel | `MessageReader<MouseMotion>`, `MessageReader<MouseWheel>` |
| Gamepad | `Query<&Gamepad>` (requires `bevy_gilrs`) |
| Touch | `Res<Touches>` |

```rust
fn input(keys: Res<ButtonInput<KeyCode>>, mouse: Res<ButtonInput<MouseButton>>) {
    if keys.just_pressed(KeyCode::Space) {
        println!("jump!");
    }
    if keys.pressed(KeyCode::KeyW) {
        println!("moving forward");
    }
    if mouse.just_pressed(MouseButton::Left) {
        println!("fire!");
    }
}
# use bevy::prelude::*;
```

| Method | Meaning |
|--------|---------|
| `pressed(b)` | `true` every frame the input is held. |
| `just_pressed(b)` | `true` only on the frame it went down. |
| `just_released(b)` | `true` only on the frame it went up. |

### 11.4 Game states

States model high-level modes — main menu, playing, paused, game over. Define an enum implementing `States`, register it, and gate systems on it.

```rust
use bevy::prelude::*;

#[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)]
enum AppState {
    #[default]
    Menu,
    InGame,
    Paused,
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .init_state::<AppState>()
        .add_systems(OnEnter(AppState::InGame), spawn_level)
        .add_systems(OnExit(AppState::InGame), despawn_level)
        .add_systems(Update, gameplay.run_if(in_state(AppState::InGame)))
        .run();
}
# fn spawn_level() {}
# fn despawn_level() {}
# fn gameplay() {}
```

| Hook | Fires when |
|------|-----------|
| `OnEnter(S)` | You transition *into* state `S`. |
| `OnExit(S)` | You transition *out of* state `S`. |
| `in_state(S)` | Run condition: true while in state `S`. |

Change state by setting the `NextState<AppState>` resource: `next.set(AppState::Paused)`.

States require the `bevy_state` feature (enabled by default).

### 11.5 Drawing debug gizmos

Gizmos draw immediate-mode debug lines and shapes — great for visualizing colliders, rays, and grids. They don't persist; you redraw them every frame.

```rust
fn draw_debug(mut gizmos: Gizmos) {
    gizmos.line(Vec3::ZERO, Vec3::new(0.0, 5.0, 0.0), Color::srgb(0.0, 1.0, 0.0));
    gizmos.circle_2d(Vec2::ZERO, 50.0, Color::WHITE);
}
# use bevy::prelude::*;
```

### 11.6 Building a UI

Bevy includes its own ECS-driven UI framework (`bevy_ui`). UI elements are entities with `Node` components, laid out with a flexbox-style system.

```rust
use bevy::prelude::*;

fn spawn_ui(mut commands: Commands) {
    commands.spawn((
        Node {
            width: Val::Percent(100.0),
            height: Val::Percent(100.0),
            justify_content: JustifyContent::Center,
            align_items: AlignItems::Center,
            ..default()
        },
    )).with_children(|parent| {
        parent.spawn((
            Text::new("Hello, Bevy!"),
            TextColor(Color::WHITE),
        ));
    });
}
```

### 11.7 Spawning and despawning at runtime

```rust
fn spawn_bullet(mut commands: Commands, origin: Vec3) {
    commands.spawn((
        Bullet,
        Transform::from_translation(origin),
        Velocity(Vec3::Z * 20.0),
    ));
}

fn despawn_offscreen(mut commands: Commands, bullets: Query<(Entity, &Transform), With<Bullet>>) {
    for (entity, transform) in &bullets {
        if transform.translation.length() > 1000.0 {
            commands.entity(entity).despawn();
        }
    }
}
# use bevy::prelude::*;
# #[derive(Component)] struct Bullet;
# #[derive(Component)] struct Velocity(Vec3);
```

### 11.8 Exiting the app

Send the `AppExit` message to quit cleanly:

```rust
fn quit_on_escape(keys: Res<ButtonInput<KeyCode>>, mut exit: MessageWriter<AppExit>) {
    if keys.just_pressed(KeyCode::Escape) {
        exit.write(AppExit::Success);
    }
}
# use bevy::prelude::*;
```

---

## 12. Cargo Features Cheat Sheet

Bevy exposes a large set of Cargo features. Enabling more adds functionality at the cost of longer compile times and bigger binaries. Features are organized into three tiers: **profiles** (high-level), **collections** (mid-level), and **individual features**.

### 12.1 Profiles

Pair these with `default-features = false` to compile only the slice of Bevy you need.

| Profile | Description |
|---------|-------------|
| `default` | The full Bevy experience — a combination of `2d`, `3d`, `ui`, and `audio`. |
| `2d` | Core framework + 2D functionality + scenes + picking. |
| `3d` | Core framework + 3D functionality + scenes + picking. |
| `ui` | Core framework + Bevy UI + scenes + picking. |

```toml
# A lean 2D game:
bevy = { version = "0.18", default-features = false, features = ["2d"] }
```

### 12.2 Selected collections

| Collection | Enables |
|------------|---------|
| `dev` | Dev-time conveniences: `debug`, `bevy_dev_tools`, `file_watcher` (asset hot-reloading). **Do not ship with this.** |
| `audio` | `bevy_audio` + `vorbis`. |
| `audio-all-formats` | All audio decoders (`aac`, `flac`, `mp3`, `mp4`, `vorbis`, `wav`). |
| `scene` | `bevy_world_serialization` + `bevy_scene`. |
| `picking` | All picking backends (`mesh_picking`, `sprite_picking`, `ui_picking`). |
| `default_app` | Baseline for headless apps (no renderer). |
| `default_no_std` | Recommended defaults for `no_std` targets. |

### 12.3 Commonly toggled individual features

| Feature | What it adds |
|---------|--------------|
| `dynamic_linking` | Faster iterative compiles (dev only; never ship). |
| `file_watcher` | Hot-reload assets when files change on disk. |
| `multi_threaded` | Multithreaded engine parallelism (on by default). |
| `serialize` | `serde` serialization support. |
| `trace` / `trace_tracy` / `trace_chrome` | Performance tracing back-ends. |
| `webgl2` / `webgpu` | Web rendering back-ends (`webgpu` overrides `webgl2`). |
| `wayland` / `x11` | Linux display-server back-ends. |
| Image formats | `png`, `jpeg`, `hdr`, `ktx2`, `dds`, `webp`, `exr`, `bmp`, `gif`, `tga`, `tiff`, `qoi`, `pnm`, `ff`, `basis-universal`. |
| Audio formats | `vorbis`, `flac`, `mp3`, `wav`, `aac`, `mp4`. |
| `meshlet` | Experimental high-poly meshlet renderer. |
| `bevy_solari` | Experimental raytraced lighting. |
| `dlss` | NVIDIA Deep Learning Super Sampling. |

> [!TIP]
> The canonical, always-current feature list — including which `bevy_*` sub-crate each feature toggles — is generated into `docs/cargo_features.md` in the repository and rendered in the [Bevy API docs](https://docs.rs/bevy/latest/bevy/). The Admin Guide documents the full set.

---

## 13. Building and Shipping

### 13.1 Desktop

```sh
# Development
cargo run

# Release build (optimized)
cargo run --release
cargo build --release   # binary in target/release/
```

Remember to ship your `assets/` directory alongside the executable — the `AssetServer` loads files relative to it.

### 13.2 Web (WebAssembly)

```sh
rustup target add wasm32-unknown-unknown
cargo build --release --target wasm32-unknown-unknown
```

Then use a tool like `wasm-bindgen` (or `wasm-server-runner` / `trunk`) to produce the JS glue and serve it. Choose a web rendering backend with features:

=== "WebGL2 (broadest support)"

    ```toml
    bevy = { version = "0.18", features = ["webgl2"] }
    ```

=== "WebGPU (best performance)"

    ```toml
    bevy = { version = "0.18", features = ["webgpu"] }
    ```

> [!NOTE]
> `webgpu` overrides `webgl2` when both are enabled — a single Wasm build targets one or the other, not both. WebGL2 lacks compute shaders, so some advanced rendering features are WebGPU-only.

### 13.3 Mobile

Bevy supports Android and iOS. The repository's `examples/mobile` shows a complete setup. For Android, the modern path uses **GameActivity** (`android-game-activity`, the default); the older `android-native-activity` is used by the deprecated `cargo-apk` tool.

```sh
# Android targets
rustup target add aarch64-linux-android armv7-linux-androideabi
```

> [!IMPORTANT]
> Bevy's example apps target Android API level 33 by default. If you use `bevy_audio`, the minimum supported Android API version is 26 (Android 8 / Oreo).

---

## 14. Troubleshooting

### Error: `cannot find a window` / nothing appears on screen

**Cause:** No camera was spawned, or you used `MinimalPlugins` (which has no window).
**Solution:** Spawn a `Camera2d` or `Camera3d` in a `Startup` system, and use `DefaultPlugins`.
**Prevention:** Every visual app needs both a window-providing plugin group and a camera.

### Error: everything in my 3D scene renders solid pink

**Cause:** The default tonemapper needs look-up tables that aren't bundled.
**Solution:** Enable the `tonemapping_luts` feature, or set a different `Tonemapping` on your camera.
**Prevention:** Keep `tonemapping_luts` enabled (it is part of the default 3D feature set).

### Error: my sprite/model is invisible but no error is logged

**Cause:** The asset is still loading, the entity is outside the camera's view, or it has no `Transform`.
**Solution:** Confirm the file path is correct and under `assets/`, check the camera position, and ensure a `Transform` is present (most renderable components require it automatically).
**Prevention:** Use asset events or a loading state to wait until assets are ready before relying on them.

### Error: `Resource requested by ... does not exist`

**Cause:** A system accessed `Res<T>`/`ResMut<T>` for a resource that was never inserted.
**Solution:** Call `insert_resource(T)` or `init_resource::<T>()` during app setup before the system runs.
**Prevention:** Initialize resources in the same plugin that adds the systems depending on them.

### Error: my system never runs

**Cause:** It was added to the wrong schedule, gated behind a `run_if` that's always false, or filtered out by an empty `Single`/`Populated`.
**Solution:** Verify the schedule (`Update` vs `Startup`), check the run condition, and confirm matching entities exist.
**Prevention:** Start with `Update` and no run conditions, then add gating once the system works.

### Error: a newly spawned entity isn't visible to another system this frame

**Cause:** `Commands` are deferred and applied at the next sync point.
**Solution:** Read the entity in a later schedule, or insert an `ApplyDeferred` step between the spawning and reading systems.
**Prevention:** Treat structural changes as "queued"; don't assume they're immediate within one schedule run.

### Error: input feels laggy or movement speed varies by machine

**Cause:** Game logic isn't scaled by `Time::delta_secs()`, so it depends on frame rate.
**Solution:** Multiply per-frame changes by `time.delta_secs()`, or move the logic into `FixedUpdate`.
**Prevention:** Always scale continuous motion by delta time.

### Error: my `MessageReader` misses some messages

**Cause:** Messages are double-buffered (live ~2 frames); a reader running too infrequently drops them.
**Solution:** Ensure the reader runs every frame, or switch to an observer for guaranteed, immediate handling.
**Prevention:** Use observers for must-handle events.

### Error: compile times are painfully long

**Cause:** Compiling the whole engine, unoptimized dependencies, or no fast-linker setup.
**Solution:** Enable `dynamic_linking` for dev, optimize dependencies via `[profile.dev.package."*"]`, and follow the Fast Compiles setup.
**Prevention:** Trim Cargo features to only what you use.

### Error: `failed to find an appropriate adapter` / GPU initialization fails

**Cause:** No compatible GPU backend (Vulkan/Metal/DX12) or outdated drivers.
**Solution:** Update graphics drivers; on Linux ensure Vulkan is installed. As a fallback you can force a backend (see the Admin Guide's `WgpuSettings` / `WGPU_BACKEND` coverage).
**Prevention:** Test on target hardware early.

### Error: audio doesn't play

**Cause:** The `bevy_audio` feature or the relevant format decoder isn't enabled.
**Solution:** Enable `bevy_audio` plus the matching format feature (`vorbis` for `.ogg`, `flac`, `mp3`, `wav`).
**Prevention:** Use the `audio` or `audio-all-formats` collection.

---

## 15. Frequently Asked Questions

**Q: Is Bevy production-ready?**
Bevy is powerful and used for real games and tools, but it is still pre-1.0 and ships breaking changes roughly every three months. Pin a version and budget time for migrations between releases.

**Q: What's the difference between a Component and a Resource?**
A component is data attached to a specific entity (you may have thousands). A resource is a single global value not tied to any entity (the clock, asset stores, settings).

**Q: When should I use `Update` vs `FixedUpdate`?**
Use `Update` for anything tied to rendering and responsiveness (input handling, UI, camera). Use `FixedUpdate` for deterministic simulation (physics) that must advance at a constant rate regardless of frame rate.

**Q: How do I run systems in a guaranteed order?**
Use `.before()`, `.after()`, or `.chain()` when adding them, and organize coarse phases with system sets via `configure_sets`. Systems with no declared order may run in parallel in any order.

**Q: What replaced `Events`/`EventReader`/`EventWriter`?**
The buffered communication API is now `Message` / `MessageReader` / `MessageWriter` (register with `add_message`). For immediate, targeted reactions, use `Event`/`EntityEvent` with observers (`On<...>` + `add_observer`).

**Q: How do I make one entity a child of another?**
Spawn children with `.with_children(|parent| { ... })`, or attach the `ChildOf` relationship. Children inherit their parent's transform, and despawning a parent despawns its children.

**Q: How do I quit the game from code?**
Send `AppExit::Success` through a `MessageWriter<AppExit>`.

**Q: Do I need to enable rendering features for a headless server?**
No. Use `MinimalPlugins` (or `default_app` without a renderer) and add a `ScheduleRunnerPlugin` loop. This is ideal for dedicated servers and CLI tools.

**Q: Where do my asset files go?**
In an `assets/` directory next to your project. `AssetServer::load("sprites/player.png")` resolves to `assets/sprites/player.png`. Ship the `assets/` folder with your build.

**Q: How do I hot-reload assets during development?**
Enable the `file_watcher` feature (or the `dev` collection). Edits to files on disk are reloaded live.

**Q: Can I use only one `bevy_*` sub-crate instead of the umbrella `bevy` crate?**
Yes. Each module of the `bevy` crate (except the prelude) is published separately as `bevy_app`, `bevy_ecs`, `bevy_render`, and so on. Most users depend on the umbrella `bevy` crate for convenience.

**Q: How do I target `no_std` (embedded / niche platforms)?**
Disable default features and enable the `default_no_std` collection (plus `libm` and `critical-section` as needed). Note that some features require `std`.

**Q: Why is my whole CPU core pinned at 100% in a headless app?**
`ScheduleRunnerPlugin` loops as fast as possible by default. Configure it with `run_loop(Duration)` to cap the iteration rate, or `run_once` for a single tick.

**Q: How do I detect when a component changed instead of polling every frame?**
Add the `Changed<T>` (or `Added<T>`) filter to your query. The query then only yields entities whose `T` changed since your system last ran.

**Q: How do I customize the window title/size?**
Configure `WindowPlugin` via `DefaultPlugins.set(WindowPlugin { primary_window: Some(Window { .. }), .. })`.

**Q: Where can I learn more?**
Start with the official [Quick Start Guide](https://bevy.org/learn/quick-start/introduction), browse the [examples](https://github.com/bevyengine/bevy/tree/latest/examples), and read the [API docs](https://docs.rs/bevy). For deployment, configuration, and architecture, see the companion **Bevy Admin Guide**.

---

_Generated June 2026 from bevyengine/bevy at 457b918. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
