bevy_rl
Library Listed
Build environments for reinforcement learning with bevy
- Downloads
- 33
- Dependents
- 1
- Stars
- 104
- Forks
- 3
- Contributors
- 1
- Commits
- 97
- Latest release
- 0.17.0 Β·
About

Reinforcement Learning for Bevy Engine
Build Reinforcement Learning Gym environments with Bevy engine to train AI agents that can learn from screen pixels or defined obeservation state.
πFeatures
- Set of APIs to implement OpenAI Gym interface, such as
reset,step,renderand associated simulator states - Multi-Agent support
- Rendering screen pixels to RAM buffer β for training agents with raw pixels
- REST API to control agents
π©βπ» Usage
1. Define Action and Obeservation Space
Observation space needs to be Serializable for REST API to work.
// Action space
#[derive(Default)]
pub struct Actions {
// actuator_signals: [f32; 3],
}
// Observation space
#[derive(Default, Serialize, Clone)]
pub struct Observations {
// agent_coords: [(f32, f32); 16],
}
2. Enable AI Gym Plugin
Width and height should exceed 256, otherwise wgpu will panic.
Read the full README
// Setup bevy_rl
let ai_gym_state = AIGymState::<Actions, State>::new(AIGymSettings {
width: u32, // Width and height of the screen
height: u32, // ...
num_agents: 1, // Number of agents β each will get a camera handle
render_to_buffer: false, // You can disable rendering to buffer
pause_interval: 0.01, // 100 Hz
..default()
});
app.insert_resource(ai_gym_state)
.add_plugins(AIGymPlugin::<Actions, Observations>::default());
2.1 (Optional) Enable Rendering to Buffer
If your environment wants to export raw pixels, you will need to attach a render target to each camera you want to export them from. Render targets are copied each frame from GPU memory to RAM buffers so that they can be accessed with REST API.
pub(crate) fn spawn_cameras(
ai_gym_state: Res<AIGymState<Actions, Observations>>,
) {
let mut ai_gym_state = ai_gym_state.lock().unwrap();
let ai_gym_settings = ai_gym_state.settings.clone();
for i in 0..ai_gym_settings.num_agents {
let render_image_handle = ai_gym_state.render_image_handles[i as usize].clone();
let render_target = RenderTarget::Image(render_image_handle);
let camera_bundle = Camera3dBundle {
camera: Camera {
target: render_target, // Render target is baked in bevy_rl and used to export pixels
priority: -1, // set to -1 to render at the firstmost pass
..default()
},
..default()
};
commands.spawn(camera_bundle);
}
}
4. Handle bevy_rl events
bevy_rl will communicate with your environment through events. Those events initiate from REST API or bevy_rl.SimulationPauseTimer that pauses the simulation with given interval (AIGymSettings.pause_interval).
| Event | Description | Usage |
|---|---|---|
EventReset | Reset environment to initial state | You should rebuild your evnironment here |
EventControl | Switch to control state | You should recieve actions here and apply them to your environment (and resume simulation) |
EventPause | Pause environment execution | Pause physics engine or game clock and take snapshot of your game state |
Here's example of how to handle those events:
// EventPauseResume
fn bevy_rl_pause_request(
mut pause_event_reader: EventReader<EventPauseResume>,
ai_gym_state: Res<AIGymState<Actions, State>>,
) {
for _ in pause_event_reader.iter() {
// Pause simulation (physics engine)
// ...
// Collect state into serializable struct
let env_state = Observations(...);
// Set bevy_rl gym state
let mut ai_gym_state = ai_gym_state.lock().unwrap();
ai_gym_state.set_env_state(env_state);
}
}
// EventControl
fn bevy_rl_control_request(
mut pause_event_reader: EventReader<EventControl>,
mut simulation_state: ResMut<State<SimulationState>>,
) {
for control in pause_event_reader.iter() {
let unparsed_actions = &control.0;
for i in 0..unparsed_actions.len() {
if let Some(unparsed_action) = unparsed_actions[i].clone() {
let action: Vec<f64> = serde_json::from_str(&unparsed_action).unwrap();
// Pass control inputs to your agents
// ...
}
}
// Resume simulation (physics engine)
// ...
// Return to running state; note that it uses pop/push to avoid
// entering `SystemSet::on_enter(SimulationState::Running)` which initialized game world anew
simulation_state.pop().unwrap();
}
}
/// Handle bevy_rl::EventReset
pub(crate) fn bevy_rl_reset_request(
mut reset_event_reader: EventReader<EventReset>,
mut commands: Commands,
mut walls: Query<Entity, &Wall>,
mut players: Query<(Entity, &Actor)>,
mut simulation_state: ResMut<State<SimulationState>>,
ai_gym_state: Res<AIGymState<Actions, Observations>>,
) {
if reset_event_reader.iter().count() == 0 {
return;
}
// Reset envrionment state here
// Return simulation in Running state
simulation_state.set(SimulationState::Running).unwrap();
// tell bevy_rl that environment is reset and return response to REST API
let ai_gym_state = ai_gym_state.lock().unwrap();
ai_gym_state.send_reset_result(true);
}
Register systems to handle bevy_rl events.
app.add_systems(
Update,
(
.with_system(bevy_rl_control_request)
.with_system(bevy_rl_reset_request)
.with_system(bevy_rl_pause_request),
).in_set(SimulationState::PausedForControl)
);
π» AIGymState API
Those methods are available on AIGymState resource. You should use them to alter bevy_rl internal state.
| Method | Description | Usage |
|---|---|---|
set_reward(agent_index: usize, score: f32) | Set reward for an agent | When a certain event happens, you can set reward for an agent. |
set_terminated(agent_index: usize, result: bool) | Set termination status for an agent | Once your agent is killed, you should set it's status to true. Useful for Multi-agent. |
reset() | Reset bevy_rl state | You should call this method when you reset your environment to clear exported state history |
set_env_state(state: State) | Set current environment state | When you serialize your environment state, you should set it here. |
send_reset_result(result: bool) | Send reset result to REST API | You should call this method when you have reset your environment to sychronize with REST API |
π REST API
Accessing bevy_rl-enabled environment is possible through REST API. Here's a list of available endpoints:
| Method | Verb | bevy_rl version |
|---|---|---|
| Camera Pixels | GET | http://localhost:7878/visual_observations |
| State | GET | http://localhost:7878/state |
| Reset Environment | GET | http://localhost:7878/reset |
| Step | GET | http://localhost:7878/step?payload=ACTION |
bevy_rl_shooter implements an example Python wrapper.
βοΈ Examples
- bevy_rl_shooter β example FPS project
- bevy_quadruped_neural_control β quadruped locomotion with bevy_mujoco and bevy_rl
Compatibility
- Runs on
- WebGPU
What shows it
- WebGPU: bevy_rl dependency wgpu
- Native code
- None found
- No native code found
- Python bindings
- No Python binding crate found
- License
- Apache-2.0 OR MIT
Compare with similar projects
Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.
| Project | Downloads | Dependents | Stars | Latest release | Runs on (GPU) | Native code | License |
|---|---|---|---|---|---|---|---|
|
Build environments for reinforcement learning with bevy |
33 downloads over 30 days | 1 | 104 | 0.17.0 | WebGPU | No native code found | Apache-2.0 OR MIT |
|
nexar Listed
Distributed runtime that replaces MPI between nodes: point-to-point messages, 11 collectives and RPC over QUIC, with no mpirun or MPI library. |
1,191 downloads over 30 days | 5 | 5 | 0.2.1 | CUDA | Binds native code: ring. Build uses a native toolchain: bindgen, pkg-config | Apache-2.0 |
|
Flexible, reusable reinforcement learning (Q learning) implementation |
150 downloads over 30 days | 0 | 165 | 0.6.0 | GPU support unknown | No native code found | MPL-2.0 |
|
A fast, extensible reinforcement learning framework in Rust |
80 downloads over 30 days | 0 | 204 | 0.8.1 | GPU support unknown | Binds native code: lapack-sys | MIT |
|
Open AI environments bindings for Rust |
75 downloads over 30 days | 2 | 70 | 2.2.1 | GPU support unknown | No native code found | Apache-2.0 OR MIT |
|
Rust implementation of real-coded genetic algorithm for solving optimization problems and training of neural networks. The latter is also known as neuroevolution. |
9 downloads over 30 days | 0 | 20 | 0.2.1 | GPU support unknown | No native code found | GPL-3.0 |
|
Reinforcement learning library written in Rust |
Not measured | Not applicable | 24 | Not measured | Not measured | Not measured | None stated |
Why ListedNo archive, New or Featured rule places it, so it is Listed.
What it lacks for Featured
- It has 0 active dependents and 0 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days. The repository route reads 104 stars, 3 forks and 1 contributor. It needs 4,539 stars, 434 forks and 79 contributors together.
What else the check found
- The last activity is on 22 Jun 2026, 140 days ago. The rules expect an update within 365 days. Dormancy rule
Exact rules: Listed, Featured library. The check on applied thresholds version 9.
Every rule outcome, as the check records it
expected-interval: version 0.17.0 base 140, raised to the 365-day floor: E = 365 daysdormancy: last activity 2026-06-22, 140 days ago, E = 365: activefeatured: not featured: active_users 0 < 11 and new_adopters 0 < 9 and repository route stars 104 (needs 4539), forks 3 (needs 434), contributors 1 (needs 79)listed: listed: no archive, new or featured rule applies
Measurements and sources
Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.
Sources6 sources
- Description: the crates.io description
- crates.io database dump, fetched
- RustSec advisory database, fetched
- GitHub repository, fetched
- crates.io package, fetched
- GitHub contributors, fetched
Adoption0 active dependents, 0 new dependents in 365 days1 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Active dependents | 0 | crates.io database dump | Yes | |
| New dependents (365 days) | 0 | crates.io database dump | Yes | |
| Peak active dependents | 0 | crates.io database dump | Yes | |
| Active dependents as a share of the peak | 1 | crates.io database dump | Yes | |
| Binary downloads per release | Not measured | Yes |
MaintenanceLatest human commit: 4 months ago3 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Latest human commit | 2026-06-22 | GitHub repository | Yes | |
| Latest release | 2026-06-22 | crates.io database dump | Yes | |
| First release | 2022-04-25 | crates.io database dump | Yes | |
| Latest version | 0.17.0 | crates.io database dump | Yes | |
| Days the oldest outside issue waits for a reply | 0 | GitHub repository | Yes | |
| Maintainer replies over 365 days | 0 | GitHub repository | Yes | |
| Repository archived | false | GitHub repository | Yes | |
| Repository gone | false | GitHub repository | Yes | |
| Release commit or manifest in the repo | true | crates.io package | Yes | |
| Published docs | true | crates.io database dump | Yes | |
| Latest release fails cargo check | Not measured | Yes | ||
| Build check date | Not measured | Yes | ||
| Build check toolchain | Not measured | Yes |
SecurityUnpatched vulnerabilities: none
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Unpatched vulnerabilities past the grace window | none | RustSec advisory database | Yes | |
| RustSec unmaintained advisory | none | RustSec advisory database | Yes | |
| Deprecation notice | none | crates.io database dump | Yes | |
| Deprecated requirement | none | crates.io database dump | Yes |
Distribution36 releases, 33 downloads over 30 days5 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Releases | 36 | crates.io database dump | Yes | |
| Downloads over 30 days | 33 | crates.io database dump | Yes | |
| Binary downloads over the last 3 releases | Not measured | Yes | ||
| Homebrew installs on request over 365 days | Not measured | Yes | ||
| Repology repository families | Not measured | Yes | ||
| Docker pull growth over 90 days | Not measured | Yes | ||
| Docker pulls at the growth baseline | Not measured | Yes | ||
| Every version a prerelease | false | crates.io database dump | Yes | |
| Every version 0.0.x | false | crates.io database dump | Yes | |
| Every version yanked | false | crates.io database dump | Yes | |
| Crate deleted from crates.io | false | crates.io database dump | Yes |
Repository104 stars, 3 forks, 1 contributors, 97 commits. Stars alone never qualify a project.
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| GitHub stars | 104 | GitHub repository | Yes β one part of the repository route | |
| GitHub forks | 3 | GitHub repository | Yes β one part of the repository route | |
| Contributors with a GitHub account | 1 | GitHub contributors | Yes β one part of the repository route | |
| Commits on the default branch | 97 | GitHub repository | No | |
| Repository's main crate left out of the entry | none | crates.io database dump | Yes |
Facts that never count
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| License | Apache-2.0 OR MIT | crates.io database dump | No | |
| Runs on, from listed crates and their direct dependencies | WebGPU | crates.io database dump | No | |
| What shows each backend | WebGPU: bevy_rl dependency wgpu | crates.io database dump | No | |
| Native code, from listed crates and their dependencies | No native code found | crates.io database dump | No | |
| Python bindings, from direct dependencies of listed crates | No Python binding crate found | crates.io database dump | No | |
| Crates that depend on a listed crate directly | 1 | crates.io database dump | No |
Corrections and review history
No correction applies to this entry.
Judgments
A judgment enters only through an approved issue and a merged pull request.
No judgment applies to this entry.