agentsclimarketplace

Bevy development

Skill MAHDTech/agent-skills/skills/game-development/bevy-development

Make AI Agents great again!

Install
npx -y skills add MAHDTech/agent-skills --skill bevy-development

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Expert guidance for building 2D and 3D games in Bevy 0.19, Rust's data-driven ECS game engine — components, systems, scheduling, states, queries, input, assets, messages, and performance. Use when writing or modernizing Bevy code, laying out ECS data and systems, scheduling or gating systems, handling input/assets/messages, or migrating off deprecated Bevy APIs like bundles, delta_seconds, EventReader, or Parent.

SKILL.md

8.8 KB, as published. Nobody here has run it

Bevy Game Engine Expert

Patterns for building high-performance, modular games with Bevy — the data-driven ECS game engine built in Rust.

Targets Bevy 0.19 (latest stable). Bevy moves fast and breaks APIs between releases; if a project pins an older version, verify against that version's docs before applying these snippets. The migration cheat sheet below covers the churn since ~0.14.

When to Use This Skill

  • Developing 2D or 3D games and simulations in Rust with Bevy.
  • Structuring ECS data layouts, writing queries, and designing systems.
  • Ordering, grouping, and scheduling systems (fixed timesteps, state transitions).
  • Handling input, asset loading, and message/event-driven communication.
  • Optimizing Bevy performance (parallel queries, sparse sets, change detection, batching).
  • Modernizing a stale Bevy codebase off deprecated APIs.

Reference Files

Load these for depth:

  • resources/auto/learn-migration-guides.md — Bevy migration guides and release notes.

Migration Cheat Sheet (older Bevy -> 0.19)

Old code you will meet in stale projects, and its current form:

Old (deprecated / removed)Current (0.19)
time.delta_seconds()time.delta_secs()
time.elapsed_seconds()time.elapsed_secs()
*Bundle typesrequired components (#[require(..)])
Camera2dBundle::default()Camera2d
SpriteBundle { .. }Sprite::from_image(handle)
SpatialBundle::default()(Transform::default(), Visibility::default())
Parent componentChildOf (read via child_of.parent())
despawn_recursive()despawn()
Query::single() panicssingle() returns Result
EventReader / EventWriterMessageReader / MessageWriter
#[derive(Event)] (buffered)#[derive(Message)]
App::add_event / .send()App::add_message / .write()
Trigger<E> (observers)On<E>
Input<T>ButtonInput<T>

1. ECS Fundamentals

Components are plain data structs; systems are functions; resources are global singletons. Use required components for default setups, child-parent relationships for hierarchy, and query filters for optimizing storage access.

use bevy::prelude::*;

#[derive(Component, Reflect, Default)]
#[reflect(Component)]
pub struct Health {
    pub current: f32,
    pub max: f32,
}

#[derive(Component, Default)]
pub struct Player; // marker (ZST) for filtering queries

fn movement_system(
    time: Res<Time>,
    mut query: Query<(&mut Transform, &Velocity), With<Player>>,
) {
    for (mut transform, velocity) in &mut query {
        // delta_secs() — renamed from delta_seconds() in 0.16.
        transform.translation += velocity.0.extend(0.0) * time.delta_secs();
    }
}

2. App & Plugin Structure

Split game logic into plugins to decouple features and keep incremental compiles fast.

use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins) // windowing, rendering, input, ...
        .add_plugins(PlayerPlugin)
        .init_resource::<GameScore>()
        .add_systems(Startup, setup_camera)
        .add_systems(Update, score_display_system)
        .run();
}

fn setup_camera(mut commands: Commands) {
    commands.spawn(Camera2d); // was Camera2dBundle::default()
}

pub struct PlayerPlugin;

impl Plugin for PlayerPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(Startup, spawn_player)
            .add_systems(Update, movement_system);
    }
}

3. Scheduling & Ordering

Systems run in parallel unless their accesses conflict. Add ordering only for real data dependencies. Use system sets, states, and run conditions to organize and gate systems.

// Sequential chain.
app.add_systems(Update, (read_input, apply_movement, check_collisions).chain());

// Gate on state or resource presence.
app.add_systems(Update, gameplay.run_if(in_state(GameState::Playing)));

// Deterministic simulation at a fixed rate (default 64 Hz).
app.insert_resource(Time::<Fixed>::from_hz(64.0));
app.add_systems(FixedUpdate, physics_step);

4. Queries & Change Detection

Filter with With / Without; react to changes with Changed<T> / Added<T>. Use ParamSet to resolve system query conflicts, and Ref<T> to inspect component metadata and change ticks.

fn enemy_targeting(
    mut attackers: Query<&mut Target, With<Enemy>>,
    targets: Query<&Transform, (With<Player>, Without<Dead>)>,
) { /* only alive players */ }

fn on_transform_change(query: Query<&Transform, Changed<Transform>>) {
    for _transform in &query { /* only entities whose Transform changed */ }
}

Read input via ButtonInput<T>; load assets via AssetServer; use messages (buffered events, renamed from EventReader/EventWriter in 0.17) for decoupled communication. Use observer events for immediate reaction to trigger events.

fn player_input(keyboard: Res<ButtonInput<KeyCode>>) {
    if keyboard.just_pressed(KeyCode::Space) { /* jump */ }
}

fn load_assets(mut commands: Commands, asset_server: Res<AssetServer>) {
    let texture: Handle<Image> = asset_server.load("sprites/player.png");
    commands.spawn(Sprite::from_image(texture)); // was SpriteBundle
}

#[derive(Message)] // was #[derive(Event)] for buffered events
struct Scored(u32);

5. Performance Patterns

  • Parallel iteration: for large independent workloads, use par_iter_mut().
  • SparseSet storage: for frequently added/removed components (buffs, statuses) — use #[component(storage = "SparseSet")] to optimize storage access patterns.
  • Batch spawning: commands.spawn_batch(..) beats a loop of individual spawn calls.
  • Change filters: put Changed<T> on reactive systems (UI, animation) to skip stable data.
fn parallel_update(mut query: Query<(&mut Transform, &Velocity)>) {
    query.par_iter_mut().for_each(|(mut transform, velocity)| {
        transform.translation += velocity.0.extend(0.0);
    });
}

6. Developer Commands

# Fast iterative dev builds via dynamic linking (much faster incremental compiles).
cargo run --features bevy/dynamic_linking

# Optimized build.
cargo run --release
TaskCommand
Check for compile errorscargo check 2>&1 | head -30
List component definitionsgrep -rn "derive(Component)" src/ --include="*.rs"
Find systems using queriesgrep -rn "fn.*Query<" src/ --include="*.rs"
Identify state machine declarationsgrep -rn "derive.*States" src/ --include="*.rs"
Spot system ordering hooksgrep -rn "\.add_systems|\.chain()|\.after(|\.before(" src/ --include="*.rs"
Find deprecated bundle usagegrep -rn "Bundle" src/ --include="*.rs"
Find deprecated Time callsgrep -rn "delta_seconds|elapsed_seconds" src/ --include="*.rs"

7. Best Practices

  • Do: access singletons with Res<T> rather than ResMut<T> unless you mutate — read-only access lets the scheduler run more systems concurrently.
  • Do: use marker components / ZSTs to filter queries cheaply.
  • Do: apply Changed<T> to reactive systems (UI updates, animation) to skip stable data.
  • Do: prefer required components over reintroducing bundle-shaped wrapper structs.
  • Don't: run heavy nested loops over >1,000 entities without par_iter_mut() or a cached query.
  • Don't: poll asset-loaded checks inside gameplay frames — gate them behind a loading state.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.