Open-source project
djeedai/bevy_hanabi avatar
djeedai/bevy_hanabi

Hanabi moves Bevy particle simulation onto the GPU

🎆 Hanabi — a GPU particle system plugin for the Bevy game engine.

1,430 stars130 forksRustApache-2.0

At a glance

What is it?
bevy_hanabi is a particle system plugin for the Bevy engine that runs the simulation in compute shaders and keeps the CPU out of the per particle work. It is honest about being under heavy development, with an explicit list of unimplemented features and a WebAssembly path that works only through WebGPU.
Who is it for?
Hanabi suits a Bevy developer who needs moderate-size effects and is comfortable writing effect descriptions in Rust rather than in an editor, and it suits a team willing to accept an API that is still moving.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A particle system whose simulation lives on the GPU

Hanabi is a plugin that gives the Bevy game engine a modern, GPU based particle system. The stated design goal is scale: producing visual effects in real time by offloading most of the work to the GPU with minimal CPU intervention, and the design is described as inspired by the particle systems found in other industry leading game engines.

That last clause is the interesting one for an engine user. A particle system written with the CPU in the loop spends its budget per particle per frame, which means the effect size and the frame rate are in direct competition. Moving the simulation into compute shaders changes that relationship, and the compute shader requirement is the price: the plugin makes heavy use of compute shaders to do the work in a performant way.

The audience is a Bevy developer building real time effects, and the plugin fits the Bevy model closely. It is a plugin added to the app, effects are assets, and effects are instantiated in the world as entities, so the mental model is the same as for any other Bevy subsystem rather than a separate engine bolted on.

The project states its own maturity plainly. It is under heavy development and is currently lacking both features and performance and usability polish, but for moderate size effects it can already be used in a project, and feedback and contributions on both design and features are welcome. That sentence is the honest summary to carry into an evaluation, and the feature list in the documentation is written in the same spirit, with checked and unchecked boxes side by side.

An effect is a set of modifiers over particle attributes

The API is built around a small set of ideas that are worth understanding before writing any code.

An EffectAsset describes a visual effect. It has a maximum number of particles alive at a time, a spawner setting that defines the rate at which particles are created, and a sequence of modifiers applied at different stages. The modifiers come in three families in the documented feature list: initialisation, which sets the starting position, velocity, color, size, age and lifetime of a particle; update, which integrates motion, applies forces and accelerations, and can carry a simulation condition such as always running even when hidden or only running when visible; and render, which draws the particle with things like a color gradient over its lifetime.

The building blocks are shapes rather than raw coordinates. A SetPositionSphereModifier places a particle over the surface of a sphere of a given radius, and a SetVelocitySphereModifier gives it a radial speed away from a centre, so an effect is described in terms of shapes and rates rather than arithmetic. SetAttributeModifier sets an attribute such as the lifetime, and AccelModifier applies an acceleration, which in the example is a constant downward pull standing in for gravity.

Underneath, everything is an expression module. The example builds a Gradient with color keys, creates a Module, and writes literals into it with module.lit(). The documentation points at the Expressions API for going further, and says that effect authors can customise effects by assigning individual particle attributes such as position and color. That is the escape hatch that makes the modifier set sufficient rather than limiting: a modifier covers the common case, and the expression module covers everything else without changing the plugin.

Adding the plugin, the dependency and the first effect

The dependency goes into Cargo.toml, and the version in the documentation matches the Bevy generation it targets:

toml
[dependencies]
bevy_hanabi = "0.19"

The plugin is then added to the app alongside Bevy's own default plugins:

rust
use bevy_hanabi::prelude::*;

App::default()
    .add_plugins(DefaultPlugins)
    .add_plugins(HanabiPlugin)
    .run();

Creating an effect starts from the asset system, and the modifiers are set up as the example does, first a position over a sphere surface:

rust
  let init_pos = SetPositionSphereModifier {
      center: module.lit(Vec3::ZERO),
      radius: module.lit(2.),
      dimension: ShapeDimension::Surface,
  };

The effect asset is then created with a particle budget, a spawn rate and the expression module, and the modifiers are chained onto it:

rust
  let effect = EffectAsset::new(
    // Maximum number of particles alive at a time
    1024,
    // Spawn at a rate of 5 particles per second
    SpawnerSettings::rate(5.0.into()),
    // Move the expression module into the asset
    module
  )
  .with_name("MyEffect")

The asset is inserted into the asset system, and the effect is instantiated in the world as an entity with a ParticleEffect component and a transform:

rust
commands.spawn((
    ParticleEffect::new(effect_handle),
    Transform::from_translation(Vec3::Y),
));

That last step is the part that makes the design fit Bevy. The effect asset is data, and many entities can reference the same handle, so a firework or a fountain is spawned by adding a component, not by allocating particles.

The feature list shows exactly which boxes are unticked

The documented feature list is unusual and useful, because it is a checklist with the gaps left visible.

On the spawn side, everything is implemented: constant rate, one time burst, repeated burst, spawner resetting, spawner activation and deactivation, and randomised spawning parameters. On initialisation, the implemented items cover constant position, position over a circle, sphere and cone or truncated cone in 3D, random position offset, velocity over a circle, sphere and tangent with random speed, and constant or random per particle color, size, age and lifetime.

The gaps are marked too. Cube and plane shapes are unchecked, and generic mesh or point cloud initialisation is unchecked and marked with a question. So a developer who needs particles to start on a specific mesh, which is a common requirement for a hit effect aligned to a surface, will find that shape missing and will have to place particles another way.

The update section shows the same mix. Simulation conditions are implemented, including always running even when the effect is hidden and only running when visible, motion integration with Euler is implemented, and the force list covers constant acceleration for gravity, radial acceleration, tangential acceleration and a force field.

The design intent behind the list is stated at the top: it contains the major fixed features, and beyond that the Expressions API lets authors customise effects further by assigning individual particle attributes. So the checklist is a map of the shortcuts, not of the limits, and the honest reading is that a routine effect is a few lines of modifiers while an unusual one becomes a small piece of expression code.

WebAssembly works, but only through WebGPU

Hanabi can run in a browser, and the support has a precise shape that you need to know before you plan a web build. Support for compute shaders on the wasm target is available as of v0.13, corresponding to Bevy 0.14, and it works only through WebGPU.

That is the whole of the constraint. WebGPU is the graphics and compute API that browsers expose to WebAssembly, and it is not universally available, so an effect that runs on a desktop GPU through wgpu may not run in a browser on a machine without a WebGPU capable browser or GPU. For a project with a web version, that is a deployment decision rather than a technical detail.

The repository makes the web path easy to inspect. The examples/wasm/ folder holds a web demo built on the WebAssembly target that shows all the examples, and you can open index.html in any browser to see a GIF of all of them. Running the actual WebAssembly example requires serving the files with an HTTP server, and the documentation suggests doing that with NodeJS installed by running:

bash
npx http-server examples/wasm

There is a platform note for Linux users as well. The examples build with the bevy/x11 feature by default to enable support for the X11 display server, and if you want to use the Wayland display server instead you add the bevy/wayland feature. That is a small thing that costs an afternoon if you do not know it, which is why it is worth reading before building the examples on a modern desktop.

Bevy version tracking, a dev manifest and no tagged releases

The plugin's compatibility with Bevy is the maintenance question that matters most, and the project documents it directly. The plugin is compatible with Bevy versions of 0.6 and later, and the tracking badge points at the Bevy plugin guidelines for tracking the main branch, with the current badge reading Bevy tracking v0.19. The example dependency in the documentation pins bevy_hanabi to 0.19, which is the version aligned with that Bevy generation.

Inside the repository, the manifest is ahead of the published crate. The package version is 0.20.0-dev, so the main branch carries the next version as a development build, with the rust-version set to 1.95.0 and the edition at 2021. The published crate on crates.io and the documentation on docs.rs are what a project should depend on, and the branch is where the next breaking change will land first.

The GitHub repository has no tagged releases, so there is no release history to browse there; the version numbers live in the crate and in the changelog file at the repository root. The last push was on 2026-10-15, and the repository is not archived, so work is landing.

Two build level details say something about how the project is engineered. The default feature set is 2d, 3d and gpu_tests, and the comment on the gpu_tests feature explains that it enables GPU based tests, which otherwise fail on a CI machine without a graphic adapter or without proper drivers. The trace feature enables tracing annotations and is disabled by default for performance. The dependency list pins wgpu to the same versions as Bevy 0.19 for bevy_render, which is the kind of alignment that has to be maintained by hand on every Bevy upgrade and is the main recurring maintenance task behind a Bevy plugin.

The licence is dual: the badge and the manifest both say MIT or Apache 2.0, with LICENSE-MIT and LICENSE-APACHE2 files in the repository, while the licence field on the GitHub page lists Apache-2.0. Either way the obligations are the standard permissive ones.

Editorial conclusion

Hanabi suits a Bevy developer who needs moderate-size effects and is comfortable writing effect descriptions in Rust rather than in an editor, and it suits a team willing to accept an API that is still moving. It is the wrong choice if you need a stable, feature complete particle system today, because the project states it is under heavy development and lacking features and polish, and a poor match if your target platform is the web, because WebAssembly support works only through WebGPU. Before adopting, pin the plugin version that matches your Bevy version, check which spawn shapes and render modes are still unchecked in the feature list, and confirm the renderer you ship with supports the compute shader path.

Frequently asked questions

How do I add the Bevy Hanabi particle plugin to a project?

Add bevy_hanabi = "0.19" to the dependencies in Cargo.toml, add HanabiPlugin to the app next to Bevy's DefaultPlugins, then create an EffectAsset describing the effect and spawn an entity with ParticleEffect::new(effect_handle) to instance it.

Does the Hanabi particle system support WebAssembly?

Yes, since v0.13 corresponding to Bevy 0.14, but only through WebGPU. The repository includes a web demo in the examples/wasm folder, and running it needs the files served over HTTP, for example with npx http-server examples/wasm.

Which Bevy versions does Hanabi support?

The plugin is compatible with Bevy versions of 0.6 and later, with the current tracking badge at Bevy v0.19 and the documented dependency pinned to bevy_hanabi 0.19. The repository manifest is ahead of the published crate at version 0.20.0-dev.

What licence does bevy_hanabi use?

It is licensed MIT or Apache 2.0 at your option, with both licence files in the repository, although the licence field on the GitHub page lists Apache-2.0.

Official sources

  1. djeedai/bevy_hanabi on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/djeedai-bevy-hanabi.svg)](https://hysenlabs.com/projects/djeedai-bevy-hanabi)

Was this useful?